本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系2024958085@qq.com
这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第4节:Getting Down to Drawing。这个超级长的节上次讲到了顶点部分,这一期我们讲变换部分。
再次这一节的各小节的标题列在下面,以供大家参考:
1、Using Vertices (使用顶点)
2、Flexible Vertex Format (灵活顶点格式)
3、Using Vertex Buffers (使用顶点缓存)
4、Vertex Streams (顶点流)
5、Vertex Shaders (顶点着色器)
6、Transformations(变换)
7、The World Transformation (世界变换)
8、The View Transformation (视角变换)
9、The Projection Transformation (投影变换)
10、Materials and Colors (材质和颜色)
11、Clearing the Viewport (清除视口)
12、Beginning and Ending a Scene (开始和结束场景)
13、Rendering Polygons (渲染多边形)
14、Presenting the Scene (展示场景)
这一期要从Transformations讲到TheProjection Transformation。
原文翻译:
===============================================================================
到了现在,你已经学会了如何初始化图形系统并创建顶点。如果你在处理3-D物体,例如多边形,那么这些顶点很可能定义于局部空间中。如果是这样的,你通过一些变换(世界、视角以及投影变换)来传递这些顶点,以保证在你渲染这些物体时它们位于正确的位置。每一个变换都需要构造一个代表适当的位置(或投影)值的特殊的矩阵。下面的几节内容将告诉你如何构造并使用这三种变换;先从世界变换开始吧。
定义于局部空间中的顶点需要被放置到它们在世界空间中的相应的坐标上去。例如,如果你使用顶点创建了一个盒子(在局部空间中),并且像让它在世界中某个特定点出现,你对它运用一个世界变换(如图2.12所示)。
你使用你的老朋友,D3DX库,来帮助构造世界变换矩阵。为了摆放一个物体,你需要构造三个旋转矩阵(绕每个坐标轴旋转都有一个)、一个平移矩阵和一个缩放矩阵:
D3DXMATRIX matWorld; D3DXMATRIX matRotX,matRotY, matRotZ; D3DXMATRIX matTrans; D3DXMATRIX matScale; // Create therotation matrices D3DXMatrixRotationX(&matRotX,XAngle); D3DXMatrixRotationY(&matRotY,YAngle); D3DXMatrixRotationZ(&matRotZ,ZAngle); // Create thetranslation matrix D3DXMatrixTranslation(&matTrans,XPos, YPos, ZPos); // Create the scalingmatrix D3DXMatrixScaling(&matScale,XScale, YScale, ZScale);
下一步,你将所有的矩阵组合成一个世界矩阵。它们必须以这样的顺序进行结合:缩放、绕x-轴旋转、绕y-轴旋转、绕z-轴选择和最后的平移。
// Set matWorld toidentity D3DXMatrixIdentity(&matWorld); // Combine allmatrices into world transformation matrix D3DXMatrixMultiply(&matWorld,&matWorld, &matScale); D3DXMatrixMultiply(&matWorld,&matWorld, &matRotX); D3DXMatrixMultiply(&matWorld,&matWorld, &matRotY); D3DXMatrixMultiply(&matWorld,&matWorld, &matRotZ); D3DXMatrixMultiply(&matWorld,&matWorld, &matTrans);
你就快完成任务了。现在,你只要告诉Direct3D来使用刚刚创建的世界变换。你通过以下函数来实现这一点:
HRESULTIDirect3DDevice9::SetTransform( D3DTRANSFORMSTATETYPE State, // D3DTS_WORLD CONST D3DMATRIX *pMatrix); // World matrix to set
注意第二个参数是指向一个D3DMATRIX结构体的指针,但是谢天谢地,你可以使用你构造的D3DXMATRIX对象。将第一个参数设为D3DTS_WORLD来告诉Direct3D这个矩阵用于世界变换,并且在这之后绘制的任何物体都要通过这个矩阵来进行位置调整。
如果你要在世界中摆放多于一个物体,那么只需要为每个物体构造一个新的世界变换矩阵(基于各自的位置),然后再次调用SetTransform函数,但是要确保在进入下一个世界变换之前要绘制好该物体。
用基本的术语来说,视角变换的功能很像一个摄像机(称为观察点(viewpoint))。通过构造一个包含了你摆放世界中的顶点的offsets的矩阵,你可以将整个场景绕着观察点排列。All vertices must be oriented (using the view transformation) around the center of the world at the same relative position in which they are located around the viewpoint. (求大神!这句话不会翻译!)
为了创造一个视角变换,你从观察点的位置和旋转角出发建立一个矩阵,这一次使用这样的顺序:平移、绕z-轴旋转、绕y-轴旋转,然后是绕x-轴旋转。然而,这里的窍门是你要是用位置和旋转角的相反值。例如,如果观察点位于X=10, Y=0, Z=-150的地方,纳闷你使用X=-10, Y=0, Z=150。
这里是构建视角变换矩阵的代码:
D3DXMATRIX matView; D3DXMATRIX matRotX,matRotY, matRotZ; D3DXMATRIX matTrans; // Create therotation matrices (opposite values) D3DXMatrixRotationX(&matRotX,-XAngle); D3DXMatrixRotationY(&matRotY,-YAngle); D3DXMatrixRotationZ(&matRotZ,-ZAngle); // Create thetranslation matrix (opposite values) D3DXMatrixTranslation(&matTrans,-XPos, -YPos, -ZPos); // Set matView toidentity D3DXMatrixIdentity(&matView); // Combine allmatrices into view transformation matrix D3DXMatrixMultiply(&matView,&matView, &matTrans); D3DXMatrixMultiply(&matView,&matView, &matRotZ); D3DXMatrixMultiply(&matView,&matView, &matRotY); D3DXMatrixMultiply(&matView,&matView, &matRotX);
为了让Direct3D使用你建立的视角变换矩阵,再次使用IDirect3DDevice9::SetTransform函数,而这次将State参数设为D3DTS_VIEW:
// g_pD3DDevice =pre-initialized device object if(FAILED(g_pD3DDevice->SetTransform(D3DTS_VIEW,&matView))) { // Error occurred }
你可以看到,设定视角变换很容易;而构造视角矩阵却是一个问题。为了让事情更简单,D3DX提供了一个函数,只需要调用一次就建立了视角变换矩阵:
D3DXMATRIX*D3DXMatrixLookAtLH( D3DXMATRIX *pOut, // output view transformation matrix CONST D3DXVECTOR3 *pEye, // coordinates of viewpoint CONST D3DXVECTOR3 *pAt, // coordinates at target CONST D3DXVECTOR3 *pUp); // up direction
一眼看上去,这个D3DXMatrixLookAtLH函数令人感到不知所云。你可以看到典型的输出矩阵指针,但是那三个D3DXVECTOR3对象是啥?D3DXVECTOR3跟D3DXMATRIX对象很像,除了它只包含3个值(称为x, y和z)以外——在当前情况下,是三个坐标值。这个D3DXVECTOR3对象称为一个向量对象(vector object)。
pEye代表观察点的坐标,而pAt代表观察点正在看的目标的坐标。pUp是一个代表观察点的向上的方向的向量。一般来说,pUp可以设为0, 1, 0 (意味着pUp是沿着y-轴的正向的),但是由于观察点可以倾斜(就像你左右倾斜你的脑袋一样),所以向上的方向可以指向任何方向、沿着任何坐标轴。
为了使用D3DXMatrixLookAtLH函数,你可使用下面的一块代码(假设观察点位于XPos, YPos, ZPos并看着原点):
D3DXMATRIX matView; D3DXVECTOR3 vecVP,vecTP, vecUp(0.0f, 1.0f, 0.0f); vecVP.x = XPos; vecVP.y = YPos; vecVP.z = ZPos; vecTP.x = vecTP.y =vecTP.z = 0.0f; D3DXMatrixLookAtLH(&matView,&vecVP, &vecTP, &vecUp);
最后我们迎来的是投影变换,它将3-D顶点(未变换的)转换成Direct3D用于将图形绘制到显示屏上的2-D坐标(变换后的)。可以把投影变换想象成一种将3-D图形“压扁”到你的显示屏上的方式(如图2.13所示)。
当处理投影变换时,有很多方面的东西会进入我们的视野,例如视口的横纵比(aspect ratio)、field of view以及近和远裁剪范围(near and far clipping ranges)。
裁剪……啥?在绘制3-D物体的时候,有一些物体离观察点太近或者太远了;你让Direct3D直到什么时候去裁减掉这些部分(以便加速程序的运行)。为了构造投影矩阵并定义物体可见从而不会被裁减掉的区域,你使用D3DXMatrixPerspectiveFovLH函数:
D3DXMATRIX*D3DXMatrixPerspectiveFovLH( D3DXMATRIX *pOut, // Output matrix FLOAT fovy, // Field of view, inradians FLOAT Aspect, // Aspect ratio FLOAT zn, // Z-value of nearclipping plane FLOAT zf); // Z-value of far clipping plane
注意
===============================================================================
D3DXMatrixPerspectiveFovLH函数使用左手坐标系来建立透视转换矩阵(perspective transformation matrix)。如果你在使用右手坐标系的话,那么就使用D3DXMatrixPerspectiveFovRH函数(它使用的参数与左手坐标系版本的一样)。
===============================================================================
fovy参数表示投影的视角的宽度,所以这个数越大,你看到的东西越多。然而,这是一把双刃剑,因为如果你使用的fovy的值太小或太大的话,那么你看到的景象就会变得歪歪扭扭的。fovy的典型的值是D3DX_PI/4,它是pi的四分之一(由于pi弧度等于180度,所以这个值等于45度)。
下一个重要的参数是Aspect,它是观察区域的横纵比。如果你有一个400×400像素的窗口,那么横纵比是1:1,或1.0(因为它是一个正方形)。如果你的窗口是400×200(宽度是高度的两倍),那么横纵比是2:1,或2.0。为了计算这个数值,将窗口的宽度除以窗口的高度:
FLOAT Aspect =(FLOAT)WindowWidth / (FLOAT)WindowHeight;
zn和zf参数为近和远裁剪平面(clipping planes)的值,并且单位与你用于定义3-D顶点的单位相同。用于近和远裁剪平面的典型值分别是1.0和1000.0。这两个值表示离观察点的距离小于1.0(和大于1000.0)的多边形不会被绘制。你也许想在自己的项目中将zf设为高一些的值,如果你想要绘制远于1000.0单位的物体的话。
在你构造了投影矩阵之后,你使用IDirect3DDevice9::SetTransform函数来设定投影变换矩阵,而这次将State参数设为D3DTS_PROJECTION:
// g_pD3DDevice =pre-initialized device object D3DXMATRIX matProj; // Create theprojection transformation matrix D3DXMatrixPerspectiveFovLH(&matProj,D3DX_PI/4, 1.0f, 1000.0f,); // Set the projectionmatrix with Direct3D if(FAILED(g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj))) { // Error occurred }
===============================================================================
好啦,这几小节关于变换的内容就讲完了。内容不多,不过可能大家看起来有点费劲。其实作者在讲视角变换和投影变换的时候不是很好,尤其是投影变换部分,至少应该把平截头体(frustum)画出来呀!这方面的内容希望大家去参考一下“龙书“第二版的第6章,那里讲述得比较详细清楚。
DirectX 9.0c游戏开发手记之RPG编程自学日志之九 ——Drawing with DirectX Graphics (用DirectX图形绘图)(第4节)(B)
原文地址:http://blog.csdn.net/u011873969/article/details/39293197