日期:2014-05-17 浏览次数:20975 次
使用DirectX实际开发中,模型的形状不可能都是一成不变,只依靠移动摄像机去实现动画。这里用实时更新顶点缓冲的方式生成一个水波模型,最终效果类似向水面扔石子时出现的水波纹。有了上一篇建立好的模型,实现这个效果仅需要更改WaterModel类和Renderer类里m_water的相关调用。
首先更改WaterModel的头文件,添加模拟变量成员和临时缓冲区指针,并增加两个方法Disturb和Update,整个类代码如下:
class WaterModel { public: WaterModel(void); ~WaterModel(void); void Initialize(ID3D11Device* d3dDevice, int m, int n, float dx, float dt, float speed, float damping); void Render(ID3D11DeviceContext* d3dContext); void Disturb(int i, int j, float magnitude); void Update(ID3D11DeviceContext* d3dContext, float dt); private: Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer; Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer; uint32 m_vertexCount,m_indexCount; //二维网格的行数、列数 int xRange; int zRange; // 欲计算的模拟常量. float mK1; float mK2; float mK3; float mTimeStep; float mSpatialStep; //顶点临时缓冲 XMFLOAT3* mPrevSolution; XMFLOAT3* mCurrSolution; };
完成后就开始更改WaterModel的构造方法,使用初始化列表初始化成员:
WaterModel::WaterModel(void): m_indexCount(0),m_vertexCount(0), mK1(0.0f),mK2(0.0f), mK3(0.0f), mTimeStep(0.0f),mSpatialStep(0.0f), mPrevSolution(0),mCurrSolution(0), xRange(128),zRange(128) { }
然后是更改Initialize方法。其中模拟常量等与算法有关的部分按照DirectX 10的例子进行计算,代码如下:
xRange = m; zRange = n; m_vertexCount = m*n; m_indexCount = (m-1)*(n-1)*2*3; mTimeStep = dt; mSpatialStep = dx; float d = damping*dt+2.0f; float e = (speed*speed)*(dt*dt)/(dx*dx); mK1 = (damping*dt-2.0f)/ d; mK2 =(4.0f-8.0f*e) / d; mK3 = (2.0f*e) / d;
接着要为临时缓冲区分配空间并初始化,假设静止时水面的y坐标均为零。
mPrevSolution = new XMFLOAT3[m*n]; mCurrSolution = new XMFLOAT3[m*n]; //生成水平面 for(int row=0;row<xRange; ++row) { float zPos = row*dx; for(int col=0;col<zRange; ++col) { float xPos = col*dx; mPrevSolution[xRange*row+ col] = XMFLOAT3(xPos, 0.0f, zPos); mCurrSolution[xRange*row+ col] = XMFLOAT3(xPos, 0.0f, zPos); } }
为了让顶点缓冲区能够动态更新,需要将Usage和CPUAccessFlags两个标志分别设置为D3D11_USAGE_DYNAMIC和D3D11_CPU_ACCESS_WRITE。另外,顶点缓冲区会在Update方法里填充,所以将CreateBuffer方法中代表数据源地址的第二个参数设为0。
D3D11_BUFFER_DESC vertexBufferDesc; vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; vertexBufferDesc.ByteWidth = sizeof(VertexPositionColor) * m_vertexCount; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; DX::ThrowIfFailed( d3dDevice->CreateBuffer( &vertexBufferDesc, 0, &m_vertexBuffer ) );
xRange与zRange现在不是常量,需要使用new的方式新建数组。
unsigned short* Indices = new unsigned short[3*2*(xRange-1)*(zRange-1)];
Indices现在是一个指针,不能用sizeof(Indices)来获得索引数组的大小,所以构造索引缓冲区的代码改为:
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(unsigned short) * m_indexCount, D3D11_BIND_INDEX_BUFFER);
在Initialize方法最后,删除Indices指向的索引数组,完成Initialize<