欢迎来到EasyLiu的博客 !
参考:directxtutorial.com DirectX.9.0.3D游戏开发编程基础
In the last lesson you built a simple, flat triangle lit with simple diffuse lighting. This triangle was not 3D, it was flat. If you managed to change it, you found it was a 2D triangle drawn
in screen coordinates. The triangle you made was pre-transformed, meaning you took no action to convert it from 3D coordinates to screen coordinates, but just gave Direct3D the screen coordinates.
翻译:在上一节课中我们建立了一个简单的,具有简单漫反射光的平面三角形。这个三角形不是3D的,它是平面的。如果你想改变它,你会发现它是一个平面坐标下的二维三角形。你画的这个三角形是预先经过转换的,意思是你并没有采取任何措施而将它从三维坐标变换成了屏幕坐标,而是直接把三角形的屏幕坐标给了Direct3D进行绘制。
In this lesson, you will learn to transform vertices, or convert them from 3D coordinates to screen coordinates. You will also learn to position the 3D camera, set the 3D "lens", and put your triangle
into a 3D world with other 3D objects in it.
翻译:在这节课,我们将学习顶点的转换或者三维坐标到屏幕坐标的转换。我们也将学习放置3D摄像头,设置3D“透镜”,并且把你的三角形放入具有其它三维物体的世界中。
绘制流水线
一个简单的绘制流水线如下图所示:需要经过坐标变换、背面消隐、光照、裁剪、投影、视口坐标系、光栅化等过程,这里主要讲一下局部坐标系到世界坐标系的转换(世界变换)、世界坐标系到观察坐标系的转换(取景变换)、投影(投影变换)。
The Geometry Pipeline(几何管道)
Before we get into the actual transformation code, let‘s take a look at everything that happens to translate something from 3D coordinates to a flat image. There
is a sequence of actions which must occur before an object appears on the screen properly. This sequence of actions is known as theGeometry Pipeline. It is called a pipeline because vertices are put through each step one at a time, and at
each step along the "pipe", the vertex is rendered into its flat image form.
When a model first starts out, it is generally centered on the origin, meaning the center of the object is at (0, 0, 0). This also means that all the objects in your game will be in the exact center
of the world, all piled up on top of each other, which doesn‘t make a very excellent game. The first step is to sort out the new positions of all the models in relation to each other.This is called World Transformation.
Once all the objects in the world have been sorted out and the vertices‘ positions have been altered to represent world coordinates, then we have to change the entire coordinate system to create
a virtual camera. What this means is that we have to change the direction of each axis, in order to position everything in the most efficient way for the video card. This process is known as View Transformation.
After the coordinate system has been rearanged, then it is time to convert all the 3D models into 2D images. In this step, the 3D coordinates are converted into screen coordinates. This process is
known as Projection Transformation.
上面介绍了世界转换、视图转换(取景变换)以及投影变换的概念以及为什么要进行这些变换,下图代表了变换的过程:
World Transformation(世界变换概述)
World
Transformation, in essence, changes coordinates from model space to world space. In other words, it places a model in a world at an exact point defined by coordinates. Following is an overhead demonstration of how this works:
This
is known as translation. Translation refers to the movement of a vertex along a coordinate system axis. For example, the above diagram shows movement of a tree along the x and y axes. Of course, we could also translate the tree along the z-axis, but our ground
here is flat, and having trees floating ten feet high just outside the local village tends to scare the tourists away (not to mention the players).
Of course, being able to move an object into world space is always useful, but it can get rather limiting if your model is always facing the same direction. A spaceship that can only face East is rather dull and does not elicit much thrill or adrenaline (or
so I find).
And so another part of World Transformation is rotation(世界变换的另一部分是旋转). Rotation is the process of spinning 3D objects along an axis. Like translation, it can be done along multiple axes simultaneously, allowing you to position
your model as desired.
Another important part of World Transformation is scaling(世界变换中另外一个重要的变换是缩放). Scaling is the action of making a 3D object larger or smaller. When an object is scaled, each vertex in the object is multiplied by a given number. These numbers can be different
for each axis, resulting in various stretching effects.
位于局部坐标系中的物体通过世界变换的运算变换到世界坐标系中,该变换通常包括平移、旋转以及比例运算。世界变换通过一个矩阵来表示,并由Direct3D通过SetTransform(D3DTS_WORLD, &matWorld)方法来加以应用,第二个参数表示所采用的世界变换矩阵。例如,我们想要一个立方体的中心位于世界坐标系中的的点(-3,2,6),让一个球体的中心位于点(5,0,-2),可以这样实现:
D3DXMATRIXA16 cubeWorldMatrix; D3DXMatrixTranslation(&cubeWorldMatrix, -3.0f, 2.0f, 6.0f); D3DXMATRIXA16 sphereWorldMatrix; D3DXMatrixTranslation(&sphereWorldMatrix, 5.0f, 0.0f, -2.0f); g_pd3dDevice->SetTransform(D3DTS_WORLD, &cubeWorldMatrix); //绘制立方体 g_pd3dDevice->SetTransform(D3DTS_WORLD, &sphereWorldMatrix); //绘制球体
View Transformation(取景变换)
在世界坐标中,几何体和摄像机是相对世界坐标系定义的。但是当摄像机的位置和朝向任意时,投影变换以及其他类型的变换就略显困难或者效率不高。为了简化运算,我们将摄像机变换至世界坐标系的原点,并将其旋转,使得摄像头的光轴与世界坐标系的Z轴正方向一致。同时,世界坐标系中的所有几何体随着摄像头一同进行变换,保证摄像头的视场恒定,变换称为取景变换,我们称变换后的几何体位于观察坐标系中,如下图所示:
Project Transformation(投影变换)
投影变换定义了视域体,并负责将视域体中的几何体投影到投影窗口中。投影矩阵比较复杂,可以使用如下函数:
// Build a perspective projection matrix. (right-handed)
D3DXMATRIX* WINAPI D3DXMatrixPerspectiveFovRH( D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf );
其中pOut代表投影之后的矩阵,Aspect代表横纵比(投影窗口中的几何体最终会变换到屏幕显示区,从方形(投影窗口)到矩形的显示屏的的变换会导致拉伸畸变,所谓纵横比就是显示屏纵横两维尺寸的比率,长用于校正由正方形到矩形的映射而引发的畸变,纵横比=屏幕宽度/屏幕高度),其余的三个参数的含义如下图所示:fovy代表观察范围夹角,zn代表投影中心距离近平面的距离,zf代表投影中心距离远平面的距离。
下面实现一个效果:使一个三角形绕Y轴一直旋转。主要函数是自定义的一个函数SetupMatrices,用于设定世界、观察、投影变换矩阵,代码如下所示:
VOID SetupMatrices() { // For our world matrix, we will just rotate the object about the y-axis. D3DXMATRIXA16 matWorld; // Set up the rotation matrix to generate 1 full rotation (2*PI radians) // every 1000 ms. To avoid the loss of precision inherent in very high // floating point numbers, the system time is modulated by the rotation // period before conversion to a radian angle. UINT iTime = timeGetTime() % 1000;//获取当前时间 FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;//1000ms旋转360度 D3DXMatrixRotationY(&matWorld, fAngle);//旋转矩阵 g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);//设置世界变换 // Set up our view matrix. A view matrix can be defined given an eye point, // a point to lookat, and a direction for which way is up. Here, we set the // eye five units back along the z-axis and up three units, look at the // origin, and define "up" to be in the y-direction. D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f);//观察点,摄像头的位置 D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);//朝原点看,代表摄像头朝向 D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);//垂直方向为y轴 D3DXMATRIXA16 matView; D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec); g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); // For the projection matrix, we set up a perspective transform (which // transforms geometry from 3D view space to 2D viewport space, with // a perspective divide making objects smaller in the distance). To build // a perpsective transform, we need the field of view (1/4 pi is common), // the aspect ratio, and the near and far clipping planes (which define at // what distances geometry should be no longer be rendered). D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f); g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); }
同时在初始化里面关闭背面消隐以及关闭光照:
// Turn off culling, so we see the front and back of the triangle g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // Turn off D3D lighting, since we are providing our own vertex colors g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);</span>
最后,Render()函数:
VOID Render() { // Clear the backbuffer to a black color g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); // Begin the scene if (SUCCEEDED(g_pd3dDevice->BeginScene())) { // Setup the world, view, and projection matrices SetupMatrices(); // Render the vertex buffer contents g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX)); g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1); // End the scene g_pd3dDevice->EndScene(); } // Present the backbuffer contents to the display g_pd3dDevice->Present(NULL, NULL, NULL, NULL); }
效果如下:由于是动态的,从图片看不出什么效果。
版权声明:本文为博主原创文章,未经博主允许不得转载。