在学习了 DIRECTX.9.0.3D游戏开发编程基础 一书 前4章后,终于写了一个简单dome,将前4章内容进行了整合。
此dome主要涉及坐标转换、正交投影矩阵、DrawPrimitive、SetRenderState 等知识点。现将主要代码进行讲解。
1、初始化DirectX3D组件
bool UIMain::InitD3d(HINSTANCE hInst, int width, int height)
{
m_hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 100, 100, width, height,
NULL, NULL, m_wc.hInstance, NULL );
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return false;
}
ShowWindow( m_hWnd, SW_SHOWDEFAULT );
UpdateWindow( m_hWnd );
return true;
}
2、顶点数据初始化
struct Vertex //顶点数据
{
Vertex() {};
Vertex(float _x, float _y, float _z, D3DCOLOR _color)
{
x = _x;
y = _y;
z = _z;
color = _color;
}
float x, y, z;
DWORD color;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ |D3DFVF_DIFFUSE;
bool DrawPrimitiveDlg::InitData()
{
if( FAILED( g_pd3dDevice->CreateVertexBuffer( PointNum * sizeof(Vertex),
D3DUSAGE_WRITEONLY, Vertex::FVF,
D3DPOOL_DEFAULT, &m_VB, NULL ) ) )
{
return false;
}
Vertex* vertices = NULL;
m_VB->Lock(0,0,(void**) &vertices, 0);
vertices[0] = Vertex(-1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0)); //一个正方形
vertices[1] = Vertex(-1.0f, 1.0f, 0.0f, D3DCOLOR_XRGB( 0, 255, 0));
vertices[2] = Vertex( 1.0f, 1.0f, 0.0f, D3DCOLOR_XRGB( 0, 0, 255));
vertices[3] = Vertex(1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0));
vertices[4] = Vertex(0.0f, 0.0f, 0.0f, D3DCOLOR_XRGB( 0, 255, 0));
vertices[5] = Vertex(0.0f, -1.0f, 0.0f, D3DCOLOR_XRGB( 0, 0, 255));
m_VB->Unlock();
return true;
}
3、绘制函数
利用D3DXMatrixTransformation函数获取了 平移+旋转的 转换矩阵。并用D3DXMatrixOrthoLH函数获取了正交投影矩阵。
分别绘制了直线(D3DPT_LINELIST)、折线(D3DPT_LINESTRIP)、孤立三角新(D3DPT_TRIANGLELIST)、三角形条带(D3DPT_TRIANGLESTRIP)、三角形扇形(D3DPT_TRIANGLEFAN)。
代码中的注释已经相当详细,不用过多解释。
void DrawPrimitiveDlg::Render()
{
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET , D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
D3DXMATRIXA16 matWorld;
UINT iTime = timeGetTime() % 1000;
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f; //旋转角度
D3DXMatrixRotationY( &matWorld, fAngle );
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false); //关闭光照
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); //完全禁用背面消隐
D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-10.0f ); //相机位置
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); //相机 观察中心点
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); //相机 向上视角点,一般都设此值
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); //设置相机坐标 及 视角
D3DXMATRIXA16 matProj;
//透视投影矩阵的计算,本dome不需要
/* D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2, 1024.0f/768.0f, 2.0f, 100.0f );*/
//正交投影 矩阵计算 14, 14, 我需要绘制的在世界坐标系中,x的取值范围(-6, 6)
D3DXMatrixOrthoLH(&matProj, 14, 14, 0.1f, 1000.0f);
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); //设置投影变化
g_pd3dDevice->SetStreamSource( 0, m_VB, 0, sizeof(Vertex) ); //将顶点数据 注册
g_pd3dDevice->SetFVF( Vertex::FVF ); //设置顶点数据格式
D3DXMATRIXA16 m_worldMatrix;
/* D3DXMatrixTranslation(&m_worldMatrix, -5.0f, 0.0f, 0.0f); */ //平移矩阵这里不需要用
//四元数 Q = [cos(O/2) sin(O/2)N] = [ cos(O/2) ( sin(O/2)Nx sin(O/2)Ny sin(O/2)Nz ) ]
D3DXQUATERNION angle;
angle.x = 0;
angle.y = sin(fAngle/2.0);
angle.z = 0;
angle.w = cos(fAngle/2.0);
//孤立 直线的绘制
D3DXVECTOR3 pinyi(-5.0f, 0.0f, 0.0f);
//不能用 旋转矩阵(D3DXMatrixRotationY) * 平移矩阵(D3DXMatrixTranslation) 获取转换矩阵
// 这样算的矩阵会绕 y轴选择, 可以试试D3DXMatrixRotationAxis 函数
// D3DXMatrixTranslation(&m_worldMatrix, -2.5f, 0.0f, 0.0f);
// D3DXMatrixRotationY( &m_worldMatrix, fAngle );
//根据平移向量 和 四元数(旋转) 计算转换矩阵
D3DXMatrixTransformation(&m_worldMatrix, NULL, NULL, NULL, NULL, &angle, &pinyi);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix); //将物品坐标系映射到世界坐标系
//D3DPT_LINELIST 将顶点作为孤立的直线段列表 绘制孤立直线 3(6个点 3条线)
g_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, 3 ); //比如ABCDEF, 分别会画出:AB CD EF 三条线
//折线 的绘制
pinyi.x = -2.5f;
D3DXMatrixTransformation(&m_worldMatrix, NULL, NULL, NULL, NULL, &angle, &pinyi);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);
//D3DPT_TRIANGLELIST 将顶点作为单个折线呈现 将多个点连接成折线 5(6个点 依次连接成 5条线)
g_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, 5 ); //比如ABCDEF, 分别会连接:AB BC CD DE EF 线段
//孤立三角形的绘制
pinyi.x = 0.0f;
D3DXMatrixTransformation(&m_worldMatrix, NULL, NULL, NULL, NULL, &angle, &pinyi);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //平面着色,即以第一个顶点颜色绘制
//D3DPT_TRIANGLELIST 将指定顶点作为孤立三角形序列 每组三个顶点定义了一个独立的三角形 6个点 2个三角形
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);//比如ABCDEF, 分别会画出以下三角形:ABC DEF
//三角形条带 的绘制
pinyi.x = 2.5f;
D3DXMatrixTransformation(&m_worldMatrix, NULL, NULL, NULL, NULL, &angle, &pinyi);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); //渐变着色,根据顶点颜色渐变
//D3DPT_TRIANGLESTRIP 将顶点作为三角形条带 6个点 4个 三角形
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 4); //比如ABCD, 分别会画出以下三角形:ABC BCD
//三角形扇形 的绘制
pinyi.x = 5.0f;
D3DXMatrixTransformation(&m_worldMatrix, NULL, NULL, NULL, NULL, &angle, &pinyi);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
//D3DPT_TRIANGLEFAN 渲染顶点为三角形扇形 6个点 4个 三角形
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 4); //比如ABCD,分别会画出以下三角形:ABC ACD
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
4、展示