• (转)学习directx遇到的问题


    1 MaxSimultaneousTextures 纹理同时叠加最大数目
    device->GetDeviceCaps( &Caps );
    int maxActiveTextures = Caps.MaxSimultaneousTextures;
    即在 DrawPrimitive  顶点之前,最多设置的纹理数量。如果你的机器显卡较差,这个数为2,就是刚刚好支持多纹理。
    如下代码所示如果MaxSimultaneousTextures < 4 将不能输出图形。注意:即使相同的纹理也算1个数量。如果做的纹理效果多于MaxSimultaneousTextures ,可以拆成多次调用DrawPrimitive 函数,达到相同效果。不过对于速度有影响
    例如 quake3 最多有10次渲染之多
     pd3dDevice->SetTexture( 0, g_pBackgroundTexture );
      pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
      pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
      pd3dDevice->SetTexture( 1, g_pWallTexture);
      pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX,  0);
      pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE );
      pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
      pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
      pd3dDevice->SetTexture(2, g_pEnvTexture);
      pd3dDevice->SetTextureStageState( 2, D3DTSS_TEXCOORDINDEX, 0);
      pd3dDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );
      pd3dDevice->SetTextureStageState( 2, D3DTSS_COLORARG2, D3DTA_CURRENT );
      pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP,   D3DTOP_ADD );
      pd3dDevice->SetTexture(3, g_pEnvTexture);
      pd3dDevice->SetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 0);
      pd3dDevice->SetTextureStageState( 3, D3DTSS_COLORARG1, D3DTA_TEXTURE );
      pd3dDevice->SetTextureStageState( 3, D3DTSS_COLORARG2, D3DTA_CURRENT );
      pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP,   D3DTOP_ADD );

      pd3dDevice->SetFVF(FVF );
      pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(VERTEX) );
      pd3dDevice->DrawPrimitive (D3DPT_TRIANGLESTRIP, 0, 2);
     
    2 DrawPrimitive()函数的 D3DPT_TRIANGLESTRIP  标志用的顶点第一个三角形为顺时针,第二个逆时针。。依次迭代。
    例如:记住uv 顺序即可 (0,0)->(1,0)->(0,1)->(1,1)
    VERTEX Vertices[] =
     {
      {  0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,},
      {  width,0.0f, 0.5f, 1.0f, 1.0f,0.0f, },
      {  0.0f,height, 0.5f, 1.0f, 0.0f, 1.0f,}, // x, y, z, rhw, tu, tv
      {  width,height, 0.5f, 1.0f, 1.0f,1.0f,},
     };
     
    3 获取窗口高度和宽度 IDirect3DSurface9,注意IDirect3DSurface9 Height 和 Width成员都是1。 #ifdef D3D_DEBUG_INFO这个宏时包围了这些成员。应该通过GetDesc获得表面属性,D3DSURFACE_DESC里面的height和width 才正确。
     IDirect3DSurface9* m_d3dsdBackBuffer;
     pd3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&m_d3dsdBackBuffer);
     //int height = m_d3dsdBackBuffer->Height;
     //int width = m_d3dsdBackBuffer->Width;
     m_d3dsdBackBuffer->GetDesc(pBackBufferSurfaceDesc)
     int height = pBackBufferSurfaceDesc->Height;
     int width = pBackBufferSurfaceDesc->Width;
     m_d3dsdBackBuffer->Release();  //一定要释放。
     
    4 创建设备时指定D3DCREATE_PUREDEVICE标志。可以参考D3DPRESENT_PARAMETERS参数说明
     
    5 无效纹理区域
      通过给纹理指定无效区域,应用程序可以对需要复制纹理的哪些子集进行优化,只有那些被标记为无效的区域才会被IDirect3DDevice9::UpdateTexture方法更新。当创建纹理时,整个纹理被标记为无效的。只有以下几种操作可以改变纹理的无效状态。
    • 给一个纹理添加一个无效区域。
    • 锁定纹理中的一些区域。此操作会把被锁定的区域添加到无效区域中,如果应用程序明确知道哪些是真正的无效区域,那么也可以关闭对无效区域的自动更新。
    • 将纹理作为目标表面进行更新的话会把整个纹理标记为无效的。
    • 对纹理调用IDirect3DDevice9::UpdateTexture方法会清除该纹理的所有无效区域。
    • 为了得到设备上下文(device context)而调用IDirect3DDevice9::GetDC

    对于mipmap纹理而言,无效区域被设在最高一级的纹理上,为了最小化对mipmap纹理中每一级的纹理更新所需复制的字节数,IDirect3DDevice9::UpdateTexture方法可以扩展无效区域并沿mipmap链更新子纹理。注意子级中无效区域的纹理坐标被向上舍入,也就是说,它们的小数部分被向上取整到纹理中最近的像素。

    因为每种类型的纹理具有不同类型的无效区域,所以每种类型的纹理都有相应的方法表示无效区域。二维纹理使用矩形,立体纹理使用立方体。

    • IDirect3DCubeTexture9::AddDirtyRect
    • IDirect3DTexture9::AddDirtyRect
    • IDirect3DVolumeTexture9::AddDirtyBox

    把以上方法的pDirtyRectpDirtyBox参数设置为NULL会扩大无效区域并使之覆盖整个纹理。
    每种锁定方法都有D3DLOCK_NO_DIRTY_UPDATE标志,使用这个标志可以防止对纹理无效区域的改变。更多信息,请参阅锁定资源
    如果在锁定操作时可以得到已改变区域的完整集合,那么应用程序应该使用D3DLOCK_NO_DIRTY_UPDATE标志。注意,对纹理一个的子级的锁定或复制操作(也就是说,未对纹理的最高一级进行锁定或复制操作)不会更新该纹理的无效区域。当应用程序锁定了纹理的子级而没有锁定纹理的最高一级时,它同样有责任对无效区域进行更新。

    6 固定管线怎么没有使用 SetFVF
    看了一个程序dxquake3中没有使用SetFVF,但也没有顶点或者像素shader。其实FVF在内部被DX转换为VertexDeclaration,所以用FVF或是VertexDeclaration都行。不使用SetFVF而是使用SetVertexDeclaration和SetVertexShader代替,SetVertexDeclaration声明数据存储格式,SetVertexShader提供数据处理方法SetFVF 是 dx9 新函数为了使写法更简单。dxquake3 中使用SetVertexDeclaration来提供的顶点格式,函数参数类似于
    D3DVERTEXELEMENT9 decl[] = 
    {
    { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
    { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
    D3DDECL_END()
    };
    但没有使用SetVertexShader设置着色器。相对于使用SetFVF,使用SetVertexDeclaration更有利于以后的扩展,实现可编程shader

    7 使用mesh调用ConvertToBlendedMesh 失败, 如果创建设备时设置 D3DCREATE_HARDWARE_VERTEXPROCESSING 很可能因为顶点不够用而失败
    使用 D3DCREATE_MIXED_VERTEXPROCESSING 参数会更好(使用skinmesh noindex 例子时候)。

    8  加入d3dx9dt.lib 而不是d3dx9.lib 这样对于没有 Release() 的资源会才报内存泄漏(调用 _CrtSetDbgFlag ) 。而 vld 之类的内存泄漏库才能检测到没有Release 的对象

    9 关键色
    加载图片的时候:  
      D3DXCreateTextureFromFileEx(m_pd3dDevice, "test.bmp", D3DX_DEFAULT, D3DX_DEFAULT,1,0,   D3DFMT_UNKNOWN,  
               D3DPOOL_DEFAULT,D3DX_FILTER_LINEAR,  D3DX_FILTER_LINEAR,0xffff00ff,NULL,NULL,&m_texture);   
                                                                       ~~~~~~~~~~ColorKey
      渲染的时候:  
      渲染前  
      m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);  
      m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);        //使用加载图片 srcalpha  
      m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);   //使用 1-srcalpha
      渲染  
      render()  
      渲染后恢复  
      m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);  
      m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);  
      m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);
    估计是加载的时候判断颜色相同。设置该像素 alpha 为 0

    10
    Lock VertexBuffer 时。使用偏移地址要同时指标值 D3DLOCK_NOOVERWRITE .这样除了更新的一小部分。其他部分不会被丢弃掉,当然是用默认参数0也可以。但用0效率很差
    对于动态缓存。使用偏移地址并不能增加多效效率。因为偏移的时候不能使用 DISCARD.不然没被更新的部分也会被丢弃。而往往希望没有更新的保留。不使用偏移地址将更新缓存所有地方。(特别是更新完整个缓存才unlock,反倒能快一些)

    上面认识错误。DISCARD 表示自己不再用那块显存。马上给我一块新的。原来用的位置可以被设备使用(如果还用完里面的顶点数据)。数据不会丢弃里面的内容。"丢弃"意味开发人员不再用了。至于何时扔掉有directx 管理
     同样NOOVERWRITE 也不是不覆盖的意思。只是表示开发者认为写入的位置不会覆盖被dx正在使用的顶点(draw),不用等待显卡draw结束(默认参数0表示等待结束),直接覆盖掉相应位置顶点数据(即使该顶点正在用来画图也会被强制覆盖)。这样反倒是表现起来截然"相反"了


    如果缓存数据没有变换。不要更新他.(只更新变化的数据能提高速度).一段缓存需要几次更新。可以开始锁定一次。最后unlock 就好。这个似乎不太影响性能

    11  D3DXLoadSurfaceFromMemory 的使用。可以把一种格式转换为另一种格式
     IDirect3DSurface9* temp;
     d3dOK( m_aTex[tex].m_pTex->GetSurfaceLevel(level,&temp) );

     int w = Get2PowerHigh(sz.cx);   //即 pitch 对齐到32位置
     //源缓存的尺寸
     RECT srcRc = { 0, 0, w, sz.cy };
     RECT dstRc = rt;
     //pixelFormatBits 得到的是每种表面格式的字节数. 可以参考dxtex 程序 如 D3DFMT_A8R8G8B8 返回 32
     unsigned char bytes = PixelFormatBits(pf)/8;
     
     HRESULT hr;
     //pitch = w * bytes  必须用纹理的宽度。这个宽度不一定等于参数width。指纹理pitch而不是buffer缓存数组的宽度
     //IDirect3DSurface9 是目标区域的 surface,第二个可以是NULL(256色的时代早就过去了). rt 是目标纹理需要更新的区域(2的幂次方可以有效防止失真)
     //data 是颜色缓冲数据。每个元素(a8r8g8b8)代表一个颜色值。pf data 的颜色格式(如 D3DFMT_A8R8G8B8)
     //NULL 为调色板,srcRc 为缓冲区的一块区域。D3DX_FILTER_NONE 过滤模式
     //最后参数为关键色
     if( FAILED(hr = D3DXLoadSurfaceFromMemory(temp,NULL,&rt,data,pf,w*bytes,NULL,&srcRc,D3DX_FILTER_NONE,0)))
     {
      ri->Error(ERR_D3D,_T("更新纹理,转换表面格式时失败:%0x\n"),hr);
     }

     if(m_aTex[tex].m_bmipmap)
     {
      d3dOK( D3DXFilterTexture( m_aTex[tex].m_pTex,NULL,0,D3DX_DEFAULT ) );
     }

  • 相关阅读:
    Cable master--hdu1551(二分法)
    Pie--hdu1969(二分法)
    Ice_cream's world I--hdu2120
    How Many Tables--hdu1213(并查集)
    畅通工程--hdu1232(并查集)
    小希的迷宫--hdu1272(并查集)
    More is better--hdu1856(并查集)
    Windows Message Queue--hdu1509
    期末考试--nyoj-757
    网络开发之使用Web Service和使用WCF服务
  • 原文地址:https://www.cnblogs.com/lancidie/p/1848108.html
Copyright © 2020-2023  润新知