Click here to Skip to main content
15,438,095 members
Articles / Multimedia / GDI+
Posted 8 Jul 2008

Tagged as


57 bookmarked

3D Graphics - Cube with Shading

Rate me:
Please Sign up or sign in to vote.
4.63/5 (18 votes)
8 Jul 2008CPOL4 min read
Create a cube you can rotate and shade using only GDI+.


Based on the original Euler Rotation article, it’s time to revisit the 3D graphics GDI+ world. In the last article, we discussed the fundamentals for drawing a simple cube shape on a two-dimensional bitmap surface. Now, it’s time to take it up a notch. We are going to draw a cube with shaded sides, and we are going to find a way around the pesky Gimbal Lock problem.

Avoiding Gimbal Lock

First things first, Gimbal Lock. In the last article, we encountered a strange problem when rotating the cube around separate axes. Due to the fact that matrix multiplication is not cumulative, rotating around different axes in different order produced results that were not always the same.

A way to avoid that problem is to step up to more advanced mathematics such as quaternions. However, a more simple solution is to restructure the way the Cube class handles rotations.

Let’s compare the original structure and the new improved one. The way rotations were handled originally was to:

  • Fill in the cube’s 3D points
  • Rotate them (X-axis, then Y-axis, then Z-axis)
  • Project it on the 2D surface

Can you spot the problem? Whenever a rotation is applied, the cube starts from scratch and reapplies all the rotations. Thus, certain rotations can seem to be going the wrong way. The answer is simple:

  • Fill in the cube’s 3D points when the class is initiated
  • Rotate the existing points the difference between the new rotation and the last rotation
  • Project it on the 2D surface

Basically, instead of starting from scratch every time, we rotate what we already have.

Introducing Faces

Before going on to shading the cube, we have to restructure another part of the project. Instead of handling all the cube’s points separately, it is better to group them into cube faces. The advantages of doing things this way is we can avoid writing manually which points should connect to which when drawing the cube. All we have to do is tell how each face will be drawn.

Also, when it comes to shading the cube, we’ll have to know the order in which to draw the faces.

The faces class will only need some basic properties:

  • Array of 2D points that correspond to the face
  • Array of 3D points that correspond to the face
  • The side of the cube it represents
  • A 3D point that represents the center

We’ll also need to include a CompareTo function where the z value of the center points are compared.

public int CompareTo(Face otherFace)
     return (int)(this.Center.z - otherFace.Center.z);

2D Plotting Fixed

One last thing to fix before shading the cube: the 3D projection. When I first started writing the shading routine, I discovered that the 2D plotting from the Euler Rotation article was flawed. It was drawing everything backwards! After much simplification and review, this is the new function:

private PointF Get2D(Vector3D vec)
     PointF returnPoint = new PointF();

     float zoom = (float)Screen.PrimaryScreen.Bounds.Width / 1.5f;
     Camera tempCam = new Camera();
     tempCam.position.x = cubeOrigin.x;
     tempCam.position.y = cubeOrigin.y;
     tempCam.position.z = (cubeOrigin.x * zoom) / cubeOrigin.x;
     float zValue = -vec.z - tempCam.position.z;
     returnPoint.X = (tempCam.position.x - vec.x) / zValue * zoom;
     returnPoint.Y = (tempCam.position.y - vec.y) / zValue * zoom;

     return returnPoint;

Let’s go over the code. The truth is this is the most basic form of 3D projection. The X and Y values are simply x/z and y/z of the 3D point. Only, we are factoring in the position of the perspective, or camera, which we placed at the center of the cube. The last key factor is the zoom variable. When projecting 3D points into a 2D surface, we have to factor in the area. In a smaller area, the cube would be more squished and vice versa. In this case, we use the width of the entire screen to keep straight lines in the cube parallel/perpendicular to the entire screen.

Shading the Cube

At last, time to shade in the cube. Believe it or not, it will be very simple, thanks to all the time we spent creating a solid foundation. Fittingly, a cube face will be shaded based on the 2D points already projected. Since the four corners could create any random quadrilateral, it is best to use the FillPolygon function:

g.FillPolygon(Brushes.Gray, GetTopFace());

where g is the Graphics object drawing to whatever surface is appropriate. Also, don’t worry about the GetTopFace() call, it’s in the source code, and all it does is it finds the 2D corner points of the cube face (the top face in this example).

Now, a bit of reasoning will reveal that shading the faces at a specific order will not always display correctly. The order in which we want to fill in the cube’s faces depends on which way the cube is facing.

Luckily, that’s what the CompareTo function in the Face class is for. We can add all the faces into an array, sort the array, and then iterate through it. Remember that the faces are sorted based on the z value of their center. That means the closest ones to the screen will be first. These are actually the last ones that should be filled. Thus, we iterate through the array backwards, starting from the end.


The result is impressive considering that it is all done with GDI+. A further improvement will be to create shading based on lighting. That, however, is beyond the scope of this article. For now, the sides are shaded based on a color specified.


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

Written By
United States United States
Visit Visual C# Kicks for more free C#.NET articles, resources, and downloads at

Comments and Discussions

Question2 cubes in picture Pin
CristianoCronos1-May-17 19:38
MemberCristianoCronos1-May-17 19:38 
GeneralMy vote of 5 Pin
kburman62-Apr-13 8:45
professionalkburman62-Apr-13 8:45 
GeneralZero position Pin
PCHRIST12317-Mar-11 0:53
MemberPCHRIST12317-Mar-11 0:53 
QuestionMove cube Pin
csit_shagrat28-Nov-10 5:09
Membercsit_shagrat28-Nov-10 5:09 
AnswerRe: Move cube Pin
csit_shagrat29-Nov-10 8:05
Membercsit_shagrat29-Nov-10 8:05 
GeneralRe: Move cube Pin
VCSKicks29-Nov-10 9:55
MemberVCSKicks29-Nov-10 9:55 
GeneralRe: Move cube Pin
csit_shagrat29-Nov-10 21:47
Membercsit_shagrat29-Nov-10 21:47 
GeneralRe: Move cube Pin
ishan2ma3-Dec-11 4:16
Memberishan2ma3-Dec-11 4:16 
QuestionUsage with VB? WinForm-Control? Pin
Member 44427726-Aug-09 3:34
MemberMember 44427726-Aug-09 3:34 
QuestionHow to rotate this cube along X and Y axis on buttonclick? Pin
rajesh kumar swain1-Jan-09 23:10
Memberrajesh kumar swain1-Jan-09 23:10 
AnswerRe: How to rotate this cube along X and Y axis on buttonclick? Pin
VCSKicks2-Jan-09 9:41
MemberVCSKicks2-Jan-09 9:41 
GeneralThis is amazing Pin
Chrisblackwell19-Oct-08 6:03
MemberChrisblackwell19-Oct-08 6:03 
GeneralRe: This is amazing Pin
VCSKicks19-Oct-08 8:37
MemberVCSKicks19-Oct-08 8:37 
GeneralRe: This is amazing Pin
Chrisblackwell11-Nov-08 10:03
MemberChrisblackwell11-Nov-08 10:03 
GeneralRe: This is amazing Pin
VCSKicks11-Nov-08 19:51
MemberVCSKicks11-Nov-08 19:51 
QuestionHow to resize Cube? Pin
hungud16-Aug-08 0:00
Memberhungud16-Aug-08 0:00 
AnswerRe: How to resize Cube? Pin
VCSKicks17-Aug-08 21:31
MemberVCSKicks17-Aug-08 21:31 
QuestionDrawing Bitmaps Pin
FlaryCZ21-Jul-08 10:52
MemberFlaryCZ21-Jul-08 10:52 
AnswerRe: Drawing Bitmaps Pin
VCSKicks23-Jul-08 8:29
MemberVCSKicks23-Jul-08 8:29 
GeneralSample works Great, but Sources Don't! Pin
schamese9-Jul-08 5:01
Memberschamese9-Jul-08 5:01 
GeneralRe: Sample works Great, but Sources Don't! Pin
VCSKicks9-Jul-08 7:33
MemberVCSKicks9-Jul-08 7:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.