绘制流水线

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DY_1024/article/details/84145954

一旦我们建立了3D场景的几何描述,确定好虚拟摄影机,接下来的任务就是在显示器中建立3D场景的2D表示,为了实现这一个过后才能,我们专门的流程来完成它,我们称之为绘制流水线。大致如下图:(从左至右)

在绘制流水线中,有几个比较重要的部分就是,是坐标系的变换,这类坐标的变换通常是使用矩阵来实现的,Direct3D可以帮助我们实现这些变换,我们所提供的仅仅只是提供需要变换的矩阵以及变换的类型,,Direct3D中变换矩阵的方法如下:

IDirect3DDevice9->SetTransform方法,该方法有两个参数:一个变换的类型,一个是需要变换的矩阵。

我们将在你接下来的部分详细讨论。

局部坐标系

用于定义构成物体的三角单元列表的坐标系,也就是以模型为中心的坐标系。

优点:简化建模过程

世界坐标系

将很多个物体组织在一起的时候,就是一个大的场景,这个场景为了统一一个标准,就会使用世界坐标系,从局部坐标系到世界坐标系的变换叫做:世界变换。该变换通常包括缩放、平移、旋转等。

世界变换通过一个矩阵来表示,并且IDirect3DDevice9::SetTransform方法来加以应用,我们将该方法的第一个参数设置为:D3DTS_WOLED,然后地问个参数表示所采用的世界变换的矩阵。

例如:假定我们想一个立方体的中心位于世界坐标的中的(-3,2,6)点上面,让一个球体的中心位于点(5,0,-2)上,可以这么实现:

//构建立方体的
D3DXMATRIX cubeWorldMatrix;
D3DXMatrixTranslation(&cubeWorldMatrix, -3.0f, 2.0f, 6.0f);

//构建球体的
D3DXMATRIX sphereworldMatrix;
D3DXMatrixTranslation(&sphereworldMatrix, 5.0f, 0.0f, -2.0f);

//设置多维数据集的转换
Device->SetTransform(D3DTS_WORLD, &cubeWorldMatrix);
drawCube();

Device->SetTransform(D3DTS_WORLD, 6sphereworldMatrix);
drawsphere();// draw the sphere

观察坐标系

在世界坐标中,几何体和摄影机的定义都是相对于世界坐标的,但是当摄影机的位置以及朝向任意的时候,摄影变换就会变得其他类型的变换就会变得困难以及效率不高。为了简化,我们将摄影机变换值世界坐标系中的原点,然后使其摄影机的光轴和世界坐标的z轴正方向一直,同时世界坐标系中的物体也随着摄影机一同变换,以保证摄影机的视场恒定。这种变换称之为取景变换,我们称变换之后的几何体位于观察坐标系中。

大概是下面这个意思:

扫描二维码关注公众号,回复: 4181947 查看本文章

观察矩阵由下面得函数计算得到:

D3DXMATRIX*D3DXMatrixLookAtLH(
	D3DXMATRIX* pOut,			//接收结果观察矩阵的样子
	CONST D3DXVECTOR3* pEye,	//摄影机在世界坐标中的位置
	CONST D3DXVECTOR3* pAt,		//被观察的点在世界坐标中的位置 
	CONST D3DXVECTOR3* pUp		//该参数是世界坐标系中向上方向的向量
);	

例子:假定摄影机位于世界坐标系中的(5,3,-10)中,被观察的点位于世界坐标系的原点,我们可以这样创建取景变换矩阵:

D3DXVECTOR3 position(5.0f,3.0f,-10.0f);
D3DXVECTOR3 targetPoint(0.0f,0.0f,0.0f);
D3DXVECTOR3 wor1dUp(0.Of,1.0f,0.0f);
D3DXMATRIX   V;
D3DXMatrixLookAtLH(&V,sposition,&targetPoint,bworldup);
//取景变换需要用IDirect3DDevice9.::SetTransform方法来设定,其中对应于变换类型的参数需指定为D3DTS_VIEW:
Device->SetTransform(D3DTS_VIEW,&V);

背面消隐

书上给出的概念比较复杂,我觉得背面消隐就是摄影机能看到的地方叫做正面,不能看到的地方叫做背面,当我们在3D场景中。如果只画摄影机可以看到的正面,其实和全部画出来是一模一样的,随意我们索性就不管背面了,这就是背面消隐。

如图展示,前向称之为正面朝向多边形,后向称之为背面朝向多边形。

经过背面消隐之后,大概是下面这样的:

两者画出来的效果是一模一样的。

当然为了实现背面消隐,Direct3D需要知道哪些是正面朝向,哪些是背面朝向。默认状态下,当在观察坐标系中,Direct3D认为顶点排列顺序为顺时针的三角单元是正面朝向,顶点朝向为逆时针的三角单元是背面朝向。

由于某些原因,默认的消隐方式不能满足我们的需求的话,我们可以更改绘制状态:D3DRS_CULLMODE来达到目的:

Device->SetRenderState(D3DRS_CULLMODE,Value);
其中,Value可取以下值:
·D3DCULL_NONE 完全禁用背面消隐。
·D3DCULL_CW只对顺时针绕序的三角形单元进行消隐。
·D3DCULL_CCW默认值,只对逆时针绕序的三角形单元进行消隐。

光照

光源是在世界坐标系中定义的,但必须经取景变化到观察坐标系中方可使用,在观察坐标系中,光源照亮了场景中的物体,从而获得比较逼真的效果。

裁剪

我们将不再视域体之内的物体,丢弃掉,这个过程叫做裁剪。

有些模型 一部分在视域体之内,一部分没有在,那么在视域体之内的东西将保留,不再视域体之内的东西不会保留。

投影

观察坐标系中我们的任务是获取3D场景的2D表示,。从n维变换成n-1维的过程我们称之为投影。实现投用的方式有很多种,我们现在之关心“透视投影”,透视投影会产生透视缩短,也就是远小近大的效果,这类投影使得我们可以使用2D图形表示3D场景。

投影变换定义了视域体,并负责将视域体中几何体投影到投影窗口上面,投影矩阵我们可以通过D3DX函数获取,其功能是根据现在视域体的描述信息创建一个投影矩阵。

D3DXMATRIX *D3DXMatrixPerspectiveFovLH(
	D3DXMATRIX& pOut,		//返回的投影矩阵
	FLOAT fovY,				//视域体的视域角 
	FLOAT Aspect,			//纵横比 
	FLOAT zn,				//到近平面的距离
	FLOAT zf				//到元平面的举例
);

纵横比 = 屏幕宽度/屏幕高度

纵横比是为了校正正方形到矩形的映射而发生的畸变。

投影矩阵的使用方法:将SetTransform的第一个参数变成D3DTS_PROJECTION

例子:

本例中视域体的视域角(field of view)为90°,近裁剪面到坐标原点的距离是1,远裁剪面到原点的距离是1000。
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovH(
&proj,PI*0.5f,(float)width/(float)height,1.0f,1000.0f);
Device->SetTransform(D3DTS_PROJECTION,&prOj);

视口变换

视口变换的任务是将顶点坐标从投影窗口转换到屏幕的矩形区域中,该矩形区域称之为视口,在游戏中,视口通常是整个屏幕的矩形区域,但是视口也可以是屏幕的子区,比如窗口模式运行。视口总是相对于窗口来描述的,因为视口总是处于窗口内部,并未其位置也是窗口坐标来指定。

Direct3D中视口用下面的结构体表示:

typedef struct D3DV1EWPORT9{
DWORDX;DWORDY; 
DWORD Width; 
DWORD Height; 
DWORD Min2;
DWORD Max2;
)D3DVTEWPORT9;

该结构的前4个数据成员定义了视口矩形相对于其父窗口的位置及大小。成员变量MinZ指定了深度缓存中的最小深度值,MaxZ指定了深度缓存中的最大深度值。Direct3D将深度缓存的深度范围设在[0.1]区间内,所以除非想要追求某种特效,MinZ和MaxZ应限制在该指定区间内。
一旦我们填充好D3DVIEWPORT9结构,就可这样来设置视口:
D3DVTEWPORT9 vp={0,0,640,480,0,1);
Device->SetViewport(&vp);

光栅化

顶点坐标变换到屏幕坐标之中,我们就有了一个2D三角形单元列表。光栅化的任务就是计算绘制每一个三角形单元的里面每一个像素的颜色的值。

光栅化过程的计算量非常大,我们应尽量借助专用图形卡的加速功能。光栅化的最终结果是显示在屏幕上的一幅2D图像。

光栅化的步骤:

1、读取模型的顶点。3个3个读取,因为要绘制三角形

2、将顶点2个2个的链接在一起,形成三角形

3、计算屏幕像素点是在三角形外还是在三角形内,在内部就上色,在外部就不上色。

     注意:如果一个三角形挡在了另外一个三角形前面,那我们就要判断当前准备上色的像素点是不是已经被上过色了

4、不断的循环,然后完成整个3D模型的绘制

小结:

1、3D物体可以用三角形网格来表示,使用的是一个逼近物体形状和轮廓的三角形单元列表

2、视域体用来表示基本的虚拟摄影机的模型,位于视域体内部的场景是摄影机可以观察到的

3、构成场景的许多的3D模型在局部坐标系中进行构建以及定义,然后变换到世界坐标系中去,接着为了使投影和裁剪以及其他运算的时候更方便一些,再将其变换到观察坐标系中去,在观察坐标系中,摄影机在世界坐标系的原点,摄影机的光轴是Z轴的正方向。变换到观察坐标系之后,就可以通过投影将几何体映射到投影窗口中去,接着视口变换就会将投影窗口中的几何体映射到视口中去,最后在光栅化的阶段将计算出三角形单元在屏幕像素点的颜色值,最后显示出2D图像。

猜你喜欢

转载自blog.csdn.net/DY_1024/article/details/84145954