如何创建 DirectX 3D 虚拟世界






3.90/5 (10投票s)
一个允许用户创建 3D 世界的项目。
- 下载 d3d9.zip - 665 KB
- 下载 d3dx9d_26.zip - 1.37 MB
- 下载 d3dx9d_27.zip - 1.39 MB
- 下载 d3dx9d_30.zip - 1.44 MB
- 下载 d3dx9_26.zip - 1 MB
- 下载 d3dx9_27.zip - 1.01 MB
- 下载 d3dx9_31.zip - 1.06 MB
- 下载 d3dx9_32.zip - 1.48 MB
- 下载源代码 - 398 KB
- 下载演示 - 3.16 MB
引言
本文介绍了如何使用从 3D Studio MAX 导出的对象(.3ds)和 DirectX 对象(.x)来创建 3D 虚拟世界。
背景
Microsoft DirectX(Direct eXtension,Direct 扩展)是一组用于处理与 多媒体 相关的任务的 应用程序编程接口(API),尤其是在 微软 平台上进行 游戏编程 和视频处理。它是 Khronos Group 维护的 OpenGL 标准的直接竞争对手。
Direct3D 被广泛用于 Microsoft Windows、Microsoft Xbox 和 Microsoft Xbox 360 的 电脑游戏 开发中。DirectX 也被用于其他软件生产行业,尤其是在工程领域,因为它能够使用支持 DirectX 的 显卡 快速 渲染 高质量的 3D 图形。
DirectX 运行时 和 软件开发工具包 都可以免费获得,但它们是专有和闭源软件。DirectX 运行时最初是由 游戏开发者 与他们的游戏一起重新分发的,但后来它被包含在 Microsoft Windows 中。游戏开发者仍然经常包含一个更新版本的 DirectX,该版本会在游戏安装后自动提示安装,以确保程序的正常运行。
DirectX 的最新发布版本,DirectX 10 和 DirectX 9Ex,仅限于 Windows Vista。微软声称原因是 Windows 图形架构在引入 Windows 显示驱动程序模型 后进行了大量的修改。
Using the Code
所有 DirectX 函数调用都封装在 D3DX
类中。这个类是本项目的主要类。这个类在代码中有注释。
AbstractShape
类是此程序中加载的所有对象的基类。这个类的所有函数都在代码中有注释。从这个类派生出
- 类
Shape3DSBlob
-> 这个类用于加载具有 .3ds 扩展名的对象。 - 类
ShapeXBlob
-> 这个类用于加载具有 .x 扩展名的对象。
AbstractShape 类接口
class AbstractShape : public CObject
{
DECLARE_SERIAL( AbstractShape );
protected:
AbstractShape();
public:
virtual ~AbstractShape();
virtual void Serialize( CArchive& archive )
virtual void DoDraw( LPDIRECT3DDEVICE9 &p, DrawingEvent e = eFromWinMessage )
virtual void Release( );
virtual void SetNewTexture( LPDIRECT3DTEXTURE9 pTexture )
virtual void SaveObject( const CString& fName )
}
关于如何使用本文或代码的简要说明可以在代码中每个函数声明后的注释中找到。
这是绘制每个对象的函数。DoDraw
函数在 AbstractShape
类中被声明为一个虚函数,并在每个派生类中实现。
void DoDraw( LPDIRECT3DDEVICE9 &p, DrawingEvent e /* = eFromWinMessage */)
{
if( FALSE == m_ShowObject )
return;
if( m_pMeshObj )
{
if( m_pTranslationMatrix )
{
D3DXMATRIX Mat;
D3DXMatrixTranslation( m_pTranslationMatrix, m_TranslationX,
m_TranslationY, m_TranslationZ );
D3DXMatrixScaling( &Mat , m_ZoomFactor, m_ZoomFactor, m_ZoomFactor );
D3DXMatrixMultiply( m_pTranslationMatrix, &Mat, m_pTranslationMatrix );
if( e == eFromTimer )
{
if( m_Animation.m_AnimationFlags & AnimationStruct::eXRotation )
{
m_Animation.m_Xrot += m_Animation.m_XRorationSpeed + m_rotX;
if( m_Animation.m_Xrot > 6.2831854820251465)
m_Animation.m_Xrot -= 6.2831854820251465;
}
if( m_Animation.m_AnimationFlags & AnimationStruct::eYRotation )
{
m_Animation.m_Yrot += m_Animation.m_YRorationSpeed + m_rotY;
if( m_Animation.m_Yrot > 6.2831854820251465)
m_Animation.m_Yrot -= 6.2831854820251465;
}
if( m_Animation.m_AnimationFlags & AnimationStruct::eZRotation )
{
m_Animation.m_Zrot += m_Animation.m_ZRorationSpeed + m_rotZ;
if( m_Animation.m_Zrot > 6.2831854820251465)
m_Animation.m_Zrot -= 6.2831854820251465;
}
D3DXMatrixRotationYawPitchRoll( &Mat, m_Animation.m_Xrot,
m_Animation.m_Yrot, m_Animation.m_Zrot );
}
else if ( m_Animation.m_AnimationFlags )
D3DXMatrixRotationYawPitchRoll( &Mat, m_rotX + m_Animation.m_Xrot,
m_rotY + m_Animation.m_Yrot,
m_rotZ + m_Animation.m_Zrot );
else
D3DXMatrixRotationYawPitchRoll( &Mat, m_rotX, m_rotY, m_rotZ );
D3DXMatrixMultiply( m_pTranslationMatrix, &Mat, m_pTranslationMatrix );
p->SetTransform( D3DTS_WORLD, m_pTranslationMatrix );
}
for( DWORD i = 0; i < m_dwMeshSize; ++i )
{
p->SetMaterial( &m_pMeshMaterials[i] );
p->SetTexture( 0, m_pTexture[i] );
m_pMeshObj->DrawSubset( i );
}
}
}
旋转对象的函数
void AbstractShape::RotateObject( RotationParam eParam, float angle )
{
switch ( eParam )
{
case eRotateX:
{
m_rotX += angle;
if( m_rotX > 6.2831854820251465)
m_rotX -= 6.2831854820251465;
break;
}
case eRotateY:
{
m_rotY += angle;
if( m_rotY > 6.2831854820251465)
m_rotY -= 6.2831854820251465;
break;
}
case eRotateZ:
{
m_rotZ += angle;
if( m_rotZ > 6.2831854820251465)
m_rotZ -= 6.2831854820251465;
break;
}
default:
{
ASSERT(0);
return;
}
}
}
播放已保存记录的函数(此记录仅保存相机位置和视口方向在一个列表中,并在播放时,将包含相机经过的所有点)
bool D3DX::DXPlay( tPositionVector* posVec /* = NULL*/ )
{
try
{
if( posVec )
{
Lvec = posVec;
leng_ = posVec->size();
curent_pos = 0;
m_DXflags |= ePlayback;
}
if( Lvec )
{
m_Camera = *(*Lvec)[curent_pos];
if( DXRender() )
curent_pos++;
if( leng_ == curent_pos )
{
Lvec = NULL;
leng_ = 0;
curent_pos = 0;
m_DXflags &= ~ePlayback;
return false;
}
}
}
catch ( ... )
{
if( posVec )
m_Log.WriteLogLine("Exception on D3DX::DXPlay(
tPositionVector* posVec ), posVec != NULL \n");
else
m_Log.WriteLogLine("Exception on D3DX::DXPlay(
tPositionVector* posVec ), posVec == NULL \n");
ASSERT(0);
m_DXflags &= ~ePlayback;
return false;
}
return true;
}
创建平台缓冲区的函数。此函数将创建一个具有默认平台、默认顶点的缓冲区
void D3DX::CreateWorldBuffer()
{
if( !m_WP.m_Floor.GetVertex() || !m_WP.m_Walls.GetVertex() )
{
m_Log.WriteLogLine("Error on CreateWorldBuffer, no floor and wall vertex buffer\n");
return;
}
if( !m_pD3DDevice || !m_pD3D )
{
m_Log.WriteLogLine("CreateWorldBuffer function call is from "
"serialize and the mainFrm is not created\n");
//
ASSERT(0);
//in case the function call is from serialize and the mainFrm is not created
return;
}
//vertex vector for wall && floor
unsigned char *pVertices = NULL;
m_pD3DDevice->CreateVertexBuffer(
m_WP.m_Floor.GetVertexSize()*sizeof(DXVertex)+
sizeof(DXVertex)*m_WP.m_Walls.GetVertexSize()
, 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT,
&m_pTextureVertexBuffer_FW, NULL );
m_pTextureVertexBuffer_FW->Lock( 0,
m_WP.m_Floor.GetVertexSize()*sizeof(DXVertex)+
sizeof(DXVertex)*m_WP.m_Walls.GetVertexSize(),
(void**)&pVertices, 0);
memcpy( pVertices, m_WP.m_Floor.GetVertex(),
sizeof(DXVertex)*m_WP.m_Floor.GetVertexSize() );
memcpy( (void*) (pVertices+sizeof(DXVertex)*m_WP.m_Floor.GetVertexSize()),
m_WP.m_Walls.GetVertex( ),
sizeof(DXVertex)*m_WP.m_Walls.GetVertexSize() );
m_pTextureVertexBuffer_FW->Unlock();
}
有很多函数我可以注释,但几乎所有函数都有代码注释。
关注点
此程序可用于加载 .3ds 和 .x 对象并创建虚拟世界。
历史
1994 年底,微软正处于发布其下一代 操作系统 Windows 95 的边缘。决定消费者对其新操作系统的价值的主要因素很大程度上取决于能够运行哪些程序。三位微软员工——Craig Eisler、Alex St. John 和 Eric Engstrom——感到担忧,因为 程序员 倾向于认为微软之前的操作系统 DOS 是一个更好的游戏编程平台,这意味着只有少数游戏会为 Windows 95 开发,而该操作系统也不会那么成功。
DOS 允许直接访问显卡、键盘 和 鼠标、声卡以及系统的所有其他部分,而 Windows 95 及其保护内存模型限制了对所有这些的访问,而是基于一个更加标准化的模型。微软需要一种方法让程序员得到他们想要的,并且他们需要快速;操作系统即将发布。Eisler、St. John 和 Engstrom 密谋解决这个问题,并最终将其解决方案命名为 DirectX。
DirectX 的第一个版本于 1995 年 9 月作为 Windows Games SDK 发布。它是 Win32 对 Windows 3.1 的 DCI 和 WinG API 的替代。ATI 的一个开发团队引起了微软对基本游戏图形技术的关注。DirectX 的开发由 Eisler(开发负责人)、St. John 和 Engstrom(程序经理)组成的团队领导。简单来说,它允许所有版本的 Microsoft Windows(从 Windows 95 开始)集成高性能多媒体。Eisler 在他的博客中谈到了 构建 DirectX 1 至 5 的狂热。
在 DirectX 存在之前,微软已经在其 Windows NT 平台上包含了 OpenGL。当时,OpenGL 需要“高端”硬件,并且仅限于 工程 和 CAD 用途。Direct3D(由 Eisler、Engstrom 和 St. John 作为 SGI OpenGL 的替代品推出)旨在成为支持当时较慢的 OpenGL 用于游戏用途的轻量级伙伴。随着 显卡 和运行它们的计算机性能的提高,OpenGL 成为了事实上的标准和主流产品。那时,一场“战斗”在跨平台 OpenGL 的支持者和仅限 Windows 的 Direct3D 之间展开,许多人认为这是微软 拥抱、扩展和熄灭 商业策略的又一个例子(请参阅 Fahrenheit 或 Direct3D vs. OpenGL)。尽管如此,DirectX 的其他 API 经常与 OpenGL 一起用于 电脑游戏 中,因为 OpenGL 不包含 DirectX 的所有功能(例如声音或操纵杆支持)。然而,OpenGL 和 OpenAL 的组合在此目的上的使用正变得越来越流行。
在控制台专用版本中,DirectX 被用作微软 Xbox 和 Xbox 360 游戏机 API 的基础。该 API 由微软和 NVIDIA 联合开发,NVIDIA 开发了初代 Xbox 使用的定制图形硬件。Xbox API 与 DirectX 8.1 版本相似,但像其他游戏机技术一样不可更新。Xbox 的代号是 DirectXbox,但为了商业名称缩短为 Xbox。
2002 年,微软发布了 DirectX 9,支持使用比以往更长的着色器程序,并支持像素和顶点着色器 2.0 版本。此后,微软继续更新 DirectX 套件,在 2004 年 8 月发布的 DirectX 9.0c 中引入了着色器模型 3.0。
截至 2005 年 4 月,DirectShow 已从 DirectX 中移除,并转移到 Microsoft Platform SDK。但是,DirectX 仍然是构建 DirectShow 示例所必需的。
注意
这个程序还没有准备好,它有一些未完成的功能。我仍在进行这个项目。例如,.dx 文件的功能尚未完成。对于对象旋转,我仍然有一些小问题。