zoukankan      html  css  js  c++  java
  • Direct3D9的绘制流水线

    Direct3D的渲染过程大致可以分为以下几步

    渲染流水线示意

    0. 模型表示

    所有的三维实体都可以由有限的三角形mesh来逼近地表示

    • D3D绘制图形的最小单位(图元)通常为三角形mesh,但D3D也支持点图元和线图元(例如用于粒子系统)
    • 为了描述一个三角形mesh,我们需要一个顶点列表,D3D中的顶点和数学上的顶点有所区别,除了数学上顶点所有的位置信息外,D3D的顶点还包含了光照,颜色,法向量等信息,这些信息可以由用户自由组织,即FVF(灵活顶点格式)
    #define COLORED_VERTEX D3DFVF_XYZ | D3DFVF_DIFFUSE
    struct COLORED_VERTEX
    {
    	FLOAT _x, _y, _z;
    	DWORD _color;
    }
    
    #define NORMAL_TEXED_VERTEX D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1
    struct normalTexedVertex
    {
    	FLOAT _x, _y, _z;
    	FLOAT _nx, _ny, _nz;
    	FLOAT _u, _v;
    }
    
    • 需要注意的是,FVF宏的定义顺序必须和顶点结构体中相应变量的顺序保持一致

    1. 顶点缓存和索引缓存
    cube Vertex
    可以通过这样一个顶点数组来描述以上图形

    Vertex rect[6] = { {v0, v1, v2,},
    				   {v0, v2, v3,}};
    

    不难发现,这样有一些顶点是被重复缓存的,这样在处理较复杂场景时,会有大量顶点被重复缓存,造成空间的浪费,因而我们进一步采用索引缓存来解决这一问题

    • 索引缓存即把所有顶点放在一个缓存中,再通过每个顶点的下标来访问这些顶点,如此可以避免顶点的重复缓存,于是上图可以描述为
    Vertex vertices[4] = {v0, v1, v2, v3,};
    DWORD indexes[6] = { {0, 1, 2,},
    					 {0, 2, 3,},};
    
    • 顶点缓存中,顶点的绕序不是随便定义的,在后面的背面消隐过程中会使用顶点的绕序作为操作的参考,因此在定义顶点缓存或索引缓存时需要注意绕序的问题

    2. 摄像机
    摄像机用于指定一个三维场景中的可见区域,视角(FoV),近裁剪面和远裁剪面构成的平头锥体即可视区,这个区域内的三维场景最终会被投影到投影面上,D3D中,投影面被定义为z=1的平面。

    3. 局部坐标(Local space)
    局部坐标描述了一个三维模型各个顶点的相对位置,使用局部坐标时不用考虑位置,大小,朝向等问题,有利于简化建模过程,大多数模型开始就处于局部坐标系中。

    4. 世界坐标系(World Space)
    作为一个三维场景,必须要处理各个场景物体的大小,相对位置,朝向等一系列问题,因而需要一个统一的坐标系,即世界坐标。
    D3D的变换可以由IDirect3DDevice9::SetTransform方法实现,第一个参数表示变换类型,世界变化适用D3DTS_WORLD,第二个参数即相应的世界变换矩阵。 要注意的是,对于三维场景中的不同物体,世界变换矩阵并不一定相同。

    //一个世界变换(平移变换)的例子
    D3DXMATRIX objWorldMatrix;
    D3DXMATRIXTranslation(&objWorldMatrix, 3.0f, 0.0f, 2.0f);
    
    Device->SetTransform(D3DTX_WORLD, &objWorldMatrix);
    
    drawObj();
    

    5. 观察坐标系(View Space)
    在三维场景中,几何体和摄像机是相对于世界坐标系定位的,为了简化运算,我们将摄像机平移到世界坐标远点的位置,朝向和世界坐标z轴正方向重合,为了保持摄像机视场的固定,场景中的其他物体也必须和摄像机进行同样的变换,这种变换即取景变换,变换后的物体位于观察坐标系内

    View Space Transform

    • 取景变换的矩阵由D3DXMatrixLookAtLH函数计算得到
    D3DXMATRIX *D3DMatrixLookAtLH(D3DXMATRIX *pOUt,
    				   const D3DXVECTOR3 *pEye,
    				   const D3DXVECTOR3 targetPoint,
    				   const D3DXVECTOR3 *pUp);
    
    • pEye指定摄像机在世界坐标系中的坐标
    • pAt指定摄像机观察点在世界坐标系中的坐标
    • pUp定义了世界坐标系中“上”方向

    6. 背面消隐
    每个多边形都有朝向摄像机的一面和偏离摄像机的一面,因为摄像机不能进入场景中实体的内部,所以摄像机不可能观察到多边形的背面,因此我们在绘图时可以将多边形的背面删除,以改善性能,这一过程即背面消隐

    • 为了实现北面消隐,D3D需要区分哪些多边形是正面朝向摄像机的,哪些是背面朝向摄像机的,默认情况下,D3D将观察坐标系中顶点绕序为顺时针的mesh认为是正面朝向的,反之认为是背面朝向的进行消隐,这一默认值可以修改RenderState的D3DRS_CULLMODE来改变
    Device->SetRenderState(D3DRS_CULLMODE, Value);
    
    • value取值如下
      • D3DCULL_NONE 禁用背面消隐
      • D3DCULL_CW 对顺时针绕序的三角形mesh进行消隐
      • D3DCULL_CCW 对逆时针绕序的三角形mesh进行消隐

    7. 光照
    光源和几何体一样经过多次变换变换到观察坐标系内,可以通过固定功能流水线和可编程流水线实现光照

    8. 裁剪
    视域体决定了一个几何体是否会出现在摄像机的视场中,裁剪过程会将视域之外的几何体剔除以改善性能

    • 裁剪有三种情况,取决于几何体和视域体的关系
      • 几何体完全在视域内部,保留并送入下一阶段处理
      • 几何体完全在视域外部,直接剔除
      • 几何体部分在视域内部,部分在外部,将几何体拆分成两部分,视域外的部分丢弃,视域内的部分被保留并送入下一阶段处理

    9. 投影

    在观察坐标系中获取3D场景的2D表示这一过程叫投影,投影有多种方式,我们使用透视投影,用于使用2D图象表示3D场景,使用下列函数创建投影矩阵

    D3DXMATRIX *D3DXMatrixPerspectiveFovLH(
    						D3DXMATRIX *pOUT, //returns matrix
    						FLOAT fovY, //vertical field of view
    						FLOAT AspectRatio, //width/height
    						FLOAT zn, //distance to near panel
    						FLOAT zf //distance to far panel
    						);
    
    • 其中AspectRatio用于修正投影窗口和显示屏纵横比不同造成的畸变

    10. 视口变换
    视口变换是将顶点坐标从投影窗口变换到屏幕上的一个矩形区域中,视口指的就是这个矩形区域

    • D3D中,视口用D3DVIEWPORT9结构体表示
    typedef struct D3DVIEWPORT9
    {
    	DWORD x;
    	DWORD y;
    	DWORD width;
    	DWORD height;
    	DWORD minZ;
    	DWORD maxZ;
    }D3DVIEWPORT9;
    
    • 一但填充好D3DVIEWPORT9结构,可以用下列方式设置视口,设置好视口后,D3D会自动为我们完成视口变换
    D3DVIEWPORT9 vp = {0, 0, 640 ,480, 0, 1};
    device->SetViewport(&vp);
    

    11. 光栅化

    顶点坐标转换为屏幕坐标后,我们就有了一个在二维平面上的三角形列表,光栅化就是为屏幕上每个像素计算颜色值,以绘制这些三角形

    Written with StackEdit.

  • 相关阅读:
    【Java EE 学习 21 上】【其它类型的监听器】【使用HttpSessionActivationListener监听session的活化和钝化】
    【Java EE 学习 20】【使用过滤器实现登陆验证、权限认证】【观察者模式和监听器(使用监听器实现统计在线IP、登录IP 、踢人功能)】
    【Java EE 学习 19】【使用过滤器实现全站压缩】【使用ThreadLocal模式解决跨DAO事务回滚问题】
    【stut 逆置正整数】
    【JAVA使用XPath、DOM4J解析XML文件,实现对XML文件的CRUD操作】
    【JAVA与DOM4J实现对XML文档的CRUD操作】
    【JAVA解析XML文件实现CRUD操作】
    【JAVA与XML、dtd约束、Schema约束】
    【JAVA正则表达式综合练习】
    【JAVA正则表达式】
  • 原文地址:https://www.cnblogs.com/current/p/3991801.html
Copyright © 2011-2022 走看看