前面三步已经实现了从普通Win32 SDK程序到D3D程序的转变, 并且对于设备的初始化和绘图框架也结合程序作了介绍. 接下来就要实现图形从静态到动态, 从平面到立体的变换.
第四步: 让图形动起来
在图形学中, 三维图形的绘制和运动是通过基本变换 (平移 (transition), 缩放 (Scaling), 旋转 (Rotation)) 的综合运用辅以时间控制实现. 前面我提到过, 几何变换在计算机中通过矩阵运算实现. 所以, 在这一步中, 矩阵是重头戏.
从几何学中的图形到进入人的视界的对象, 主要经过了三种变换: 世界变换 (World Transform), 摄像机变换 (Camera Transform), 投影变换 (Projection Transform), 在借助计算机实现时, 它们分别对象三种矩阵: World Metrix, View Metrix, Projection Metrix. 下面通过程序说明:
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"d3dx9.lib")
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#include
<MMSystem.h> // 时间函数
#include <d3d9.h> // 设备初始化及操作
#include <d3dx9.h> //
矩阵操作
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
//
函数: InitInstance(HINSTANCE, int)
//
//
目的: 保存实例句柄并创建主窗口
//
//
注释:
//
//
在此函数中,我们在全局变量中保存实例句柄并
//
创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int
nCmdShow)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
......
if (SUCCEEDED(InitD3D(hWnd)))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(SUCCEEDED(InitGeometry())) // 使用InitGeometry函数
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
}
}
return TRUE;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
BOOL InitD3D(HWND hWnd)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
......
// 卷起, 渲染三角形前面及后面
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 顶点具有颜色值, 起到光源作用
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
return S_OK;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
HRESULT InitGeometry()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
// 渲染三角形顶点
CUSTOMVERTEX vertices[] =
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{-1.0f, -1.0f, 0.0f, 0xffff0000}, // x, y, z, rhw
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{1.0f, -1.0f, 0.0f, 0xff00ff00},
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{0.0f, 1.0f, 0.0f, 0xff0000ff}
};
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 创建顶点缓冲
if(FAILED(g_pD3DDevice->CreateVertexBuffer(3 * sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
return E_FAIL;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 写入顶点缓冲
VOID *pVertices;
if(FAILED(g_pVB->Lock(0, sizeof(vertices), (void **)&pVertices, 0)))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
return E_FAIL;
}
memcpy(pVertices, vertices, sizeof(vertices));
g_pVB->Unlock();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
return S_OK;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
void
SetupMatrices()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
// 世界矩阵
D3DXMATRIXA16 matWorld;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
UINT iTime = timeGetTime() % 1000;
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
D3DXMatrixRotationY(&matWorld, fAngle); // 绕Y轴旋转
g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 视图矩阵
D3DXMATRIXA16 matView;
D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f); // 眼睛的位置
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); // 眼睛观察的位置
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); // 表现顶点方向的上方向量
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 投影矩阵
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
void
Render()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if(NULL == g_pD3DDevice)
return;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 清除后置缓冲区, 同时设置为蓝色 (0, 0, 255)
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 开始渲染
if(SUCCEEDED(g_pD3DDevice->BeginScene()))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
// 创建矩阵
SetupMatrices();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 绘制顶点缓冲三角形
// 绑定设备数据流
g_pD3DDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 指定顶点着色信息(FVF)
g_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 输出三角形
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 结束渲染
g_pD3DDevice->EndScene();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 显示后置缓冲的画面
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
1) 由于涉及对象的旋转, 因此, 对三角形的前后都需要渲染;
2) 设定三种矩阵.