Microsoft & .NETVisual C#Creating an Interactive 3D world with C# and DirectX

Creating an Interactive 3D world with C# and DirectX content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Building 3D applications has always been a cumbersome task for programmers. Rendering of 3D objects is quite a time-consuming process and, if some code has to be debugged or rewritten, the programmers usually get exhausted in compiling the application again and again. Until now, game developers have mostly worked in Visual C++, which is quite difficult to use, and using a graphics API such as OpenGL or DirectX along with it, making it even more difficult. Managed programming languages like C#.NET have made programmers lives a bit easier and the advent of the new features in DirectX have given a boost to the way these 3D applications are coded. You cannot imagine how easy it is to create a 3D scene with DirectX 9.0 API and a 3D Engine.

DirectX is an advanced suite of multimedia application programming interfaces (APIs) built into Microsoft Windows’ operating systems. It provides a standard development platform for Windows-based PCs to access specialized hardware features with easy programming code. This technology was introduced in 1995 and is now widely used. The latest version of the DirectX family is DirectX 9.0 that has improved graphics, security, and performance in comparison to its previous versions. There are a number of 3D graphics engines available for .NET developers. These are usually built to enhance productivity in less time by creating a one-line method for tens of lines of code. A comprehensive list of these engines can be found at:

In this tutorial, I am using 3D Engine (TrueVision TV3DSDK), downloadable from and Managed DirectX 9.0 SDK, downloadable from to make this application. If you do not want to install the complete SDK, just install the DirectX runtime environment to run the code uploaded with this article.

I have defined the following steps in creating any 3D scene, based on simple objects and their movements and in this application; these will be carried out one by one:

  1. Imagine (What Is to be Built?)
  2. Design and Load 3D Models (Virtual Actors)
  3. Set Camera
  4. Apply Special Effects
  5. Define User Input Controls/li>
  6. Define Object Boundaries for Movement and Collision Detection
  7. Apply the Laws of Physics (if required)
  8. Render Everything!

1. Imagine (What Is to be Built?)

I have imagined making a 3D room having carpet, sofas, a glass table, dining table with six chairs, a hanging scenery, a lamp, chest of drawers, and a shelf table, as in a real home.

Figure 1: A 3D Room

Now, you start working on your application:

Make a new C# project as a Windows Application and name it DirectX Application1. Download the TrueVision SDK trial version from, install it, and then Import the TrueVision Engine and TrueVision Media libraries through Project–>Add Reference.

Figure 2: Adding the TrueVision Libraries in the Project

Place a PictureBox on the Form1 and name it pictureBox1 and a button to quit this application.

Figure 3: Placing a Picture Box and a Button on the Form

Include these libraries in your project:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using TrueVision3D;
using DxVBLibA;

TV3DEngine is written using DirectX and provides powerful functions to accomplish amazing 3D abstraction. If you need to develop a powerful 3D Application/Game in a short time, TV3DEngine will help you with this. It wraps some of the more powerful features of DirectX into easily used functions and procedures. Accomplish the same results 10 times faster than with Core DirectX using your favorite language! It has some built-in classes that you have to load in the project; for example, TVEngine, TVInputEngine, TVLightEngine, TVTextureFactory, TVMaterialFactory, TVScene, TVLandscape, TVActor, TVCamera, and so forth. Some of the necessary classes used in this application will be discussed along with the code.

Declare and initialize TrueVision Variables in the Form1 class:

//Declaring and initializing the objects for the rendering Engine,
//Input Engine, Light Engine, Texture Factory, Material Factory,
//Scene, and Global classes of TrueVision (TV) library
TVEngine TV = new TVEngine();
TVInputEngine Inp = new TVInputEngine();
TVLightEngine TVLightEngine = new TVLightEngine();
TVTextureFactoryClass TexFactory = new TVTextureFactoryClass();
TVMaterialFactory MatFactory = new TVMaterialFactory();
TVScene TVScene = new TVScene();
TVGlobals global = new TVGlobals();

TVEngine is the main TrueVision class used to create a TV object that is just similar to an Application Window on which the whole rendering is to be done. This object is used to set the application properties, such as Window Mode, Search Directory Path, Window Title, and so on. TVScene is the portion on the window or whole of the window where you have to render everything. TVInputEngine is for handling all the keystroke and mouse inputs. TVGlobals handles the global engine built-in variables. TVLightEngine handles the lights in the scene and the other two handle all texture bindings and material mapping on the mesh objects respectively.

In the Form1_Load event, add the following code:

private void Form1_Load(object sender, System.EventArgs e)
   //Before trying to play with TrueVision, we have to create the TV8 object.
   TV = new TVEngine();
   //Now create a windows handle for the pictureBox1 so that all the rendering
   //will be done on the picture box
   TV.Init3DWindowedMode(this.pictureBox1.Handle.ToInt32(), true);
   //This is the  path where our media (texture and meshes) files are placed
   //This is to set the rotation angle to degrees (the other option is radians)

2. Design and Load 3D Models (Virtual Actors)

3D models are the mesh objects that are to be placed in the 3D scene. A mesh is a series of polygons grouped to form a surface. They can include hall, terrain, roads, factory, machines, cars, people, and the like. Design the 3D mesh objects (animated or unanimated) in any 3D graphics software available (for example, 3D Studio Max, Maya, Light Wave, and so on) and covert them into a format that can be imported in .NET (as in the .x file format for DirectX). Other file formats are also supported by the engine. I have used 3D Studio Max to design the mesh objects and converted them to X files using Panda Exporter. You can find many other 3D graphics software available both for purchase and for free to download on the Web. The other easy way is to download pre-built 3D models uploaded at many different Web sites like and

Figure 4: Designing 3D models in 3D Studio Max

You have created 10 objects here. They are to be placed at different positions in the room, as shown in the first picture above.

//Declaring our 3D mesh objects here
TVMesh Obj1, Obj2, Obj3, Obj4, Obj5, Obj6, Obj7, Obj8,
       Obj9, Obj10;
TrueVision3D.TVMeshClass Room;

In the Form1_Load event, you add:

//Initialize all 3D objects as TVMesh class objects
Obj1 = new TVMesh();
//Create a 3D Room mesh
Room = (TVMeshClass)TVScene.CreateMeshBuilder("roommesh");

The engine can load these types of textures:

  • Standard window formats: BMP, JPG, PNG, DIB, TGA
  • DirectX texture format: DDS

PNG, TGA, and DDS can have an alpha channel that controls the transparency of the texture.

The function for loading texture in this engine is “LoadTexture” that can be called by the TVScene object or the TextureFactory object. It returns the Texture index in the texture factory. The list of the parameters is as follows:

TVScene.LoadTexture(Filename As String, Width As Long,
                    Height As Long, TextureName As String)
TVTextureFactory. LoadTexture(Filename As String, Name As String,
                              Width As Long, Height As Long,
                              Colorkey As CONST_TV_COLORKEY,
                              FilterTexture As Boolean,
                              multialpha As Boolean)

I hope all the arguments of the “LoadTexture” are clear enough to understand except for two. The colorkey of the texture will not be rendered, resulting in transparency. The multialpha is used to mask; if multialpha is true, you have only two possible alpha values (0 and 1). If it’s set to false, the alpha value has 64 possible values, or 256 if it’s 32bits. Now, it’s time to load all the textures in the code:

//Load all the textures
TexFactory.LoadTexture("MediaTexturesbottom.bmp", "Carpet", -1, -1,
                       CONST_TV_COLORKEY.TV_COLORKEY_NO, true, true);
TexFactory.LoadTexture("MediaTexturesfloor1.bmp", "Wall", -1, -1,
                        CONST_TV_COLORKEY.TV_COLORKEY_NO, true, true);

Now, move on to building a room having four walls and two floors (including a ceiling). The TrueVision engine contains three functions for creating the wall and adding it to a single mesh “Room” that you created. These are:

AddWall Creates a wall (quad) that is perpendicular to the y plane along a line.
AddWall2 Creates a wall (quad) that is perpendicular to the y plane along a line with different y altitudes.
AddWall3D Adds a 3D wall (solid wall made of 4 or 6 faces)
TVMesh.AddWall(Texture As Long, x1 As Single, Z1 As Single, x2 As Single,
               Z2 As Single, Height As Single, Altitude As Single, tilew As Single,
               tileh As Single, NewFace As Boolean, OtherFaceSet As Boolean)

This simple method allows you to create textured walls easily. The X and Z coordinates are the same that for a line on a plane.

TVMesh.AddWall2(Texture As Long, x1 As Single, Z1 As Single, x2 As Single,
                Z2 As Single, height1 As Single, height2 As Single,
                Altitude1 As Single, Altitude2 As Single, tilew As Single,
                tileh As Single, NewFace As Boolean, OtherFaceSet As Boolean)

This simple method allows you to create textured walls easily. The X and Z coordinates are the same that for a line on a plane. This method allows the wall to start at a specified altitude and to stop at another, so it’s a little more powerful than TVMesh.AddWall2.

TVMesh.AddWall3D(Texture As Long, x1 As Single, Z1 As Single, x2 As Single,
                 Z2 As Single, Height As Single, Size As Single,
                 DisableTop As Boolean, DisableBottom As Boolean,
                 Altitude As Single, tilew As Single, tileh As Single)

Adds a 3D wall (solid wall made of four or 6 faces) to the current mesh.

Here, I am using the AddWall3D function to create solid walls.

//Load the room coordinates and assigns a texture to it
Room.AddWall3D(global.GetTex("RoomTexture"), 350.0f, -350.0f, -350.0f,
               -350.0f, 350.0f, 5.0f, true, false, -50.0f, 5.0f, 1.0f);
Room.AddWall3D(global.GetTex("RoomTexture"), -350.0f, -350.0f, -350.0f,
               350.0f, 350.0f, 5.0f, true, false, -50.0f, 5.0f, 1.0f);
Room.AddWall3D(global.GetTex("RoomTexture"), -350.0f, 350.0f, 350.0f,
               350.0f, 350.0f, 5.0f, true, false, -50.0f, 5.0f, 1.0f);
Room.AddWall3D(global.GetTex("RoomTexture"), 350.0f, 350.0f, 350.0f,
               -350.0f, 350.0f, 5.0f, true, false, -50.0f, 5.0f, 1.0f);

Now, add the floor to the Room mesh:

TVMesh.AddFloor(Texture As Long, x1 As Single, Z1 As Single, x2 As Single,
                Z2 As Single, Altitude As Single, tilew As Single, tileh As Single,
                NewFace As Boolean, OtherFaceSet As Boolean)

The above function adds a floor face to the current mesh. Floor face is a rectangular horizontal plane on the Y plane.

// Like the "add wall" method, we will add a floor to this room.
Room.AddFloor(global.GetTex("RoomTexture"), -350.0f, -350-0f, 350.0f, 350.0f,
              -50.0f, 10.0f, 10.0f, true, false);
Room.AddFloor(global.GetTex("RoomTexture"), -350.0f, -350-0f, 350.0f, 350.0f,
              300.0f, 10.0f, 10.0f, true, false);

Then, you load the Room mesh at the proper location in the Scene specifying the values of x, y, and z as follows:

//Set the position  of the room mesh
Room.SetPosition(x_move, y_move, z_move);

The 3D room with the “RoomTexture” applied to it looks like this:

Figure 5: Creating a Room mesh and loading it in the scene

Then, you create the first mesh object to load the “Drawer” in the room:

TVScene.CreateMeshBuilder (Name As String)

Creates a new empty mesh builder (TVMesh) and add it in the scene graph. You must ALWAYS use this method to create a new mesh or to load one; otherwise, it will not be included in the scene graph, and will probably be not rendered.

//Create 3D object mesh
Obj1 = TVScene.CreateMeshBuilder("Obj1");

Then, load the X files here from the 3D object models that you created in 3D Studio Max and exported them as “.x” files. There are three functions to load an X file, depending on whether the file is animated or not or whether you need to import the material and texture from 3D Studio Max.

TVMesh.LoadXFile(Filename As String, LoadTextures As Boolean,
                 LightingMaterial As Boolean)

Loads a X (DirectX Format) static model into this empty mesh.

TVMesh.LoadSkinMesh(Filename As String)

Loads a SKinned Mesh file (x animated file) into this empty mesh.

TVMesh.LoadXFileHierarchy(Filename As String,
                          WithAnimation As Boolean,
                          WithMaterials As Boolean)

Loads a SKinned Mesh file (x animated file) into this empty mesh.

//Here we load the X files for the meshes one by one for all the 10 objects
Obj1.LoadXFile("MediaMeshesdrawer1.x", true, true);

When you load the obj1 object in the scene, you get the following result:


Figure 6: Loading an object in the room

After applying the texture to the floor and the drawer object, your scene is modified to resemble this:

Room.AddFloor(global.GetTex("Carpet"), -350.0f, -350-0f, 350.0f, 350.0f,
              -50.0f, 10.0f, 10.0f, true, false);

Figure 7: Applying texture

I like to change the walls, too, so apply another texture “Wall”:

Figure 8: Applying texture to the walls

Likewise, you have to add all the objects in the scene, specifying their positions, textures, and other properties if required.

3. Set Camera

In the Form1 class, you declare and initialize some variables to set up the camera position and then move it through the scene as follows:

//Declaring variables for camera movement
float sngPositionX;
float sngPositionY;
float sngPositionZ;
float snglookatX;
float snglookatY;
float snglookatZ;
float sngAngleX;
float sngAngleY;

Now, coming back to the Form1_Load event, you set the position of the camera:

//Set the view to perspective

The arguments for the above function are:

sAngleFOV Angle in degrees representing the FOV (Field of vision) of the view.
sFarPlane Maximum distance of vision. Everything after this imaginary far plane will be not rendered.
//set our camera location and lookat point, etc.
sngPositionX = 0.0f;
sngPositionY = 0.3f;
sngPositionZ = 0.0f;
snglookatX   = 0.0f;
snglookatY   = 0.0f;
snglookatZ   = 0.0f;
sngAngleY    = -1.57f;

With SetCamera, you can’t define a camera with a totally vertical orientation. To do this, you have to use the RotateX method or use special matrices. SetCamera also can be used with a trigonometry equation to get a fully working camera system.

TVScene.SetCamera(xpos As Single, ypos As Single,
                  zpos As Single, xlookat As Single,
                  ylookat As Single, zlookat As Single)
xpos X coordinate of the camera position
ypos Y coordinate of the camera position (altitude)
zpos Z coordinate of the camera position
xlookat X coordinate of the camera look at point
ylookat Y coordinate of the camera look at point (altitude)
zlookat Z coordinate of the camera look at point

The behaviour is undefined if you use Position = LookAtPoint values.

//The camera is initially set to the origin (0, 0, 0) values
TVScene.SetCamera(sngPositionX, sngPositionY, ngPositionZ, snglookatX,
                  snglookatY, snglookatZ);

Figure 9: Setting camera position and look at position

4. Apply Special Effects

Special effects are nothing but the real-world look and feel given to the 3D scene. This includes the following effects applied:

  • Texture mapping
  • Material mapping
  • Shading
  • Lighting
  • Reflection
  • Shadows
  • Blending
  • Fog
  • Anti-aliasing
  • Sound effects

In this example application, not many of the effects are utilized, but you can add these as per the requirements of your own applications. Here, texture, material, and lighting effects are used.

//Load the texture
//Declaring a light
DxVBLibA.D3DLIGHT8 light;
//Initializing the light with values
light.ambient.a    = 0.8f;
light.ambient.r    = 0.8f;
light.ambient.g    = 0.8f;
light.ambient.b    = 0.8f;
light.diffuse.a    = 1.0f;
light.diffuse.r    = 1.0f;
light.diffuse.g    = 1.0f;
light.diffuse.b    = 1.0f;
light.specular.a   = 1f;
light.specular.r   = 0.2f;
light.specular.g   = 0.2f;
light.specular.b   = 0.2f;
light.Direction    = global.Vector3(0.0f,1.0f,0.0f);
light.Position     = global.Vector3(0.0f, 400.0f, 10.0f);
light.Range        = 1000.0f;
light.Attenuation0 = 0.5f;
light.Falloff      = 1;
light.Phi          = 3.14f / 4.0f;
light.Theta        = light.Phi / 2;
//Create the light in the scene
TVLightEngine.CreateLight(ref light,"light", false);

Figure 10: Applying special effects

Here, the table is given a material of glass in 3D Studio Max and loaded with its material preserved, as seen in the above picture.

Figure 11: Setting material properties in 3D studio Max

5. Define User Input Controls

In the Form1 class, define the variables for mouse and keyboard movement:

// Now, for the mouse input...
int tmpMouseX,tmpMouseY;
short tmpMouseB1,tmpMouseB2,tmpMouseB3;
int tmpMouseScrollOld,tmpMouseScrollNew;
// We could have done this in many ways, but we added some smoothing to
// the movement see we need to declare two additional variables.
float sngWalk;
float sngStrafe;

I have made a Check_Input method and have called it in the main loop:

private void Check_Input()
   sngWalk = 0.0f;
   sngStrafe = 0.0f;
   // Check if we pressed the PAGEUP key, if so, then scene moves in +y direction
      TVScene.SetCamera(sngPositionX, sngPositionY+=0.5f, sngPositionZ,
                        snglookatX, snglookatY+=0.5f, snglookatZ);
   // Check if we pressed the PAGEDOWN key, if so, then scene moves in -y direction
      TVScene.SetCamera(sngPositionX, sngPositionY-=0.5f, sngPositionZ,
                        snglookatX, snglookatY-=0.5f, snglookatZ);
   // Check if we pressed the UP arrow key, if so, then we are
   // walking forward.
      sngWalk = 0.1f;
   // If we are not walking forward, maybe we are walking backward
   // by using the DOWN arrow? If so, set walk speed to negative.
      sngWalk = -0.1f;
   // Check if we pressed the LEFT arrow key, if so, then strafe
   // on the left.
      sngStrafe = 0.1f;
   // If we are not strafing left, maybe we want to strafe to the
   // right, using the RIGHT arrow? If so, set strafe to negative.
      sngStrafe = -0.1f;
   // Actual value to old mouse scroller value.
   tmpMouseScrollOld = tmpMouseScrollNew;
   // Get the movement of the mouse.
   Inp.GetMouseState(ref tmpMouseX, ref tmpMouseY, ref tmpMouseB1,
                     ref tmpMouseB2, ref tmpMouseB3,
                     ref tmpMouseScrollNew);
   // Update the camera angles.
   sngAngleX = sngAngleX -( (float)tmpMouseY / 100);
   sngAngleY = sngAngleY -( (float)tmpMouseX / 100);

6. Define Object Boundaries for Movement and Collision Detection

In this scene, only the camera or the viewer’s eye is allowed to move and no other object in the scene is moving. This also can be done just by adding a little more code. But, for the sake of simplicity, I am moving only the camera. I have made another method, Check_Movement, that takes care of all the movements:

private void Check_Movement()
   // Simple check of the mouse.
   if(sngAngleX > 1.3f)
      sngAngleX = 1.3f;
   if(sngAngleX < -1.3)
      sngAngleX = -1.3f;
   // Update the vectors using the angles and positions.
   sngPositionX = sngPositionX + (float)(System.Math.Cos((double)sngAngleY)
                * sngWalk / 5.0f * TimeElapsed)
                + (float)(System.MathCos((double)sngAngleY + 3.141596/2)
                * sngStrafe / 5.0f * TimeElapsed);
   sngPositionZ = sngPositionZ + (float)(System.Math.Sin((double)sngAngleY)
                * sngWalk / 5.0f * TimeElapsed)
                + (float)(System.Math.Sin((double)sngAngleY + 3.141596/2)
                * sngStrafe / 5.0f * TimeElapsed);
   // We update the look at position.
   snglookatX = sngPositionX + (float)System.Math.Cos((double)sngAngleY);
   snglookatY = sngPositionY + (float)System.Math.Tan((double)sngAngleX);
   snglookatZ = sngPositionZ + (float)System.Math.Sin((double)sngAngleY);
   // With the new values of the camera vectors (position and
   // look at), we update the scene's camera.
   TVScene.SetCamera(sngPositionX, sngPositionY, sngPositionZ, snglookatX,
                     snglookatY, snglookatZ);

Now it’s time to enable Collision Detection. Because the demo application is very simple and does not require any collision detection, I have not added it in the code sample.

TVMesh.SetCollisionEnable(Collision As Boolean, Group As Integer)

Disables/Enables collision test for the entire mesh or a group of this mesh. Collision test is True by default on all new created/loaded meshes. Don’t hesitate to disable collisions when it’s not useful because it will free the CPU from some computations.


Returns the mesh that has been collided/mousepicked if the object type is Mesh. If you’re not sure that a mesh has been collided, always a test for the object type.

TVScene.AdvancedCollision(linestart As D3DVECTOR,
                          lineend As D3DVECTOR, 
                          ret_CollisionResult As TV_COLLISIONRESULT,
                          objecttocheck As CONST_TV_OBJECT_TYPE,
                          TestType As CONST_TV_TESTTYPE,
                          findclosest As Boolean)

Do an advanced collision test on landscape, mesh, and Actor entities. This is basically a ray collision test that returns the closest hit between the line start and line end (or the first hit found if you specify so). The information returned by this function can be used to do more physics computations about the collision and do sliding or bouncing. To get the maximal accuracy for the returned information, you should use the TV_TESTTYPE_ACCURATETESTING checking mode.

TVMesh.Collision (linestart As D3DVECTOR,
                  lineend As D3DVECTOR,
                  CheckType As CONST_TV_TESTTYPE,
                  Ret_Distance As Single)

Does a simple a collision test on this mesh. This is basically a ray collision test that returns the closest hit between the line start and line end (or the first hit found if you specify so).

linestart Start point of the line test
lineend End point of the line test
CheckType Defines the type of test that will be done for collision detection. Bounding box or bounding sphere are the fastest ones, but gives less accurate information.
Ret_Distance (Optional, value = 0) Returns the distance from t
//This is for collision detection
if (Room.Collision(ref linestart, ref lineend,
                   ref distance)== true)
   //Do not move camera
   //Add code here for setting the camera's position. It's not done.

Figure 12: Moving camera through the scene with mouse and keyboard input

7. Applying the Laws of Physics

Real-time physics laws—including gravity, collision, and topography—are applied in movements such as that of a plane, ball, car, and so forth. Because in this scene, this is not required, I have skipped this step in this application. I will be applying it in my next tutorials. For example, if you want to check the gravity in the scene, you can do so this way:

TVScene.CheckGravity(TVCamera() As CameraGravity,
                     TimeElapsed As Single,
                     ValueDown As Single, ValueUp As Single,
                     landscape As Boolean)

Check Gravity is a function that checks the camera position movement on Collision and Gravity.

8. Render Everything on the Screen

Here you go!

//Clear the Screen
//Enable the RenderAllMeshes property true
// Then, we display everything that we have rendered
// (from the objects of the world) to the screen.

Figure 13: A 3D application rendered successfully

I hope this tutorial has made you think about making a new 3D game of your own. Look how easy it is to develop a full-fledged 3D application in .NET.


Download Demo project and Source code – [4 MB]

Download TrueVision Engine – [35 MB]

About the Author

Ms. Fatima Ahmed is a B.S. (C.S.) from Department of Computer Science, University of Karachi, Pakistan. She is working as a Research Assistant at Centre for Computer Studies, Institute of Business Administration (IBA) Karachi, and is involved in research work related to Virtual Reality and Simulation System using DirectX 9.0 and .NET. She is also working on a Parallel Lab project where parallel machines are installed using PVM and Grid Computing technologies. She is also a technical article writer for JupiterMedia Corporation U.S.A since 2001 and has written a number of articles on Networking Technologies including VPN, PVM, ATM, and so forth, and Programming Languages including C#, VB .NET, and VB. Her technical papers are also being published in the European Journal of Engineering Education and IEEE journals. She was also the Editor for Proceedings of ICICT (1st International Conference on Information and Communication Technologies) 2005, Karachi. She is also an active participant in organizing and taking part in different national and international events including seminars, conferences, and exhibitions. She is a Microsoft’s MVP for DirectX and a local Microsoft Technical Speaker for the local events held at different educational institutes in Pakistan.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories