DirectX基础学习系列8 渐进网格以及外接体
1 IUnknown--> ID3DXBUFFER D3D泛型接口:
Retrieves a pointer to the data in the buffer.
Retrieves the total size of the data in the buffer.
使用完之后需要进行释放:Release()
2XFILE
//从文件中加载xfile文件
HRESULT D3DXLoadMeshFromX(
__in LPCTSTR pFilename, //xfile文件名
__in DWORD Options, //加载可选项
__in LPDIRECT3DDEVICE9 pD3DDevice, //设备
__out LPD3DXBUFFER *ppAdjacency, //临街信息,DWORD数组
__out LPD3DXBUFFER *ppMaterials, //材质信息
__out LPD3DXBUFFER *ppEffectInstances, //
__out DWORD *pNumMaterials, //材质数目
__out LPD3DXMESH *ppMesh
);
//材质结构:ppMaterials结构中第I项 对应第I个子集
typedef struct D3DXMATERIAL {
D3DMATERIAL9 MatD3D;
LPSTR pTextureFilename;
} D3DXMATERIAL, *LPD3DXMATERIAL;
加载时,首先加载XFILE文件,然后遍历纹理数据,将纹理数据加载,在渲染的时候,先设置纹理和纹理
3生成顶点法线
方便使用光照,网格的法向量计算方法
HRESULT D3DXComputeNormals(
__inout LPD3DXBASEMESH pMesh, //输出的网格数据
__in const DWORD *pAdjacency //临街数据
);
pMesh参数中顶点格式必须包含D3DFVF_NORMAL,所以需要从原先的mesh数据copy一份过来
4.渐进网格
类似于渐进纹理数据,通过边折叠技术对网格进行简化,并且这种操作时可逆转的
渐进网格从已有的网格数据中产生:
D3DXGeneratePMesh( LPD3DXMESH pMesh, CONST DWORD* pAdjacency, //邻接信息dword数组 CONST D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights, //指定相应顶点属性权值 涉及被移除的概率 CONST FLOAT *pVertexWeights, //指定顶点权值,涉及被移除的概率 DWORD MinValue, //面片简化的最少值,如果设置为1 表示尽可能的少 DWORD Options, //决定上面的参数为定点数或者面片数 LPD3DXPMESH* ppPMesh);
D3DXATTRIBUTEWEIGHTS 顶点属相权值结构,暂且使用默认值
D3DXPMesh提供的操作接口:
GetMaxFaces() //最多的面片数目上限
GetMinFaces() //最少的面片数目下限
GetMaxVertexs() //最多的顶点数目上限
GetMinVertexs() //最少的顶点数目下限
SetNumFaces() // 设置面片数目,
SetNumVertexs() //设置顶点数目
trimByFaces(newfacemin , newfacemax, --- ., --) // 重新设置顶点的最大,最小限制
trimByVetex(newfacemin , newfacemax, --- ., --) // 重新设置顶点的最大,最小限制
5外接体:可以用于检测碰撞以及可见性
//外接球
D3DXComputeBoundingSphere( CONST D3DXVECTOR3 *pFirstPosition, // pointer to first position 指向顶点的第一个位置
DWORD NumVertices, 数组中顶点数目 DWORD dwStride, // count in bytes to subsequent position vectors 每个顶点字节数 D3DXVECTOR3 *pCenter, 外界球中心 FLOAT *pRadius); 外接球半径
// 外界体
D3DXComputeBoundingBox( CONST D3DXVECTOR3 *pFirstPosition, // pointer to first position,指向顶点的第一个位置 DWORD NumVertices, //顶点数组中的顶点数目 DWORD dwStride, // count in bytes to subsequent position vectors 每个顶点的字节数 D3DXVECTOR3 *pMin, //返回的 D3DXVECTOR3 *pMax);
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: boundingvolumes.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Demonstrates how to use D3DXComputeBoundingSphere and D3DXComputeBoundingBox. // // -The spacebar key switches between rendering the mesh's bounding sphere and box. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUtility.h" #include <vector> // // Globals // IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Mesh = 0; ID3DXPMesh* pMesh = 0; std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); ID3DXMesh* SphereMesh = 0; ID3DXMesh* BoxMesh = 0; bool RenderBoundingSphere = true; // // Prototypes // bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere); bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box); // // Framework functions // bool Setup() { HRESULT hr = 0; // // Load the XFile data. // ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; hr = D3DXLoadMeshFromX( "bigship1.x", D3DXMESH_MANAGED, Device, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &Mesh); if(FAILED(hr)) { ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } // // Extract the materials, load textures. // if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(int i = 0; i < numMtrls; i++) { // the MatD3D property doesn't have an ambient value set // when its loaded, so set it now: mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; // save the ith material Mtrls.push_back( mtrls[i].MatD3D ); // check if the ith material has an associative texture if( mtrls[i].pTextureFilename != 0 ) { // yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; D3DXCreateTextureFromFile( Device, mtrls[i].pTextureFilename, &tex); // save the loaded texture Textures.push_back( tex ); } else { // no texture for the ith subset Textures.push_back( 0 ); } } } d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer // // Optimize the mesh. // hr = Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0); d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer if(FAILED(hr)) { ::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0); return false; } // // Compute Bounding Sphere and Bounding Box. // d3d::BoundingSphere boundingSphere; d3d::BoundingBox boundingBox; ComputeBoundingSphere(Mesh, &boundingSphere); ComputeBoundingBox(Mesh, &boundingBox); D3DXCreateSphere( Device, boundingSphere._radius, 20, 20, &SphereMesh, 0); D3DXCreateBox( Device, boundingBox._max.x - boundingBox._min.x, boundingBox._max.y - boundingBox._min.y, boundingBox._max.z - boundingBox._min.z, &BoxMesh, 0); // // Set texture filters. // Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // // Set Lights. // D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); Device->SetLight(0, &light); Device->LightEnable(0, true); Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); // // Set camera. // D3DXVECTOR3 pos(4.0f, 12.0f, -20.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // // Set projection matrix. // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { d3d::Release<ID3DXMesh*>(Mesh); for(int i = 0; i < Textures.size(); i++) d3d::Release<IDirect3DTexture9*>( Textures[i] ); d3d::Release<ID3DXMesh*>(SphereMesh); d3d::Release<ID3DXMesh*>(BoxMesh); } bool Display(float timeDelta) { if( Device ) { // // Update: Rotate the mesh. // static float y = 0.0f; D3DXMATRIX yRot; D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) y = 0.0f; D3DXMATRIX World = yRot; Device->SetTransform(D3DTS_WORLD, &World); // // Render // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); // draw the mesh for(int i = 0; i < Mtrls.size(); i++) { Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]); Mesh->DrawSubset(i); } // // Draw bounding volume in blue and at 10% opacity D3DMATERIAL9 blue = d3d::BLUE_MTRL; blue.Diffuse.a = 0.10f; // 10% opacity Device->SetMaterial(&blue); Device->SetTexture(0, 0); // disable texture Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); if( RenderBoundingSphere ) SphereMesh->DrawSubset(0); else BoxMesh->DrawSubset(0); Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); if( wParam == VK_SPACE ) RenderBoundingSphere = !RenderBoundingSphere; break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; } bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere) { HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)v, mesh->GetNumVertices(), D3DXGetFVFVertexSize(mesh->GetFVF()), &sphere->_center, &sphere->_radius); mesh->UnlockVertexBuffer(); if( FAILED(hr) ) return false; return true; } bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box) { HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingBox( (D3DXVECTOR3*)v, mesh->GetNumVertices(), D3DXGetFVFVertexSize(mesh->GetFVF()), &box->_min, &box->_max); mesh->UnlockVertexBuffer(); if( FAILED(hr) ) return false; return true; }