DirectX9:基础篇 第二章 建立3D场景的几何描述

一.简介

d3dx9mesh.h有关网格模型

 

二.灵活的顶点格式

Direct3D中的顶点不只有空间位置属性,还可以有颜色 法线向量属性等,所以可以自定义一个顶点结构

 

 

 

1.使用

struct ColorVertex{
    float _x,_y,_z;          //位置
    DWORD _color;      //颜色
};

#define FVF_COLOR(D3DFVF_XYZ | D3DFVF_DIFFUSE)  //包含位置属性和漫反射颜色属

 

struct NormaolTexVertex{
    float _x,_y,_z;           //位置
    float _nx,_ny,_nz;     //法线
    float _u,_v;               //纹理坐标
};

#define FVF_NORMAL_TEX(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//灵活的顶点格式
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(
        3*sizeof(Vertex),
        D3DUSAGE_WRITEONLY,
        Vertex::FVF,
        D3DPOOL_MANAGED,
        &Triangle,
        0);
     
}
  
bool Display(float timeDelta){
     
    //根据灵活的顶点格式来绑定模型数据
    Device->SetFVF(Vertex::FVF);
}

 

2.FVF宏定义

#define D3DFVF_RESERVED0        0x001
#define D3DFVF_POSITION_MASK    0x400E
#define D3DFVF_XYZ              0x002        //包含三维坐标
#define D3DFVF_XYZRHW           0x004
#define D3DFVF_XYZB1            0x006
#define D3DFVF_XYZB2            0x008
#define D3DFVF_XYZB3            0x00a
#define D3DFVF_XYZB4            0x00c
#define D3DFVF_XYZB5            0x00e
#define D3DFVF_XYZW             0x4002
 
#define D3DFVF_NORMAL           0x010
#define D3DFVF_PSIZE            0x020
#define D3DFVF_DIFFUSE          0x040
#define D3DFVF_SPECULAR         0x080
 
#define D3DFVF_TEXCOUNT_MASK    0xf00
#define D3DFVF_TEXCOUNT_SHIFT   8
#define D3DFVF_TEX0             0x000
#define D3DFVF_TEX1             0x100
#define D3DFVF_TEX2             0x200
#define D3DFVF_TEX3             0x300
#define D3DFVF_TEX4             0x400
#define D3DFVF_TEX5             0x500
#define D3DFVF_TEX6             0x600
#define D3DFVF_TEX7             0x700
#define D3DFVF_TEX8             0x800
 
#define D3DFVF_LASTBETA_UBYTE4   0x1000
#define D3DFVF_LASTBETA_D3DCOLOR 0x8000
 
#define D3DFVF_RESERVED2         0x6000 

 

三.顶点缓存

一个顶点缓存是一个包含顶点数据的连续内存空间,存放在显存之中,比内存快(用于存储网格顶点)

1.CreateVertexBuffer

注意:静态缓存处理快,但是更新重绘慢.动态缓存处理慢,但是更新重绘快

 

HRESULT IDirect3DDevice9::CreatVertexBuffer(    //创建顶点缓存
     UINT Length,

  DWORD Usage,

    DWORD FVF,

    D3DPOOL Pool,

    IDirect3DVertexBuffer9** ppVertexBuffer,

    HANDLE* pSharedHandle

);

 

Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex)

 

Usage:附加属性
 
      (1)D3DUSAGE_DYNAMIC  将缓存设为动态缓存
 
      (2)D3DUSAGE_POINTS   规定缓存将用于存储点图元
 
      (3)D3DUSAGE_SOFTWAREPROCESSING    指定软件顶点运算方法
 
      (4)D3DUSAGE_WRITEONLY    只写

 

FVF:存储在顶点缓冲的灵活顶点格式,参考宏定义

 

Pool:容纳缓存的内存池

 

ppVertexBuffer:用于接收所创建的顶点缓存的指针

 

pSharedHandle:不使用,设为0

 

1
2
3
4
5
6
7
8
9
10
//例子
  
IDirect3DVertexBuffer9* vb;
device->CreateVertexBuffer(
    8*sizeof(Vertex),
    0,
    D3DFVF_XYZ,
    D3DPOOL_MANAGED,
    &vb,
    0);

 

2.Lock/Unlock

HRESULT IDirect3DVertexBuffer9::Lock(

    UINT offsetToLock,

    UINT SizeToLock,

    BYTE** ppbData,
    DWORD Flags
);

 

OffsetToLock:自缓存的起始点到开始锁定的位置的偏移量,单位为字节

 

SizeToLock:所要锁定的字节数.
如果OffsetToLock和SizeToLock都为0表示锁定整个缓存

 

1
2
3
4
5
6
7
8
9
//顶点缓存
IDirect3DVertexBuffer9* Triangle=0;
  
//访问顶点缓存内存
Vertex* vertices;
Triangle->Lock(0,0,(void**)&vertices,0);
...
  
Triangle->Unlock();

 

3.示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//顶点缓存
IDirect3DVertexBuffer9* Triangle=0;
  
  
void Cleaup(){
    d3d::Release<IDirect3DVertexBuffer9*>(VB);
}
  
bool Setup{
  
    //用D3D设备类来创建顶点缓存内存
    Device->CreateVertexBuffer(
        3*sizeof(Vertex),
        D3DUSAGE_WRITEONLY,
        Vertex::FVF,
        D3DPOOL_MANAGED,  
        &Triangle,
       0);
  
    //访问顶点缓存内存
    Vertex* vertices;
    Triangle->Lock(0,0,(void**)&vertices,0);
     
    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);
  
    Triangle->Unlock();
     
}
  
  
bool Display(float timeDelta){
     
    Device->SetStreamSource(0,VB,0,sizeof(Vertex));
}

 

四.索引缓存

一个索引缓存是一个包含索引数据的连续内存空间,存放于显存之中,比内存快

构建一个3D物体的所有三角形单元中会共享许多公共顶点,为了解决重合顶点问题,用顶点列表(vertex list)和索引列表(index list)来记录坐标(决定顶点应以何种组合方式构成网格的三角形单元)

 

假设不用索引来表示一个正方形,Vectex v[6]={v0,v1,v2,v1,v2,v3},需要六个顶点坐标

加入索引之后,Vertect v[4]={v0,v1,v2,v3}  WORD indexList[6]={0,1,2,1,2,3};  只需要记录四个顶点坐标

因为索引坐标只是一个整数,用来获取顶点坐标的第几个,所以比三维坐标的Vertex更省内存

 

1.创建索引缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HRESULT IDirect3DDevice9::CreateIndexBuffer(
    UINT Length,
    DWORD Usage,
    D3DFORMAT Format,
    D3DPOOL Pool,
    IDirect3DIndexBuffer9** ppIndexBuffer,
    HANDLE* pSharedHandle);
  
Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex)
Usage:附加属性
      (1)D3DUSAGE_DYNAMIC  将缓存设为动态缓存
      (2)D3DUSAGE_POINTS   规定缓存将用于存储点图元
      (3)D3DUSAGE_SOFTWAREPROCESSING    指定软件顶点运算方法
      (4)D3DUSAGE_WRITEONLY    只写
Format:指定索引的大小
       (1)D3DFMT_INDEX16 表示16位索引
       (2)D3DFMT_INDEX32 表示32位索引
Pool:容纳缓存的内存池
ppIndexBuffer:用于接收所创建的索引缓存的指针
pSharedHandle:不使用,设为0

 

1
2
3
4
5
6
7
8
IDirect3DIndexBuffer9* ib;
device->CreateIndexBuffer(
    36*sizeof(WORD),
    D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
    D3DFMT_INDEX16,
    D3DPOOL_MANAGED,
    &ib,
    0);

 

2.访问索引缓存

1
2
3
4
5
6
HRESULT IDirect3DIndexBuffer9::Lock(
    UINT OffsetToLock,
    UINT SizeToLock,
    BYTE** ppbData,
    DWORD Flags
);

 

3.示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//索引缓存
IDirect3DIndexBuffer9* IB=0;
  
  
bool Setup(){
  
    //用D3D设备类来创建索引缓存   
    Device->CreateIndexBuffer(
        36*sizeof(WORD),
        D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16,   
        D3DPOOL_MANAGED,
        &IB,
        0);
     
    //访问索引缓存
    WORD* Iindices=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;
  
    // back side
    indices[6]  = 4; indices[7]  = 6; indices[8]  = 5;
    indices[9]  = 4; indices[10] = 7; indices[11] = 6;
  
    // left side
    indices[12] = 4; indices[13] = 5; indices[14] = 1;
    indices[15] = 4; indices[16] = 1; indices[17] = 0;
  
    // right side
    indices[18] = 3; indices[19] = 2; indices[20] = 6;
    indices[21] = 3; indices[22] = 6; indices[23] = 7;
  
    // top
    indices[24] = 1; indices[25] = 5; indices[26] = 6;
    indices[27] = 1; indices[28] = 6; indices[29] = 2;
  
    // bottom
    indices[30] = 4; indices[31] = 0; indices[32] = 3;
    indices[33] = 4; indices[34] = 3; indices[35] = 7;
  
    IB->Unlock();
}
  
void Cleanup(){
    d3d::Release<IDirect3DIndexBuffer9*>(IB);
}
  
bool Display(float timeDelta){
    //绑定模型的索引缓存
    Device->SetIndices(IB);
}

 

五.网格

1.网格简介

一个网格由一个或多个子集组成,一个子集(subsets)是网格中一组可用相同属性(材质/纹理/绘制状态)进行绘制的三角形单元

假设一个房子是网格,那么地板/墙/天花板/窗口各有自己的属性,都能用来绘制房子网格

为了区分不同的子集,给每个子集指定一个唯一的非负整数值,该值为DWORD类型所能容纳任何非负整数

网格中的每个三角形单元都被赋予了一个属性ID,该ID指定了该三角形单元所属的子集,这些三角形单元的属性ID被存储在网格的属性缓存(Attribute Buffer)中,该属性缓存实际上就是一个DWORD类型的数组.

由于每个面片(三角形)在属性缓存中都有对应项,所以属性缓存中元素的个数与网格中面皮的个数相等.

 

2.网格类(ID3DXMesh)的方法

HRESULT ID3DMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB)

HRESULT ID3DMesh::GetIndexBuffer(LPDIRECT3DVERTEXBUFFER9* ppIB)

DWORD GetFVF()

DWORD GetNumVertices()
DWORD GetNumBytesPerVertex()
DWORD GetNumFaces()

LockAttributeBuffer()

LockIndexBuffer()

LockVertexBuffer()

UnlockAttributeBuffer()

UnlockIndexBuffer()

UnlockVertexBuffer()

CloneMesh()
CloneMeshFVF()

 

1
2
3
4
5
6
7
8
9
10
DrawSubset(DWORD AttribID)   //用于绘制由参数AttribId指定的子集中的三角形单元
  
//例子
Mesh->DrawSubset(0);  //绘制子集0中的所有三角形单元
  
for(int i=0;i<numSubsets;i++){
    Device->SetMaterial(mtrls[i]);
    Device->SetTexture(0,textures[i]);
    Mesh->DrawSubset(i);
}

 

3.D3D支持网格(ID3DXMESH)的方法

HRESULT WINAPI D3DXCreateMeshFVF(
    DWORD NumFaces,        //网格所具有的面皮个数
    DWORD NumVertices,          //网格所具有的顶点个数
    DWORD Options,        //创建网格时所使用的创建标记
    DWORD FVF,             // 顶点的灵活格式
    LPDIRECT3DDEVICE9 pDevice,      // 与网格相关的设备指针
    LPD3DXMESH* ppMesh              // 所创建的网格对象的指针
);

D3DXCreateMesh()        //创建空网格

//绘制内置的网格模型
D3DXCreateTeapot()    //茶壶
D3DXCreateBox()       //正方体
D3DXCreateCylinder()
D3DXCreateTorus()
D3DXCreateSphere()
D3DXCreaetPolygon()

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//多个模型一起绘制
  
  
ID3DXMesh* Objects[5] = {0, 0, 0, 0, 0};
  
// World matrices for each object.  These matrices
// specify the locations of the objects in the world.
D3DXMATRIX ObjWorldMatrices[5];
  
//
// Framework Functions
//
bool Setup()
{
  
    //
    //茶壶模型
    //
  
    D3DXCreateTeapot(
        Device,
        &Objects[0],
        0);
  
        //
        //立方体
        //
  
    D3DXCreateBox(
        Device,
        2.0f, // width
        2.0f, // height
        2.0f, // depth
        &Objects[1],
        0);
         
        //
    //柱体
        //
         
    D3DXCreateCylinder(
        Device,
        1.0f, // radius at negative z end
        1.0f, // radius at positive z end
        3.0f, // length of cylinder
        10,   // slices
        10,   // stacks
        &Objects[2],
        0);
  
        //
        //圆环体
        //
  
    D3DXCreateTorus(
        Device,
        1.0f, // inner radius
        3.0f, // outer radius
        10,   // sides
        10,   // rings
        &Objects[3],
        0);
  
        //
        //球面体
        //
  
    D3DXCreateSphere(
        Device,
        1.0f, // radius
        10,   // slices
        10,   // stacks
        &Objects[4],
        0);
  
  
  
    //
        //多边形
        //D3DXCreatePolygon()
  
    D3DXMatrixTranslation(&ObjWorldMatrices[0],  0.0f, 0.0f,  0.0f);
    D3DXMatrixTranslation(&ObjWorldMatrices[1], -5.0f, 0.0f,  5.0f);
    D3DXMatrixTranslation(&ObjWorldMatrices[2],  5.0f, 0.0f,  5.0f);
    D3DXMatrixTranslation(&ObjWorldMatrices[3], -5.0f, 0.0f, -5.0f);
    D3DXMatrixTranslation(&ObjWorldMatrices[4],  5.0f, 0.0f, -5.0f);
  
    //
    // Set the projection matrix.
    //
  
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
        &proj,
        D3DX_PI * 0.5f, // 90 - degree
        (float)Width / (float)Height,
        1.0f,
        1000.0f);
    Device->SetTransform(D3DTS_PROJECTION, &proj);
  
    //
    // Switch to wireframe mode.
    //
  
    Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
  
    return true;
}
void Cleanup()
{
    for(int i = 0; i < 5; i++)
        d3d::Release<ID3DXMesh*>(Objects[i]);
}
  
bool Display(float timeDelta)
{
    if( Device )
    {
        // Animate the camera:
        // The camera will circle around the center of the scene.  We use the
        // sin and cos functions to generate points on the circle, then scale them
        // by 10 to further the radius.  In addition the camera will move up and down
        // as it circles about the scene.
        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 );
  
        // the camera is targetted at the origin of the world
        D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
  
        // the worlds up vector
        D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
  
        D3DXMATRIX V;
        D3DXMatrixLookAtLH(&V, &position, &target, &up);
        Device->SetTransform(D3DTS_VIEW, &V);
  
        // compute the position for the next frame
        angle += timeDelta;
        if( angle >= 6.28f )
            angle = 0.0f;
  
        // compute the height of the camera for the next frame
        cameraHeight += cameraHeightDirection * timeDelta;
        if( cameraHeight >= 10.0f )
            cameraHeightDirection = -5.0f;
  
        if( cameraHeight <= -10.0f )
            cameraHeightDirection = 5.0f;
  
        //
        // Draw the Scene:
        //
  
        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();
  
        for(int i = 0; i < 5; i++)
        {
            // Set the world matrix that positions the object.
            Device->SetTransform(D3DTS_WORLD, &ObjWorldMatrices[i]);
  
            // Draw the object using the previously set world matrix.
            Objects[i]->DrawSubset(0);
        }
  
        Device->EndScene();
        Device->Present(0, 0, 0, 0);
    }
    return true;
}

 

posted @   言午丶  阅读(596)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示