 |
|
| Loading DirectX Meshes |
In this tutorial I will demonstrate how to do DirectX Mesh loading from Microsofts .x format in Direct3d this will include displaying and rotating the mesh.
First I'll show you the code from the second tutorial written by me with the required changes to allow for the creation, rendering and rotating of a mesh file called tiger.x with textures stored in the same directory.
#include <windows.h>
#include <d3d8.h>
#include <d3dx8.h>
HWND hWnd;
LPDIRECT3D8 pD3D;
LPDIRECT3DDEVICE8 pDevice;
LPD3DXMESH pMesh = NULL; // Our mesh object in sysmem
D3DMATERIAL8* pMeshMaterials = NULL; // Materials for our mesh
LPDIRECT3DTEXTURE8* pMeshTextures = NULL; // Textures for our mesh
DWORD dwNumMaterials = 0L; // Number of mesh materials
HRESULT LoadD3DMesh(); //Reference to the function to load an D3D Mesh
LRESULT CALLBACK WndProc( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam){
switch(message){
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
bool CreateSimpWindow(int width, int height){
// Create A Window Class Structure
WNDCLASSEX wc;
wc.cbClsExtra = 0;
wc.cbSize = sizeof(wc);
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "VK3D";
wc.lpszMenuName = NULL;
wc.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;
// Register Window Class
RegisterClassEx(&wc);
// Create Window
hWnd = CreateWindowEx(0,
"VK3D", "VK3D Direct3D Tutorial 3",
WS_OVERLAPPEDWINDOW|WS_VISIBLE, 100,100,width,height,
NULL,NULL,wc.hInstance,0);
return true;
}
bool InitD3D(){
if((pD3D = Direct3DCreate8(D3D_SDK_VERSION))==NULL){
return false;
}
D3DDISPLAYMODE d3ddm;
pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
if(FAILED(pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,
&pDevice))){
return false;
}
pDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
pDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );
LoadD3DMesh();
return true;
}
HRESULT LoadD3DMesh()
{
LPD3DXBUFFER pD3DXMtrlBuffer;
// Load the mesh from the specified file
if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM,
pDevice, NULL,
&pD3DXMtrlBuffer, &dwNumMaterials,
&pMesh ) ) )
{
return E_FAIL;
}
// We need to extract the material properties and texture names from the
// pD3DXMtrlBuffer
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
for( DWORD i=0; i<dwNumMaterials; i++ )
{
// Copy the material
pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
// Set the ambient color for the material (D3DX does not do this)
pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
// Create the texture
if( FAILED( D3DXCreateTextureFromFile( pDevice,
d3dxMaterials[i].pTextureFilename,
&pMeshTextures[i] ) ) )
{
pMeshTextures[i] = NULL;
}
}
// Done with the material buffer
pD3DXMtrlBuffer->Release();
return S_OK;
}
void RenderD3DScene(){
pDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
pDevice->BeginScene();
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f,-10.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
pDevice->SetTransform( D3DTS_VIEW, &matView );
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
pDevice->SetTransform( D3DTS_PROJECTION, &matProj );
D3DXMATRIX matWorld;
D3DXMatrixRotationY( &matWorld, timeGetTime()/1000.0f );
pDevice->SetTransform( D3DTS_WORLD, &matWorld );
for( DWORD i=0; i<dwNumMaterials; i++ )
{
// Set the material and texture for this subset
pDevice->SetMaterial( &pMeshMaterials[i] );
pDevice->SetTexture( 0, pMeshTextures[i] );
// Draw the mesh subset
pMesh->DrawSubset( i );
}
pDevice->EndScene();
pDevice->Present(NULL,NULL,NULL,NULL);
}
void MessageLoop(){
MSG msg;
while(true){
RenderD3DScene();
if(PeekMessage(&msg,hWnd,0,0,PM_REMOVE)){
if(msg.message==WM_QUIT)return;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
INT WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , INT ){
if(!CreateSimpWindow(400, 400))return 1;
if(!InitD3D())return 2;
MessageLoop();
return 0;
} |
The first difference you should note is the additional global variables
LPD3DXMESH pMesh = NULL; // Our mesh object in sysmem
D3DMATERIAL8* pMeshMaterials = NULL; // Materials for our mesh
LPDIRECT3DTEXTURE8* pMeshTextures = NULL; // Textures for our mesh
DWORD dwNumMaterials = 0L; // Number of mesh materials
HRESULT LoadD3DMesh(); //Reference to the function to load an D3D Mesh |
Which are used to store the mesh and it's materials. We also declared the function
LoadD3DMesh() which we will use to load the mesh from the disk.
The changes to InitD3D are in the present parameters and the RenderState.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; |
The changes to the present parameters are to enable the stencil buffer with is required with Zbuffering to decide what to clear otherwise it will never clear the screen.
pDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
pDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); |
The render state changes are the enable the Zbuffer which is required for any true 3d processing and to set the ambient light so we can see everything.
We then run the LoadD3DMesh instead of creating the Vertex Buffer.
The LoadD3Dmesh function is the next difference. It will be explained in sequence.
| LPD3DXBUFFER pD3DXMtrlBuffer; |
We declare a Buffer to hold the Materials temporarily
// Load the mesh from the specified file
if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM,
pDevice, NULL,
&pD3DXMtrlBuffer, &dwNumMaterials,
&pMesh ) ) ){
return E_FAIL;
} |
We load the mesh from "Tiger.x", into System Memory, storing the Materials in the Temporary buffer, the number of materials in the appropriate variable and the mesh in stored in pMesh.
// We need to extract the material properties and texture names from the
// pD3DXMtrlBuffer
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials]; |
We prepare for extraction of the textures and materials by first creating the arrays to store them.
for( DWORD i=0; i<dwNumMaterials; i++ )
{
// Copy the material
pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
// Set the ambient color for the material (D3DX does not do this)
pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
// Create the texture
if( FAILED( D3DXCreateTextureFromFile( pDevice, d3dxMaterials[i].pTextureFilename, &pMeshTextures[i] ) ) )
{
pMeshTextures[i] = NULL;
}
} |
We create the materials by loading the textures from files, copying the loaded values and creating the ambient color value, which DirectX doesn't store.
// Done with the material buffer
pD3DXMtrlBuffer->Release(); |
We then delete the temporary buffer and exit the function.
pDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); |
One of the first differences you'll note in the Render function is that the clear function now clears both the Target and the Zbuffer this is required when using z-buffering with stencil buffers.
for( DWORD i=0; i<dwNumMaterials; i++ )
{
// Set the material and texture for this subset
pDevice->SetMaterial( &pMeshMaterials[i] );
pDevice->SetTexture( 0, pMeshTextures[i] );
// Draw the mesh subset
pMesh->DrawSubset( i );
} |
The only other difference is that for the mesh we have to load it by subsets where each subset has the same material and texture. We first setup the current Material and Texture to be the correct one and then use DrawSubset to render that subset.
Included in the .zip file are the example Tiger.x and Tiger.bmp that are required to render the mesh.
If you have any comment or need any information email me by clicking my name below or contact me at the yahoo group real-game-programming.
Download Source File |
Posted on : 31 May 2004 Darren Foster |
|
|