看完二、三章,新的概念太多了,而且写过第一个例子之后回头再看第一章才能真正理解许多概念到底是什么意思,所以正确的方法应该是先粗略地读一下第一章,看完二三章再回头看第一章。这章概念是真的多,干脆直接把这些概念啊,函数啊放在实例里来说算了,方便理解。


先把DirectX绘图的大概思路捋一遍:

1.设置全局变数:包括 IDirect3DDevice9的实例*Device、屏幕的长(int width)和高(int height)、 是否窗口化(bool windowed)、顶点缓存的指针(IDirect3DVertexBuffer9 *vb)、引索缓存的指针(IDirect3DIndexBuffer9 *ib)等等,暂时用到这么多。

2.设置灵活顶点格式(P60):本质上定义一个Vertex的结构体,可以自己写成员类型,但注意还要定义一个FVF标记来描述顶点格式,可以在结构体外面或里面用DWORD定义,可以宏定义,可以用的时候直接写。(有很多种,用的时候翻文档吧)

3.setup()函数在本例中的功能:

(1)顶点缓存分配空间Device->CreateVertexBuffer():

HRESULT CreateVertexBuffer(
UINT Length, /*分配顶点的位元组数 (X * sizeof(Vertex)) */
DWORD Usage, /*附加属性P74*/
DWORD FVF, /*灵活顶点格式*/
D3DPOOL Pool, /*内存池 每种特性不一样 P42*/
IDirect3DVertexBuffer9 **ppVertexBuffer, /*顶点缓存的指针*/
HANDLE *pSharedHandle /*一般为0*/
);

(2)引索缓存分配空间Device->CreateIndexBuffer():

HRESULT CreateIndexBuffer(
UINT Length, /*分配顶点的位元组数 (X * sizeof(Vertex)) */
DWORD Usage, /*附加属性P74*/
D3DFORMAT Format, /*引索格式 翻文档*/
D3DPOOL Pool, /*内存池 每种特性不一样 P42*/
IDirect3DIndexBuffer9 **ppIndexBuffer, /*引索缓存的指针*/
HANDLE *pSharedHandle /*一般为0*/
);

(3)为顶点缓存赋值:

流程:创建一个顶点指针(Vertex *vertices)--->锁定缓存区(vb->Lock(0, 0, (void**)&vertices, 0);)--->用vertices[]数组为顶点缓存赋值--->解锁缓存区(vb->Unlock();)

(4)为引索缓存赋值:

流程:创建一个引索指针(WORD *indices)--->锁定缓存区(ib->Lock(0, 0, (void**)&indices, 0);)--->用indices[]数组为顶点缓存赋值--->解锁缓存区(ib->Unlock();)

4. Display()函数在本例中的功能(实例中有补充的注释):

  • 设定观察矩阵、投影矩阵。
  • 世界坐标系中的矩阵变换:物体的平移、旋转、缩放...
  • 观察坐标系中的矩阵变换:摄像机的平移、旋转、缩放...
  • 设定投影矩阵
  • 设定绘制状态(绘制三角形、点、线……)
  • 指定顶点缓存:Device->SetStreamSource();
  • 指定引索缓存:Device->SetIndices(ib);
  • 设置灵活顶点格式:Device->SetFVF(Vertex::FVF);
  • Device->BeginScene();
  • 进行绘制:Device->DrawIndexedPrimitive();
  • Device->EndScene();
  • Device->Present(0,0,0,0);

5.Cleanup()函数在本例中的功能:

  • 释放顶点缓存:d3d::Release<IDirect3DVertexBuffer9*>(vb);
  • 释放引索缓存:d3d::Release<IDirect3DIndexBuffer9*>(ib);

源代码commonFunc.h

#pragma once
#ifndef COMMONFUNC_H
#define COMMONFUNC_H

#include "d3dUtility.h"
IDirect3DDevice9 *Device = 0;
extern const int width = 1800;
extern const int height = 900;
extern bool windowed = true;

IDirect3DVertexBuffer9 *vb = 0; //顶点缓存
IDirect3DIndexBuffer9 *ib = 0; //引索缓存

struct Vertex {
Vertex(){}
Vertex(float x, float y, float z) {
_x = x; _y = y; _z = z;
}
float _x, _y, _z;
static const DWORD FVF;
};

const DWORD Vertex::FVF = D3DFVF_XYZ;

bool Setup() {
Device->CreateVertexBuffer(8 * sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &vb, 0);
Device->CreateIndexBuffer(36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ib, 0);
Vertex *vertices; //为获取顶点缓存内容而创建的指针
vb->Lock(0, 0, (void**)&vertices, 0); //锁定顶点缓存

vertices[0] = Vertex(-1.0f, -1.0f, -1.0f);
vertices[1] = Vertex(-1.0f, 1.0f, -1.0f);
vertices[2] = Vertex(1.0f, 1.0f, -1.0f);
vertices[3] = Vertex(1.0f, -1.0f, -1.0f);
vertices[4] = Vertex(-1.0f, -1.0f, 1.0f);
vertices[5] = Vertex(-1.0f, 1.0f, 1.0f);
vertices[6] = Vertex(1.0f, 1.0f, 1.0f);
vertices[7] = Vertex(1.0f, -1.0f, 1.0f);

vb->Unlock();

WORD *indices = 0;
ib->Lock(0, 0, (void**)&indices, 0);

indices[0] = 0; indices[1] = 1; indices[2] = 2;
indices[3] = 0; indices[4] = 2; indices[5] = 3;
indices[6] = 4; indices[7] = 6; indices[8] = 5;
indices[9] = 4; indices[10] = 7; indices[11] = 6;
indices[12] = 4; indices[13] = 5; indices[14] = 1;
indices[15] = 4; indices[16] = 1; indices[17] = 0;
indices[18] = 3; indices[19] = 2; indices[20] = 6;
indices[21] = 3; indices[22] = 6; indices[23] = 7;
indices[24] = 1; indices[25] = 5; indices[26] = 6;
indices[27] = 1; indices[28] = 6; indices[29] = 2;
indices[30] = 4; indices[31] = 0; indices[32] = 3;
indices[33] = 4; indices[34] = 3; indices[35] = 7;

ib->Unlock();

return true;
}

void Cleanup() {
d3d::Release<IDirect3DVertexBuffer9*>(vb);
d3d::Release<IDirect3DIndexBuffer9*>(ib);

}

bool Display(float timeDelta) {
if (Device)
{
D3DXVECTOR3 position(0.0f, 0.0f, -3.0f); //摄影机的位置坐标
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); //摄像机看向的方向经过的一个点
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); //世界坐标系向上的方向向量
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up); //计算取景变换矩阵(观察矩阵)
Device->SetTransform(D3DTS_VIEW, &V); //设定取景变换矩阵(观察矩阵)

D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, 3.1415926f*0.5f, (float)width / (float)height, 1.0f, 100.0f);
//计算投影矩阵 参数:[1]输出矩阵的地址 [2]视角广度(弧度制) [3]横纵比 [4]最近能看见的距离 [5]最远能看见的距离
Device->SetTransform(D3DTS_PROJECTION, &proj);
//设定投影矩阵
Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
//设定绘制状态 参数 :[1]要改变的某类绘制状态 [2]将该类绘制状态改为...状态

D3DXMATRIX Rx, Ry;
D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);
//绕x轴旋转45°

static float y = 0.0f;
D3DXMatrixRotationY(&Ry, y);
//绕y轴旋转timeDelta°
y += timeDelta;

if (y >= 6.28f)
y = 0.0f;

D3DXMATRIX p = Rx * Ry;
Device->SetTransform(D3DTS_WORLD, &p);
//改变世界坐标系

Device->SetStreamSource(0, vb, 0, sizeof(Vertex));
//指定数据输入源 参数[1]标识顶点缓存 [2]顶点缓存的指针 [3]偏移量(要使用要先检查D3DDEVCAPS2_STREAMOFFSET标记) [4]顶点元素大小(位元组)
Device->SetIndices(ib);
//设定引索缓存
Device->SetFVF(Vertex::FVF);
//设置灵活顶点格式

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, RGB(0, 255, 255), 1.0f, 0);
//清空后台缓存把它变为某一种颜色并将其提供给前台缓存
Device->BeginScene();
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
//进行绘制 参数[1]绘制图元类型 [2]引索的基数(P80) [3]最小引索值 [4]引用的顶点数 [5]读取起始点的元素的引索 [6]要绘制的图元总数
Device->EndScene();
Device->Present(0,0,0,0);
}
return true;
}

#endif

效果:

注:该程序中立方体的旋转是通过旋转世界坐标,即整个世界都会旋转,单独旋转某个物体的方法还不知道。

推荐阅读:

相关文章