Draw3D就跟Programming.Role.Playing.Games.with.DirectX书上的源码不一样,书上的是之前的2D图片带上旋转。我将他改成Cube,还是老规则,左边的是用固定管线实现的,右边是用Shader实现的。右边的明暗变化不是很明显,其实效果是跟Draw2D一样的,因为PixelShader代码是一样的。只是没截好图。
代码是在之前Draw2D上改的,Cube是用36个顶点构成的,uv想了一会,没有用到索引缓存(IDirect3DIndexBuffer9),如果用索引缓存的话,8个顶点是可以的,但是uv坐标不对,导致有些面上是不正确的。
来看下渲染的代码:
固定管线:
void ModelClass::Render(IDirect3DDevice9* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
D3DXMATRIX xRotationMatrix, yRotationMatrix;
D3DXMATRIX translationMatrix;
// Rotation
::D3DXMatrixRotationX(&xRotationMatrix, D3DX_PI * 0.25f);
::D3DXMatrixRotationY(&yRotationMatrix, -(float)::timeGetTime() / 1000.0f);
// Translate
::D3DXMatrixTranslation(&translationMatrix, -2.0f, 0.0f, 0.0f);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &xRotationMatrix);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &yRotationMatrix);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translationMatrix);
device->SetTransform(D3DTS_WORLD, &worldMatrix);
device->SetTransform(D3DTS_VIEW, &viewMatrix);
device->SetTransform(D3DTS_PROJECTION, &projectionMatrix);
device->SetRenderState(D3DRS_LIGHTING, false);
device->SetTexture(0, m_texture->GetTexture());
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_vertexCount / 3);
device->SetTexture(0, nullptr);
}
在Draw2D代码上增加了变化矩阵,设置了3个矩阵:世界矩阵,观察矩阵,投影矩阵。世界矩阵,就是将模型从模型坐标转换到世界坐标中,可以根据缩放(Scale),旋转(Roation),平移(Translation)顺序来构成矩阵,算法就是世界矩阵=缩放矩阵*旋转矩阵*平移矩阵=缩放矩阵*x轴旋转矩阵*y轴旋转矩阵*z轴旋转矩阵*平移矩阵。
观察矩阵也可以通过上面的算法进行计算,但顺序是反正的,但是算起来有点累,可以通过dx自带的D3DXMatrixLookAtLH来计算,投影矩阵没什么好说的,就是将3D转换为2D,用dx自带的D3DXMatrixPerspectiveFovLH来计算。
接着就关闭灯光,用SetRenderState(D3DRS_LIGHTING, false),不然的话,你会看到全黑的Cube。
Shader渲染:
void ShaderModelClass::Render(IDirect3DDevice9* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
float time;
D3DXMATRIX xRotationMatrix, yRotationMatrix;
D3DXMATRIX translationMatrix;
bool result;
UINT passMaxNum;
time = (float)::timeGetTime() / 1000.0f;
// Rotation
::D3DXMatrixRotationX(&xRotationMatrix, D3DX_PI * 0.25f);
::D3DXMatrixRotationY(&yRotationMatrix, time);
// Translate
::D3DXMatrixTranslation(&translationMatrix, 2.0f, 0.0f, 0.0f);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &xRotationMatrix);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &yRotationMatrix);
::D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translationMatrix);
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
result = m_colorShader->Render(device, m_texture->GetTexture(), time, worldMatrix, viewMatrix, projectionMatrix);
if (!result)
return;
m_colorShader->GetEffect()->Begin(&passMaxNum, 0);
for (UINT pass = 0; pass < passMaxNum; ++pass)
{
m_colorShader->GetEffect()->BeginPass(pass);
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_vertexCount / 3);
m_colorShader->GetEffect()->EndPass();
}
m_colorShader->GetEffect()->End();
}
跟之前Draw2D上的也差不多,只是把3个矩阵:世界矩阵,观察矩阵,投影矩阵传入到Effect中,用于顶点着色器(VertexShader)阶段进行计算。
Shader:
texture modelTexture;
float time;
float4x4 worldMatrix;
float4x4 viewMatrix;
float4x4 projectionMatrix;
sampler ModelTextureSampler = sampler_state
{
Texture = <modelTexture>;
MipFilter = POINT;
MinFilter = POINT;
MagFilter = POINT;
//MipFilter = LINEAR;
//MinFilter = LINEAR;
//MagFilter = LINEAR;
//MipFilter = ANISOTROPIC;
//MinFilter = ANISOTROPIC;
//MagFilter = ANISOTROPIC;
};
struct VertexInputType
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct PixelInputType
{
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
};
PixelInputType ColorVertexShader(VertexInputType input)
{
PixelInputType output;
float4x4 worldViewMaxtrix = mul(worldMatrix, viewMatrix);
float4x4 worldViewProjectionMatrix = mul(worldViewMaxtrix, projectionMatrix);
output.pos = mul(input.vertex, worldViewProjectionMatrix);
output.texcoord = input.texcoord;
return output;
}
float4 ColorPixelShader(PixelInputType input) : COLOR
{
float param = max(0.5, cos(time));
float4 color = tex2D(ModelTextureSampler, input.texcoord) * param;
return color;
}
technique ColorTechnique
{
pass pass0
{
VertexShader = compile vs_2_0 ColorVertexShader();
PixelShader = compile ps_2_0 ColorPixelShader();
}
}
不同点就是标红的3句,就是将顶点从模型坐标转换到齐次裁剪空间。
源码下载:下载地址