麒麟子

~~

导航

<2025年6月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

统计

常用链接

留言簿(12)

随笔分类

随笔档案

Friends

WebSites

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜

#

从Xfile加载MESH模型

首先介绍ID3DXBuffer 接口
此类型有两个方法
LPVOID ID3DXBuffer::GetBufferPointer();//返回指向缓存中数据起始位置的指针
DWORD ID3DXBuffer::GetBufferSize()//返回缓存的大小,单位为字节

下面函数用于创建一个空的ID3DXBuffer对象

HRESULT D3DXCreateBuffer(DWORD NumBytes, LPD3DBUFFER *ppBuffer);


再来介绍一个D3DXMATRIAL结构
typedef struct D3DXMATERIAL
{
      D3DMATERIAL9 Mat3D; //存储材质
      LPSTR pTextureFilename;//存储纹理路径名
}D3DXMATERIAL;

再来看看一个重要的函数
HRESULT D3DXLoadMeshFromX(
LPCSTR pFilename,//文件名
DWORD Options,//创建网格时所使用的标记
LPDIRECT3DDEVICE9 *pDevice,
LPD3DXBUFFER *ppAdjacency,//邻接表信息
LPD3DXBUFFER *ppMaterials,//材质和纹理信息. D3DXMATRIAL结构
LPD3DXBUFFER *ppEffectInstances,//
PDWORD pNumMaterials,//材质数目
LPD3DXMESH *ppMesh//返回填充好的Mesh对象
};

下面是一个实用的例子

class MyMesh
{
...........

private:
ID3DXMesh* Mesh = 0;
std::vector<D3DMATERIAL9> Mtrls(0);
std::vector<IDirect3DTexture9*> Textures(0);
......
};

bool MyMesh::LoadMyMesh( LPCSTR pName,IDirect3DDevice9* Device)
{
   ID3DXBuffer* adjBuffer = 0;
   ID3DXBuffer* mtrlBuffer = 0;
   DWORD numMtrls = 0;
   HRESULT hr = D3DXLoadMeshFromX(pName,D3DXMESH_MANAGED,Device,&adjBuffer,&mtrlBuffer,0,&numMtrls,&Mesh);
   if(FAILED(hr))
   {
     ::MessageBox(NULL,"D3DXLoadFromX() - FAILED",0,0);
    return false;
   }
   if(mtrlBuffer!=0&&numMtrls!=0) //如果有材质
    { 
        D3DXMATERIAL* mtrls  =
        (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();//GetBufferPointer() 为了适合各种类型,因为返回VOID*类型 需要强制转换
        for(int i = 0;i<numMtrls;i++)
        {
          //得到的材质没有环境光,我们得自己加上,让它等于漫射光
           mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;
           Mtrls.push_back(mtrls[i].MatD3D);
         }
        if(mtrls[i].pTextureFilename!=0)//纹理不为空
        IDirect3DTexture9* tex = 0;
        D3DXCreateTextureFromFile(Device,mtrls.pTextureFilename,&tex);
        Textures.push_back(tex);
        }
        else
         {
            Textures.push_back(0);
         }
     }
 adjBuffer->Release();
 mtrlBuffer->Release();
 return true;
}

//加载好后,设置好矩阵,就可以进行绘制了.由于Mesh是分为许多子集的,所以要一个一个渲染
void MyMesh::DrawMyMesh(IDreict3DDevice9* Deivice)
{
     for(int i =0;i<Mtrls.size();i++)
     {
       Device->SetMaterial(&Mtrls[i]);
       Device->SetTexture(0,Textures[i]);
       Mesh->DrawSubset(i);
     }
}

posted @ 2009-04-18 10:02 麒麟子 阅读(425) | 评论 (0)编辑 收藏

用模版缓存实现镜面效果

一直不知道那一堆长长的代码是什么意思,今天上课无聊的时候就在那里想,一不留神就想通了,真是谢天谢地!

首先将模版缓存清空
Device->Clear(    0,
                           0,
                           D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, //清空模版缓存,深度缓存
                           0ff000000,//颜色
                           1.0f,
                           0)//清空后的模版缓存值

//接下来就是模版缓存进行设置
Device->SetRenderState(D3DRS_STENCILENABLE,true) //开启模版缓存
Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);//将模版测试设置为总是成功,因为我们是在画镜面,不管镜面如何,都要画上去
Device->SetRenderState(D3DRS_STENCILREF,0x1);//设置模版参考值为1,这样将会用0x1来标记镜面区域
Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff);//设置模版掩码,0xffffffff表示不屏蔽任何位
Device->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff)//模版写掩码
Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_REPLACE);//当模版测试成功时,便用模版参考值(0x1)去替换缓存中的值
Device->SetRenderState(D3DRS_ZWRITEENALBE,false);//关闭深处缓存的写功能,以便阻止对深缓存的更改

Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true);//开启ALPHA混合功能
Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);//将源融合因子设置为(0,0,0,0);
Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);//将目标融合因子设置为(1,1,1,1);

//在这里画镜面,此时的镜面会通过模版缓存进行绘制,并且模版缓存中的代表镜面的部分被标记为0x1,而其它区域为0;

//接下来就要绘制我们的物体了
Device->SetRenderState(D3DRS_ZWRITEEABLE,true);//重新开启ZWRITE

Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL);//将模版测试规则设置为相等
Device->SetRenderState(D3DRS_STENCILZFAIL,D3DSTENCILOP_KEEP);
Device->SetRenderState(D3DRS_STENCILFAIL,D3DSTENCILOP_KEEP);//这两排表示如果深度和模版测试失败,则不对模版中的内容作更改
Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);//若测试成功也不对其作更改


//使用D3DXMatrixReflect(&R,&plane);求出物体的镜像,其中plane为镜面平面;

//若此时绘画我们会看不到物体,因为物体的深度大于镜面的深度,于是我们要清空深度缓存

Device->Clear(0,0,D3DCLEAR_ZBUFFER,0,1.0f,0);

//为了能达到物体在镜子中的效果,我们依然要用到ALPHA混合

Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);//(Rd,Gd,Bd,Ad)
Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);//(0,0,0,0);
//由于物体在镜面中的显示为物体的像,于是我们要变改镜像绘制时的背面消隐模式
Device->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);//顺时针


最后的工作就是绘制出你的物体,然后关闭开启的功能,并恢复消隐模式
Device->SetRenderState(D3DRS_ALPHABLEND,false);
Device->SetRenderState(D3DRS_STENCILENABLE,false);
Device->SetRenderState(D3DRS_CULLMODE,CCW);//恢复默认(逆时针)
  

posted @ 2009-04-18 10:01 麒麟子 阅读(798) | 评论 (0)编辑 收藏

透明纹理

对于一些纹理,我们不要求全部显示出来,如用公告板显示的一棵树的纹理,此时就要求让背景不显示出来,只显示树的部分。
//首先图片的背景要处理成透明,显然我们看到是透明的了,但是对于计算机来说,同样会将透明背景后的物品遮住。
//此时就要在渲染纹理前对其进行ALPHA混合

/*

alpha测试根据当前像素是否满足alpha测试条件(即是否达到一定的透明度)来控制是否绘制该像素,图形程序应用alpha测试可以有效地屏蔽某些像素颜色。与alpha混合相比,alpha测试不将当前像素的颜色与颜色缓冲区中像素的颜色混合,像素要么完全不透明,要么完全透明。由于无需进行颜色缓冲区的读操作和颜色混合,因此alpha测试在速度上要优于alpha混合。

比如一棵树,我们将它的背景ALPHA值设置为小于1。0,那么,我们可以将ALPHAREF 设置为1。0 即0x000000ff 然后ALPHAFUNC 设置为GREATEREQUAL (>=) 所以,只有当ALPHA值大于等于1的部份被渲染,这样树的背景就不用画了!
*/

 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );//开启ALPHA混合功能
 g_pMyd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);//设置源混合因子为(As,As,As,As)
 g_pMyd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);//设置目标混合因子为(1-As,1-As,1-As,1-As);

 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );//开启ALPHA测试功能
 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHAREF,        0x0f );//设置ALPHA测试参考值
 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL );//设置APLHA测试比较规则


//在此处加载纹理和渲染


在渲染完毕后,不要忘了关闭开启的功能

 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
 g_pMyd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

  

posted @ 2009-04-18 10:00 麒麟子 阅读(960) | 评论 (0)编辑 收藏

公告板

开始只是知道公告板就是不管摄相机怎么转,对象总是在摄相机前面。这是公告板中的一种,也是最常见的一种
如游戏中人物、NPC的名字等,就是用贴图技术,然后再用公告板,这样不管玩家怎么转动视角,总是能看见名字正对着自己,
终于自己实现了一回公告板函数

void Billboard(IDirect3DDevice9* Device,D3DXMATRIX &matInput,D3DXMATRIX &matOutput)
{
   //=========================
   //公告板技术
   //==========================
   D3DXMATRIX matBillboard,matView;
   D3DXMatrixIdentity(&matBillboard);//初始化为单位矩阵
   Device->GetTransform(D3DTS_VIEW,&matView);//取得观察矩阵
   matBillboard._11 = matView._11;//赋值
   matBillboard._13 = matView._13;
   matBillboard._31 = matView._31;
   matBillboard._33 = matView._33;

   D3DXMatrixInverse(&matBillboard,NULL,&matBillboard);//求其逆矩阵
   matOutput = matBillboard * matInput;
   //公告板结束
}

函数说明:
返回值:void
Device 是一个IDirect3DDevice9* 类型的参数
&matInput 是一个D3DXMATRIX 类型的参数
&matOutput 是一个D3DXMATRIX 类型的参数

功能,将传入的matInput 矩阵,与摄相机矩阵的Look方向矩阵相乘,得到matOutput

用法
D3DXMATRIX matWorld;
D3DXMatrixIdentity(&matWorld);

D3DXMatrixTranslation(&matWorld,1,1,1); //对matWorld 进行必要的变换 如translation ,rotation 之类的。

Billboard(g_pDevice,matWorld,matWorld);

g_pDevice->SetTransform(D3DTS_WORLD,&matWorld);

接下来就可以进行材料,纹理设置、绘制等工作了!   
虽然是很简单的技术,但却很实用。

    

posted @ 2009-04-18 09:59 麒麟子 阅读(535) | 评论 (1)编辑 收藏

字节填充函数

貌似是在《3D游戏编程大师技巧》上看到的这两个函数,当时觉得很牛耶,于是就记下来了,不过至今没有怎么用到,我想估计以后会有用吧。

//内嵌汇编的用于4字节填充的函数
inline  void Mem_Set_QUAD(VOID *dest, UINT data, int count )
{
     _asm
          {
           mov  edi, dest  ; edi指向目标内存
      mov  ecx, count  ;要移动的32位字数
      mov  eax, data   ;32位数据
      rep  stosd    ;移动数据
     }//end asm
 }//end Mem_Set_QUAD

//用于2字节(DWORD)数据填充的函数
inline  void Mem_Set_WORD(VOID *dest, USHORT data, int count )
{
     _asm
          {
           mov  edi, dest  ; edi指向目标内存
      mov  ecx, count  ;要移动的16位字数
      mov  ax, data   ;16位数据
      rep  stosw    ;移动数据
     }//end asm
 }//end Mem_Set_WORD



posted @ 2009-04-18 09:58 麒麟子 阅读(670) | 评论 (0)编辑 收藏

仅列出标题
共38页: First 25 26 27 28 29 30 31 32 33 Last