Click here to Skip to main content
Click here to Skip to main content

How to create a DirectX 3D virtual world

By , 17 Jul 2007
Rate this:
Please Sign up or sign in to vote.

Screenshot - DXPrintScreen.jpg

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 /* = 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 );
        }
    }
}

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 /* = 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;
}

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);
        //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();
}

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

Screenshot - lights.jpg

Fog

Screenshot - fog.jpg

Screenshot - fogRed.jpg

3D Earth

Screenshot - earth.jpg

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Adrian Brutus
Web Developer
Romania Romania
No Biography provided

Comments and Discussions

 
GeneralWow! PinmemberBoyDeveloper22-Aug-10 14:15 
QuestionI have problem,who can help me,please,Thank you Pinmembershfnoopy27-Aug-07 19:38 
AnswerRe: I have problem,who can help me,please,Thank you PinmemberAdrian Brutus27-Aug-07 21:07 
QuestionNo error but no response Pinmembershfnoopy28-Aug-07 17:24 
AnswerRe: No error but no response PinmemberAdrian Brutus29-Aug-07 23:52 
GeneralRe: No error but no response Pinmembercczm11-Oct-07 15:32 
GeneralPerformance. PinmemberMarc Leger18-Jul-07 4:05 
JokeRe: Performance. Pinmembersk8er_boy28720-Nov-08 0:47 
GeneralRe: Performance. PinmemberAdrian Brutus20-Nov-08 0:59 
GeneralRe: Performance. Pinmembersk8er_boy28720-Nov-08 2:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140421.2 | Last Updated 18 Jul 2007
Article Copyright 2007 by Adrian Brutus
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid