0xAA55 发表于 2014-1-26 23:20:53

【D3D入门】教你理解3D游戏的算法

你要了解3D编程,你必须知道3D编程的原理。3D编程其实一点也不难,你要知道的第一点就是如何把一个空间里的顶点投影到屏幕上。
首先,假设你有一堆模型数据,也就是顶点数据,如下图所示


用数组表示就是下面这样的:

D3DXVECTOR3 vModel=//立方体八个顶点
{
        {+1,+1,+1},
        {-1,+1,+1},
        {+1,-1,+1},
        {-1,-1,+1},
        {+1,+1,-1},
        {+1,-1,-1},
        {-1,+1,-1},
        {-1,-1,-1}
};

没错,这就是顶点数据。我们要如何才能把一个模型显示到屏幕上呢?那就是让它去×世界矩阵,观察矩阵,投影矩阵。
先别急,我教大家怎么取得顶点数据在屏幕中的位置。
首先你不可能只把模型数据显示在坐标原点附近吧?你需要在别处显示这个模型,不能总在一个地方显示模型,也不要为了移动模型的位置而修改模型数据,那样太慢了,耗费CPU资源。因此我们需要掌握一个概念叫“世界矩阵”。
所谓“世界矩阵”就是一个相对坐标系,顶点数据×这矩阵之后,顶点数据表示的位置就会从绝对坐标移动到相对坐标的位置。这样物体的移动就能实现了。
举个例,假如我有一个顶点的位置在(0,0,1),然后我在位置(1,0,0)处重新建立了一个坐标系,那么这个坐标系可以用“世界矩阵”来表示,那么当我把这个顶点拿去×这个矩阵的时候呢,顶点的位置就变换到了(1,0,1)。这么一说大家就知道“世界矩阵”的意义了吧?

世界矩阵是一个4x4矩阵,你可以像下面这样理解:

typedef struct
{
        D3DXVECTOR4 X轴;
        D3DXVECTOR4 Y轴;
        D3DXVECTOR4 Z轴;
        D3DXVECTOR4 坐标系原点;
}Matrix;

可以注意到每个向量都是四维向量。不要管第四维是什么(前面三维用xyz表示,第四维用w表示,也就是(x,y,z,w)这样的表示方法)
第四维就让它的值为1就行了。
然后大家要知道的就是顶点×矩阵的计算方法,我来这样介绍。

首先把矩阵沿对角线翻转过来,这被称作矩阵转置(Transpose),看!


没错,就是这样!
开个玩笑,其实是矩阵的转置,第一行分别是矩阵成员的“X轴”、“Y轴”、“Z轴”、“坐标系原点”的X,然后是……
靠,这种表达方式太费劲。我重新来给大家表示下
假如原先的矩阵是这样的:

typedef struct
{
        FLOAT _11,_12,_13,_14;//X轴
        FLOAT _21,_22,_23,_24;//Y轴
        FLOAT _31,_32,_33,_34;//Z轴
        FLOAT _41,_42,_43,_44;//坐标系原点
}Matrix;

那么进行矩阵转置后,就是下面这样的:(睁大你们的眼睛好好看看除了注释以外,最重要的区别在哪里,可不要遗漏任何一个细节哦)


typedef struct
{
        FLOAT _11,_21,_31,_41;
        FLOAT _12,_22,_32,_42;
        FLOAT _13,_23,_33,_43;
        FLOAT _14,_24,_34,_44;
}Matrix;

其实区别也就是转置了一下,转置嘛!这样说就能明白了吧。
然后呢,我们要进行向量×矩阵的算法,也就是进行矩阵变换(Transform)。
矩阵变换很简单,就是拿你的原向量去和这个已经转置过的矩阵的每一行进行点乘,就可以得到新的向量。
不过因为矩阵是4x4矩阵,如果向量不是四维的,那也很简单,给它补个1来充当w(w就是第四维,我们用x,y,z,w四个字母表示四个维度),让它变成4维的就行了。
那么就是这样:

结果.x = 向量·矩阵第一行;
结果.y = 向量·矩阵第二行;
结果.z = 向量·矩阵第三行;
结果.w = 向量·矩阵第四行;

当然如果你只需要得到一个三维向量就直接扔掉那个“结果.w”就行了。
哈?你居然说不懂?唉,那我再举个例子来给大家演示一下。快感谢我吧!为了感谢我,你们得多在论坛交流就是了。
首先我不可能自己去一个顶点一个顶点的去算,这是GPU的工作,可不能交给我!我可不是显卡,我是人类(也许吧)。
那么我从刚才的那个立方体中找一个顶点来做例子。啊,就是它了,(1,1,1)
那么我要把这个立方体移动到(5,5,5)的位置(当然一个矩阵不止包括了平移的信息,还能包括旋转、拉伸的信息)
于是我建立一个坐标系。因为不需要旋转,因此这个坐标系的X轴还是指向原先的X轴,Y轴还是指向原先的Y轴,Z轴还是指向原先的Z轴,然后我们用不到W,因此三个坐标轴的W都是0。最后这个矩阵是要平移到(5,5,5)的位置,因此我需要把矩阵的原点位置设立好。因此我们得到了如下的矩阵:
1,0,0,0
0,1,0,0
0,0,1,0
5,5,5,1
嗯,就是这样。现在我们把矩阵转置一下,就是下面这个样子的了:
1,0,0,5
0,1,0,5
0,0,1,5
0,0,0,1
嗯,w被果断无视了。很不错。我们的顶点数据是(1,1,1),是个三维向量。矩阵是4x4矩阵,我们在顶点数据后面补上一个1,就是(1,1,1,1)。
我们将进行以下的变换操作:
结果.x = (1,1,1,1)·(1,0,0,5)
结果.y = (1,1,1,1)·(0,1,0,5)
结果.z = (1,1,1,1)·(0,0,1,5)
结果不需要w
最后得到的结果是(6,6,6),因为这个顶点对应的是立方体原先的(1,1,1)这个顶点,也就是相对于立方体中央的。照这么说,立方体的中央就是(5,5,5)了。没错,这就是矩阵变换。
说了那么多,这样大家就应该理解了吧?


然后继续,我说到哪了?嗯,世界矩阵说完了,接下来是观察矩阵。
所谓观察矩阵就是镜头的位置,方向,组成的反矩阵。为什么要×观察矩阵呢?因为这样才能把要观察的东西移动到镜头前呗。
其实是为了方便计算,为了定位顶点的位置而设置的算法。原本空间坐标系里面镜头附近的顶点×了观察矩阵之后,它就会被移动到原点附近,这样才能算作是“投影”。透视什么的之后再说,那个属于投影矩阵的范围。
当顶点数据×了观察矩阵之后,我们可以把x、y轴上的平面当做显示器屏幕,z轴当做顶点与屏幕的距离。这样一来就很容易计算了。
不过呢,因为计算单位的原因,我们还要进行透视投影矩阵的×法计算。只有好好×了各个矩阵,才能得出顶点的确切位置。


投影矩阵就是这样的矩阵,顶点×了投影矩阵之后,顶点的x、y轴在屏幕上的位置的区间就被控制在[-1,1]区间了,对应的显示屏幕左边和右边,或者上边和下边。然后z轴的位置就是“深度”。所谓“深度”就是距离,用来进行距离判断的参数,会被写入“深度缓冲”。D3D在画每一个像素的时候,只要你开启了“深度比较”功能,它就会进行深度比较,深度比深度缓冲深的像素意味着它已经被“眼前”的物体遮挡住了,因此就没有画出来。这就是目前3D游戏解决遮挡处理的办法。可不是有些人想象中的通过“排序得到渲染次序”、“裁剪模型”。那些被用在别的领域(比如水面倒影、平面反射等)
而顶点×投影矩阵的时候,w成员不能丢。w是用来进行纹理拉伸的一个参数。这个我在这里一时半会儿也解释不清,因为这里涉及到贴图坐标的问题。贴图坐标可不是简单的把像素的位置当做纹理坐标就可以了的,那要通过这个w来计算的。

我有个梦 发表于 2014-3-26 16:37:38

谢谢分享

sowhy 发表于 2019-2-27 17:22:05

{:3_45:}大佬有什么推荐的资料么

C1garet 发表于 2024-3-3 14:00:48

很好的东西,学习了

tlwh163 发表于 2024-3-3 19:03:16

问题来了 矩阵的算法 有吗?

0xAA55 发表于 2024-3-3 20:59:07

tlwh163 发表于 2024-3-3 19:03
问题来了 矩阵的算法 有吗?

帖子里不就有么


```
结果.x = 向量·矩阵第一行;
结果.y = 向量·矩阵第二行;
结果.z = 向量·矩阵第三行;
结果.w = 向量·矩阵第四行;
```


页: [1]
查看完整版本: 【D3D入门】教你理解3D游戏的算法