個人檔案飘零风雨亭部落格清單 工具 說明

部落格


12月18日

maxsdk图解

参见:
3DSMAX_SDK_DavidLanier.pdf
max_pipeline(instance)max_pipeline(refrence)max_pipelineNodeTM
11月20日

游戏中换装处理(备忘)

游戏中换装处理(备忘)
一.cha 结构:
cha中可有几个model(对应为部位,可切换)
每个model可有几个mtl(即subset), 
每个mtl可作为一个pass, 该mtl中可有几层贴图
但是由于硬件多层贴图的限制可考虑只充许2层, 否则可能需要多次pass
二.cha update:
updatebone(计算当前骨骼运行时矩阵) -- 注意,骨骼的骨架数据及骨骼的动画数据可共享
updatemodel(计算模型中动画)        -- 注意,模型的网格数据及模型的动画数据可共享
注意:
  需要将每model中引用到的骨骼运行时矩阵(在updatebone中计算好了)拷贝到该model中,
  以便在后面渲染每个模型时能用上.
 
优化:
    人物不可见时可不更新动画,但要更新动作(即当前播放第几个动作的第几帧),
故上述两函数可再追加一个标志说明是更新动作还是动画
三.cha render:
遍历渲染每一个model:
for(i loop models)
{
 1. 设置每个模型的vb和ib: (vb和ib是静态创建的)
    setstream(model's vb && ib)
 
 2. 渲染每一个模型
   a. 把model引用到的运行时矩阵乘上MVP设置给vs
   b. 分pass画:
  for(i loop mtls){
     把每个mtl设置给vs
     drawpass(i)
  }
}
优化:
   在第2部时要把model引用到的运行时矩阵乘上MVP设置给vs中的常量寄存器,
然后用每个顶点的矩阵索引及权重进行混合(矩阵索引需要vs1.1中的寻址寄存器a0.x)
另外,只有整体transform变换的模型(没有顶点或骨骼动画, 如地面上不同位置不同面向的不动的树)要与人物模型分开处理,
这类物件可用类似上述的常量矩阵数组的技术进行instancing批次渲染(带skin的instancing批次渲染由于常量寄存器已变骨骼矩阵使用,
因此一般需要硬件支持,如使用顶点纹理来保存骨骼矩阵,参见前面文章instancing批次渲染)

疑问:
目前有一个疑问,上述的渲染需不需要换成按贴图排序再渲染.
还有怎么在只支持vs1.1的显卡下实现skin instancing,或者有其它什么优化的方案?
11月19日

instancing批次画

instancing批次画:
具体实现参见dxsdk9.0c中的instancing_2005(未包括最后一种需要sm3.0支持的技术)
一.单个shade const:
    V( g_pEffect->Begin( &cPasses, 0 ) );
    for( iPass = 0; iPass < cPasses; iPass++ )
    {
        V( g_pEffect->BeginPass( iPass ) );
           
        // Render the boxes with the applied technique
        V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
        for( int nRemainingBoxes = 0; nRemainingBoxes < g_NumBoxes; nRemainingBoxes++ )
        {
            // set the box instancing array
            V( g_pEffect->SetVector( g_HandleBoxInstance_Position, &g_vBoxInstance_Position[nRemainingBoxes] ) );
            V( g_pEffect->SetVector( g_HandleBoxInstance_Color, (D3DXVECTOR4*)&g_vBoxInstance_Color[nRemainingBoxes] ) );
           
            // The effect interface queues up the changes and performs them
            // with the CommitChanges call. You do not need to call CommitChanges if
            // you are not setting any parameters between the BeginPass and EndPass.
            V( g_pEffect->CommitChanges() );
           
            V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );
        }
        V( g_pEffect->EndPass() );
    }
    V( g_pEffect->End() );
二.多个shade const(因为使用类似于矩阵板实现skin bone的方法,所以存在冲突不能同时使用在骨骼动画中)
    V( g_pEffect->Begin( &cPasses, 0 ) );
    for( iPass = 0; iPass < cPasses; iPass++ )
    {
        V( g_pEffect->BeginPass( iPass ) );
           
        // Render the boxes with the applied technique
        V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
        int nRemainingBoxes = g_NumBoxes;
        while( nRemainingBoxes > 0 )
        {
            // determine how many instances are in this batch (up to g_nNumBatchInstance)          
            int nRenderBoxes = min( nRemainingBoxes, g_nNumBatchInstance );
            // set the box instancing array
            V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Position, g_vBoxInstance_Position + g_NumBoxes - nRemainingBoxes, nRenderBoxes) );
            V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Color, (D3DXVECTOR4*)(g_vBoxInstance_Color + g_NumBoxes - nRemainingBoxes), nRenderBoxes) );
           
            // The effect interface queues up the changes and performs them
            // with the CommitChanges call. You do not need to call CommitChanges if
            // you are not setting any parameters between the BeginPass and EndPass.
            V( g_pEffect->CommitChanges() );
           
            V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, nRenderBoxes * 4 * 6, 0, nRenderBoxes * 6 * 2 ) );
            // subtract the rendered boxes from the remaining boxes
            nRemainingBoxes -= nRenderBoxes;
        }
        V( g_pEffect->EndPass() );
    }
    V( g_pEffect->End() );

三. vs3.0 的hwinstance(需要多流INSTANCEDATA支持):
   这种方法是GPU通过虚拟复制(virtually duplicating)把顶点从第一个流打包到第二个流中。(也就是硬件使用多流和自动打包的方式帮忙实际了类似上述第二种的instance批次画)
 
    // Stream zero is our model, and its frequency is how we communicate the number of instances required,
    // which in this case is the total number of boxes
    V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof(BOX_VERTEX)) );
    V( pd3dDevice->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | g_NumBoxes ) );
       
    // Stream one is the instancing buffer, so this advances to the next value
    // after each box instance has been drawn, so the divider is 1.
    V( pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, 0, sizeof( BOX_INSTANCEDATA_POS ) ) );
    V( pd3dDevice->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
    V( pd3dDevice->SetIndices( g_pIBBox ) );
       
    // Render the scene with this technique
    // as defined in the .fx file
    V( g_pEffect->SetTechnique( g_HandleTechnique ) );
       
    V( g_pEffect->Begin( &cPasses, 0 ) );
    for( iPass = 0; iPass < cPasses; iPass++ )
    {
        V( g_pEffect->BeginPass( iPass ) );
           
        // Render the boxes with the applied technique
        V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
           
        // The effect interface queues up the changes and performs them
        // with the CommitChanges call. You do not need to call CommitChanges if
        // you are not setting any parameters between the BeginPass and EndPass.
        V( g_pEffect->CommitChanges() );
           
        V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );
           
        V( g_pEffect->EndPass() );
    }
    V( g_pEffect->End() );
       
    V( pd3dDevice->SetStreamSourceFreq( 0, 1 ) );
    V( pd3dDevice->SetStreamSourceFreq( 1, 1 ) );

四. 带骨骼实现的批次(顶点纹理方式):
    上述方法不好同时实现skinning, 如果需要实现skinning,可以尝试把所有实体的所有骨骼信息储存为一张纹理,之后为相应的实体选择正确的骨骼,这需要用到Shader Model3.0中的顶点纹理访问功能。如果使用这种技术,那么访问顶点纹理带来的性能消耗是不确定的,应该实现进行测试。
 
 
具体例子也可以参考:
NoInstancing:
NoInstancing
ShaderInstancing:
ShaderInstancing
HardwareInstancing:
HardwareInstancing
VFetchInstancing:
VFetchInstancing
 
 
 
11月14日

WOW的地形shader祥细解释

WOW的地形shader祥细解释
SPXG // 标识
// 用到5张图片:
{
   blendTexture  = 0
   layer0Texture = 1
   layer1Texture = 2
   layer2Texture = 3
   layer3Texture = 4
}
!!ARBfp1.0
// 定义常量:
PARAM c[1] = { { 1, 0.30000001, 0.69999999 } };
// 声明3个寄存器:
TEMP R0;
TEMP R1;
TEMP R2;
// 开始混合:
// 一.第0层和第1层使用第4张图的x通道作为alpha进行混合:
TEX R1, fragment.texcoord[0], texture[0], 2D;
TEX R0, fragment.texcoord[1], texture[1], 2D;
ADD R2, R0, -R1;
// r2=Tex1-Tex0
TEX R0, fragment.texcoord[4], texture[4], 2D;
MAD R2, R0.x, R2, R1;
// r2 = Tex4.x*r2+Tex0
// 说明:
// 其中的Tex4.x是对应第1层alpha值, 下面把Tex4.x当a1看
// 即 r2 = a1 * (Tex1-Tex0) + Tex0
// 转换一下即是: Tex0*(1-a1)+a1*Tex1, 呵呵,看到了吧,这就是混合公式!
// 二.第2层和前面结果使用第4张图的y通道作为alpha进行混合:
TEX R1, fragment.texcoord[2], texture[2], 2D;
ADD R1, R1, -R2;
// r1=Tex2-r2
MAD R2, R0.y, R1, R2;
// r2 = Tex4.y*r1+r2, 即 a2*r1+r2 = a2*(Tex2-r2)+r2, 即r2*(1-a2)+Tex2*a2, 其中r2即是上次0和1层混合后的结果
// 三.第3层和前面结果使用第4张图的z通道作为alpha进行混合:
TEX R1, fragment.texcoord[3], texture[3], 2D;
ADD R1, R1, -R2;
// r1=Tex3-r2
MAD R1, R0.z, R1, R2;
// r1=a3*r1+r2 , 即 a3*r1+r2 = a3*(Tex3-r2)+r2, 即r2*(1-a3)+Tex3*a3
// 这样r1就保存了最终的混合结果
// 四.让阴影地表光泽系数为0(Tex4.w即a通道代表地形的阴影,0为阴影,1为正常.而每层贴图中的a通道是光泽通道,所以R1.w保存的是最终的光泽通道值):
MUL R0.x, R1.w, R0.w;
// r0.x = r1.w(光泽)*Tex4.w(阴影值, 是阴影则=0,否则=1)
// 计算削减系数?
MAD R0.w, R0, c[0].y, c[0].z; // r0乘上0.3(削减了30%)再加上一个常量0.69999999
// 反射高光 = secondary_color(反射光)*光泽:
MUL R0.xyz, R0.x, fragment.color.secondary;
// 贴图最终color = 最终贴图混出的color*削减系数:
MUL R1.xyz, R1, R0.w;
// 贴图最终color * primary_color(光照色或是顶点色) + 反射高光:
MAD result.color.xyz, R1, fragment.color.primary, R0;
// alpha:
MOV result.color.w, c[0].x;
END
  
  
  
参考资料:
<WOW的地形渲染>:
http://dev.csdn.net/author/ZERO2046/1b8df53b7f034e7999d70e0cac5665f6.html
魔兽世界的地形渲染,基本上有三种渲染路径:固定渲染管线(其中是不是又分几种就不清楚了);shader(带高光);shader(不带高光)
  用到shader的渲染路径又分别针对1层,2层,3层,4层(最多允许每个chunk使用4层纹理)专门写了shader代码。
  用MyWarCraftStudio打开WOW的misc.mpq包,shader \ pixel \ 目录下以"terrain"打头的bls文件就是地形渲染使用的shader,带有"_s"后缀的是带高光的渲染,否则就是不带高光的。
  我仔细看了其中的terrain4_s.bls(用UltraEdit之类的工具可以直接当成文本文件打开)。是汇编形式的ps代码,由于之前俺只用过c形式的HLSL所以看起来有点吃力,好在还是看明白了。
  texture0~3就是待混合的4层纹理,每层纹理的a通道是该层纹理对应的高光通道;texture4是一张用来控制混合权重的alpha纹理。texture4的r,g,b通道分别对应texture1~3的alpha值,而texture4.a则代表地形的阴影,0为阴影,1为正常。
  混合的公式为res_n = res_n-1 * ( 1 - alpha_n ) + texture_n * alpha_n。其中n代表第n层纹理。res_n代表第n层混合后的结果。
  从代码可以看出,最终混合结果的a通道(高光通道)被乘以阴影值,也就是说阴影中没有高光。同时,阴影中的diffuse光照被削减了30%。
  1,2,3层纹理混合,以及不带高光的情况想必也没有什么特别之处,也不去细看了。
  值得一提的是我原来一直以为WOW的地形渲染只用了ps_1_1,但从这个shader看用了5张纹理,超出了ps_1_1的4个纹理采样的限制,所以至少使用了ps_1_4(允许6个纹理采样)。而1~3层纹理混合的情况使用ps_1_1就够了。我不知道在渲染时频繁切换ps版本会不会收到性能上的惩罚,但有些显卡(比如NV的5200)同样的代码在ps_1_4上运行要比在ps_1_1上运行慢很多。
  至于固定渲染管线的渲染路径,由于不可能看到代码,具体如何实现多层纹理混合无法揣测,集合了各层纹理混合系数的alpha图应该不能直接用于渲染,因为固定渲染管线似乎只能用a通道来控制混合系数,可能需要将这张纹理拆成4张才行。。。

地形上网格投射阴影(备忘)

地形上网格投射阴影:
目前有很多游戏及引擎用到了这种方法,
如开源的glest即时战略游戏和OGRE3D,
方法是:
照相到对到光线方向,渲染地表到深度缓冲,再渲染要投影的物件到贴图
然后将照相机设到顶视图,设置投影映射纹理把贴图贴到地面.

具本参见:
Generating Mesh Shadows On Terrain Using OpenGL
http://gpwiki.org/index.php/Generating_Mesh_Shadows_On_Terrain_Using_OpenGL

地形pvs

地形pvs
将地形分成n*n个区域,分成32层
然后,遍历每个区域, 在每个区域上的每层上向其它区域拉一直接,测试它们之间是否有障碍(不用测试三角形只用比较经过的区域内每个格子高度),是则表示当前所在区域看不见所测区域,保存此PVS供用.
注意PVS要用bit来保存,否则很大

参见:
GameDev.net -- Terrain Geomorphing in the Vertex Shader
http://www.gamedev.net/columns/hardcore/geomorph/

geomorph可将格子进行4次lod, 并在不同lod的格子边界进行插入点形成新的三角形(以免出现T形裂缝)
由于lod形成的高度差,所以还可以设置一个error充许值.具体参见原文(该地形也实现了类似目前一些网游所用的alpha混合多层贴图)

地形碰撞高度计算(备忘)


地形碰撞计算:
一.如果是鼠标点击地面,
可将射线固定长度并分段,然后用射线与每一个分段上的点所落在的地面tile(两个三角形)进行求交,
相交则返回对应位置,否则继续与下一个段上的点所落在的地面tile求交
/*
      0      1
       ---->
      | \  |
      |  \ |
    2 V ---  3   
*/
这里不讨论点击屏幕求射线方法与射线分段处理,只算求交
如下d3d求交得出uv,再求位置:
 VECTOR3 vPickPos;
 // 右边:
 if( D3DXIntersectTri(&v0, &v1, &v3, &vOrig, &vDir, &u, &v, NULL) == TRUE)
 {
  vPickPos = v0 + u * (v1 - v0) + v * (v3 - v0); 
  return vPickPos.z;
 }
 // 左边:
 if( D3DXIntersectTri(&v0, &v3, &v2, &vOrig, &vDir, &u, &v, NULL) == TRUE)
 {
  vPickPos = v0 + u * (v3 - v0) + v * (v2 - v0);  
  return vPickPos.z;
 }

二.如果是仅是求地表某点高度
则可用uv重心求法(注意上述第一点的d3d的那个uv重心求法不太一样,他的uv跟他的向量走?)
 float u = (fX-(int)fX);
 float v = (fY-(int)fY);

 float p0 = fHeight[0];
 float p1 = fHeight[1];
 float p2 = fHeight[2];
 float p3 = fHeight[3];

 if(u>v){ // 右边
  return p0 + u * (p1 - p0) + v * (p3 - p1);; 
 }
 else{  // 左边
  return  p0 + u * (p3 - p2) + v * (p2 - p0);
 }

 

11月12日

d3d中实现简单的水

1. 最简单的一张带alpha的贴图直接uv动画
2. 另一种是使用序列贴图, 即水的动画贴图,可在每个自定义大小的格子播放相同的一帧图片来实现.

tt
3. 反射水面:
   上述其中一种方法再加上带bump map效果的反射图

water 

下面给出最后一种具体例子:

用d3d固定管道实现bump mapping振动/移动的水:

(注意:该例子只用D3DTOP_BUMPENVMAP没用D3DTOP_BUMPENVMAPLUMINANCE):
  // 混合状态:
  m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

  // 贴图基台0:
  // 贴图因子(见后面的alpha参数D3DTA_TFACTOR):
  m_pD3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, 0x90000000);
  // 设置Bump map: 就是一些uv偏移值,保存在bump贴图中(还可以保存一个附加的光照值)
  m_pD3DDevice->SetTexture(0, m_pTexBump);
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP);
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTA_DIFFUSE);//D3DTOP_DISABLE);
                // bump矩阵(参见上面msdn链接说明):
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT00, F2DW(0.05f));
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT01, F2DW(0.0f));
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT10, F2DW(0.0f));
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT11, F2DW(0.05f));
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVLSCALE, F2DW(1.0f));
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f));
                // uv矩阵(uv动画用):
  m_pD3DDevice->SetTransform(D3DTS_TEXTURE0, &m_MatTransEau);
  m_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);

                // 贴图基台1:
                // 反射图(可实时计算):
  // Etage 1 : affichage de la texture de r閒lexion
  m_pD3DDevice->SetTexture(1, m_pEnvMiroir->GetMiroir());
                //
  m_pD3DDevice->SetTextureStageState (1, D3DTSS_COLOROP,   D3DTOP_SELECTARG1);
  m_pD3DDevice->SetTextureStageState (1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  m_pD3DDevice->SetTextureStageState (1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
  m_pD3DDevice->SetTextureStageState (1, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
                // uv矩阵(投影矩阵,将贴图映射到水面用):
  m_pD3DDevice->SetTransform(D3DTS_TEXTURE1, &m_pScene->GetCameraCourante()->GetMatriceProjectionTexture());
  m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
  m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_PROJECTED |D3DTTFF_COUNT3);
  m_pD3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU,  D3DTADDRESS_CLAMP);
  m_pD3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV,  D3DTADDRESS_CLAMP);

                // set fvf, vb 和 ib:
  m_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
  m_pD3DDevice->SetStreamSource(0, m_pVB, 0, sizeof(CUSTOMVERTEX));
  m_pD3DDevice->SetIndices(m_pIB);

                // draw:
  m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, NB_VERTEX_EAU, 0, NB_TRIANGLE_EAU);

提示:

上述的bump矩阵只是简单的偏移,实际的uv动画使用了另一个贴图uv矩阵(每帧更新,使得uv移动)来设置的,

另外一个更好技巧是可以使用bump矩阵直接应用sin函数,这样会使用得水波有一定的振动,效果挺好:

   D3DXMATRIX matBumpMat;

   const static DWORD startick(GetTickCount());
   DWORD dwtime=GetTickCount()-startick;
   float time=(float)dwtime/1000;
   FLOAT r = 0.005f;
   matBumpMat._11 = r*cosf(time*8.0f);
   matBumpMat._12 = r*sinf(time*8.0f);
   matBumpMat._21 = r*sinf(time*8.0f);
   matBumpMat._22 =-r*cosf(time*8.0f);

   m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT00,F2DW(matBumpMat._11));
   m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT01,F2DW(matBumpMat._12));
   m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT10,F2DW(matBumpMat._21));
   m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT11,F2DW(matBumpMat._22));


上述方法需要检测是否支持 D3DTEXOPCAPS_BUMPENVMAP

关于bump mapping参见msdn:

1. Bump Mapping (Direct3D 9)
http://msdn2.microsoft.com/en-us/library/bb172379.aspx

2. Bump Mapping Formulas (Direct3D 9)
http://msdn2.microsoft.com/en-us/library/bb172380.aspx

3. Bump Map Pixel Formats (Direct3D 9)
http://msdn2.microsoft.com/en-us/library/bb172381.aspx

4.Using Bump Mapping (Direct3D 9)
http://msdn2.microsoft.com/en-us/library/bb206304.aspx

原理参见第2点,使用方法参见第4点

 

附:

关于bumpmap图是可以直接程序创建的,下面给出该方法的代码(这是从 盖小房(BYOH)source code中看到的,直接贴这里可参考):

LPDIRECT3DTEXTURE9 CreateBumpMap(LPDIRECT3DDEVICE9 device,  DWORD dwWidth, DWORD dwHeight,D3DFORMAT d3dBumpFormat )
{
 LPDIRECT3DTEXTURE9 psBumpMap;

// Create the bump map texture
 if( FAILED( device->CreateTexture( dwWidth, dwHeight, 1, 0/* Usage */,
  d3dBumpFormat, D3DPOOL_MANAGED,&psBumpMap,NULL ) ) )
  return NULL;

// Lock the surface and write in some bumps for the waves
 D3DLOCKED_RECT d3dlr;
 psBumpMap->LockRect( 0, &d3dlr, 0, 0 );
 CHAR* pDst = (CHAR*)d3dlr.pBits;
 CHAR  iDu=0, iDv=0;

 for( DWORD y=0; y<dwHeight; y++ )
 {
  CHAR* pPixel = pDst;
  for( DWORD x=0; x<dwWidth; x++ )
  {
   FLOAT fx = x/(FLOAT)dwWidth - 0.5f;
   FLOAT fy = y/(FLOAT)dwHeight - 0.5f;
   FLOAT r = sqrtf( fx*fx + fy*fy );
//  iDu  = (CHAR)( 32 * cosf( 300.0f * r ) * expf( -r * 5.0f ) );
   iDu += (CHAR)( 128 * cosf( 100.0f * ( fx + fy ) ) );
//  iDu += (CHAR)( 16 * cosf( 140.0f * ( fx * 0.85f - fy ) ) );
//  iDv  = (CHAR)( 32 * sinf( 300.0f * r ) * expf( -r * 5.0f ) );
   iDv += (CHAR)( 128 * sinf( 100.0f * ( fx + fy ) ) );
//  iDv += (CHAR)( 16 * sinf( 140.0f * ( fx * 0.85f - fy ) ) );
   *pPixel++ = iDu;
   *pPixel++ = iDv;
  }
  pDst += d3dlr.Pitch;
 }
 psBumpMap->UnlockRect(0);

 return psBumpMap;
}

11月8日

区域选择显示图

最近做的魔兽里区域选择显示图, 这个与地面贴花不一样,要求边框不会因为区域放大而跟着

缩放(与魔兽不一样的是中间不用小格子省点顶点), 而关于地面贴花可以用匹配地形网格再放绽放uv进行调整

并且设置边框模式或clamp模式(图片边框需透明)而简单得到,当然复杂的也可以用投影贴图来作,(类似于实时影子的作法:

先渲染场景深度,再调相机到灯光处渲染需需投影的物件到贴图上,最后将贴图以顶视图方式投影到地形上)

{A751E3AF-7568-4CEE-9B5C-8086E61082FB}{FF92B66A-87B6-4B20-A4C5-C2AEFF66E7E9} 

11月1日

real time 3d scene post processing

具体请参见<<real time 3d scene post processing>>:
http://ati.amd.com/developer/gdce/Oat-ScenePostprocessing.pdf
 
下面说说简单的hdr原理,
读取hdr文件
将颜色转到64位浮点原贴图中
将原贴图以1/4大小渲染到downsample贴图中(只取高光,即亮度低于1的被过滤掉)
对downsample进行横向和纵向blur
最后将blur与原贴图合成tone map, 即按比例混合在一起(并调整uv越近图中心的越亮,最后还进行高光指数pow)
最后的tone map就是最终的贴图了
 具体参见hdr教程参见(非常简单):
http://www.gamedev.net/columns/hardcore/hdrrendering/
 
另外bloom作法一般是类似的(只是可以不用精度浮点贴图):
渲染场景到原贴图
取出高亮部分(只取高光,即亮度在一定值以上)
blur 一下
最后与原贴图混合一下得出最终的tone map


如下是azure的一个bloom处理方法:
http://www.azure.com.cn/article.asp?id=195
uniform sampler2D texture;
uniform float blurfactor;
uniform float expfactor;
const float cdelp = 0.001953125;
uniform float sharpness;
float4 xposure(float4 cl,float e)
{
 return ( exp(expfactor) - exp(expfactor-e)) * cl;
}
void main( float2 texcoord : TEXCOORD0,
    out float4 finalColor : COLOR)
{
 float delp = blurfactor* cdelp;
 float4 texColor = tex2D(texture, texcoord);
 float4 color = texColor*2.0 / 22.0;
 color += tex2D(texture,float2(texcoord.x+delp, texcoord.y+delp))*5.0 /22.0;
 color += tex2D(texture,float2(texcoord.x+delp, texcoord.y- delp))*5.0 /22.0;
 color += tex2D(texture,float2(texcoord.x- delp, texcoord.y- delp))*5.0 /22.0;
 color += tex2D(texture,float2(texcoord.x- delp, texcoord.y+delp))*5.0 /22.0;
 float e = color.r * 0.3 + color.g * 0.59 + color.b * 11;
 finalColor = xposure(texColor*sharpness + color*(1-sharpness),e);
}
 
10月23日

设备获取

设备获取
 
#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#pragma comment(lib, "setupapi.lib")
int main( int argc, char *argv[ ], char *envp[ ] )
{
    HDEVINFO hDevInfo;
    SP_DEVINFO_DATA DeviceInfoData;
    DWORD i;
    // Create a HDEVINFO with all present devices.
    hDevInfo = SetupDiGetClassDevs(NULL,
        0, // Enumerator
        0,
        DIGCF_PRESENT | DIGCF_ALLCLASSES );
   
    if (hDevInfo == INVALID_HANDLE_VALUE)
    {
        // Insert error handling here.
        return 1;
    }
   
    // Enumerate through all devices in Set.
   
    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
        &DeviceInfoData);i++)
    {
        DWORD DataT;
        LPTSTR buffer = NULL;
        DWORD buffersize = 0;
       
        //
        // Call function with null to begin with,
        // then use the returned buffer size
        // to Alloc the buffer. Keep calling until
        // success or an unknown failure.
        //
        while (!SetupDiGetDeviceRegistryProperty(
            hDevInfo,
            &DeviceInfoData,
            SPDRP_DEVICEDESC,
            &DataT,
            (PBYTE)buffer,
            buffersize,
            &buffersize))
        {
            if (GetLastError() ==
                ERROR_INSUFFICIENT_BUFFER)
            {
                // Change the buffer size.
                if (buffer) LocalFree(buffer);
                buffer = (char*)LocalAlloc(LPTR,buffersize);
            }
            else
            {
                // Insert error handling here.
                break;
            }
        }
       
        printf("Result:[%s]\n",buffer);
       
        if (buffer) LocalFree(buffer);
    }
   
   
    if ( GetLastError()!=NO_ERROR &&
         GetLastError()!=ERROR_NO_MORE_ITEMS )
    {
        // Insert error handling here.
        return 1;
    }
   
    //  Cleanup
    SetupDiDestroyDeviceInfoList(hDevInfo);
   
    return 0;
}
9月27日

获取显存的方法

获取显存的方法:
1. dx7 ddraw方法:
   GetAvailableVidMem( DWORD &dwTotal, DWORD &dwFree );
   主要问题:
      发现在一台机器的vista系统下创建ddraw时crash!
2. dx9下设备查询方法:
   GetAvailableTextureMem();
   主要问题: 
      只获得剩余显存大小(包括AGP),不知道总显存大小.
此函数msdn说明:
IDirect3DDevice9::GetAvailableTextureMem() returns the total available memory, including AGP. Allocating resources based on an assumption of how much video memory you have is not a great idea. For example, what if the card is running under a Unified Memory Architecture (UMA) or is able to compress the textures? There might be more space available than you might have thought. You should create resources and check for 'out of memory' errors, then scale back on the textures. For example, you could remove the top mip-levels of your textures.
3. dxdiag的方法:
   需要创建dxidag相关的com对象来查询,只知道总的,不知道当前所剩的.
4. 其它(16位系统的中断获取方法不在考虑范围内):
   通过WMI获取系统信息(包括显卡及显存信息)

我们的解决方案:
因为第3和第4方法相对麻烦,而且不知道会不会因为写多这些代码在不同的玩家机器上引起其它的crash问题
所以不考虑第3和第4方法.
目前MPRender提供第1和第2种方法,第1种ddraw方法用在初始init.log中并且判断系统如果是vista的系统第一种方法将不起作用. 当crash发现需输出显存信息时先尝试使用第1种ddraw方法, 不行(vista系统不使用)则使用第2种方法仅打印所剩显存大小.
 
第4种方式csdn论坛上一位网友给出的代码:
 
// videmem.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
//   Get   video   card   name   and   memory   size.  
//tested   by   onega   VC20003,windows   2003  
#include   "stdafx.h"  
#define   _WIN32_DCOM  
#include   <iostream>  
using   namespace   std;  
#include   <comdef.h>  
#include   <Wbemidl.h>  
#   pragma   comment(lib,   "wbemuuid.lib")  
int   main(int   argc,   char   **argv)  
{  
 HRESULT   hres;  
   
 //   Step   1:   --------------------------------------------------  
 //   Initialize   COM.   ------------------------------------------  
   
 hres   =     CoInitializeEx(0,   COINIT_MULTITHREADED);    
 if   (FAILED(hres))  
 {  
  cout   <<   "Failed   to   initialize   COM   library.   Error   code   =   0x"    
   <<   hex   <<   hres   <<   endl;  
  return   1;                                     //   Program   has   failed.  
 }  
   
 //   Step   2:   --------------------------------------------------  
 //   Set   general   COM   security   levels   --------------------------  
 //   Note:   If   you   are   using   Windows   2000,   you   need   to   specify   -  
 //   the   default   authentication   credentials   for   a   user   by   using  
 //   a   SOLE_AUTHENTICATION_LIST   structure   in   the   pAuthList   ----  
 //   parameter   of   CoInitializeSecurity   ------------------------  
   
 hres   =     CoInitializeSecurity(  
  NULL,    
  -1,                                                     //   COM   authentication  
  NULL,                                                 //   Authentication   services  
  NULL,                                                 //   Reserved  
  RPC_C_AUTHN_LEVEL_DEFAULT,       //   Default   authentication    
  RPC_C_IMP_LEVEL_IMPERSONATE,   //   Default   Impersonation      
  NULL,                                                 //   Authentication   info  
  EOAC_NONE,                                       //   Additional   capabilities    
  NULL                                                   //   Reserved  
  );  
   
   
 if   (FAILED(hres))  
 {  
  cout   <<   "Failed   to   initialize   security.   Error   code   =   0x"    
   <<   hex   <<   hres   <<   endl;  
  CoUninitialize();  
  return   1;                                         //   Program   has   failed.  
 }  
   
 //   Step   3:   ---------------------------------------------------  
 //   Obtain   the   initial   locator   to   WMI   -------------------------  
   
 IWbemLocator   *pLoc   =   NULL;  
   
 hres   =   CoCreateInstance(  
  CLSID_WbemLocator,                            
  0,    
  CLSCTX_INPROC_SERVER,    
  IID_IWbemLocator,   (LPVOID   *)   &pLoc);  
   
 if   (FAILED(hres))  
 {  
  cout   <<   "Failed   to   create   IWbemLocator   object."  
   <<   "   Err   code   =   0x"  
   <<   hex   <<   hres   <<   endl;  
  CoUninitialize();  
  return   1;                                   //   Program   has   failed.  
 }  
   
 //   Step   4:   -----------------------------------------------------  
 //   Connect   to   WMI   through   the   IWbemLocator::ConnectServer   method  
   
 IWbemServices   *pSvc   =   NULL;  
   
 //   Connect   to   the   root\cimv2   namespace   with  
 //   the   current   user   and   obtain   pointer   pSvc  
 //   to   make   IWbemServices   calls.  
 hres   =   pLoc->ConnectServer(  
  _bstr_t(L"ROOT\\CIMV2"),   //   Object   path   of   WMI   namespace  
  NULL,                                         //   User   name.   NULL   =   current   user  
  NULL,                                         //   User   password.   NULL   =   current  
  0,                                               //   Locale.   NULL   indicates   current                            
  NULL,                                         //   Security   flags.  
  0,                                               //   Authority   (e.g.   Kerberos)                  
  0,                                               //   Context   object    
  &pSvc                                         //   pointer   to   IWbemServices   proxy  
  );  
   
 if   (FAILED(hres))  
 {  
  cout   <<   "Could   not   connect.   Error   code   =   0x"    
   <<   hex   <<   hres   <<   endl;  
  pLoc->Release();            
  CoUninitialize();  
  return   1;                                 //   Program   has   failed.  
 }  
   
 cout   <<   "Connected   to   ROOT\\CIMV2   WMI   namespace"   <<   endl;  
   
   
 //   Step   5:   --------------------------------------------------  
 //   Set   security   levels   on   the   proxy   -------------------------  
   
 hres   =   CoSetProxyBlanket(  
  pSvc,                                                 //   Indicates   the   proxy   to   set  
  RPC_C_AUTHN_WINNT,                       //   RPC_C_AUTHN_xxx  
  RPC_C_AUTHZ_NONE,                         //   RPC_C_AUTHZ_xxx  
  NULL,                                                 //   Server   principal   name    
  RPC_C_AUTHN_LEVEL_CALL,             //   RPC_C_AUTHN_LEVEL_xxx    
  RPC_C_IMP_LEVEL_IMPERSONATE,   //   RPC_C_IMP_LEVEL_xxx  
  NULL,                                                 //   client   identity  
  EOAC_NONE                                         //   proxy   capabilities    
  );  
   
 if   (FAILED(hres))  
 {  
  cout   <<   "Could   not   set   proxy   blanket.   Error   code   =   0x"    
   <<   hex   <<   hres   <<   endl;  
  pSvc->Release();  
  pLoc->Release();            
  CoUninitialize();  
  return   1;                               //   Program   has   failed.  
 }  
   
 //   Step   6:   --------------------------------------------------  
 //   Use   the   IWbemServices   pointer   to   make   requests   of   WMI   ----  
   
 //   For   example,   get   the   name   of   the   operating   system  
 _bstr_t   wmi_query_str("SELECT   *   FROM   Win32_VideoController");  
 //bstr_t("SELECT   *   FROM   Win32_OperatingSystem")  
 IEnumWbemClassObject*   pEnumerator   =   NULL;  
 hres   =   pSvc->ExecQuery(  
  bstr_t("WQL"),    
  wmi_query_str,  
  WBEM_FLAG_FORWARD_ONLY   |   WBEM_FLAG_RETURN_IMMEDIATELY,    
  NULL,  
  &pEnumerator);  
   
 if   (FAILED(hres))  
 {  
  cout   <<   "Query   for   operating   system   name   failed."  
   <<   "   Error   code   =   0x"    
   <<   hex   <<   hres   <<   endl;  
  pSvc->Release();  
  pLoc->Release();  
  CoUninitialize();  
  return   1;                               //   Program   has   failed.  
 }  
   
 //   Step   7:   -------------------------------------------------  
 //   Get   the   data   from   the   query   in   step   6   -------------------  
   
 IWbemClassObject   *pclsObj;  
 ULONG   uReturn   =   0;  
   
 while   (pEnumerator)  
 {  
  HRESULT   hr   =   pEnumerator->Next(WBEM_INFINITE,   1,    
   &pclsObj,   &uReturn);  
  
  if(0   ==   uReturn)  
  {  
   break;  
  }  
  
  VARIANT   vtProp;  
  VariantInit(&vtProp);  
  
  //   Get   the   value   of   the   Name   property  
  hr   =   pclsObj->Get(L"Caption",   0,   &vtProp,   0,   0);  
  wcout   <<   "   Caption   :   "   <<   vtProp.bstrVal   <<   endl;  
  VariantClear(&vtProp);  
  
  hr   =   pclsObj->Get(L"AdapterRAM",   0,   &vtProp,   0,   0);  
  wcout   <<   "   AdapterRAM   :   "<<   vtProp.lVal/(1024*1024)<<"   MB"   <<   endl;  
  VariantClear(&vtProp);  
  
 }  
   
 //   Cleanup  
 //   ========  
   
 pSvc->Release();  
 pLoc->Release();  
 pEnumerator->Release();  
 pclsObj->Release();  
 CoUninitialize();  
   
 return   0;       //   Program   successfully   completed.  
   
  }
 
9月6日

ogl绘制两圆(转)

ogl绘制两圆 (转)
 
#include <math.h>
#include <vector>
#include <gl/glut.h>
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glut32.lib")
const float PI = 3.14159265358979323846f;
struct MyVector
{
float x;
float y;
float z;
};

class StackedSphere
{
public:
StackedSphere(const float radius = 1.0f, const unsigned int stacks = 8, const unsigned int slices = 16);
void render() const;
private:
std::vector<MyVector> geometryData_;
std::vector<unsigned short> indexData_;
};
StackedSphere::StackedSphere(const float radius, const unsigned int stacks, const unsigned int slices)
{
unsigned int stackNumber = 0;
for (stackNumber = 0; stackNumber <= stacks; ++stackNumber)
{
for (unsigned int sliceNumber = 0; sliceNumber < slices; ++sliceNumber)
{
float theta = stackNumber * PI / stacks;
float phi = sliceNumber * 2 * PI / slices;
float sinTheta = sin(theta);
float cosTheta = cos(theta);
float sinPhi = sin(phi);
float cosPhi = cos(phi);
MyVector ge = {radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta};
geometryData_.push_back(ge);
}
}
for (stackNumber = 0; stackNumber < stacks; ++stackNumber)
{
for (unsigned int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber)
{
indexData_.push_back((stackNumber * slices) + (sliceNumber % slices));
indexData_.push_back(((stackNumber + 1) * slices) + (sliceNumber % slices));
}
}
}
void StackedSphere::render() const
{
glVertexPointer(3, GL_FLOAT, 0, &geometryData_[0]);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLE_STRIP, indexData_.size(), GL_UNSIGNED_SHORT, &indexData_[0]);
}
class SpiralSphere
{
public:
SpiralSphere(const float radius = 1.0f, const unsigned int loops = 8, const unsigned int segmentsPerLoop = 16);
void render() const;
private:
std::vector<MyVector > geometryData_;
std::vector<unsigned short> indexData_;
};
SpiralSphere::SpiralSphere(const float radius, const unsigned int loops, const unsigned int segmentsPerLoop)
{
unsigned int loopSegmentNumber = 0;
for (loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
{
float theta = 0;
float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop;
float sinTheta = sin(theta);
float sinPhi = sin(phi);
float cosTheta = cos(theta);
float cosPhi = cos(phi);
MyVector ge = {radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta};
geometryData_.push_back(ge);
}
unsigned int loopNumber = 0;
for (loopNumber = 0; loopNumber <= loops; ++loopNumber)
{
for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
{
float theta = (loopNumber * PI / loops) + ((PI * loopSegmentNumber) / (segmentsPerLoop * loops));
if (loopNumber == loops)
{
theta = PI;
}
float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop;
float sinTheta = sin(theta);
float sinPhi = sin(phi);
float cosTheta = cos(theta);
float cosPhi = cos(phi);
MyVector ge = {radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta};
geometryData_.push_back(ge);
}
}
for (loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
{
indexData_.push_back(loopSegmentNumber);
indexData_.push_back(segmentsPerLoop + loopSegmentNumber);
}
for (loopNumber = 0; loopNumber < loops; ++loopNumber)
{
for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
{
indexData_.push_back(((loopNumber + 1) * segmentsPerLoop) + loopSegmentNumber);
indexData_.push_back(((loopNumber + 2) * segmentsPerLoop) + loopSegmentNumber);
}
}
}
void SpiralSphere::render() const
{
glVertexPointer(3, GL_FLOAT, 0, &geometryData_[0]);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLE_STRIP, indexData_.size(), GL_UNSIGNED_SHORT, &indexData_[0]);
}
StackedSphere sphere1(4, 8, 16);
SpiralSphere sphere2(4, 8, 16);
int r = 0;
void reshape(int width, int height){
if (height == 0)
{
height = 1;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -25);
glPushMatrix();
glTranslatef(-5, 0, 0);
glRotatef(r, 0, 1, 0);
sphere1.render();
glPopMatrix();
glPushMatrix();
glTranslatef(5, 0, 0);
glRotatef(r, 0, 1, 0);
sphere2.render();
glPopMatrix();
glutSwapBuffers();
r++;
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(512,512);
glutCreateWindow("Sphere Test");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(display);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
glutMainLoop();
return 0;
}
 
 
7月4日

常用链接(转)

常用链接(转)
来自: http://www.hays.com.cn/viewthread.php?tid=256
Graphics Engines
Ogre 3D (http://www.ogre3d.org/)
Nebula Device (http://www.radonlabs.de/nebula.html)
Haddd (http://www.haddd.com/)
Irrlicht (http://irrlicht.sourceforge.net/)
Haaf's Game Engine (http://hge.relishgames.com/) (hardware accelerated 2D games engine)

Axiom 3D (http://www.axiom3d.org/) (OGRE for .NET)
TrueVision (http://truevision.sourceforge.net/)
Revolution3D (http://www.revolution3d.net/)
Genesis3D (http://www.genesis3d.com/)
Crystal Space 3D (http://www.crystalspace3d.org/tikiwiki/tiki-view_articles.php)
Panda3D (http://panda3d.etc.cmu.edu/)
Quake 2 Source Code (http://www.fileshack.com/file.x?fid=7547)
Quake 2 (http://www.fileplanet.com/6621/0 ... -Source-Code-v3.21) (complete sources)

Tenebrae (http://tenebrae.sourceforge.net/) (Quake with per pixel lights and shaders)
Wild Magic (http://www.geometrictools.com/index.html) (David Eberly's engine)
Apocalyx (http://apocalyx.sourceforge.net/)
ClanLib Game SDK (http://www.clanlib.org/)
DevLib (http://www.devlib-central.org/mambo/)
kjAPI (http://www.kjapi.com/)
Portable Game Library (PLIB) (http://plib.sourceforge.net/)

RealmForge GDK (http://realmforge.com/)
Delta3D (http://delta3d.org/)
G3D (http://g3d-cpp.sourceforge.net/)
NeoEngine (http://www.neoengine.org/)
QuakeForge (http://www.quakeforge.net/)
XEngine (http://xengine.sourceforge.net/)
Yake (http://www.yake.org/)
Kyra Sprite Engine (http://www.grinninglizard.com/kyra/)



Libraries
Free Game Development Libraries (http://abattoir.wolfpaw.net/personal/gamelibs.php) (external list)
Graphics:
Crazy Eddie's GUI system (http://www.cegui.org.uk/modules/news/)
Cal3D (http://cal3d.sourceforge.net/) (character animation library)
GLFW (http://glfw.sourceforge.net/) (OpenGL Framework)

GLee (http://elf-stone.com/glee.php) (OpenGL easy extension library)
DevIL (http://openil.sourceforge.net/)
Game Texture Loader (http://www.gamedev.net/community ... sp?topic_id=334348)
SDL (http://www.libsdl.org)
Cpw (http://www.mathies.com/cpw/about.html) (another OGL framework)
Allegro (http://www.talula.demon.co.uk/allegro/)
Open Scene Graph (http://www.openscenegraph.org/)

Corona (http://corona.sourceforge.net/)
Titan (http://titan.sourceforge.net/)
SFont (http://www.linux-games.com/sfont/)
CxImage (http://www.xdp.it/cximage.htm)
CImg (http://cimg.sourceforge.net/)
FreeImage (http://freeimage.sourceforge.net/)
BMF_Font (http://trenki.gippsbiz.com/bmf/)
BFont (http://www.cs.unibo.it/%7Edbilli/bfont/bfont.html)
FreeType (freetype.sf.net) (font rendering library)

PaintLib (http://www.paintlib.de/paintlib/)
GLEW (http://glew.sourceforge.net/) (OpenGL extension wrangler library)
gluX
(http://www-evasion.imag.fr/Membres/Sylvain.Lefebvre/glux/)GLUT (http://www.opengl.org/resources/ ... lut_downloads.html)
FreeGLUT (http://freeglut.sourceforge.net/)
Open Inventor (http://oss.sgi.com/projects/inventor/)
FTGL (http://homepages.paradise.net.nz/henryj/code/index.html#FTGL) (OpenGL Font Library

nVidia Scene Graph SDK (http://developer.nvidia.com/object/nvsg_home.html)
OpenSG (http://www.opensg.org/)
ParaGUI (http://www.paragui.org/)
LibUFO (http://libufo.sourceforge.net/index.html) (OpenGL GUI Toolkit)
GPUmesh (http://www-evasion.imag.fr/Membres/Sylvain.Lefebvre/GPUmesh/)
GNU Triangulated Surface Library (http://gts.sourceforge.net/)
libASE (http://interreality.org/projects/libase)
lib3DS (http://lib3ds.sourceforge.net/)

GLOD (http://www.cs.jhu.edu/%7Egraphics/GLOD/) (Geometric Level of Detail for OpenGL)
Video:
FFmpeg (http://ffmpeg.sourceforge.net/index.php)
Dirac (http://sourceforge.net/projects/dirac)
Theora (http://www.theora.org/)
XviD (http://www.xvid.org/)
Networking:
RakNet (http://www.rakkarsoft.com/)

OpenTNL (http://www.opentnl.org/) (Torque network library)
HawkNL (http://www.hawksoft.com/hawknl/)
OpenPlay (http://developer.apple.com/darwin/projects/openplay/)
ReplicaNet (http://www.replicanet.com/)
Game Networking Engine (http://www.rit.edu/%7Ejpw9607/gne/)
Sound:
FMOD (http://www.fmod.org/)
OpenAL (http://www.openal.org/)

Audiere (http://audiere.sourceforge.net/)
BASS (http://www.un4seen.com/)
libsndfile (http://www.mega-nerd.com/libsndfile/)
Ogg Vorbis (http://www.vorbis.com/)
Physics and Collision:
Open Dynamics Engine (ODE) (http://ode.org/)
Tokamak (http://www.tokamakphysics.com/)
Newton Game Dynamics (http://www.physicsengine.com/)
NovodeX SDK (http://www.ageia.com/novodex.html)

Physical (http://physical.alecrivers.com/)
True Axis (http://www.trueaxis.com/)
Open Dynamics Framework (http://www.physicstools.org/)
ColDet (http://photoneffect.com/coldet/) (Free 3D Collision Detection Library)
Opcode (http://www.codercorner.com/Opcode.htm)
RAPID (http://www.cs.unc.edu/%7Egeom/OBB/OBBT.html)
FreeSOLID (http://www.win.tue.nl/%7Egino/solid/index.html)
V-Collide (http://www.cs.unc.edu/%7Egeom/V_COLLIDE/)

Scripting and XML:
Lua (http://www.lua.org/)
AngelScript (http://www.angelcode.com/angelscript/)
CInt (http://root.cern.ch/root/Cint.html)
EOS (http://eosscript.sourceforge.net/)
GameMonkey Script (http://www.somedude.net/gamemonkey/)
Guile (http://www.gnu.org/software/guile/guile.html)
IO (http://www.iolanguage.com/about/)
javascript (http://www.mozilla.org/js/)

Squirrel (http://squirrel.sourceforge.net/)
Small (http://www.compuphase.com/small.htm)
Ruby (http://www.ruby-lang.org/en/)
Python (http://www.python.org/)
Tcl (http://tcl.sourceforge.net/)
Perl (http://www.perl.com/)
LibXML (http://xmlsoft.org/)
TinyXML (http://www.grinninglizard.com/tinyxml/)
Expat (http://expat.sourceforge.net/)

Apache XML libraries (http://xml.apache.org/)
ezXML (http://ezxml.sourceforge.net/)
Compression and File Systems:
zlib (http://www.zlib.net/)
bzip2 (http://www.bzip.org/)
LZMA SDK (http://www.7-zip.org/sdk.html)
LZO (http://www.oberhumer.com/opensource/lzo/)
PhysicsFS (http://icculus.org/physfs/)
#ZipLib (http://www.icsharpcode.net/OpenSource/SharpZipLib/) (native C# archive library)

SharpFS (http://www.gamedev.net/community ... sp?topic_id=391656) (native C# VFS)
unrarlib (http://www.unrarlib.org/)
ZipArchive (http://www.artpol-software.com/index_zip.html)

Note: Much of the above lists (but not all) were taken from this page (http://abattoir.wolfpaw.net/personal/gamelibs.php), maintained by Kylotan here (http://www.gamedev.net/community ... p?topic_id=291432).

Applications and Utilities:

Development Environments:
Code::Blocks IDE (http://www.codeblocks.org/)
Dev-C++ (http://www.bloodshed.net/devcpp.html)
Visual Studio 2005 betas (http://lab.msdn.microsoft.com/vs2005/)
SharpDevelop (http://www.icsharpcode.net/OpenSource/SD/)
ActivePython (http://www.activestate.com/Products/ActivePython/)
Graphics Development:
gDEBugger (http://www.gremedy.com/)
FX Composer (http://developer.nvidia.com/object/fx_composer_home.html)

RenderMonkey (http://www.ati.com/developer/rendermonkey/)
NVIDIA SDK (http://developer.nvidia.com/object/sdk_home.html)
ATI Radeon SDK (http://www.ati.com/developer/radeonSDK.html)
DirectX Developer Center (http://msdn.microsoft.com/directx/)
NVIDIA Cg (http://developer.nvidia.com/page/cg_main.html)
Sh (http://libsh.org/) (shader language)
Modeling:
SoftImage|XSI Mod Tool (http://www.softimage.com/community/xsi_mod_tool/default.aspx)

Milkshape 3D (http://www.swissquake.ch/chumbalum-soft/) (not free, $25)
Wings 3D (http://www.wings3d.com/)
Blender (http://www.blender3d.com/cms/Home.2.0.html)
Anim8or (http://www.anim8or.com/)
DeleD (http://www.delgine.com/index.php ... eled&menus=off)
World Building:
Quake Army Knife (QuArK) (http://dynamic.gamespy.com/%7Equark/)
GtkRadiant (http://www.qeradiant.com/)

Getic3D (http://www.zalsoft.com/index.php)
Audio:
ModPlug (http://www.modplug.com/)
Audacity (http://audacity.sourceforge.net/)
SynthEdit (http://www.synthedit.com/)
Buzz Machines (http://www.buzzmachines.com/)
KVR Audio (http://www.kvraudio.com/) (not actually software, but has tons of links)
Images:

Paint.NET (excellent free image editor)
(http://www.eecs.wsu.edu/paint.net/)The GIMP (http://www.gimp.org/)
BMFont (http://www.angelcode.com/products/bmfont/) (font texture generator)

Media
Textures:
Transmogrifying Textures Vol. I (NVIDIA) (http://developer.nvidia.com/object/IO_TTVol_01.html)
Mayang's Free Textures (http://www.mayang.com/textures/)

3D Cafe's Free Textures (http://www.3dcafe.com/asp/textures.asp)
Absolute Background Textures Archive (http://www.grsites.com/textures/)
Image * After (http://www.imageafter.com/)
Media Link's Free Backgrounds and Textures (http://my.erinet.com/%7Ecunning1/textures.htm)
Free Game Textures (http://www.vb3d.com/Textures.html)
Seamless Textures -- Absolute Cross (http://www.absolutecross.com/graphics/textures/)
3D Millenium Free Textures (http://www.m3corp.com/a/download/3d_textures/pages/index.htm)
Pixel Poke (http://www.pixelpoke.com/FREE%20PIXELS.html)
The Texture Studio (http://www.planethalflife.com/studio/)

Textures (http://astronomy.swin.edu.au/%7Epbourke/texture/)
Marlin Studios (http://www.marlinstudios.com/samples/samples.htm)
Free Foto (http://www.freefoto.com/browse.jsp?id=33-00-0)
Free Textures (http://www.noctua-graphics.de/english/freetex_e.htm)
Free Textures (http://www.indiaeye.com/free.htm)
MorgueFile (http://www.morguefile.com/)
Psionic3D (http://www.psionic3d.co.uk/)
Models:
3D Millenium Free Models (http://www.m3corp.com/a/download/models/index.htm)

Polycount (http://www.planetquake.com/polycount/)
Marlin Studios (http://www.marlinstudios.com/samples/samples.htm)
Free 3D Model Collections (http://www.amazing3d.com/modfree.html)
Free 3D Models (http://www.rocky3d.com/free3d.htm)
Digital Animators Models (http://www.digitalanimators.com/ ... s/3dModelsMain.htm)
Psionic3D (http://www.psionic3d.co.uk/)
Sprites
This thread has lots...and lots...and lots... (http://www.gamedev.net/community ... sp?topic_id=272386)
Sounds:

SFX and Music Resources (http://www.gamedev.net/community ... sp?topic_id=279518) (another long GDNet post)
Jamendo (http://www.jamendo.com/us/) (Creative Commons licensed music)
A1 Free Sound Effects (http://www.a1freesoundeffects.com/noflash.htm)
Sound Effects (http://www.pacdv.com/sounds/index.html)
Tintagel's Free Sound File Archive (http://freesoundfiles.tintagel.net/Audio/)
Free Sound Effects (http://www.partnersinrhyme.com/pir/PIRsfx.html)
Sound Hunter (http://www.soundhunter.com/)

Wav Sound Complete Archive (http://www.members.tripod.com/%7Ebuggerluggs/ie/wav-dir184.htm)
deusX Sound Design (http://www.deusx.com/studio.html)
FindSounds (http://www.findsounds.com/) (sound search engine)
Absolute Sound Effects Archive (http://www.grsites.com/sounds/)
7月2日

vc常微分方程初值问题求解(转)

Visual C++常微分方程初值问题求解 (转)
http://www.yesky.com/20021122/1641169.shtml
 
2002-11-22· ·信息产业部电子第二十二研究所青岛分所郎锐··YESKY
 
1 2  下一页

  摘要:本文讲述了以计算机为辅助计算工具,分别使用欧拉算法、改进欧拉算法以及经典龙格-库塔算法对常微分方程的初值问题进行数值求解的实现算法。
  一、 引言
  在工程计算中我们经常要去解一些常微分方程,虽然在高等数学和其他一些涉及微分方程的专业书籍中介绍了不少类型的常微分方程,及各自的解法。但工程
技术人员在工程和科学研究中所关心的往往只是常微分方程的近似数值解,而非从事数学研究的技术人员所注重的"过程"。采用常规的人工推导、求解无疑是效率
非常低下的,而且工程上的常微分方程往往结构非常复杂,要给出一般方程解的表达式也是非常困难的。实际上到目前为止,我们只能对有限的几种特殊类型的方
程求精确解,这远不能满足工程需要,对那些不能用初等函数来表达的方程就只能去求其近似的数值解,而且这样还可以借助于运算速度快的计算机来进行辅助求
解,大大提高求解的速度和精度,修改也比较灵活。
  二、 使用欧拉算法及其改进算法进行一般求解
  所谓的数值求解,就是求问题的解y(x)在一系列点上的值y(xi)的近似值yi。欧拉(Euler)算法是其中最基本、最简单的算法,但其求解精度较低,一般不在
工程中单独进行计算。其实现的依据是用向前差商来近似代替导数。对于常微分方程:
  dy/dx=f(x,y),x∈[a,b]
  y(a)=y0
  可以将区间[a,b]分成n段,那么方程在第xI点有y'(xI)=f(xI,y(xI)),再用向前差商近似代替导数则为:(y(xI+1)-y(xI))/h= f(xI,y(xI)),因此可以根
据xI点和yI点的数值计算出yI+1来:
  yI+1= yI+h*f(xI ,yI)
  下面就在Visual C++ 6.0编程环境下对一个简单的常微分方程
  y'=x-y+1,x∈[0,0.5]
  y(0)=1
  求近似数值解,由于该简单方程可以用数学方法求得其精确描述式y(x)=x+e-x,所以可以据此检验近似数值解同真实解的误差情况。对于其他一些结构复杂的
常微分方程的数值解实现方法也是一样的。下面就通过代码来实现上述算法,并对计算结果作了比较:
float y[6]; file://用于存放计算出的常微分方程数值解
float r; file://同真实解的误差情况
memset(y,0,sizeof(float)*6);//清零
y[0]=1; file://y(0)=1
……
for(float x=0;x<0.6;x+=0.1) file://区间分5段,步长为0.1
{
r=x+expf(-x); file://真实解y(x)=x+e-x
y[i+1]=y[i]+0.1*(x-y[i]+1); file://数值解(近似)
r=fabs(r-y[i]); file://误差
str.Format("y[%d]=%f r=%f\r\n",i,y[i],r);
i++;
msg+=str;
}
AfxMessageBox(msg);
……
  经过程序计算,得出y(xi)在各点的近似数值解及各自同真实解的误差,现列表如下,以兹对照:
xI(各分点) yI (数值解) y(xi) (真实值) | y(xi)- yI | (误差)
0.0 1.000000 1.000000 0.000000
0.1 1.000000  1.004837 0.004837
0.2  1.010000  1.018731 0.008731
0.3 1.029000  1.040818 0.011818
0.4 1.056100  1.070320  0.014220
0.5  1.090490 1.106531  0.016041
  虽然从实验结果看误差不算太大,但这仅仅是一个用于实验的非常简单的常微分方程,对于实际工程中应用的结构复杂的方程其求解结果的误差要远比此大的
多,由于还存在着局部截断误差和整体截断误差,有必要采取措施来抑制、减少误差,尽量使结果精确。在构造欧拉公式时采取的一个重要步骤--用向前差商来代
替导数,如将其改为向后差商也是行的通的。此时的欧拉公式就变成了:yI+1= yI+h*f(xI+1,yI+1),由于该式是一个隐式公式,所以可用迭代法进行计算,直至
获取到满足精度要求的yI+1。从数学上可以证明,该式的局部截断误差和前面的欧拉公式的截断误差在主部上之相差正负号,所以只要将显示和隐式的两个欧拉公
式相加后再行求解会大大减少误差。可以解得改进后的欧拉公式的表达式为:
  yI+1= yI+h*(f(xI, yI)+f(xI+1, yI+hf(xI,yI)))/2
  对此式进行编程,就要比前面的代码要麻烦些,需要分步对其进行计算,以达到最高的运算效率,减少运算量:
……
for(float x=0;x<0.6;x+=0.1)
{
r=x+expf(-x);
T1=y[i]+0.1*(x-y[i]+1); file://分步进行计算
T2=y[i]+0.1*((x+0.1)-T1+1);
y[i+1]=(T1+T2)/2;
r=fabs(r-y[i]);
str.Format("y[%d]=%f r=%f\r\n",i,y[i],r);
i++;
msg+=str;
}
AfxMessageBox(msg);
  从下表得出的实验数据可以看出,这种经过改进的欧拉算法所存在的误差已大为减少,可以直接单独应用于实际的工程计算。误差的减少主要是由于先利用了
欧拉公式对yI+1的值进行了预估,然后又利用梯形公式对预估值作了校正,从而在预估--校正的过程中减少了误差。
xI(各分点) yI (数值解) y(xi) (真实值) | y(xi)- yI | (误差)
0.0  1.000000 1.000000 0.000000
0.1  1.005000  1.004837 0.000163
0.2  1.019025 1.018731 0.000294
0.3  1.041218  1.040818  0.000400
0.4  1.070802  1.070320  0.000482
0.5 1.107076  1.106531 0.000545
 
三、 使用经典龙格-库塔算法进行高精度求解
  龙格-库塔(Runge-Kutta)方法是一种在工程上应用广泛的高精度单步算法。由于此算法精度高,采取措施对误差进行抑制,所以其实现原理也较复杂。同前
几种算法一样,该算法也是构建在数学支持的基础之上的。对于一阶精度的欧拉公式有:
  yi+1=yi+h*K1
  K1=f(xi,yi)
  当用点xi处的斜率近似值K1与右端点xi+1处的斜率K2的算术平均值作为平均斜率K*的近似值,那么就会得到二阶精度的改进欧拉公式:
  yi+1=yi+h*( K1+ K2)/2
  K1=f(xi,yi)
  K2=f(xi+h,yi+h*K1)
  依次类推,如果在区间[xi,xi+1]内多预估几个点上的斜率值K1、K2、……Km,并用他们的加权平均数作为平均斜率K*的近似值,显然能构造出具有很高精度
的高阶计算公式。经数学推导、求解,可以得出四阶龙格-库塔公式,也就是在工程中应用广泛的经典龙格-库塔算法:
  yi+1=yi+h*( K1+ 2*K2 +2*K3+ K4)/6
  K1=f(xi,yi)
  K2=f(xi+h/2,yi+h*K1/2)
  K3=f(xi+h/2,yi+h*K2/2)
  K4=f(xi+h,yi+h*K3)
  下面的具体程序实现同改进的欧拉算法类似,只需作些必要的改动,下面将该算法的关键部分代码清单列出:
……
for(float x=0;x<0.6;x+=0.1)
{
r=x+expf(-x);
K1=x-y[i]+1; file://求K1
K2=(x+(float)(0.1/2))-(y[i]+K1*(float)(0.1/2))+1; file://求K2
K3=(x+(float)(0.1/2))-(y[i]+K2*(float)(0.1/2))+1; file://求K3
K4=(x+0.1)-(y[i]+K3*0.1)+1; file://求K4
y[i+1]=y[i]+(float)(0.1*(K1+2*K2+2*K3+K4)/6); file://求yi+1
r=fabs(r-y[i]); file://计算误差
str.Format("y[%d]=%f r=%f\r\n",i,y[i],r);
i++;
msg+=str;
}
AfxMessageBox(msg); file://报告计算结果及误差情况
  从下表记录的程序运行结果来看,在步长为0.1的情况下所计算出来的常微分方程的数值解是非常精确的,用浮点数进行运算时由近似所引入的误差几乎不会
对计算结果产生影响,这样高的精度是非常令人满意的。无论是从计算速度上还是从计算精度要求上,都能非常好的满足工程计算的需要。
xI(各分点) yI (数值解) y(xi) (真实值) | y(xi)- yI | (误差)
0.0 1.000000 1.000000 0.000000
0.1  1.004838  1.004837  0.000001
0.2  1.018731  1.018731  0.000000
0.3  1.040818  1.040818 0.000000
0.4  1.070320  1.070320 0.000000
0.5  1.106531  1.106531  0.000000
  小结:本文针对工程计算中遇到的常微分方程初值问题的求解,根据实际情况引如了计算机作为辅助计算工具,并根据高等数学的有关知识将欧拉公式、改进
的欧拉公式、经典龙格-库塔方法等融入到计算机程序算法之中,充分利用了计算机的速度优势,大大减轻了工程技术人员的劳动强度,同时也使计算结果更加可
靠、准确。但在实际应用时,针对不同的工程函数选择合适的求解方法需要有较高的要求,既要考虑到方法的简易,又要减少计算量,同时又不能让截断误差超出
指定范围。一般来说经典龙格-库塔算法精确度高又利于计算机编程实现,稳定性也很好,可以考虑作为首选实现算法。
 

四阶Runge-Kutta法(转)


一阶常微分方程:
u'=f(t,u) a<t<b
u(t(0))=u(0)

Runge-Kutta非线性高阶单步法,p阶R-K法的整体阶段误差为O(h^p)
R-K四阶算法:
u(i+1)=u(i)+h*(k1+3*k2+3*k3+k4)/8
k1=f(t(i),u(i))
k2=f(t(i+h/3),u(i+h*k1/3))
k3=f(t(i+h/3),u(i+h*k2/3))
k4=f(t(i+h),u(i+h*k3))
四阶程序如下:
class RK{
private:
double k1,k2,k3,k4;
double h,b,u,a;
public:
void seth(double l=0){h=l;} //设步长
void setf(double xa=0,double xb=0,double y=0) //设初值和范围(xa,xb)
{
b=xb;
a=xa;
u=y;
}
double f(double t,double u) //函数值,修改它以适应各自需要
{
//函数设定
double f=u-2*t/u;
return f;
}
void dork() //R-K 主函数
{
for(int count=0;count<(b-a)/h;count++)
{
k1=f(a+count*h,u);
k2=f(a+count*h+h/3,u+h*k1/3);
k3=f(a+count*h+2*h/3,u-h*k1/3+h*k2);
k4=f(a+count*h+h,u+h*k1-h*k2+h*k3);
u=u+h*(k1+3*k2+3*k3+k4)/8;
count<<u<<endl;
}
}
};
void main()
{
RK my;
my.seth(0.1);
my.setf(0,1,1);
my.dork();
}
5月21日

D3D9的一些更新(转)

由于Aug 8造成的D3D9恐惧症已经完全消除了,这一章将会给大家介绍将3D引擎转向D3D9的各个方面,包括终于出现的全屏幕模式。从这章以后,我将使用D3D9作为讲解的语言继续D2D教程。
【OP结束,开始正片】
『Why?』
  估计大家首先要问的就是“Why?”为什么要前进到D3D9?理由如下:
1、D3D9修复了D3D8已知的所有Bug,因此运行起来更稳定,速度也要快。
2、D3D9提供了许多便利的新功能,虽然绝大多数是面向3D的,但是也有不少2D适用的,比如IDirect3DDevice9::StretchRect,以及对IDirect3DSurface9的改进等等。D3DX库就更多了,比如D3DXSaveSurfaceToFileInMemory,一开始没发现这个函数有啥用处,现在基本离不开了。
3、HLSL。就像上一话我说的那样,D2D教程以后会有PixelShader的内容。我可不想拿汇编来写Shader,会死人的(祝贺我吧,终于抛弃汇编Shader了……)。虽然说这不是决定性的理由,因为还有Cg什么的,不过我想编写显卡无关的代码,因此我不去研究Cg(反正和HLSL差不多)以及R2VB之类。
4、ID3DXFont,往下看你就知道了。
《D3D的变化》
『界面名称变化』
  一句话:8改成9就行。
『“创建”型方法的一个统一变化』
  许多Create*()方法,比如创建设备、创建纹理、创建顶点缓冲等等,多了一个HANDLE* pSharedHandle参数,无用,NULL之(看来微软原打算弄个共享句柄之类,不过被D3D10巨大的变化浮云了)
『创建D3D设备的变化』
  D3DPRESENT_PARAMS的FullScreen_PresentationInterval变成了PresentationInterval,也就是说即使在窗口模式下也可以做到垂直同步来防止撕裂现象(2D的福音啊)。相应的,D3DSWAPEFFECT_COPY_VSYNC消失了,反正这个效果也不咋的,消失了也好。
  要做到垂直同步需要给PresentationInterval赋值D3DPRESENT_INTERVAL_DEFAULT或D3DPRESENT_INTERVAL_ONE。其中D3DPRESENT_INTERVAL_ONE的效果比D3DPRESENT_INTERVAL_DEFAULT好一点,不过相应的也会占用多一点点系统资源……真的只有一点点而已,实在是无所谓的……
  如果不要垂直同步,想要看看实际祯速的话,D3DPRESENT_INTERVAL_IMMEDIATE。
  注意在窗口模式下,你只能使用这三种Present模式,全屏幕模式下就可以使用别的(但是要首先检测D3DCAPS9以查看显卡是否支持)。不过我感觉对99%的游戏来说,有这三个就足够了。
  另外在窗口模式下,BackBufferFormat也可以设置成D3DFMT_UNKNOWN,D3D会自动获取当前桌面的格式设定成后备缓冲的格式,省去GetDisplayMode。实际上,窗口模式下的后备缓冲已经不需要和桌面格式相同,你可以通过IDirect3D9::CheckDeviceFormatConversion来检查,如果这个设备支持这两种颜色格式之间的转换,就可以给程序的后备缓冲设定上不同的格式。我试过在桌面格式为32Bit(D3DFMT_X8R8G8B8)时将程序的后备缓冲格式设置为D3DFMT_R5G6B5(16Bit),发现了速度提升,也就是说这个设定是有意义的。
  可创建的设备类型多了一种D3DDEVTYPE_NULLREF,在安装了D3D SDK的机子上等同于D3DDEYTYPE_REF,在其他的机子上,这种设备实际上没有创建真正意义的D3D设备,只是允许你创建的纹理、表面等资源,但是Render、Present等操作都会无效(实际上这些资源都创建在了D3DPOOL_SCRATCH池里,不管你设定使用的是什么POOL)。也就是说,仅仅在模拟基本的运行而已。你可以用这个设备来编写一个利用D3DX函数库进行图像格式转换的程序,比如把一大堆不同的格式转换成易于D3D9使用的DDS格式。因为实际上没有创建设备,你甚至可以编写成控制台的,通过GetConsoleWindow的方法获得HWND。Mercury 3用的MIF格式的转换器就是这么做出来的。注意D3DDEVTYPE_NULLREF只能用在IDirect3D::CreateDevice时,其他的方法都不行。
『创建表面的变化』
  创建表面(Surface)的方法变成了IDirect3DDevice9::CreateOffscreenPlainSurface,参数很简单不用多说,需要注意的是可以选择POOL了。
『设定FVF的变化』
  设定FVF时,原来通过IDirect3DDevice8::SetVertexShader,现在有了一个专门用来设定FVF的方法:IDirect3DDevice9::SetFVF。这是个很好的变化,省得把FVF和Shader弄混(题外话:也就是因为这个变化,让Shader在设备Reset后得以保存,不错不错)
『获取后备缓冲』
  D3D9现在允许有多个后备缓冲交换链,不过对于2D来说,基本不需要这种东西,IDirect3DDevice9::GetBackBuffer多出来的第一个参数赋值0即可。如果你有兴趣,可以去研究一下这个玩意,有时候可以用来做分场。
『SetStreamSource』
  这个方法的功能被扩展了,对比参数就可以知道,多出来的OffsetInBytes允许你选择一个顶点缓冲的Offset,D3D9将从这个Offset之后开始读取数据。因此你可以把几组用来渲染纹理的正方形顶点存储到一个顶点缓冲里面。
『SetSamplerState』
  这个是D3D9的新方法,把原先SetTextureStageState的一些功能独立了出来,和2D关系最密切的就是纹理过滤了。原先的D3DTSS_MINFILTER变成了D3DSAMP_MINFILTER,相应的D3DTSS_MAGFILTER也变成D3DSAMP_MAGFILTER,D3DTSS_MAXANISOTROPY变成D3DSAMP_MAXANISOTROPY。另外还有更多的,比如纹理寻址等。你去看一下D3DSAMPLERSTATETYPE枚举类型的内容就知道它“迁移”了些什么。
  这个变化对于Shader来说很方便。改成Sampler的东西在PixelShader过程也会有效,而没有更改的东西在PixelShader就不会有效了。D3D8时候把这些全都放在了一起,容易造成混乱。
『SetRenderTarget』
  D3D9现在允许多重RenderTarget存在,不过我们基本上只用一个,RenderTargetIndex设为0,第二个参数仍然是需要设定的表面。与D3D8相同的是,在设定之前仍然需要先通过GetSurfaceLevel获得表面才行。
『顶点缓冲的锁定』
  注意IDirect3DVertexBuffer9::Lock的第三个参数,从原来的BYTE**变成了void**。也就是这样了……
『其他的一些变化』
1、CopyRects变成了UpdateSurface。和UpdateTexture一样,只能从D3DPOOL_SYSTEMMEM拷贝到D3DPOOL_DEFAULT
2、增加了一个比较有用的IDirect3DDevice9::ColorFill方法,作用是向D3DPOOL_DEFAULT的某个区域填充颜色,和Clear的功能类似,但是在使用目的上要比Clear明确的多,并且由于不牵扯深度缓冲之类,速度要快一些。
3、增加了一个IDirect3DDevice9::StretchRect方法,通过这个方法就可以在D3DPOOL_DEFAULT的表面或纹理之间进行带过滤器的缩放操作,免去利用Render的过程,非常有用。不过这个方法由于使用了硬件处理,限制较多,请大家仔细看SDK文档的Remarks部分。
《D3DX的变化》
  D3DX的变化实际上相当的多,但正如我一开始所说,基本都是面向3D的。需要我们注意的有以下几种:
1、D3DX***FromFile之类的函数支持的图像格式增加了,不过所增加的都是很少见的格式。平时基本上还是用BMP、TGA和PNG就足够。
2、增加了D3DXSave***ToFileInMemory,将会把文件写入内存。这个函数的作用似乎不是很容易想到,但是如果你要写一个集成了转换、打包功能的工具,这个就很有用了,省去了通过临时文件操作造成的各种问题。另外如果你熟悉某种图形文件的格式的话,还可以通过直接访问这个文件获得RAW信息。注意,这类函数写入的是一个ID3DXBuffer,这个东西很简单,只有两个特定的方法,一看便懂,不再多言。
3、增加了一个ID3DXLine,可以方便你在2D上画线,创建ID3DXLine的方法是D3DXCreateLine。这个东西也不复杂,使用方法有点像ID3DXSprite,稍微研究一下就能弄懂,注意每次Draw的是D3DPT_LINESTRIP。用它比直接用顶点缓冲的好处是可以方便的打开反锯齿,效果嘛……基本满意。
4、增加了一个ID3DXRenderToSurface,“理论上来说”方便了利用RenderTarget的过程……不过我感觉反而弄得复杂了。创建的方法是D3DXCreateRenderToSurface,有心情的朋友自己研究看看吧,我就不讲了。
  ID3DXSprite和ID3DXFont在Summer 2004的DX9 SDK(也就是第一版DX9.0c)开始发生了很大变化,下面详述:
『ID3DXSprite』
  你会发现ID3DXSprite::DrawTransform不见了,取而代之的是其功能被整合到ID3DXSprite::SetTransform里面,也就是说为了缩放和旋转,我们不得不和矩阵打交道了。其实也不会太复杂,因为我们只是做一些矩阵运算,学过线性代数的朋友肯定会很熟悉,就算你不怎么熟悉线性代数,也没关系,D3DX函数库提供了现成的矩阵运算函数,你只要用就行了。
D3DXMatrixScaling
D3DXMatrixRotationZ
D3DXMatrixTranslation
  按照顺序调用这三个函数……或许学过3D的马上就想到这点了,的确是没错啦。注意顺序哦:Scaling -> Rotation -> Translation,简称SRT(看过全金属狂潮吗?看过的话这个单词很好记吧^_^),弄错了可是得不到正确结果的。
  你是不是想到把同一个D3DXMATRIX当作参数使用三次?错啦!你要用矩阵乘法。创建三个D3DXMATRIX,比如mat1、mat2、mat3,分别用这三个函数将其创建为缩放矩阵、旋转矩阵和平移矩阵,然后在ID3DXSprite::SetTransform时,这样写:
SetTransform(mat1 * mat2 * mat3);
  有够麻烦的是不?ID3DXSprite方便了做3D的,可害苦了做2D的,所以我已经不直接用这个了(什么叫不直接用?往下看)。
『ID3DXFont』
  大家来欢呼吧!Summer 2004改进的ID3DXFont彻底枪毙掉了上一话那个字体引擎……
  这东西的改进,怎么说呢,应该说是改头换面吧,速度、效果都和以前不是一个数量级。可怜的PixelFont,才存在了一话就要被抛弃了。
  ID3DXFont多出来的几个方法,Preload*()这类的,就是把一些常用的字的字模提前读取到内存里面加快速度,同时还可以使用ID3DXSprite渲染,进一步加快速度。虽然内部仍然有GDI的部分,不过很明显工作方式发生了极大的变化。根据我的估计,这次的ID3DXFont很聪明的利用GDI获得文字的轮廓,然后通过纹理来渲染。这样的速度就快得多了,而且文字质量也得到了很好的控制,基本和直接用GDI的质量相同了。
  由于PreloadCharacters()和PreloadGlyphs()不是那么好理解,一般用PreloadText()就行。建议将所有ASCII字符、标点符号和部分汉字预读进去。这个预读过程略微有点慢,而且根据预读的文字数量和你创建文字的字号,占用的内存也不同。这里给大家一堆文字,你Copy过去就行:

引用
const char strPreloadText[] = " 1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM~!@#$%^&*()-=[]\\;',./_+{}|:\"<>? 、。·ˉˇ¨〃—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}我人有的和主产不为这工要在第一上是中国经已发了民同";

  注意第一个字符是空格哦!把空格预读进去可是很重要的^_^
  看上去并不多,因为要考虑到内存占用及速度,我只预读了一些符号和五笔的一键字。这些字符在24号字时候已经占用了快1MB了,比起PixelFont字库占用的要大得多。天知道ID3DXFont到底预读了些什么……
  PreloadText()的第二个参数不要用strlen,sizeof(strPreloadText)即可。
  然后就是利用ID3DXSprite来渲染。注意ID3DXFont::DrawText的第一个参数就是LPD3DXSPRITE,因此如果要利用ID3DXSprite,要将ID3DXFont::DrawText放到ID3DXSprite::Begin和ID3DXSprite::End之间。这就是我刚才说的不直接用ID3DXSprite的意思,ID3DXFont会完成ID3DXSprite的全部调用,你不用担心。
  另外你应该注意到ID3DXSprite::Begin增加了参数,实际上DX文档里面没说,但是示例里面有,如果想让ID3DXSprite发挥作用并且最大幅度的提升效率,参数上设定D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE即可。意思很明白:打开Alpha过滤和纹理筛选。这里DX文档上有个错误一直没改:文档里给出的是D3DXSprite__SORT_TEXTURE,但是你可以试试,绝对报错。
  剩下的就没啥了,ID3DXFont的使用方法上一话已经讲过。要注意的是D3DXCreateFont和D3DXCreateFontIndirect都发生了变化。D3DXCreateFont已经不再牵扯GDI了,D3DXCreateFontIndirect所使用的结构也变成了D3DXFONT_DESC,相对于LOGFONT结构,除去了一些用不着的参数,增加了一个MipLevels,就是MipMap等级啦,不用多说,2D下只用1。其他的上一话都有。实际上由于D3DXCreateFont已经不再关联GDI,D3DXCreateFontIndirect的存在仅仅是由于历史原因(为了兼容像我这种人的使用习惯),大家还是用D3DXCreateFont吧,省事。
  截图就不贴了,没啥意义。你可能觉得直接向后备缓冲上DrawText还不够好看,那么就先画到一张纹理上,然后将纹理错位渲染到后备缓冲并且打开线型过滤,就可以达到和PixelFont相同的效果了。
  速度嘛……我画了整整一屏幕字,在不缓冲文字的情况下(这个“缓冲文字”和ID3DXFont的文字缓冲可不是一回事啊!看过上一话的都应该知道我这里指的是什么),速度仍然在120FPS以上。或许你会觉得速度还是有点慢,但是,如果用D3D8的ID3DXFont画上这么一屏幕,基本就只剩20FPS了。
  使用ID3DXFont替换掉PixelFont的优势就是可以方便的自定义字体字号了,并且也不再受GB2312字库的限制。所以大家都换了吧……都换了吧……把PixelFont忘了吧……
『稳定的DX9 SDK版本』
  我现在用的是April 2006,而且应该会用很长时间。August 2006我是肯定不会去用啦!即使我不再恐惧D3D9,也会对这个SDK避让三分的。其实对于2D,我感觉用到April 2006就足够了,之后的DX9 SDK主要在D3DX的3D函数库部分进行更改……其实也是秋后的蚂蚱蹦达不了几天,D3D10马上就要出来了。要说D3D10啊……你还是看我另外一篇日志好了,总之打死我都不拿它做2D。
  实际上仅仅是2D的话,从D3D8转向D3D9并没有多少变化,主要是稳定嘛!只要你不调用一些D3D9专用的功能,即使拿D3D9来做2D,在绝大多数显卡上还是能够运行的。嗯……GF2等级以上吧,GF2之前的,也太老了,无视好了。
《再上点菜好了:全屏幕模式》
  其实并不是多么复杂的问题,让我拖了这么久……不拖了,这里就教给大家如何做全屏幕模式以及如何处理设备丢失的问题。
『创建全屏幕模式』
  D3DPRESENT_PARAMS里面,Windowed设定为false,并且一定要设定BackBufferWidth和BackBufferHeight,完毕。
  哈哈,就这么简单,或许早就有人尝试过了,但是你试试按下Alt+Tab,再切换回去,保证你什么都看不到。
  之前曾经说过,DX8之前的版本,在全屏幕下工作比在窗口下容易,到DX8之后就则完全颠倒过来。因为在窗口模式下不用担心设备丢失(除非你更改桌面分辨率),全屏幕模式下就会有这个问题了。下面详述:
『设备、资源丢失』
  设备丢失会发生在全屏幕模式下切换回桌面时(不论是通过Alt+Tab还是QQ上有人给你发了张图片-_-bbb),而且如果在调用IDirect3DDevice9::Reset(从现在开始就是D3D9了啊!忘记D3D8吧……)的时候发生错误,设备也会丢失。
  设备丢失会造成资源丢失:所有创建在D3DPOOL_DEFAULT池的资源都会丢失,需要重新创建,其内容当然也会消失,需要重写。
  然而创建在D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH池的资源不会受到影响。创建在D3DPOOL_MANAGED池的资源也不会丢失,而且在设备重新可用的时候,D3DPOOL_MANAGED池的资源也可以立即投入使用,内容也不会改变。看这个池名字:托管池就能知道,D3D帮你处理了所有问题。
  因此避免设备丢失后资源丢失的简易方法就是将所有资源创建在D3DPOOL_MANAGED池内。不过这并不是个好方法,这意味着不能用渲染对象——记得吗?RenderTarget只能创建在D3DPOOL_DEFAULT。实际上最好的方法是跟踪所有D3DPOOL_DEFAULT资源,比如利用std::list,将所有D3DPOOL_DEFAULT资源勾住,在设备发生丢失的时候释放掉资源,设备可以继续使用的时候重新创建资源,记得把数据写回去。对于其他的池就不用这么折腾了。
『当设备丢失之后』
  不论通过任何方式发生了设备丢失,所有的操作几乎都会失效,只有Release()可以用——其实D3D会保证有部分操作可以成功,但是也仅仅是“可以”成功而不是“一定”成功,所以你还不如认定丢失的时候全都会失败比较好——以及IDirect3DDevice9::TestCooperativeLevel。因此在设备丢失之后,你应该停止整个游戏循环,而通过反复调用IDirect3DDevice9::TestCooperativeLevel判断设备是否可用。
『IDirect3DDevice9::TestCooperativeLevel』
  这个方法检测当前的设备状态。返回值有四种:D3D_OK一切正常,D3DERR_DEVICELOST设备丢失,D3DERR_DEVICENOTRESET设备可以Reset。另外还有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到这个你就完蛋了,基本不可能恢复了,终止程序吧。
  按照顺序来讲,如果游戏在正常运行,D3D_OK会返回;如果发生了设备丢失并且在这个时候不能恢复,比如全屏幕模式的时候用户切换到了Windows桌面,就会返回D3DERR_DEVICELOST;如果用户又切换回了游戏,设备可以恢复了(还没恢复呢!只是“可以”恢复而已),就会返回D3DERR_DEVICENOTRESET。
  另外,IDirect3DDevice9::Present也会返回类似的值,不过你最好别指望这个,老老实实的用TestCooperativeLevel。因为Present在设备可以恢复的时候还是返回D3DERR_DEVICELOST(外一句:D3D10的时候TestCooperativeLevel就会完全整合到Present里面了,可喜可贺可喜可贺)
『处理设备丢失』
  看下面的伪代码:
switch (IDirect3DDevice9::TestCooperativeLevel()){
  case D3D_OK:
    GameLoop();
    break;
  case D3DERR_DEVICELOST:
    break;
  case D3DERR_DEVICENOTRESET
    OnLostDevice();
    IDirect3DDevice9::Reset();
    OnResetDevice();
    break;
  default:
    QuitGame();
    break;
}
  GameLoop()就是你的游戏运行的过程了。把这个switch写在我们游戏框架的GameMain()部分,具体的位置可以看任何一话附带的源代码。
  好像我一直没有讲IDirect3DDevice9::Reset的参数啊?因为只有一个参数,就是指向D3DPRESENT_PARAMS的指针。把你第一次创建设备时使用的D3DPRESENT_PARAMS结构保存起来,供Reset来用。
  OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的资源,OnResetDevice()就是Create*()恢复啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在这个时候调用的。如果你没有这么做,也就是说还保留着任何D3DPOOL_DEFAULT的资源的话,IDirect3DDevice9::Reset就一定会失败。
  另外在OnResetDevice里面你还要重新进行SetRenderState、SetSamplerState等等,Reset之后这些东西也丢失了。实际上Reset和重新创建一次设备类似,所不同的是重新创建设备的话你需要连D3DPOOL_MANAGED的资源也Release掉。这个话题就不讨论了。
  从代码可以看出来,D3DERR_DEVICELOST时程序什么都没做,只是在傻等。我认为这是一个好习惯,因为实在不能保证在D3DERR_DEVICELOST时除了Release还能干什么,与其这样还不如等设备能用了再说。
  实在懒得管资源的话,全部D3DPOOL_MANAGED好了。至于渲染对象?自己想办法。
『人工制造“设备丢失”』
  “干嘛还要制造设备丢失啊?”如果更改游戏分辨率、色深、切换全屏幕及窗口状态,进行这样的操作也要通过Reset,同样的,Reset之前也要释放掉所有D3DPOOL_DEFAULT资源(其实严格来说,还有更多的资源也要释放,不过在2D下基本不会创建这类资源,你就不用管了)并且调用ID3DXSprite::OnLostDevice之类的方法。这就是人工制造“设备丢失”了。实际上在这个过程设备并没有真正的丢失,只是会有一段时间处于不可用的状态,此时Reset尚未返回,整个D3D设备就好像死了一样。举个例子,你切换桌面分辨率,会有那么一段时间显示器上什么都不显示,然后很快就正常了。和这个现象是同一个原因。Reset成功后记得恢复资源。
  你可能注意到这里的Reset和上面的Reset不是一回事。的确是这样,这里是为了重设状态而不是恢复设备。因此更改分辨率、色深的Reset需要写到switch外面,也就是别和它搅和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。记住:正确的调用Reset不会造成设备丢失,这个概念别弄混了。
『切换全屏幕模式时的注意事项』
  注意WindowStyle的变化。切换成全屏幕模式后,只能使用WS_POPUP,不然显示会变得怪怪的,你可以通过SetWindowLongPtr函数更改窗口外观,第二个参数指定GWL_STYLE即可。别忘了WS_VISIBLE啊!不然你什么都看不见。
『更详细的文档』
  我这里只是简单讨论了造成设备丢失的原因及处理方法,更详细的内容你可以参考DX SDK文档的Lost Device文章,人家是权威的。
【以上,正片结束,后面是ED】
  我们前进到了D3D9,赶上了时代。
  我们创建了全屏幕游戏,赶上了时代。
  我却变得一脑子浆糊,被观众抛弃了。
  哈哈,开玩笑啦,不过这一话很乱倒是真的,因为不论是更新到D3D9还是设备丢失,牵扯的东西都太散太杂,结果弄得这一话也是一盘散沙(居然又没有附带代码)。唉,大家就忍了吧,忍不了的话就来PIA我吧。
  关于更新至D3D9更多的内容,你可以参考SDK文档的《Converting to Direct3D 9》。
【以上,ED结束,后面是……】
  第一季完结了……
  回过头来看看,从第一话创建一个Windows窗口,到这一话的设备丢失,话题的层次一直在深入,现在已经深入到了不再是“学习”而是“研究”的范围。我也不再想仅仅是搞“教学”而是想和大家“讨论”。不过第一季主要还是教学吧。能坚持着看D2D教程到现在的,应该基本能够写出完整的2D Demo来了吧。如果有什么问题的话,欢迎提出,我在看到后会立刻回答的……只要你这个问题不太RP的话……
  那么,第二季会是什么样子?
  第二季就不再是教学了,而开始我和大家的讨论过程。第二季的第一话,也就是第09话,我将提供一些高级技巧给大家,并希望有兴趣的朋友和我一起进行这些技巧的研究。另外在第二季里面,我们还要创建一个2D图形引擎。原来打算给大家讲解Medux 2,不过现在感觉这东西实在小儿科,绝对会让大家B4的。那么既然如此,干脆介绍Mercury 3好了,有意见无?
  透漏一点下一话的内容吧:模糊精度和多次纹理渲染,嘿嘿,听上去挺高深的是不?实际上超级简单,就看你能不能想到而已。
  希望你在看完这一话之后,返回去再把前面的内容看看,相信你会得到新的收获。搞不好你还能抓出几个Bug呢!因为我是想到什么写什么,没个章法,Bug是难免的。
posted on 2007-01-04 00:57 @王一伟 阅读(475) 评论(2)  编辑 收藏 引用
5月10日

游戏中输入法处理

游戏中输入法处理:
一。 假全屏:
    // 去掉窗口标题:
  SetWindowLong(hWnd, GWL_STYLE, WS_VISIBLE|WS_POPUP);
  
  // 重调客户端大小:
  AdjustWindowRect(&rc, _dwLastWindowStyle, FALSE);
  // 重设窗口:
  SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE);
   
    // 最后重设d3ddevice的分辨率(这步如果省略,将看到被拉伸模糊后的效果)
    // 这个就不列了,只写出大概步骤:先释放所有用到的显存资源,再设置分辨率等参数后调用m_pd3dDevice->Reset(),
    // 然后重新创建和恢复所有用到的显存资源:
   
二。 兼容GDI方式的真全屏:
    d3ddevice->SetDialogBoxMode(TRUE); 即可,不过需满足以下条件:
   
  IDirect3DDevice9::SetDialogBoxMode
  This method allows the use of GDI dialog boxes in full-screen mode applications.
  
  HRESULT SetDialogBoxMode(
    BOOL bEnableDialogs
  );
  Parameters
  bEnableDialogs
  [in] TRUE to enable GDI dialog boxes, and FALSE to disable them.
  Return Values
  If the method succeeds, the return value is D3D_OK. If the method fails,
  the return value can be D3DERR_INVALIDCALL unless all of the following are true.
  
  The application specified a back buffer format compatible with GDI,
  in other words, one of D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, or D3DFMT_X8R8G8B8.
  The application specified no multisampling.
  The application specified D3DSWAPEFFECT_DISCARD.
  The application specified D3DPRESENTFLAG_LOCKABLE_BACKBUFFER.
  The application did not specify D3DCREATE_ADAPTERGROUP_DEVICE.
  The application is not between BeginScene and EndScene.
  
  Remarks
  The GDI dialog boxes must be created as child to the device window.
  They should also be created within the same thread that created the device
  (提示: 关于这个windows会把系统输入法加载到能使用输入法的每一个线程中)
  because this enables the parent window to manage redrawing the child window.
  The method has no effect for windowed mode applications, but this setting
  will be respected if the application resets the device into full-screen mode.
  If SetDialogBoxMode succeeds in a windowed mode application,
  any subsequent reset to full-screen mode will be checked against
  the restrictions listed above. Also, SetDialogBoxMode causes all
  back buffers on the swap chain to be discarded, so an application
  is expected to refresh its content for all back buffers after this call.
  
  Requirements
  Header: Declared in D3d9.h.  
  
   说明: 这个方式比较容易,但是D3D的刷新频率下降。
   该方式d3d8下不行,d3d9下可以。
  
三。ddraw的裁剪方式:
    给主表面设置一个裁剪器,这样就可以正确显示GDI。很久以前做的GDI输入框测试通过。
    可参看FullScreenDialog例子
   
四。真全屏下使用IME处理:
    使用IME的自绘输入法侯选框。
   
   
    由于时间问题,目前已先修改成第2种方式。
    待后再使用第四种真全屏下自绘输入框使用IME来处理
    http://game.lihuasoft.net/showart.php?id=3397
    及
    http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Dec_2005/Using_an_Input_Method_Editor_in_a_Game.asp
4月16日

d3d api 耗时计算

寻找渲染耗时不对的原因:
d3d调用占用耗时计算不能简单地计算,而要使用device的query()方法将comand queue的内容丢给驱动。如下:
/////////////////////////////////////////////////////////
void  DXTimeBegin()
{
    if(_dwFrequency==1)
    {
        LARGE_INTEGER l; QueryPerformanceFrequency(&l); // current frequency
        _dwFrequency = (DWORD)((double)l.QuadPart / (double)1000);
    }
    _dwTimeCount = 0;
 if( NULL==_pQuery ){
  // Create an event query from the current device
  g_Render.GetDevice()->CreateQuery(D3DQUERYTYPE_EVENT, &_pQuery);
 }
 // Add an end marker to the command buffer queue.
 _pQuery->Issue(D3DISSUE_END);
 // Empty the command buffer and wait until the GPU is idle.
 while(S_FALSE == _pQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ));
    QueryPerformanceCounter(&_liStartTime);    
}
DWORD DXTimeEnd()
{
 if( _pQuery ){
  // Add an end marker to the command buffer queue.
  _pQuery->Issue(D3DISSUE_END);
  // Force the driver to execute the commands from the command buffer.
  // Empty the command buffer and wait until the GPU is idle.
  while(S_FALSE == _pQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ));
 }
    LARGE_INTEGER   liEndTime;
    QueryPerformanceCounter(&liEndTime); 
    _dwTimeCount = (DWORD)(liEndTime.QuadPart - _liStartTime.QuadPart);
    _dwTimeCount = _dwTimeCount / _dwFrequency;
    _dwFrequency = 1;
    return _dwTimeCount;
}
 
参考dx帮助:Accurately Profiling Direct3D API Calls
感谢senshi的帮助
//////////////////////////////////////////////////////
4月11日

Direct3D9: (WARN) :Ignoring redundant SetSamplerState Sampler (转)

Direct3D9: (WARN) :Ignoring redundant SetSamplerState Sampler (转)
摘自:http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=697424&SiteID=1
You're running the debug version of direct3d
Your debug output level is set far enough towards "More"
A sampler is set (by you, by the effect, by anything) to a value that it already had.
 
So, to not see these particular warnings, you can either move the slider, run retail d3d, or remove sampler states from the effect (if possible, given what you're rendering).
 
...advanced info below, read at your own risk...
In general, you want to avoid setting states redundantly.  In general, it won't harm you much performance-wise where you don't.  The D3D runtime has an early-out for redundant states being set.  The exception is pure device in d3d, but it looks like there's no equivalent in the XNA Framework (which is good).  A "pure" device let the application be responsible for any state caching and redundant state filtering - but the price you pay when redundant states survive until the driver itself filters them (or doesn't) is very high...