前言:
在前面的章节中,我们讲了如何绘制一个正方体,那么现在有个问题,如何绘制一个如图的正方体呢?
或许你想的是通过很多点来模拟,但是用很多顶点来模拟的方式效率无疑是底下的。正确的方式:先绘制一个正方体,延后将2D图像“贴”在正方体上。这就是所谓的纹理映射技术的简单理解。或者通俗来讲,纹理映射技术就是将2D的图像映射到3D的物体上的技术。而纹理是一种像素矩阵,它可以被映射到三角形单元中,我们通过将图像数据映射到三角形单元中,以达到绘制上图所示正方体的目的。
(如上图所示,你可以看到纹理映射技术的好处。在场景中利用纹理映射技术可以显著的增加所绘制场景的真实性。)
纹理映射流程:
1.纹理坐标:
Direct3D所使用的纹理坐标由沿水平方向的u轴和沿垂直方向的v轴构成。并且用(u,v)坐标对来标识纹理元素,被称作纹理元。
但是要注意的是,在Direct3D中,为了能够处理不同尺度的纹理,Direct3D将纹理坐标做了规范化处理,使之限定在区间范围[0,1]中。
那么问题来了:
纹理坐标的区间必须规定在0-1范围内,但是有时坐标是超过这个范围的。此时该如何处理呢?
这里不得不提到Direct3D的寻址模式。Direct3D定义了4中用来处理纹理坐标超出[0,1]区间的纹理映射模式。
1.重复模式寻址模式
2.边界颜色寻址模式
3.筘位寻址模式
4.镜像寻址模式
从左到右如图所示:
回到主话题,为了能够实现该映射,我们需要重新修改顶点结构:
//顶点结构
struct Vertex
{
float _x, _y, _z; // 位置
float _u, _v; //纹理坐标
Vertex(){}
Vertex(float x, float y, float z, float u, float v)
:_x(x), _y(y), _z(z), _u(u), _v(v){}
};
2.顶点数据写入:
为了能够正确的达到我们想要的绘制结果,我们必须对此正方体的顶点数据进行写入。要写入数据,那么顶点缓存和索引缓存就必须要做了。一个多边形中相邻的交汇点称为顶点,描述三角形单元时,我们需要指定该三角形3个顶点的位置。那么如果我们要通过三角形单元来描述一个物体,就需要指定构成该物体的三角形单元。
但是要知道的是,在构成一个3D物体时,三角形单元之间会存在很多的公共顶点。如果模型的复杂度特别高,那么顶点的重复会更多。比如说:一个正方体,如果用简单的三角形构成,需要12个三角形,如果分开来算,需要36个顶点。但是实际上一个正方体只需要8个顶点。那么在Direct3D中使用了顶点缓存和索引缓存来处理这种情况。
例如:对于一个立方体:
我们利用顶点缓存,来存储这8个顶点并对顶点进行编号,然后利用索引缓存来记录每个三角形都使用了哪些顶点:
Vertex vertexList[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
WORD IndexList[6] = { 0, 1, 2 //三角形0
0,2,3//三角形1
}
那么现在我们来写入正方体数据:
//顶点缓存 和索引缓存
bool InitCube()
{
//创建顶端缓存
_device->CreateVertexBuffer(
24 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
FVF_VERTEX,
D3DPOOL_MANAGED,
&_vb,
0);
Vertex* v;
//数据锁定,写入
_vb->Lock(0, 0, (void**)&v, 0);
// 正面数据
v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f);
v[2] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f);
v[3] = Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f);
//背面数据
v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f);
v[5] = Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f);
v[6] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
v[7] = Vertex(-1.0f, 1.0f, 1.0f,1.0f, 0.0f);
/