DirectX 9.0c游戏开发手记之RPG编程自学日志之7: Drawing with DirectX Graphics (用DirectX图形绘图)(第3节)

45 篇文章 0 订阅
40 篇文章 1 订阅

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系2024958085@qq.com

 

        这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第3节:The Math of 3-D。这一节应该比较容易。不过由于篇幅的限制,它讲述地特别省略。推荐大家去参考一下其他的书籍,比如说“龙书”第二版(不知道啥叫“龙书”第二版以及找不到下载地址的请联系我!)的前三章,对于3-D数学基础部分讲述地比较透彻,学过线性代数的同学都应该能看懂。

 

        另外看了本期的同学们有福了!我把这本书的中译本找到了,现在分享给大家!

中译本第一部分

中译本第二部分


        当然,作为一个有良心的翻译者,我是不会参考这本书的,哈哈!下载了这本书后,大家可以从此把这系列博客给弃了;当然,如果你想要继续追的话,那我也是非常欢迎的!

 

        原文翻译:

 

===============================================================================

   

2.3 The Math of 3-D(3-D的数学)

 

        正如你现在也许已经看出来的那样,使用3-D图形会用到非常多的数学,并且会处理如此多的数以至于很容易把事情弄得一团糟。很多年前,实时的3-D图形只是一个梦想,而非现实。这是因为那时候的计算机没能够足够快地进行计算。

        当然,随着时间的流逝,事情好转了,现在你可以实现很多炫酷的效果了。与3-D图形有关的数学的进步是这种改观的一个原因。

 

 

2.3.1 Matrix Math (矩阵数学)

 

        不,这一节并不是关于基阿努·里维斯以及他的下一部关于他陷入一个计算器的电影!(当然,这是十年前的事情了。)矩阵数学是这样一种线性代数,它简化、减轻了某些运算。就你的目的而言,这些计算是我刚刚提到的3-D变换。

        因为每一个3-D物体都由很多顶点组成,Direct3D的工作就是将这些顶点变换到准备好将图形渲染到显示屏上的坐标。在每一帧中,你可以变换组成一个场景的上千个顶点。这可是真的数学——足以让任何大学教授咽气。

 

        注意:

===============================================================================

        注意到矩阵数学只有在你用到3-D坐标的时候才出现。如果你在使用变换后坐标(屏幕空间的坐标),你不需要再给它们进行变换了。

===============================================================================

 

        Direct3D通过使用矩阵来处理所有的变换。矩阵是数的一张网格,网格中的每一个元素具有确定的意义。就你目前的目的而言,这些书代表你想要作用在顶点上的变换。通过将所有的必要的计算整合到一个打包的形式——例如一个矩阵——中,其中的数学就大大简化了。

 

 

2.3.2 Matrix Construction (矩阵的构造)

 

        矩阵可以有很多的尺寸,但是就你目前需要考虑的东西而言,其大小是4×4,这意味着你有一个四行四列的网格。Direct3D用一个D3DMATRIX结构体来存储矩阵:

typedef struct_D3DMATRIX {
  D3DVALUE _11, _12, _13, _14;
  D3DVALUE _21, _22, _23, _24;
  D3DVALUE _31, _32, _33, _34;
  D3DVALUE _41, _42, _43, _44;
} D3DMATRIX;
</pre><p></p><p>        为了用你要使用到的变换来填充一个矩阵,你实际上可以使用D3DX库。不要使用D3DMATRIX结构体,而是使用D3DXMATRIX对象,它包含着跟D3DMATRIX同样的变量,并且还有一些有用的函数。</p><p>        你要使用的每一个变换都有其自己矩阵,但是旋转要花去三个矩阵(围绕每个坐标轴的旋转都有一个)。这意味着你需要五个变换矩阵:绕x-轴旋转、绕y-轴旋转、绕z-轴旋转、平移以及缩放。第一族函数用来建立旋转矩阵:</p><p></p><pre name="code" class="cpp">D3DXMATRIX*D3DXMatrixRotationX(
  D3DXMATRIX *pOut,            // output matrix
  FLOAT         Angle,         // X angle aroundcenter
);

D3DXMATRIX*D3DXMatrixRotationY(
  D3DXMATRIX *pOut,            // output matrix
  FLOAT         Angle,         // Y angle aroundcenter
);

D3DXMATRIX *D3DXMatrixRotationZ(
  D3DXMATRIX *pOut,            // output matrix
  FLOAT        Angle,          // Z angle around center
);

        注意:

===============================================================================

        注意到D3DX使用的所有的矩阵函数也返回一个D3DXMATRIX指针。这是一个指向输出矩阵的指针,并且它让你能够将矩阵函数内嵌地(inline)与其他的函数使用,如下所示:

D3DXMATRIX matMatrix, matResult;
matResult = D3DXMatrixRotationZ(&matMatrix, 1.57f);

===============================================================================

 

        通过向前面的每个函数传递一个矩阵(的地址)以及提供一个有理数值(以弧度计量的表示沿着轴心旋转的角),你获得了你需要使用的值。

        下一个函数创建一个平移矩阵,它用于移动物体:

D3DXMATRIX*D3DXMatrixTranslation(
  D3DXMATRIX *pOut,            // output matrix
  FLOAT  x,                    // X coordinateoffset
  FLOAT  y,                    // Y coordinateoffset
  FLOAT  z);                   // Z coordinateoffset

        这些坐标实际上是基于物体原点的offsets(不知道怎么翻译)。平移值用于将物体从局部空间坐标转换到世界空间坐标。下一行是让物体以其中心进行缩放的函数:

D3DXMATRIX*D3DXMatrixScaling(
  D3DXMATRIX *pOut,            // output matrix
  FLOAT sx,                    // X scale
  FLOAT sy,                    // Y scale
  FLOAT sz);                   // Z scale

        正常状态下,一个物体的缩放值是1.0。为了让一个物体的尺寸加倍,将值设为2.0;为了让一个物体的尺寸减半,使用0.5。你还会用到一个特殊类型的矩阵,称为恒等矩阵(identity matrix)。除了几个值以外,它的所有值都设为零;那几个例外值设为一。当作用于另外一个矩阵时,恒等矩阵没有产生任何影响,使得结果值与原来的值一样。在你想结合两个矩阵、但是不想改变原来的矩阵的值时,恒等矩阵是有用的。

        为了创建一个恒等矩阵,你可以使用下面的函数(它只将输出矩阵作为参数):

D3DXMATRIX*D3DXMatrixIdentity(D3DXMATRIX *pOut);
</pre><p></p><p>        虽然函数的原型没什么好看的,但是我还是给了一些例子:</p><p></p><pre name="code" class="cpp">D3DXMATRIX matXRot,matYRot, matZRot;
D3DXMATRIX matTrans,matScale;
 
// Setup therotations at 45 degrees (.785 radians)
D3DXMatrixRotationX(&matXRot,0.785f);
D3DXMatrixRotationY(&matYRot,0.785f);
D3DXMatrixRotationZ(&matZRot,0.785f);
 
// Setup thetranslation to move to 100, 200, 300
D3DXMatrixTranslation(&matTrans,100.0f, 200.0f, 300.0f);
 
// Scale object totwice the size in all directions
D3DXMatrixScaling(&matScale,2.0f, 2.0f, 2.0f);


2.3.3 Combining Matrices (矩阵的结合)

 

        在将变换中用到的数值填充进各种各样的矩阵中后,你可以将它们运用于每个单独的顶点。事实上,为了让计算更加简单,你可以通过矩阵的相乘来将包含着平移、旋转和缩放的数值的矩阵结合起来。这个过程叫做矩阵串联(matrix concatenation),并且这是优化所有的矩阵运算的核心。

        通过在每一帧中一次性创建一个矩阵,你可以使用该矩阵来对场景中的每一个顶点进行操作。当运用于一个顶点的时候,这个单个的矩阵达到的效果跟依次运用那些分开的矩阵的效果是一样的。

        矩阵要用起来并不难。它们只需要一点点理解。事实上,有了D3DX的力量,你可以通过使用D3DXMatrixMultiply函数不费吹灰之力地结合矩阵:

D3DXMATRIX *D3DXMatrixMultiplly(
  D3DXMATRIX        *pOut,      // output matrix
  CONST D3DXMATRIX *pM1,        // Source matrix1
  CONST D3DXMATRIX *pM1);       // Source matrix1

        通过将两个矩阵作为参数pM1和pM2传递进去,你得到一个结果矩阵(pOut),它是通过将前两个矩阵相乘而得到的。为了扩展上一节中给出的创建缩放、旋转和平移矩阵的例子,我们将它们合并成一个单个的矩阵,它代表所有的变换的总和:

D3DXMATRIX matResult;                  // The resulting matrix
 
// Clear theresulting matrix to identity
D3DXMatrixIdentity(&matResult);
 
// Multiply in thescaling matrix
D3DXMatrixMultiply(&matResult,&matResult, &matScale);
 
// Multiply inrotation matrices
D3DXMatrixMultiply(&matResult,&matResult, &matXRot);
D3DXMatrixMultiply(&matResult,&matResult, &matYRot);
D3DXMatrixMultiply(&matResult,&matResult, &matZRot);
 
// Multiply intranslation matrix
D3DXMatrixMultiply(&matResult,&matResult, &matTrans);

        另外一个将矩阵相乘的方法是使用D3DXMATRIX的乘法运算符(*),就如我在这里做的:

matResult = matXRot *matYRot * matZRot * matTrans;

 

        注意:

===============================================================================

        D3DXMATRIX的扩展,像乘法运算符,使得像单个数值一样处理矩阵成为可能。你可以使用这里展示的同样的方法对矩阵进行加法、减法、乘法甚至是除法运算,就像矩阵是单个的数一样。

===============================================================================

 

        注意你结合矩阵的顺序是很重要的。在前面的例子中,我以这样的顺序将它们结合起来:缩放、绕x-轴旋转、绕y-轴旋转、绕z-轴旋转,最后是平移。如果你想用其他任何顺序进行结合的话,那么最终的结果矩阵会有所不同,并且会导致一些未来的不可预测的结果。

 


2.3.4 The Steps from Local to View Coordinates (从局部坐标到观察坐标的步骤)

 

        为了让一个顶点用于渲染一个面,这个顶点必须从局部坐标(未变换的坐标)转换到世界坐标。世界坐标又被转换为观察坐标,最后被投影到2-D坐标(变换后的坐标)。

        你通过使用一个世界变换矩阵(world transformation matrix)(或者简称为世界矩阵)来将局部坐标转换到世界坐标。这个矩阵包含了用于将物体放置到3-D世界中(从局部到世界)的变换。第二个变换矩阵用来将物体变换到观察坐标,称为观察矩阵(viewing matrix)。最后是投影坐标(projection matrix),它将观察坐标的3-D坐标转换到用于渲染图形的变换后的顶点。

        当构造世界矩阵和观察矩阵的时候,你必须特别注意你结合单独的矩阵的顺序。对于世界变换,你以下列顺序结合单独的变换矩阵:

R = S * X * Y * Z *T

 

        R是结果矩阵,S是缩放矩阵,X是绕x-轴旋转的矩阵,Y是绕y-轴旋转的矩阵,Z是绕z-轴旋转的矩阵,而T是平移矩阵。观察矩阵必须以下列顺序结合单独的变换矩阵(只使用平移和旋转):

R = T * X * Y * Z

 

 

        注意:

===============================================================================

        当使用观察变换的时候,你必须使用观察位置的相反数来将物体摆放到视角中。你这样做是因为观察点实际上锁定在坐标0, 0, 0处。当视角“移动”的时候,世界以及所有的东西实际上在绕着你转。例如,如果你想往前走10个单位,那么就将世界的物体朝着你往后移动10个单位。向左看10度,那么实际上世界上的物体向你的右边转了10度。

===============================================================================

 

        投影矩阵是一种特殊的情形,用起来难一些。在建立投影矩阵的时候,你必须考虑很多事情,因为它并不是与平移、缩放或者旋转那样的变换有关的。我将在稍后的“投影变换”一节中使用D3DX库来帮助构建一个投影矩阵。

    

        图2.10展示了一个顶点历经各种变幻到达最终的绘制坐标所需要走的路径。

 

===============================================================================

 

        好了,这一期到这里就结束了,下一期我们将正式开始Direct3D的绘制工作!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值