direct3d 3d模型模板

本文介绍了一个使用Direct3D9实现的简单飞机模型渲染应用程序。该程序加载了一个名为airplane.x的3D模型,并通过鼠标操作实现了模型的旋转和平移。此外,程序还展示了如何设置光照、观察矩阵和投影矩阵,以及如何使用Direct3D9进行基本的3D渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


#pragma once
#include "stdafx.h"
#include "template.h"
//-----------------------------------------------------------------------------
// 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9                g_pD3D       = NULL; //Direct3D对象
LPDIRECT3DDEVICE9          g_pd3dDevice = NULL; //Direct3D设备对象


LPD3DXMESH              g_pMesh          = NULL;  //网格模型对象
D3DMATERIAL9*           g_pMeshMaterials = NULL;  //网格模型材质
LPDIRECT3DTEXTURE9*     g_pMeshTextures  = NULL;  //网格模型纹理
DWORD                   g_dwNumMaterials = 0L;    //网格模型材质数量
//-----------------------------------------------------------------------------
// 显示帧率
//-----------------------------------------------------------------------------
ID3DXFont* Font   = 0;
DWORD FrameCnt    = 0;
float TimeElapsed = 0;
float timeDelta   =0;
float FPS         = 0;
TCHAR TFPSString[100];
//-----------------------------------------------------------------------------
// Desc: 顶点结构
//-----------------------------------------------------------------------------

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)  //顶点格式

float g_fSpinX = 0.0f;
float g_fSpinY = 0.0f;
float g_fDisZ = 0.0f;


//-----------------------------------------------------------------------------
// Desc: 从绝对路径中提取纹理文件名
//-----------------------------------------------------------------------------
void RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName)
{
	//先将fullPath的类型变换为LPWSTR
	WCHAR wszBuf[MAX_PATH];
	MultiByteToWideChar( CP_ACP, 0, fullPath, -1, wszBuf, MAX_PATH );
	wszBuf[MAX_PATH-1] = L'\0';

	WCHAR* wszFullPath = wszBuf;

	//从绝对路径中提取文件名
	LPWSTR pch=wcsrchr(wszFullPath,'\\');
	if (pch)
		lstrcpy(fileName, ++pch);
	else
		lstrcpy(fileName, wszFullPath);
}
HRESULT Load3Dobject()
{
	LPD3DXBUFFER pD3DXMtrlBuffer;  //存储网格模型材质的缓冲区对象

	//从磁盘文件加载网格模型
	if( FAILED( D3DXLoadMeshFromX( L"airplane.x", D3DXMESH_MANAGED, 
		g_pd3dDevice, NULL, 
		&pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, 
		&g_pMesh ) ) )
	{
		MessageBox(NULL, L"Could not find airplane.x", L"Mesh", MB_OK);
		return E_FAIL;
	}

	//从网格模型中提取材质属性和纹理文件名 
	D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
	g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];

	if( g_pMeshMaterials == NULL )
		return E_OUTOFMEMORY;

	g_pMeshTextures  = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
	if( g_pMeshTextures == NULL )
		return E_OUTOFMEMORY;

	//逐块提取网格模型材质属性和纹理文件名
	for( DWORD i=0; i<g_dwNumMaterials; i++ )
	{
		//材料属性
		g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
		//设置模型材料的环境光反射系数, 因为模型材料本身没有设置环境光反射系数
		g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse;

		g_pMeshTextures[i] = NULL;
		if( d3dxMaterials[i].pTextureFilename != NULL && 
			strlen(d3dxMaterials[i].pTextureFilename) > 0 )
		{
			//获取纹理文件名
			WCHAR filename[256];
			RemovePathFromFileName(d3dxMaterials[i].pTextureFilename, filename);

			//创建纹理
			if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, filename, 
				&g_pMeshTextures[i] ) ) )
			{
				MessageBox(NULL, L"Could not find texture file", L"Mesh", MB_OK);
			}
		}
	}

	//释放在加载模型文件时创建的保存模型材质和纹理数据的缓冲区对象
	pD3DXMtrlBuffer->Release();  
}
HRESULT InitGeometry(HWND hWnd )
{
	Load3Dobject();

	return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 设置观察矩阵和投影矩阵
//-----------------------------------------------------------------------------
VOID SetWorldMatrix()
{
	static long curTime=0;
	static float elapsetime=0;
	elapsetime = (timeGetTime()-curTime)/1000.0f;
	curTime = timeGetTime();

	D3DXMATRIX matWorld;
	D3DXMATRIX matRotation;
	D3DXMATRIX matTranslation;
	D3DXMatrixRotationYawPitchRoll( &matRotation, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f );
	D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, g_fDisZ );
	/*D3DXMatrixRotationYawPitchRoll( &matRotation, 0.0f, 0.0f, 0.0f );
	D3DXMatrixTranslation( &matTranslation, -g_fSpinX*0.01, g_fSpinY*0.01, g_fDisZ );*/
	matWorld = matRotation * matTranslation;
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );


}
VOID SetupViewandProjMatrices()
{
	//创建并设置观察矩阵
	D3DXVECTOR3 vEyePt( 0.0f, 0.0f, -5);
	D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
	D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
	D3DXMATRIXA16 matView;
	D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
	g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

	//创建并设置投影矩阵
	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2, 1.0f, 0.1f, 100.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


void SetLight()
{

}
bool SetFont()
{
	D3DXFONT_DESC df;
	ZeroMemory(&df, sizeof(D3DXFONT_DESC));
	df.Height         = 12;    // in logical units
	df.Width          = 12;    // in logical units 
	df.Weight         = 500;   // boldness, range 0(light) - 1000(bold)
	df.Italic         = false;      
	df.CharSet        = GB2312_CHARSET;
	df.OutputPrecision   = 0;                    
	df.Quality        = 0;           
	df.PitchAndFamily = 0;           
	wcscpy(df.FaceName, L"Times New Roman"); // font style

	if(FAILED(D3DXCreateFontIndirect(g_pd3dDevice, &df, &Font)))
	{
		::MessageBox(0, L"D3DXCreateFontIndirect() - FAILED", 0, 0);
		::PostQuitMessage(0);
	}
	return true;
}
//-----------------------------------------------------------------------------
// Desc: 初始化Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
	if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return E_FAIL;

	D3DDISPLAYMODE d3ddm;

	if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
	{
		// TO DO: Respond to failure of GetAdapterDisplayMode
		return E_FAIL;
	}

	HRESULT hr;

	if( FAILED( hr = g_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
		d3ddm.Format, D3DUSAGE_DEPTHSTENCIL,
		D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
	{
		if( hr == D3DERR_NOTAVAILABLE )
			// POTENTIAL PROBLEM: We need at least a 16-bit z-buffer!
			return E_FAIL;
	}

	//
	// Do we support hardware vertex processing? if so, use it. 
	// If not, downgrade to software.
	//

	D3DCAPS9 d3dCaps;

	if( FAILED( g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, 
		D3DDEVTYPE_HAL, &d3dCaps ) ) )
	{
		// TO DO: Respond to failure of GetDeviceCaps
		return E_FAIL;
	}

	DWORD dwBehaviorFlags = 0;

	if( d3dCaps.VertexProcessingCaps != 0 )
		dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
	else
		dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	//
	// Everything checks out - create a simple, windowed device.
	//

	D3DPRESENT_PARAMETERS d3dpp;
	memset(&d3dpp, 0, sizeof(d3dpp));

	d3dpp.BackBufferFormat       = d3ddm.Format;
	d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed               = TRUE;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;

	if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		dwBehaviorFlags, &d3dpp, &g_pd3dDevice ) ) )
	{
		// TO DO: Respond to failure of CreateDevice
		return E_FAIL;
	}

	//禁用照明效果
	//g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); 

	//设置剔出模式为不剔出任何面
	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE,  D3DCULL_NONE);

	//设置环境光
	g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

	//设置变换矩阵
	SetupViewandProjMatrices();


	SetLight();
	SetFont();
	return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 释放创建对象
//-----------------------------------------------------------------------------
VOID Cleanup()
{
	//释放网格模型材质
	if( g_pMeshMaterials != NULL ) 
		delete[] g_pMeshMaterials;

	//释放网格模型纹理
	if( g_pMeshTextures )
	{
		for( DWORD i = 0; i < g_dwNumMaterials; i++ )
		{
			if( g_pMeshTextures[i] )
				g_pMeshTextures[i]->Release();
		}
		delete[] g_pMeshTextures;
	}

	//释放网格模型对象
	if( g_pMesh != NULL )
		g_pMesh->Release();

	

	//释放Direct3D设备对象
	if( g_pd3dDevice != NULL) 
		g_pd3dDevice->Release();

	//释放Direct3D对象
	if( g_pD3D != NULL)
		g_pD3D->Release();
}



//-----------------------------------------------------------------------------
// Desc: 渲染图形
//-----------------------------------------------------------------------------
VOID Render(float timeDelta)
{
	FrameCnt++;

	TimeElapsed += timeDelta;

	if(TimeElapsed >= 1.0f)
	{
		char FPSString[100];
		FPS = (float)FrameCnt / TimeElapsed;
		D3DCAPS9 d3dCaps;
		g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, &d3dCaps );
		if( d3dCaps.VertexProcessingCaps != 0 )
			sprintf(FPSString, "D3D9 %.2ffps HAL(hw vp)", FPS);
		else
			sprintf(FPSString, "D3D9 %.2ffps REF(simulate hw vp) ", FPS);

		int nLen = strlen(FPSString) + 1;  
		FPSString[nLen] = '\0'; // mark end of string
		int nwLen = MultiByteToWideChar(CP_ACP, 0, FPSString, nLen, NULL, 0);   
		MultiByteToWideChar(CP_ACP, 0, FPSString, nLen, TFPSString, nwLen); 
		TimeElapsed = 0.0f;
		FrameCnt    = 0;
	}
	//清空后台缓冲区
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(45, 50, 170), 1.0f, 0 );

	
	//开始在后台缓冲区绘制图形
	if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
	{
		RECT rect = {0, 0, 600, 500};
		Font->DrawText(0,TFPSString,-1,&rect,DT_TOP | DT_LEFT, 0xffffff00);

		
		SetWorldMatrix();

		//逐块渲染网格模型
		for( DWORD i=0; i<g_dwNumMaterials; i++ )
		{
			//设置材料和纹理
			g_pd3dDevice->SetMaterial( &g_pMeshMaterials[i] );
			g_pd3dDevice->SetTexture( 0, g_pMeshTextures[i] );

			//渲染模型
			g_pMesh->DrawSubset( i );
		}

		
		g_pd3dDevice->EndScene();
	}
	//将在后台缓冲区绘制的图形提交到前台缓冲区显示
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

//-----------------------------------------------------------------------------
// Desc: 消息处理
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	static POINT ptLastMousePosit;
	static POINT ptCurrentMousePosit;
	static bool bMousing;


	switch( msg )
	{
	case WM_LBUTTONDOWN:
		{
			ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam);
			ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam);
			bMousing = true;
		}
		break;

	case WM_LBUTTONUP:
		{
			bMousing = false;
		}
		break;
	
	case WM_MOUSEMOVE:
		{
			ptCurrentMousePosit.x = LOWORD (lParam);
			ptCurrentMousePosit.y = HIWORD (lParam);

			if( bMousing )
			{
				g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);
				g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);
			}

			ptLastMousePosit.x = ptCurrentMousePosit.x;
			ptLastMousePosit.y = ptCurrentMousePosit.y;
		}
		break;
	
	case WM_MOUSEWHEEL:
		{
			g_fDisZ +=(short)HIWORD (wParam)*0.01;
		}
		break;
	case WM_DESTROY:
		Cleanup();
		PostQuitMessage( 0 );
		return 0;
	case WM_PAINT:
		Render(timeDelta);
		ValidateRect( hWnd, NULL );
		return 0;
	}

	return DefWindowProc( hWnd, msg, wParam, lParam );
}


//-----------------------------------------------------------------------------
// Desc: 程序入口
//-----------------------------------------------------------------------------
int APIENTRY _tWinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow)
{
	WNDCLASSEX winClass;
	MSG        uMsg;

	memset(&uMsg,0,sizeof(uMsg));

	winClass.lpszClassName = L"MY_WINDOWS_CLASS";
	winClass.cbSize        = sizeof(WNDCLASSEX);
	winClass.style         = CS_HREDRAW | CS_VREDRAW;
	winClass.lpfnWndProc   = MsgProc;
	winClass.hInstance     = hInstance;
	winClass.hIcon	       = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
	winClass.hIconSm	   = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
	winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	winClass.lpszMenuName  = NULL;
	winClass.cbClsExtra    = 0;
	winClass.cbWndExtra    = 0;

	if( !RegisterClassEx(&winClass) )
		return E_FAIL;

	HWND hWnd = CreateWindowEx( NULL, L"MY_WINDOWS_CLASS", 
		L"Direct3D (DX9) - Initialization",
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 460, NULL, NULL, hInstance, NULL );

	//初始化Direct3D
	if( SUCCEEDED( InitD3D( hWnd ) ) )
	{ 
		if( SUCCEEDED(InitGeometry(hWnd)))
		{
			//显示主窗口
			ShowWindow( hWnd, SW_SHOWDEFAULT );
			UpdateWindow( hWnd );

			static float lastTime = (float)timeGetTime(); 
			//进入消息循环
			MSG msg;
			ZeroMemory( &msg, sizeof(msg) );
			while( msg.message!=WM_QUIT )
			{
				if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
				{
					TranslateMessage( &msg );
					DispatchMessage( &msg );
				}
				else
				{
					float currTime  = (float)timeGetTime();
					float timeDelta = (currTime - lastTime)*0.001f;
					Render(timeDelta);  //渲染图形
					lastTime = currTime;
				}
			}
		}
	}

	UnregisterClass( L"ClassName", hInstance);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值