Introduction
This article describes how to create a 3D virtual world using objects exported from 3D Studio MAX (.3ds) and DirectX objects (.x).
Background
Microsoft DirectX (Direct eXtension) is a collection of application programming interfaces for handling tasks related to multimedia, especially game programming and video, on Microsoft platforms. It is a direct competitor of the OpenGL standard maintained by the Khronos Group.
Direct3D is widely used in the development of computer games for Microsoft Windows, Microsoft Xbox, and Microsoft Xbox 360. DirectX is also used among other software production industries, most notably among the engineering sector because of its ability to quickly render high-quality 3D graphics using DirectX-compatible graphics hardware.
Both the DirectX runtime and the software development kit are available free of charge, but are proprietary and closed-source software. The DirectX runtime was originally redistributed by computer game developers along with their games, but later it was included in Microsoft Windows. Game developers still often include an updated version of DirectX that prompts for installation automatically after the game installation to ensure proper program functionality.
The latest release versions of DirectX, DirectX 10, and DirectX 9Ex, are exclusive to Windows Vista. Microsoft claims the reason for this is that there have been extensive changes in the Windows graphics architecture with the introduction of the Windows Display Driver Model.
Using the Code
All DirectX function calls are encapsulated in the class D3DX
. This class is the main class of this project. This class is commented in code.
The class AbstractShape
is the the base class for all objects that are loaded in this program. All of this class functions are commented in code. From this class are derived:
- class
Shape3DSBlob
-> this class is used to load objects with a .3ds extension.
- class
ShapeXBlob
-> this class is used to load objects with a .x extension.
Interface of the AbstractShape Class
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 )
}
A brief description of how to use the article or code can be found in the comments that follow each function declaration in code.
This is the function that draws each object. The DoDraw
function is declared as a virtual function in the class AbstractShape
and is implemented in each derived class.
void DoDraw( LPDIRECT3DDEVICE9 &p, DrawingEvent e )
{
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 );
}
}
}
The function that rotates objects:
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;
}
}
}
The function that plays a saved record (this record saves only the camera position and the view orientation in a list, and at playback, will have all the points where the camera has been through):
bool D3DX::DXPlay( tPositionVector* posVec )
{
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;
}
The function that create the platform buffer. This function will create a buffer with a default platform, default vertex:
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);
return;
}
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();
}
There are a lot of functions that I can comment, but almost all of them have a comment in code.
Points of Interest
This program can be used to load .3ds and .x objects and create a virtual world.
Lights
Fog
3D Earth
History
In late 1994, Microsoft was just on the verge of releasing its next Operating System, Windows 95. The main factor that would determine the value consumers would place on their new Operating System very much rested on what programs would be able to run on it. Three Microsoft employees - Craig Eisler, Alex St. John, and Eric Engstrom - were concerned, because programmers tended to see Microsoft's previous Operating System, DOS, as a better platform for game programming, meaning a few games would be developed for Windows 95 and the Operating System would not be as much of a success.
DOS allowed direct access to video cards, keyboards and mice, sound devices, and all other parts of the system, while Windows 95, with its protected memory model, restricted access to all of these, working on a much more standardized model. Microsoft needed a way that would let programmers get what they wanted, and they needed it quickly; the Operating System was only months away from being released. Eisler, St. John, and Engstrom conspired together to fix this problem, with a solution that they eventually named DirectX.
The first version of DirectX released was shipped September of 1995 as the Windows Games SDK. It was the Win32 replacement for the DCI and WinG APIs for Windows 3.1. A development team at ATI brought fundamental game graphics technology to the attention of Microsoft. The development of DirectX was led by the team of Eisler (development lead), St. John, and Engstrom (program manager). Simply put, it allowed all versions of Microsoft Windows, starting with Windows 95, to incorporate high-performance multimedia. Eisler wrote about the frenzy to build DirectX 1 through 5 in his blog.
Prior to DirectX's existence, Microsoft had already included OpenGL on their Windows NT platform. At the time, OpenGL required "high-end" hardware and was limited to engineering and CAD uses. Direct3D (introduced by Eisler, Engstrom, and St. John as an alternative to SGI's OpenGL) was intended to be a lightweight partner to back the then slower OpenGL for game use. As the power of graphics cards and the computers running them grew, OpenGL became the de-facto standard and a mainstream product. At that point, a "battle" began between supporters of the cross-platform OpenGL and the Windows-only Direct3D, which many argued was another example of Microsoft's embrace, extend, and extinguish business tactic (see Fahrenheit or Direct3D vs. OpenGL). Nevertheless, the other APIs of DirectX are often combined with OpenGL in computer games because OpenGL does not include all of DirectX's functionality (such as sound or joystick support). However, the combination of OpenGL and OpenAL for this purpose is becoming increasingly popular.
In a console-specific version, DirectX was used as a basis for Microsoft's Xbox and Xbox 360 console API. The API was developed jointly between Microsoft and NVIDIA, who developed the custom graphics hardware used by the original Xbox. The Xbox API is similar to DirectX version 8.1, but is non-updateable like other console technologies. The Xbox was code named DirectXbox, but this was shortened to Xbox for its commercial name.
In 2002, Microsoft released DirectX 9 with support for the use of much longer shader programs than before with pixel and vertex shader version 2.0. Microsoft has continued to update the DirectX suite since then, introducing shader model 3.0 in DirectX 9.0c, released in August 2004.
As of April 2005, DirectShow was removed from DirectX and moved to the Microsoft Platform SDK instead. DirectX is, however, still required to build the DirectShow samples.
Note
This program is not ready, it has functions that are not fully completed. I'm still working on this project. For example, the functionality of the .dx file is not ready. And with object rotation, I still have some minor problems.