Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

3D Plaza in C# with opengl Exploration

5.00/5 (21 votes)
15 Jul 2014CPOL3 min read 63.4K   7.4K  
A simple 3D exploration of a plaza in OpenGL and C#
This article is mainly to break the myth that 3D programming is out of reach of the average programmer. With the tools that exist today, almost any programmer can get into this matter without too much effort.

cover

Introduction

This demo makes use of the TAO framework, that is, basically an Interop library from .NET with windows OpenGL. It also contains a small engine made by myself called ShadowEngine that encapsulates tasks such as graphic initialization, texture and model loading, among others.

OK, let me explain the project step by step.

SkyBox.cs

This class is for drawing the sky and the mountains that you see in the demo, is basically a box with images. This technique is used in 90 percent of the games you see nowadays, of course mixing it with other techniques to make it more realistic.

Take a look at how I draw a portion of the skybox:

C#
Gl.glEnable(Gl.GL_TEXTURE_2D);    // enable opengl texturing  
Gl.glBindTexture(Gl.GL_TEXTURE_2D,ContentManager.GetTextureByName
    ("back.bmp"));                //enabling texture for the portion of the skybox

Gl.glBegin(Gl.GL_QUADS);
Gl.glNormal3d(-1, 1, 1);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3d(x + width, y, z);
Gl.glNormal3d(-1, -1, 1);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3d(x + width, y + height, z);
Gl.glNormal3d(1, -1, 1);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3d(x, y + height, z);
Gl.glNormal3d(1, 1, 1);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3d(x, y, z);
Gl.glEnd();

With Gl.glVertex3d, I draw a point of the square on the screen, with Gl.glTexCoord2f, I tell OpenGL where the image on the square will be and with Gl.glNormal3d, I tell openGL the direction of the square. All these calls are made between Gl.glBegin(Gl.GL_QUADS) and Gl.glEnd().

Plaza.cs and Collisions

This class handles the drawing of the plaza that is basically to draw the 3D model with textures. This process is encapsulated so you only see this in the create function:

C#
m = ContentManager.GetModelByName("plaza.3DS"); // get the model
m.CreateDisplayList();    // this loads the model in opengl memory(displays lists)

And this on the Draw function:

C#
Gl.glPushMatrix();
Gl.glTranslatef(0, 1.4f, 0); 
Gl.glScalef(0.2f, 0.2f, 0.2f); 
m.DrawWithTextures();
Gl.glPopMatrix();

The plaza has collisions implemented in a very easy way and is only for learning purposes, because games these days implement a very complex architecture for handling collisions, which leaves out of game to the normal people living on earth. The collision is for the camera and there are two types of collisions. The first is a collision point, for example the fountain and the stick holding the flag, for that collision you only have to tell the collision manager the 3D location of this points and then a number that is how much you want the camera to get close to it before firing a collision. The other is a collision line, for example, it will be four collision lines if you don’t want the user to leave the plaza, here is a sample of the code.

C#
public void CreateCollisions()
{
    CollisionPoint c1 = new CollisionPoint();
    c1.point = new Point3D(1.5f, 9.0f, 0);
    c1.ColitionDistance = 2.3f;
    c1.enabled = true; 

    CollisionPoint c2 = new CollisionPoint();
    c2.point = new Point3D(-0.35f, -3.97f, 0);
    c2.ColitionDistance = 0.3f;
    c2.enabled = true;

    Collision.AddCollisionPoint(c1);
    Collision.AddCollisionPoint(c2); 
 
    Collision.AddCollisionSegment(new Point3D(-14.4f, 28.3f, 0), 
                new Point3D(-14.5f, -11.6f, 0), 0.5f);
    Collision.AddCollisionSegment(new Point3D(-14.4f, -11.6f, 0), 
                new Point3D(20.1f, -11.7f, 0), 0.5f);
}  

Flag.cs

The explanation of how flag is made goes beyond the scope of this article I’ve borrowed most of the code from the flag tutorial at www.nehe.com. To make a difficult explanation easy, I tell that the flag is a grid of points that are multiplied by a sine function, and why a sine function, look how a sin function looks and you will understand.

3DPlazaInCSharp/image002.png

Then every frame I draw, I translate all the points one step from left to right and the last point to the right I translate it to the first left point. And voila, you see a waving flag. Here is a piece of the code:

C#
for (int x = 0; x < 47; x++)
     {
     // Loop Through The Y Plane
     for (int y = 0; y < 10; y++)
         {
             // Apply The Wave To Our Mesh
             points[x, y, 0] = (float)((x / 5.0f) - 0.1f);
             points[x, y, 1] = (float)((y / 1.125f) - 0.1f);
             points[x, y, 2] = 
(float)(Math.Sin(Helper.DegreeToRad(((x/ 5.0f) * 40.0f)) * 2.0f));
          }      
     }

Camera.cs

This class is for handling the camera movement; it has a First Person Shooter Camera. The idea is to place the mouse on the center of the screen and translate every mouse movement in X and Y into angles rotations and then put the mouse again on the screen center. Also, the camera queries the collision manager before moving in a direction. Here is a sample:

C#
if (!Collision.CheckCollision(new Point3D(-newEyeX, -newEyeZ, 0)))
   {
      eyex = newEyeX;
      eyez = newEyeZ;
   }

MainClass.cs and Mainform.cs

Mainclass is the Manager class, it contains all the objects that will be drawn on the screen if you want and object not to be drawn just comment the object in the draw function:

C#
public void DrawScene()
        {
            plaza.Draw();
            sky.Draw();
            flag.Draw();  
            //DebugMode.WriteCamaraPos(200, 200); //work only in
                                                 32bits system
            Collision.DrawColissions();         
        }

Mainform is the Windows Form that displays the project. It contains a timer for drawing and updating the entire scene.

I am hoping to receive feedback from this example. If you like it, you can leave a comment below.

History

  • 15th July, 2014: Initial version

License

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