介绍:
世界中的不同空间有以下几个:世界坐标,视角坐标,局部坐标,屏幕坐标。
我们可以使用这些效果来创建一个空间中的摄像机。为了使用这些空间,我们要把他们放在一个常量缓冲里,然后把缓冲传入VX(Vertex Shader)用来改变物体的顶点坐标。
Local Space
局部坐标是一个物体的坐标,当我们创建一个物体的时候,这个物体就在坐标的中心。这样的话,更容易定义顶点。
如果要创建一片森林,如果不用局部坐标,我们就需要知道每棵树的坐标,现在这种情况下,我们只需要创建一棵树,然后对树进行复制,然后顶点平移(在VX中)就可以了。
View Space
视角空间是基于摄像机的空间。摄像机在(0, 0, 0),看向Z轴正半轴,上方向是Y轴,当世界坐标变换为摄像机坐标系的时候,我们就需要做平移,看起来是我们的摄像机在动,其实是世界在做反方向移动。
Projection Space
这个空间就是定义了一个摄像机的一个视锥体,当物体在里面的时候,就会被渲染,如果不在,就不会被看见(相当于人的视角)
要渲染。
这个空间变换主要有以下几个部分构成。
FOV (Field of view in radians), aspect ratio, near z-plane, and far z-plane.(远近平面是说,太近的物体看不到,太远的物体看不到)
FOV是说:FOV越大,远平面对于近平面的比率就越大。
Screen Space
这是渲染的最后一个空间。就是由后台缓存的像素的X,Y坐标来表示的。左上角是0,0。
(这个空间坐标变换不需要我们来做)
Transforming Spaces
把物体从一个坐标空间转换到另一个坐标空间(通过矩阵变换来实现,但是必须要按照顺序)
Constant Buffers
常量缓冲区就是effect file中的一个变量结构体。示例代码如下:
cbuffer cbPerObject
{
float4x4 WVP;
};
常量缓冲区应该按照调用的频次来区分,比如说按照每帧,每个场景,每个物体来调用。
比如说,WVP这个变量就是按照每个物体来区分的。
Global Declarations
申明一个D3D11的缓冲区,用来存储我们的变量。
然后定义变换矩阵和照相机的方向向量
XMMATRIX WVP;
XMMATRIX World;
XMMATRIX camView;
XMMATRIX camProjection;
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;
然后我们需要创建一个结构体,对应着effect file中的相同Buffer,(布局必须一致)
struct cbPerObject
{
XMMATRIX WVP;
};
cbPerObject cbPerObj;
记得释放缓冲!
cbPerObjectBuffer->Release();
Create the Constant Buffer in code
创建一个缓冲,这个缓冲保存了我们想要传到effect file中的变量信息。首先我们需要创建他的描述信息。
D3D11_BUFFER_DESC cbbd;
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerObject);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);
最终利用缓冲描述信息来创建缓冲。
Camera
创建camera的三个向量,向量中的第四个参数我们设置为0
camPosition = XMVectorSet( 0.0f, 0.0f, -0.5f, 0.0f );
camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
camUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
接着创建视角矩阵函数
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
创建投影矩阵
XMMATRIX XMMatrixPerspectiveFovLH
(
FLOAT FovAngleY,
FLOAT AspectRatio,
FLOAT NearZ,
FLOAT FarZ
)
四个参数的意义如下:
FovAngleY - The Field of View in radians along the y-axis. (在Y轴上的视角)
AspectRatio - The aspect ratio, usually Width/Height. (长宽比)
NearZ - A float describing the distance from the camera to the near z-plane.
FarZ - A float describing the distance from the camera to the far plane.
如果一个物体太远或者太近,那么都看不到。+
camProjection = XMMatrixPerspectiveFovLH( 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f);
最终创建世界变换矩阵。
世界矩阵是一个单位矩阵,这是物体自己的位置。然后创建WVP矩阵
World = XMMatrixIdentity();
WVP = World * camView * camProjection;
Update the Constant Buffer
接下来我们要把创建好的WVP传入effect file中(这一步很重要!)
首先要对矩阵进行转置,因为effect 文件中的矩阵和 code中的矩阵行和列都是反的
然后把矩阵赋值给结构体中的矩阵。然后用结构体更新代码中的常量缓冲区,使用了DeviceContext中的UpdateSource方法。
然后我们把VX中的常量缓冲区设置为上一步中的代码中的常量缓冲对象。(这样就完成了code到effect数据的传输)
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
Updated Vertex Buffer
我们只需要加一行代码,让顶点的坐标与变换矩阵相乘。
VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.Color = inColor;
return output;
}
这样的话,我们就已经有一个静态的摄像机,并且可以从摄像机来观察世界了。
做了一个简单的思维导图以供参考:
本节内容就到这里拉。
本节内容代码可以在我的Github找到,今天在宿舍,还没有上传代码,明天到了实验室再跑一下示例代码。
游戏开发路途遥远,但我相信只要坚持,总能到达彼岸!
如果我的文章对于你学习DirectX11有点帮助,欢迎评论给出建议,让我们一起学习进步!
———————— 小明 2018.11.30 22.04