这一节我们学习如何用矩阵变换,对场景中的物体进行实时的变换。
DirectX中的变换,我们用xna数学库里的XMMATRIX类型。
XNA已经提供了构建相应矩阵的函数
XMMATRIX XMMatrixScaling
(
FLOAT ScaleX, // x=axis scale
FLOAT ScaleY, // y-axis scale
FLOAT ScaleZ // z-axis scale
)
缩放矩阵如下
[S1, 0, 0, 0]
S = [ 0,S2, 0, 0]
[ 0, 0,S3, 0]
[ 0, 0, 0, 1]
因为旋转矩阵有沿着三个不同坐标轴的旋转。
函数分别如下
//沿着X轴
[ 1, 0, 0, 0]
Rx = [ 0, cos(r),sin(r), 0]
[ 0,-sin(r),cos(r), 0]
[ 0, 0, 0, 1]
XMMATRIX XMMatrixRotationX(
FLOAT Angle //Rotation angle in radians
)
//沿着Y轴
[cos(r), 0,-sin(r), 0]
Ry = [ 0, 1, 0, 0]
[sin(r), 0, cos(r), 0]
[ 0, 0, 0, 1]
XMMATRIX XMMatrixRotationY(
FLOAT Angle //Rotation angle in radians
)
//沿着Z轴
[ cos(r),sin(r), 0, 0]
Rz = [-sin(r),cos(r), 0, 0]
[ 0, 0, 1, 0]
[ 0, 0, 0, 1]
XMMATRIX XMMatrixRotationZ(
FLOAT Angle //Rotation angle in radians
)
当我们想沿着一个特定的轴转动时可以调用函数:
XMMATRIX XMMatrixRotationAxis(
XMVECTOR Axis, //Vector describing the axis of rotation
FLOAT Angle //Rotation angle in radians
)
[ 1, 0, 0, 0]
T = [ 0, 1, 0, 0]
[ 0, 0, 1, 0]
[mx,my,mz, 1]
XMMATRIX XMMatrixTranslation(
FLOAT OffsetX, // Units translated on the x-axis
FLOAT OffsetY, // Units translated on the y-axis
FLOAT OffsetZ // Units translated on the z-axis
)
把不同的变换矩阵按照顺序相乘,(最先的变换在最右边)
为了实现变换,我们要先声明几个矩阵变量
XMMATRIX cube1World;
XMMATRIX cube2World;
XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;
因为我们现在要做旋转变换了,所以从现在开始,我们就开始绘制正方体
首先更改索引缓存大小
indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
一共6个面,每个面两个三角形
然后更改顶点缓存大小
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 8;
记得要把顶点数据也改掉!
然后更新上一节中设置的摄像机位置,这样视角会更好
camPosition = XMVectorSet( 0.0f, 3.0f, -8.0f, 0.0f );
接下来我们就在更新函数中,设定我们的旋转,平移,缩放矩阵,这里我们设置两个世界矩阵,因为要对两个正方体进行变换
void UpdateScene()
{
//Keep the cubes rotating
rot += .0005f;
if(rot > 6.28f)
rot = 0.0f;
//Reset cube1World
cube1World = XMMatrixIdentity();
//Define cube1's world space matrix
XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
Rotation = XMMatrixRotationAxis( rotaxis, rot);
Translation = XMMatrixTranslation( 0.0f, 0.0f, 4.0f );
//Set cube1's world space using the transformations
cube1World = Translation * Rotation;
//Reset cube2World
cube2World = XMMatrixIdentity();
//Define cube2's world space matrix
Rotation = XMMatrixRotationAxis( rotaxis, -rot);
Scale = XMMatrixScaling( 1.3f, 1.3f, 1.3f );
//Set cube2's world space matrix
cube2World = Rotation * Scale;
}
更新好矩阵之后我们就需要在渲染的时候把矩阵传输给EffectFile中的矩阵。
然后调用devicecontext中的drawindexed方法来绘图(以下的每个函数之前都有写过,这里不再赘述)
void DrawScene()
{
//Clear our backbuffer
float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);
//Refresh the Depth/Stencil view
d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);
///**************new**************
//Set the WVP matrix and send it to the constant buffer in effect file
WVP = cube1World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
//Draw the first cube
d3d11DevCon->DrawIndexed( 36, 0, 0 );
WVP = cube2World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
//Draw the second cube
d3d11DevCon->DrawIndexed( 36, 0, 0 );
///**************new**************
//Present the backbuffer to the screen
SwapChain->Present(0, 0);
}
这样我们就能看到一个完好的在世界中旋转的两个正方体。我们的场景终于动起来拉!
本节内容就到这里拉。
本节内容代码可以在我的Github找到,
游戏开发路途遥远,但我相信只要坚持,总能到达彼岸!
如果我的文章对于你学习DirectX11有点帮助,欢迎评论给出建议,让我们一起学习进步!
———————— 小明 2018.12.2 14.17