1.顶点缓存与索引缓存: 包含顶点数据的连续内存空间,包含索引数据的连续存储空间。
不用数组的原因:顶点缓存和索引缓存存放在位置是 显存, 而数组是放在 内存中,在绘制速度方面是 显存的速度更快
创建顶点缓存 和 索引缓存:
注意:若不指定D3DUSAGE_DYNAMIC,则创建的就是静态缓存,他通常用来存储的是不需要经常修改或访问的数据
而若指定D3DUSAGE_DYNAMIC,则适合用于频繁更新缓存数据类型
通过lock方法,但要注意使用完毕后Unlock方法释放。
lock的最后一个参数可以设置的值为0, D3DLOCK_DISCARD, D3DLOCK_NOOVERWRITE, D3DLOCK_READONLY
注意一下,后面的vb都是假设已经通过CreateVertexBuffer()创建好的顶点指针
3.获取顶点缓存和索引缓存的信息
顶点的信息包含了顶点的format,type,usage,pool,fvf,size等信息。
索引信息只少一个fvf而已。
4.绘制状态, IDirect3DDevice9::SetRenderState
这个方法会经常用到,他有很多参数,比如alpha,stencil,light,着色情况,还有很多
5.绘制的准备工作
(1)指定数据流输入源。将顶点缓存和数据流进行链接。(实质就是向数据流中给出几何体的信息):
(2)设置顶点格式,在这里指定后续绘制调用的顶点格式
(3)设置索引,这是可选的,如果使用了索引缓存就必须调用这个方法
注意:任意时刻只能使用一个 索引缓存,所以如果使用不同的索引缓存绘制物体,必须切换
原型如下:
(2)IDirect3DDevice::DrawIndexedPrimitive,用在既有顶点又有索引的时候。
原型如下:
Begin/End Scene: 最后,所有的绘制方法都必须放在IDirect3DDevice9::BeginScene 和 IDirect3DDevice9::EndScene之间
7.D3DX几何体
D3DX库提供了一些用于生成3D几何体的网格数据的办法,这些都是拿给新手玩的~
D3DXCreateBox
D3DXCreateSphere
D3DXCreateCylinder
D3DXCreateTeapot
D3DXCreatePolygon
对 4个例程 的讨论:
essential 2: 注意Setup里面的内容包含这几个部分:
1.创建顶点缓存
2.用Vertex填充这个缓存,注意释放的问题
3.设置投影矩阵并在device中使用他
4.设置绘制状态
Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //线框模式,不指定的话,绘制出来的是全部黑色的三角形
1.数据流输入源
2.灵活顶点的设置
3.在BeginScene和EndScene中添加绘制的代码,这里用的是DrawPrimitive
1.创建顶点缓存和索引缓存, CreateVertexBuffer CreateIndexBuffer
2.填充缓存的内容,注意Lock和Unlcok,用来填充的类型分别是Vertex和WORD
3.设置观察矩阵并使用 D3DXMatrixLookAtLH SetTransform
4.设置投影矩阵并使用 D3DXMatrixPerspectiveFovLH SetTransform
1.先创建x和y方向旋转矩阵,设置沿x轴和y轴旋转的角度, 由于要使立方体旋转起来,所以每帧的y都应该有所变化,
最后在y方向旋转一周完毕后将y设为0,回到初始的状态,这样就可以一直循环下去。
2.以上过程是通过世界变换完成的。
3.数据流输入源,顶点缓存, 注意,和上面不一样的是还需要指定 索引缓存
4.用DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12)来绘制,但必须放在BeginScene和EndScene中
essential 4: 体验顶点创建的顺序和空间结构...然后改变摄像机的位置,超有趣!
essential 2: Setup函数:观察矩阵和投影矩阵的建立并使用,设置绘制状态
不用数组的原因:顶点缓存和索引缓存存放在位置是 显存, 而数组是放在 内存中,在绘制速度方面是 显存的速度更快
创建顶点缓存 和 索引缓存:
HRESULT IDirect3DDevice9::CreateVertexBuffer(
UINT Length, //为缓存分配的字节数,比如sizeof(Vertex)
DOWRD Usage, //0(无附加属性) D3DUSAGE_DYNAMIC(设为动态缓存) D3DUSAGE_WRITEONLY(只写,在这里读的话会报错)
DWORD FVF, //指定灵活顶点的格式
D3DPOOL Pool, //容纳缓存的内存池
IDirect3DVertexBuffer9 **ppVertexBuffer, //接受创建顶点缓存的指针
HANDLE *pSharedHandle
);
HRESULT IDirect3DDevice9::CreateIndexBuffer(
UINT Length, //同上
DWORD Usage, //同上
D3DFORMAT Format, //D3DFMT_INDEX16表示16位索引,D3DFMT_INDEX32表示32位索引
D3DPOOL Pool, //同上
IDirect3DIndexBuffer9 **ppIndexBuffer, //接受创建索引缓存的指针
HANDLE *pSharedHandle
);
注意:若不指定D3DUSAGE_DYNAMIC,则创建的就是静态缓存,他通常用来存储的是不需要经常修改或访问的数据
而若指定D3DUSAGE_DYNAMIC,则适合用于频繁更新缓存数据类型
通过lock方法,但要注意使用完毕后Unlock方法释放。
lock的最后一个参数可以设置的值为0, D3DLOCK_DISCARD, D3DLOCK_NOOVERWRITE, D3DLOCK_READONLY
注意一下,后面的vb都是假设已经通过CreateVertexBuffer()创建好的顶点指针
Vertex * vertices;
vb->Lock(0, 0, (void**)&vertices, 0); //前面的两个参数指定为0则是表示 锁定整个缓存,这里假定vb是以创建好的 静态顶点缓存
vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);
vertices[1] = Vertex(0.0f, 1.0f, 2.0f);
vertices[2] = Vertex(1.0f, 0.0f, 2.0f);
vb->Unlock();
//也可以这样:
Vertex Data[] =
{
{ -1.0f, 0.0f, 2.0f },
{ 0.0f, 1.0f, 2.0f },
{ 1.0f, 0.0f, 2.0f }
};
void* v;
vb->Lock(0, 0, (void**)&v, 0);
memcpy( v, Data, sizeof( Data ) ); //内存复制
vb->Unlock();
3.获取顶点缓存和索引缓存的信息
顶点的信息包含了顶点的format,type,usage,pool,fvf,size等信息。
索引信息只少一个fvf而已。
D3DVERTEXBUFFER_DESC vbDesc;
vb->GetDesc( &vbDesc );
D3DINDEXBUFFER_DESC ibDesc;
ib->GetDesc( &ibDesc );
4.绘制状态, IDirect3DDevice9::SetRenderState
这个方法会经常用到,他有很多参数,比如alpha,stencil,light,着色情况,还有很多
//使用线框模式来绘制物体
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
5.绘制的准备工作
(1)指定数据流输入源。将顶点缓存和数据流进行链接。(实质就是向数据流中给出几何体的信息):
IDirect3DDevice9::SetStreamSource(
UINT StreamNumber, //标识与顶点缓存建立链接的数据流
IDirect3DVertexBuffer9 * pSD, //指定希望与给定数据流建立链接的顶点缓存指针
UINT OffsetInBytes, //从数据流起始点算起的一个偏移量,单位是字节
UINT Stride //顶点缓存中每个元素的大小,单位是字节
)
//eg:
device->SetStreamSoure(0, vb, 0, sizeof(Vertex));
(2)设置顶点格式,在这里指定后续绘制调用的顶点格式
device->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
(3)设置索引,这是可选的,如果使用了索引缓存就必须调用这个方法
device->SetIndices(ib); //假定ib已创建好的索引缓存
注意:任意时刻只能使用一个 索引缓存,所以如果使用不同的索引缓存绘制物体,必须切换
注意2:这三步是用在 绘制由顶点缓存或者索引缓存构建的 模型中的,茶壶什么的不需要这几步,茶壶的绘制是直接teapot->DrawSubset(0);
6.使用顶点缓存和索引缓存进行绘制
数据流输入源,灵活顶点,(可选)索引缓存指定好之后,接下来就是绘制了,主要有2种绘制方式:
(1) IDirect3DDevice::DrawPrimitive,用在只有顶点的时候。原型如下:
HRESULT IDirect3DDevice9::DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType, //所要绘制的图元类型(比如三角形 ,点, 线)
UINT StartVertex, //顶点数据读取起点的元素的索引
UINT PrimitiveCount //图元的数量
);
//eg:
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 4);
(2)IDirect3DDevice::DrawIndexedPrimitive,用在既有顶点又有索引的时候。
原型如下:
HRESULT IDirect3DDevice9::DrawIndexedPrimitive(
D3DPRIMITIVETYPE Type, //同上
INT BaseVertexIndex, //为索引添加一个基数
UINT MinIndex, //允许使用的最小索引值
UINT NumVertices, //本次调用中使用的顶点总数
UINT StartIndex, //标识索引的读取起始点的元素的索引
UINT PrimitiveCount //同上
);
//eg:
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
Begin/End Scene: 最后,所有的绘制方法都必须放在IDirect3DDevice9::BeginScene 和 IDirect3DDevice9::EndScene之间
//eg:
device->BeginScene();
device->DrawPrimitive(...);
device->EndScene();
7.D3DX几何体
D3DX库提供了一些用于生成3D几何体的网格数据的办法,这些都是拿给新手玩的~
D3DXCreateBox
D3DXCreateSphere
D3DXCreateCylinder
D3DXCreateTeapot
D3DXCreatePolygon
D3DXCreateTorus
注意:这些函数 生成的网格只有一个属性子集,这就是为什么DrawSubset参数填0的原因,关于属性子集的概念会在网格的时候谈到...
//eg:
ID3DXMesh * mesh = 0; //创建网格
D3DXCreateTeapot(device, &mesh, 0);
device->BeginScene();
mesh->DrawSubset(0); //用DrawSubset(0)对网格数据进行绘制,其中参数0表示的是 接受一个代表网格数据的子集的参数。
device->EndScene();
mesh->Release(); //使用网格完毕后必须释放
mesh = 0;
对 4个例程 的讨论:
1.Triangle: 结果是一个三角形的图形。(这个例子仅仅用了顶点缓存)
essential 1: 创建Vertex对象(更准确的说是结构),这里面的静态参数FVF指明了灵活顶点的格式
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;
essential 2: 注意Setup里面的内容包含这几个部分:
1.创建顶点缓存
2.用Vertex填充这个缓存,注意释放的问题
3.设置投影矩阵并在device中使用他
4.设置绘制状态
Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //线框模式,不指定的话,绘制出来的是全部黑色的三角形
1.数据流输入源
2.灵活顶点的设置
3.在BeginScene和EndScene中添加绘制的代码,这里用的是DrawPrimitive
2.Cube: 结果是一个旋转的立方体,背面消隐的。(这个例子用到了 顶点缓存 和 索引缓存)
essential 1: 创建了Vertex结构,同上。
1.创建顶点缓存和索引缓存, CreateVertexBuffer CreateIndexBuffer
2.填充缓存的内容,注意Lock和Unlcok,用来填充的类型分别是Vertex和WORD
3.设置观察矩阵并使用 D3DXMatrixLookAtLH SetTransform
4.设置投影矩阵并使用 D3DXMatrixPerspectiveFovLH SetTransform
5.设置绘制状态
1.先创建x和y方向旋转矩阵,设置沿x轴和y轴旋转的角度, 由于要使立方体旋转起来,所以每帧的y都应该有所变化,
最后在y方向旋转一周完毕后将y设为0,回到初始的状态,这样就可以一直循环下去。
2.以上过程是通过世界变换完成的。
3.数据流输入源,顶点缓存, 注意,和上面不一样的是还需要指定 索引缓存
4.用DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12)来绘制,但必须放在BeginScene和EndScene中
essential 4: 体验顶点创建的顺序和空间结构...然后改变摄像机的位置,超有趣!
3.teapot: 结果是一个旋转的茶壶。(这个例子用的是系统的 D3DXCreateTeapot,并且使用的绘制方法是 DrawSubset)
essential 2: Setup函数:观察矩阵和投影矩阵的建立并使用,设置绘制状态
essential 3: Display函数:通过设置y方向的旋转角度来控制每帧旋转的角度,在在BeginScene和EndScene之间添加DrawSubset(0)
这个例子中,动的不是物体,是摄像机,而且摄像机一边旋转,一边上下移动。下面是旋转的逻辑部分:(这是Display中的内容)
static float angle = (3.0f * D3DX_PI) / 2.0f; //设为静态,所以在每次时间变化时,都会从上一次的位置开始
static float cameraHeight = 0.0f; //摄像机的真实坐标
static float cameraHeightDirection = 5.0f; //摄像机每次变化的高度,当为负是说明摄像机下降
D3DXVECTOR3 position( cosf(angle) * 10.0f, cameraHeight, sinf(angle) * 10.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);
angle += timeDelta; //摄像机旋转角度的变化情况
if( angle >= 6.28f )
angle = 0.0f;
cameraHeight += cameraHeightDirection * timeDelta; //摄像机高度的变化情况
if( cameraHeight >= 10.0f )
cameraHeightDirection = -5.0f;
if( cameraHeight <= -10.0f )
cameraHeightDirection = 5.0f;