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.
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:
Gl.glEnable(Gl.GL_TEXTURE_2D);
Gl.glBindTexture(Gl.GL_TEXTURE_2D,ContentManager.GetTextureByName
("back.bmp"));
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:
m = ContentManager.GetModelByName("plaza.3DS");
m.CreateDisplayList();
And this on the Draw
function:
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.
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.
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:
for (int x = 0; x < 47; x++)
{
for (int y = 0; y < 10; y++)
{
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:
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:
public void DrawScene()
{
plaza.Draw();
sky.Draw();
flag.Draw();
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