In my last tutorial I have shown how to make a wireframe cube using VB.NET and GDI+. Today, we will build from the code from the last tutorial in order to make a rotating solid cube. The video below shows what we will achieve after finishing the tutorial.
THE FULL SOURCE CODE IS HERE.
The Code
The original code was divided in 2 files [Point3D.vb and Main.vb]. The Point3D.vb file defined the Point3D class which represents points in 3D space. The file Main.vb defined the Window form where the simulation runs.
The class Point3D remains unchanged and is presented below.
'
' Defines the Point3D class that represents points in 3D space.
' Developed by leonelmachava <leonelmachava@gmail.com>
' http://codentronix.com
'
' Copyright (c) 2011 Leonel Machava
'
Option Explicit On
Public Class Point3D
Protected m_x As Double, m_y As Double, m_z As Double
Public Sub New(ByVal x As Double, ByVal y As Double, ByVal z As Double)
Me.X = x
Me.Y = y
Me.Z = z
End Sub
Public Property X() As Double
Get
Return m_x
End Get
Set(ByVal value As Double)
m_x = value
End Set
End Property
Public Property Y() As Double
Get
Return m_y
End Get
Set(ByVal value As Double)
m_y = value
End Set
End Property
Public Property Z() As Double
Get
Return m_z
End Get
Set(ByVal value As Double)
m_z = value
End Set
End Property
Public Function RotateX(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, yn As Double, zn As Double
rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
yn = Me.Y * cosa - Me.Z * sina
zn = Me.Y * sina + Me.Z * cosa
Return New Point3D(Me.X, yn, zn)
End Function
Public Function RotateY(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Zn As Double
rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Zn = Me.Z * cosa - Me.X * sina
Xn = Me.Z * sina + Me.X * cosa
Return New Point3D(Xn, Me.Y, Zn)
End Function
Public Function RotateZ(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Yn As Double
rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Xn = Me.X * cosa - Me.Y * sina
Yn = Me.X * sina + Me.Y * cosa
Return New Point3D(Xn, Yn, Me.Z)
End Function
Public Function Project(ByVal viewWidth, ByVal viewHeight, ByVal fov, ByVal viewDistance)
Dim factor As Double, Xn As Double, Yn As Double
factor = fov / (viewDistance + Me.Z)
Xn = Me.X * factor + viewWidth / 2
Yn = Me.Y * factor + viewHeight / 2
Return New Point3D(Xn, Yn, Me.Z)
End Function
End Class
The file Main.vb has suffered some changes. See below its code.
'
' Simulation of a Rotating Cube using GDI+
' Developed by leonelmachava <leonelmachava@gmail.com>
' http://codentronix.com
'
' Copyright (c) 2011 Leonel Machava
'
Imports System.Drawing.Graphics
Imports System.Drawing.Pen
Imports System.Drawing.Color
Imports System.Drawing.Brush
Imports System.Drawing.Point
Imports System.Drawing.Bitmap
Public Class Main
Protected m_timer As Timer
Protected m_vertices(8) As Point3D
Protected m_faces(6, 4) As Integer
Protected m_colors(6) As Color
Protected m_brushes(6) As Brush
Protected m_angle As Integer
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Enable double-buffering to eliminate flickering.
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
InitCube()
' Create the timer.
m_timer = New Timer()
' Set the timer interval to 25 milliseconds. This will give us 1000/25 ~ 40 frames per second.
m_timer.Interval = 25
' Set the callback for the timer.
AddHandler m_timer.Tick, AddressOf AnimationLoop
' Start the timer.
m_timer.Start()
End Sub
Private Sub InitCube()
' Create the cube vertices.
m_vertices = New Point3D() {
New Point3D(-1, 1, -1),
New Point3D(1, 1, -1),
New Point3D(1, -1, -1),
New Point3D(-1, -1, -1),
New Point3D(-1, 1, 1),
New Point3D(1, 1, 1),
New Point3D(1, -1, 1),
New Point3D(-1, -1, 1)}
' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
' above.
m_faces = New Integer(,) {{0, 1, 2, 3}, {1, 5, 6, 2}, {5, 4, 7, 6}, {4, 0, 3, 7}, {0, 4, 5, 1}, {3, 2, 6, 7}}
' Define the colors of each face.
m_colors = New Color() {Color.BlueViolet, Color.Cyan, Color.Green, Color.Yellow, Color.Violet, Color.LightSkyBlue}
' Create the brushes to draw each face. Brushes are used to draw filled polygons.
For i = 0 To 5
m_brushes(i) = New SolidBrush(m_colors(i))
Next
End Sub
Private Sub AnimationLoop()
' Forces the Paint event to be called.
Me.Invalidate()
' Update the variable after each frame.
m_angle += 1
End Sub
Private Sub Main_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim t(8) As Point3D
Dim f(4) As Integer
Dim v As Point3D
Dim avgZ(6) As Double
Dim order(6) As Integer
Dim tmp As Double
Dim iMax As Integer
' Clear the window
e.Graphics.Clear(Color.LightBlue)
' Transform all the points and store them on the "t" array.
For i = 0 To 7
Dim b As Brush = New SolidBrush(Color.White)
v = m_vertices(i)
t(i) = v.RotateX(m_angle).RotateY(m_angle).RotateZ(Me.m_angle)
t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
Next
' Compute the average Z value of each face.
For i = 0 To 5
avgZ(i) = (t(m_faces(i, 0)).Z + t(m_faces(i, 1)).Z + t(m_faces(i, 2)).Z + t(m_faces(i, 3)).Z) / 4.0
order(i) = i
Next
' Next we sort the faces in descending order based on the Z value.
' The objective is to draw distant faces first. This is called
' the PAINTERS ALGORITHM. So, the visible faces will hide the invisible ones.
' The sorting algorithm used is the SELECTION SORT.
For i = 0 To 4
iMax = i
For j = i + 1 To 5
If avgZ(j) > avgZ(iMax) Then
iMax = j
End If
Next
If iMax <> i Then
tmp = avgZ(i)
avgZ(i) = avgZ(iMax)
avgZ(iMax) = tmp
tmp = order(i)
order(i) = order(iMax)
order(iMax) = tmp
End If
Next
' Draw the faces using the PAINTERS ALGORITHM (distant faces first, closer faces last).
For i = 0 To 5
Dim points() As Point
Dim index As Integer = order(i)
points = New Point() {
New Point(CInt(t(m_faces(index, 0)).X), CInt(t(m_faces(index, 0)).Y)),
New Point(CInt(t(m_faces(index, 1)).X), CInt(t(m_faces(index, 1)).Y)),
New Point(CInt(t(m_faces(index, 2)).X), CInt(t(m_faces(index, 2)).Y)),
New Point(CInt(t(m_faces(index, 3)).X), CInt(t(m_faces(index, 3)).Y))
}
e.Graphics.FillPolygon(m_brushes(index), points)
Next
End Sub
End Class
The code is pretty much self-explanatory. Below I will just list the key changes.
In the Load event I enable double buffering. This is fundamental to eliminate flickering in the animation. Try to remove the first 2 lines of code, and run the application. You will certainly see the flickering that results.
Basically I have changed the code to draw filled faces instead of lines. However, now we must make sure to draw distant faces first, and closer ones last (Painters Algorithm).
THE FULL SOURCE CODE IS HERE.
Conclusion
As I have promised in the last tutorial, today I have shown how to make a rotating solid cube. In my next VB.NET tutorial, I will show you how to make a cool game in pretty simple steps.
If you liked this article, please consider leaving a comment, or sharing this post using one of the buttons below, or even subscribing to the blog.

Parabéns bacana seu projeto
Olá Nei. Muito obrigado.
wiiii, several years ago i droped a personal project (in vb6) because i couldnt create a function that would let me rotate the axis in r3, i cant wait to modify this >w<
Hi Fabyola.
Nice. I am glad to hear that. Please, let me know about your results.
jijiji, sure n_n, ill let you know if i can get this to work with my code
oh, and thanks for this tutorial n_n
Thank you!
hello again lefam, im sorry that i didnt post anything up to now, i was really busy because i got a new job just a few weeks ago =3
well, i didnt spent too much time on this but i got some strange results xd, let me explain it (and please forgive my bad english, its not my native language)
i always like to know how things work, so i keep “discovering the circle again” over and over on diferent things that i see
some years ago i was playing with some equations and i wondered how they would look like on a 3D space, and made myself a rough but extremely precise (and slow) 3D drawing software, based on explicit 3 var functions, painting one dot at a time xd
i made some changes and painted some beatiful functions (adding colors based on the function itself makes them alive) but my software had some trouble, it was only capable of “looking” from one angle, so i wanted to rotate the functions, but i got some personal issues and droped the proyect before i could design an algorith to do so
a week ago i was surfing the net looking how to manage built in drawing functions from vb.net (because it doesnt let me know the hDC of the form anymore <.<) and found your example, it reminded me of that project and i remade it (for some reason it was really easy this time xd) and added 2 rows from your code, after some fixing it worked lovely, but for some reason, when i try to rotate more than 1 axis at a time the functions suffer horrible disforming xD
ill work on this a little more, thanks again for you example n_n
oh, and… im sorry if i wrote too much xd
see you later =3
First of all, let me tell you that I am glad to know that my articles and codes were useful to you.
The “disformation” may happen due to an error in the rotation formula (or matrix composition, if you are using matrices). Other probable cause can be the order of the transformations (rotation followed by translation may have a different result from translation followed by rotation).
Anyway, I would need to see your code to better help you.
here’s a visual example of whats happening with the points, i made this in a rush so, no back buffer = lots of flickering xD
also, i used a low dot density, that way it redraws fast even with a high refresh rate (Form_MouseMove) but it doesnt look like a solid object
the example its done with a function that creates half a sphere, that way you can see the rotation easily
well, here it is:
http://www.megaupload.com/?d=0X2ZVIB3
the entire process its done with 2 for in this way:
start FOR rows
Start FOR columns
calculate profundity for the 3d point
rotate in column axis
rotate in row axis
translate 3d point into 2d
paint it
NEXT column
NEXT row
Nice simulation (“despite the disformation”).
Probably, you are not doing correctly the composition of the transformations (I mean rotations).