zoukankan      html  css  js  c++  java
  • DirectX 总结

    DDS

    DirectXDraw Surface file format, .dds。这是微软从DirectX7开始引进的一种文件格式,它用来存储压缩的或未压缩的纹理,该格式支持mimaps cube maps和volume maps, D3DX和许多其他的DX工具都支持这种格式,比如DirectX Texture Editor(dxtex.exe)和Texture Conversion Tool(Texconv.exe),从D3D110开始,DDS文件也支持纹理数组

    DXGI

    DirectX Graphics Infrastructure 

    转换为.x格式

    MeshConvert.exe,这个tool位于Microsoft DirectX SDK \Utilities\bin\x86目录下面,可以用来转换.x文件,支持.x, .obj, .sdkmesh格式之间的相互转换,.sdkmesh是微软新的格式在DX10/DX11之后使用,用来取代.x格式,MeshConvert是一个命令行工具,使用方法如下

    Usage: meshconvert <options> <input filename>

       <input filename>    Input mesh filename.
                           The input file can be of .x, .obj, or .sdkmesh format
       /o <file>           Optional output mesh filename
       /y                  Overwrite existing destination file
       /n                  Generate normals
       /t                  Generate tangents
       /tb                 Generate tangents and binormals
       /tcount <count>     Texcoord count for the output mesh
       /a                  Output animation information
       /op                           Vertex cache optimize the mesh before exportin
     (non-functional)
       /sdkmesh            [default] convert to .sdkmesh binary file
       /x                  convert to .x binary file
       /xt                 convert to .x text file
       /v                  Verbose

    .SDKMesh is a simple custom mesh format used by new SDK samples

    使用DirectX Control Panel

    使用DirectX Control Panel可以方便的设置DirectX相关的东西,比如用Debug库还是Release库,是否检测内存泄漏,是否允许Shader调试等等,这个工具的位置在...\Microsoft DirectX SDK\Utilities\bin\x86,界面如下图。

    使用PIX分析D3D应用程序

    PIX是调试和分析D3D应用程序的,该工具位于...\Microsoft DirectX SDK\Utilities\bin\x86下,关于它的用法,DX帮助文档中有详细的说明,位于tools-DirectX Performance Tools-PIX下,工具截图

     

    注意资源释放的顺序

    有时候在释放资源的时候会出现运行时错误,这可能是由于资源之间的依赖造成的,比如下面的代码,运行时会出现一个违规访问的错误,为什么呢,因为m_SoundBuffer是依赖m_pDirectSound的,而m_pDirectSound先释放了,所以m_SoundBuffer变得不可访问了

     
    if(m_pDirectSound != NULL)
    {
        m_pDirectSound
    ->Release() ;
        m_pDirectSound 
    = NULL ;
    }

    if(m_SoundBuffer != NULL)
    {
        m_SoundBuffer
    ->Release() ;
        m_SoundBuffer 
    = NULL ;
    }

    将二者释放的顺序交换一下就好了,如下。

    if(m_SoundBuffer != NULL)
    {
        m_SoundBuffer
    ->Release() ;
        m_SoundBuffer 
    = NULL ;
    }

    if(m_pDirectSound != NULL)
    {
        m_pDirectSound
    ->Release() ;
        m_pDirectSound 
    = NULL ;
    }

    注意变换的顺序

    有很多图形学书籍都讲到过,先旋转再*移和先*移再旋转效果是不一样的,同理,先缩放再*移和先*移再缩放也是不一样的。 

    不要在Render函数中设置变换矩阵

    为了渲染,一般的对象都有个Render函数,在渲染之前要做一些变换,比如移动旋转之类的,但是切记不可在Render函数中做这些变换,因为Render函数是被实时调用的,如果在这里做变换,则一个变换会被应用很多次。

    D3D中顶点的顺序问题

     Remember in Direct3D the vertices must be defined in clockwise order. see the picture below, the order is v0, v1, v2, v3

    正确使用时间函数timeGetTime()

    这个函数返回的是当前时间-单位毫秒,可是类型是DWORD,而我们一般做计算都需要float类型,转换一下,一般应该先计算差值,再做类型转换

     
    DWORD lastTime = timeGetTime(); 

    ...

    DWORD currTime  
    = timeGetTime();
    float timeDelta = (currTime - lastTime) * 0.001f;

    ...
    //use timeDelta

    lastTime 
    = currTime;


    而不要这样做:

    static float lastTime = (float)timeGetTime(); 

    ...
    float currTime  = (float)timeGetTime();
    float timeDelta = (currTime - lastTime)*0.001f;

    这样是要损失精度的,因为DWORD是32为整数,而float只有24位精度,此法不可取。

    让代码只执行一次

    void RunOnce()
    {
        
    static bool flag = false ;

        
    if(!flag)
        {
            cout 
    << "you can not see this line twice!" << endl ;
            flag 
    = true ;
        }
    }

    头文件包含警戒

    通常我们用下面的代码来防止头文件被重复包含,这是标准的写法

    #ifndef __HEADER_H__
    #define __HEADER_H__

    // code of the file

    #endif //HEADER_H__

    还有一种方法是,这种方法是MS特有的,不适合其他*台,所以推荐使用第一种方法

    #pragma once

    // code of the file

    解决从VC6转换到VS2005/VS2008时编译和链接错误

    有很多几年前编写的游戏书籍,其中所附代码大多是基于VC6的,而我们现在用的大多是VS2005/VS2008/VS2010,所以需要一次转换,而在转换中经常会遇到编译或者链接错误,解决办法如下:

    编译错误:error C2440: '=' : cannot convert from 'char [14]' to 'LPCWSTR'

    这是由于作者默认使用的是函数的A版本,而我们的工程使用了W版本。

    解决办法一:手动将所有函数改为A版本,例如MessageBox -> MessageBoxA, 不推荐这种防范。或者将所有字符串改为宽字符串,即在字符串前加大写字母L,这个方法比较笨,但是确实好的方法。推荐使用。

    解决办法二:在工程文件上点右键-Properties-Configuration Properties-C/C++-Preprocessor-Preprocessor Definitions-点击右边的省略号按钮-在弹出的对话框中将Inherit from parent or project defaults选项去掉即可。这个方法一劳永逸,可以一次性去除所有此类编译错误。但是却不是好的编程习惯,我们应该尽量使用函数的W版本。

    链接错误:unresolved external symbol xxx

    这种错误一般都是由于缺少lib文件导致的,只要引用正确的lib文件就可以了

    解决办法:在工程文件上点右键-Properties-Configuration Properties-Linker-Input-Additional Dependencies-点击右边的小省略号按钮-将所需的lib文件加入到弹出的对话框中即可。

    调试选项的设置

    通过注册表也可以设置D3D的调试选项,这和使用DirectX控制面板是一样的,而且两者是相通的,改变一个,另一个也会跟着改变,如下,注册表位置:

    HKLM\Software\Microsoft\Direct3D

    如何求取视线

    有很多时候需要用到视线,比如Billboard技术,要求被观察物体始终面对观察者,这时候就需要该物体与视线垂直,求取视线很简单,用观察点减去眼睛的位置即可

    1 D3DXVECTOR3 viewRay = lookAt - eyePt ;

    Zoom in/Zoom out效果是如何实现的?

    很多图形软件都支持该效果,在浏览一个model的时候,鼠标滚轮向前滚时(mouse wheel rotate forward, away from the user),model会逐渐变大,谓之zoom in,鼠标滚轮向后滚时(mouse wheel rotate backward, toward the user),model会逐渐变小,谓之zoom out

    那么这个效果是如何实现的呢?在我初学DirectX的时候,一直以为用缩放变换来实现。直到研究了DXUT的Camera类以后,才发现,其实有一个更简单的办法。通过改变Camera与Model之间的距离来实现,这与现实生活中的感觉是一样的,当我们离一个物体*的时候,感觉它很大,而当我们渐渐远离它的时候,它会变得越来越小,此其所以然也!编程的乐趣就在于灵活!

    transform小结

    Transform(变换)的本质就是从一个坐标系到另一个坐标系的过程
    world transform
    model space -> world space

    view transform
    world space -> view/camera space

    projection transform
    view/camera space -> projection space


    transform engine(变换引擎) 以顶点为输入,对其进行world, view and projection transform, 然后进行剪

    裁,将结果传送给rasterizer进行光栅化

    //world transform通过下面的代码完成
    // 将model移动至原点
    D3DXMATRIXA16 matWorld ;  
    D3DXMatrixTranslation( &matWorld, 0.0f, 0.0f, 0.0f) ;
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

    //view transform通过下面的代码完成
    D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-10.0f ); //眼睛位置 
    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); //观察中心
    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );   //向上向量
    D3DXMATRIXA16 matView;  
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    projection transform通过下面的代码完成
    D3DXMATRIXA16 matProj;  
    //视角:pi/4,即45度
    //纵横比:1:1
    //*剪裁*面:1.0f
    //远剪裁*面:1000.0f
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

    如何区分Point和Vector

    在D3D中Point和vector都是用三维坐标表示的,比如,给定
    v = [x, y, z], 如何区分这是一个点还是一个向量呢
    答案是:在三维坐标下无法区分,于是在最后再加一维,形成齐次坐标
    v = [x, y, z, w], 实际应用中w通常取值1
    规定如下:
    w = 1时,v表示点
    w = 0时,v表示向量
    为什么呢?
    先看一下*移变换的矩阵

    因为向量是没有位置属性的,向量只有长度和方向两个属性,即*移一个向量是没有意义的
    所以将向量的第四维w设置为0,阻止*移。
    但是点是有位置属性的,*移一个点也是有意义的,所以将点的w置为1,使之可以*移
      

    如何从一个坐标系变换到另一个坐标系

    通常这种需求都是逆向的,因为正向的D3D已经做了
    比如对于一个view space中的model,如何把它变换到world space呢?(在D3D顶点处理流水线中world space是view space的前一个过程)
    首先我们应该知道world space -> view space 是怎样一个过程,了解了这个过程后,应用它的逆过程即可
    显然,world space -> view space是通过视图变换实现的,这个变换矩阵就是view matrix,好了,现在我们需要做的是:
    1. 找出这个view矩阵
    2. 求出它的逆矩阵
    3. 将该逆矩阵应用到要变换的模型
    下面以一个点为例,假设我们要将点p(x, y, z) 从view space变换到world space

    步骤:
    首先求出view matrix
    D3DXMATRIX view;
    Device->GetTransform(D3DTS_VIEW, &view);

    再求出它的逆矩阵
    D3DXMATRIX viewInverse;
    D3DXMatrixInverse(&viewInverse, 0, &view);

    然后将这个矩阵乘到这个点上即可
    D3DXVec3TransformCoord(p, p, viewInverse);

    注:D3DXVec3TransformCoord是用来变换点的(即w=1的vector)
    而  D3DXVec3TransformNormal是用来变换向量的(即w=0的vector)

    矩阵连乘的顺序

    如果需要对同一个图形连续进行多个变换,那么可以把多个变换矩阵连乘形成一个矩阵。

    但矩阵乘法不满足交换律,所以连乘的顺序很重要。

    大多数文档都是以左右顺序来区分的,这是不准确的,而且不便于理解和记忆。

    这里讲一个规则,比较方便

    规则:在连乘式中,离被变换顶点*的矩阵对应的变换先进行。

    比如,对顶点P(x, y, z, 1)进行如下变换

    1. *移到(1, 1, 1)点,变换矩阵为MT

    2. z轴旋转30度,变换矩阵为 MR

    3. 放大2倍,变换矩阵为 MS

    那么正确的连成顺序是

    P * MT * MR * MS (在DirectX文档里多采用这种写法)

    MTP最*,那么它是最先进行的变换,MR次之,MS再次。

    很多书籍或文档里面说是按照从左到右的顺序连乘,但是别忘了顶点在公式中的位置

    如果顶点在右边,那么就变成了下面的形式

    MS * MR * MT * PT (在以OpenGL为基础的图形学书籍里多采用这种写法)

    所以准确的说应该是,在连乘式中,先进行的变换离被变换的顶点*。

    注意如果P在连乘式右边,那么应该取其转置形式,否则无法与矩阵相乘。

    为什么变换矩阵是4 x 4的

    因为三维的矩阵无法完成某些变换,比如*移变换对应的矩阵如下

     

    这用三维矩阵是无法实现的,类似的还有透视投影变换,所以在D3D中使用4×4矩阵来实现变换,又一个问题来了,由于3D中的顶点都是三维的,三维的vector和四维的matrix是无法相乘的,于是在三维的顶点后面再加上一维,形成齐次坐标,如下

     [x, y, z, w]

    最后一维通常用w表示,而w通常取值1

    这样就可以用一个1×4vector与一个4×4matrix相乘了。

      [x, y, z, w] *

     

    d3dx9.h

    这个头文件包含了几乎D3D用到的所有头文件,如果编译、链接或者运行有问题,可以尝试包含这个文件试试。

    如何查看VertexShader和PixelShader的版本号

    如果安装了DirectX SDK,可以使用其中的工具DirectX Caps Viewer 来查看,这个工具在DirectX的开始菜单中,也在SDK安装目录的Utilities\Bin\x86(x64)下面

    打开这个工具后,依次展开结点DirectX Graphics Adapters-video card name-D3D Device Types-HAL-Caps

    注意:一定要选择HAL分支,这才是你显卡真正支持的特性,而Reference目录下存储的是所有D3D特性,这是用软件模拟的,速度奇慢,只有在安装了DirectX SDK的机器上才可用,这就是HAL Device和Reference Device的区别,大家可以查看SDK帮助文件中Device Type一节来获取详细的信息

    如果没有安装DirectX SDK, 可以使用Everest来查看

    如何发布游戏(XNA)

    这里吧,比较详细

    点积和叉积

    设u和v是两个三维向量,α是它们之间的夹角

    点积

    u·v = ux*vx + uy*vy + uz*vz =|u|*|v|*cos(α)

    乍一看,几何意义不十分明显,注意:当u和v都是单位向量时,点积就是两个向量夹角的余弦值

    D3D中经常用这种方法来求夹角或者旋转角度,或者顶点法向量与入射光的夹角。

    叉积

    u×v = [(uyvz - uzvy), (uzvx - uxvz), (uxvy - uyvx)] =|u|*|v|*sin(α)

    叉积的结果同时垂直于两个向量

    叉积的结果值是以u和v为邻边的*行四边形的面积,叉积可以用来求多边形的面积

    global variables are implicitly constant, enable compatibility mode to allow modification

    编译Shader程序时遇到以下错误

    全局变量默认是常量,貌似在Shader程序中不能修改?新版的HLSL编译器不支持

    解决办法:

    将D3DXCompileShaderFromFile的第六个参数改为D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY即可

    花屏

    如果程序执行后,窗口出现花屏现象,那么多半是由于depth buffer没有clear导致的,比如下面这幅图就是一个花屏的例子。

    解决办法,在调用Clear函数时,将depth buffer也clear一下即可。原来可能是这样调用的

    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, 0xff00ff00, 1.0, 0 ); //仅仅clear render target

    修改后如下

    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , 0xff00ff00, 1.0, 0 );

    需要注意的是,这个Clear函数可能会失败,比如你在CreateDevice的时候并没有创建depth buffer,而在Clear函数中却要Clear depth buffer,所以请检查你的CreateDevice函数,确保设备确实有一个关联的depth buffer。

    ==

    作者:zdd
    出处:http://www.cnblogs.com/graphics/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    Java 第二题
    第6次作业--static关键字、对象
    20194643 自动生成四则运算第一版报告
    软件工程 第一次作业
    MySQL主从复制与读写分离原理
    垂直拆分、读写分离、水平拆分(分库分表)详解
    MySQL InnoDB 索引原理
    MySQL架构体系&SQL查询执行全过程解析
    最全MySQL锁详解:表/行/页锁、共享/排它锁、悲观/乐观锁等
    MySQL事务ACID与隔离级别详解
  • 原文地址:https://www.cnblogs.com/graphics/p/1583682.html
Copyright © 2011-2022 走看看