H_3D_Engine
Simple 3D Engine draws 3D shapes in wireframe
Introduction
Welcome to my 3D engine.
It's called H3D
Engine, and it draws 3D shapes in wireframe, dots.
I tried to make it easy to use, and the code is different and well understood (from my viewpoint, but your suggestions will be appreciated).
Background
- A background in mathematics such as cos, sin, etc.
- A background about matrices (addition, multiplication).
- It would be better if you have a good idea about OOP, and if you don't that means this article may be not helpful for you, or it might be interesting, who knows?
- Any background about 3Ds (vertices, triangles, etc.)
Using the Code
In our engine, we have four main structures that can help us to organize data. They are defined as:
public struct tri_angle
{
public tri_angle(float x, float y, float z)
{
p1 = x; p2 = y; p3 = z;
}
public float p1, p2, p3;
}
public struct GVerts3D
{
public GVerts3D(float x, float y, float z)
{
X = x; Y = y; Z = z;
}
public float X;
public float Y;
public float Z;
}
public struct GVerts2D
{
public int X;
public int Y;
}
public enum RenderType {
DotsR = 1,
Indx
}
The first structure tri_angle
is used to describe our indices (triangles) and the second one GVerts3D
is used to describe our 3D Geometry (Vertices). The third one would help us when we project from 3D to 2D since our screen is flat and the last one is enum
, which can help us to determine the rendering type in an easy way.
Here I'm going to show you how to use H3D
Engine and if you are interested in its design, you can download the source code (from the link at the top of this page) and check it yourself.
Here we define the two main objects, and the instance from the engine which is called h3d
here.
private GVerts3D[] Geom;
private tri_angle[] trt;
private H3DX h3d;
The H3DX
is defined as:
namespace H_3D_Engine
{
class H3DX
{
// -------Constructors-------
//public H3DX()
//public H3DX(int w,int h,int FOVLens)
// -------Methods-------
//public void SetView(int w, int h)
//public void SetStream(GVerts3D[] Verts)
//public void SetStreamIndex(tri_angle[] indx)
//public void SetMatrix(CMatrix4 TM)
//public void Trnslate(int x,int y,int z)
//public CMatrix4 GetMatrix()
//public void SetRenderMode(RenderType t)
//public RenderType GetRenderMode()
//public void Clear(Color c)
//public void Push()
//public void Present(Graphics g)
//
//private GVerts2D Project2DD(GVerts3D Verts)
// -------Variables-------
//private Bitmap mb;
//private Graphics tdc;
//private CMatrix4 HMat = new CMatrix4();
//private GVerts3D[] HVerts;
//private tri_angle[] index;
//private int HWidth;
//private int Lens;
//private int HHeight;
//private int tx, ty, tz;
//private bool Ver_Render = false;
}
}
Now after we defined our variables, we can initialize them only once in Form1_Load
as:
private void Form1_Load(object sender, EventArgs e)
{
//variables needed for rotation
Angle = xAngle = yAngle = zAngle = 0;
iX = iZ = 0;
iY = 1;
//setup our cube
SetupDefaultMesh();
//initializing our variables...
h3d = new H3DX(Paper.Width, Paper.Height, 256);
hRotMatrixX = new CMatrix4();
hRotMatrixY = new CMatrix4();
hTrans = new CMatrix4();
hscaleMatrix = new CMatrix4();
objMatrix = new CMatrix4();
g = Paper.CreateGraphics();
text4.Text = ms.ToString();
}
Paper is just a PictureBox
which we are drawing into.
But the question is: what is CMatrix4
?CMatrix4
is a very helpful class that helps us to Rotate, Translate, or Scale 3D objects in an easy way and it is defined as:
namespace H_3D_Engine
{
class CMatrix4
{
// -------Constructors-------
//public CMatrix4()
// -------Methods-------
//public void RotateX(double degree); //| 0 1 2 3 |
//public void RotateY(double degree); //| 4 5 6 7 |
//public void RotateZ(double degree); //| 8 9 10 11 |
//public void Scale(float s); //| 12 13 14 15 |
//public void Translate(GVerts3D v)
//public static double ToRadian(double angle)
//operators
//static public CMatrix4 operator *(CMatrix4 m1, CMatrix4 m2)
// -------Variables-------
//public float[] _Mat = new float[16];
}
}
Now we are ready to set up our geometry. Here is a simple procedure to define a simple cube:
void SetupDefaultMesh()
{
Geom = new GVerts3D[]{
new GVerts3D( 1 ,1, 1), //0 right up
new GVerts3D(-1 ,1, 1), //1 left up
new GVerts3D(-1,-1, 1), //2 left down
new GVerts3D( 1,-1, 1), //3 right down
new GVerts3D( 1 ,1, -1), //4
new GVerts3D(-1 ,1, -1), //5
new GVerts3D(-1,-1, -1), //6
new GVerts3D( 1,-1, -1), //7
};
trt = new tri_angle[]{
new tri_angle(0,3,1),
new tri_angle(1,2,3),
new tri_angle(0,4,7),
new tri_angle(0,3,7),
new tri_angle(1,5,6),
new tri_angle(5,6,2),
new tri_angle(1,5,4),
new tri_angle(4,0,1),
new tri_angle(6,7,3),
new tri_angle(2,3,7),
new tri_angle(4,5,6),
new tri_angle(4,7,6),
};
}
So here we are going to do the interesting thing, the DrawScene
procedure, which is defined as:
void DrawScene()
{
h3d.Clear(Color.Blue);
objMatrix.LoadIdentity(45);
//scale our mesh to 1
hscaleMatrix.Scale(ms);
objMatrix *= hscaleMatrix;
//Translate to origin
hTrans.Translate(new GVerts3D(0, 0, 0));
objMatrix *= hTrans;
//rotate around (-1,0,-1) in 3 steps
//1.translate into that point
hTrans.Translate(new GVerts3D(-1, 0, -1));
objMatrix *= hTrans;
//2. do rotation
hRotMatrixY.RotateY(CMatrix4.ToRadian(yAngle));
objMatrix *= hRotMatrixY;
//3.Translate it back
hTrans.Translate(new GVerts3D(1, 0, 1));
objMatrix *= hTrans;
//hRotMatrixZ.RotateZ(CMatrix.ToRadian(zAngle));
//objMatrix *= hRotMatrixZ;
h3d.SetMatrix(objMatrix);
h3d.SetStream(Geom);
h3d.SetStreamIndex(trt);
//h3d.SetRenderMode(RenderType.Indx);
h3d.Push();
objMatrix.LoadIdentity(45);
hscaleMatrix.Scale(ms);
objMatrix *= hscaleMatrix;
hTrans.Translate(new GVerts3D(4, 0, 0));
objMatrix *= hTrans;
hRotMatrixY.RotateY(CMatrix4.ToRadian(yAngle));
objMatrix *= hRotMatrixY;
h3d.SetMatrix(objMatrix);
h3d.SetStream(Geom);
h3d.SetStreamIndex(trt);
//h3d.SetRenderMode(RenderType.DotsR);
h3d.Push();
//Present the scene...
h3d.Present(g);
}
What did we do?
At first, we made the screen clear with blue background color and then we drew our cube two times, the first time around the point (-1, 0, -1)
and the second time around its center.
Good luck!
History
- 24th January, 2009: Initial version