13,152,321 members (42,137 online)
alternative version

#### Stats

70.7K views
56 bookmarked
Posted 8 Jul 2008

# 3D Graphics - Cube with Shading

, 8 Jul 2008
 Rate this:
Create a cube you can rotate and shade using only GDI+.

## Introduction

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.

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.

## Conclusion

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.

## Share

 United States
Visit Visual C# Kicks for more free C#.NET articles, resources, and downloads at
http://www.vcskicks.com

## You may also be interested in...

 First Prev Next
 2 cubes in picture CristianoCronos1-May-17 19:38 CristianoCronos 1-May-17 19:38
 My vote of 5 kburman62-Apr-13 8:45 kburman6 2-Apr-13 8:45
 Zero position PCHRIST12317-Mar-11 0:53 PCHRIST123 17-Mar-11 0:53
 Move cube csit_shagrat28-Nov-10 5:09 csit_shagrat 28-Nov-10 5:09
 Re: Move cube csit_shagrat29-Nov-10 8:05 csit_shagrat 29-Nov-10 8:05
 Re: Move cube VCSKicks29-Nov-10 9:55 VCSKicks 29-Nov-10 9:55
 Re: Move cube csit_shagrat29-Nov-10 21:47 csit_shagrat 29-Nov-10 21:47
 Re: Move cube ishan2ma3-Dec-11 4:16 ishan2ma 3-Dec-11 4:16
 Usage with VB? WinForm-Control? Member 44427726-Aug-09 3:34 Member 4442772 6-Aug-09 3:34
 How to rotate this cube along X and Y axis on buttonclick? rajesh kumar swain1-Jan-09 23:10 rajesh kumar swain 1-Jan-09 23:10
 Re: How to rotate this cube along X and Y axis on buttonclick? VCKicks2-Jan-09 9:41 VCKicks 2-Jan-09 9:41
 This is amazing Chrisblackwell19-Oct-08 6:03 Chrisblackwell 19-Oct-08 6:03
 Re: This is amazing VCKicks19-Oct-08 8:37 VCKicks 19-Oct-08 8:37
 Re: This is amazing Chrisblackwell11-Nov-08 10:03 Chrisblackwell 11-Nov-08 10:03
 Re: This is amazing VCKicks11-Nov-08 19:51 VCKicks 11-Nov-08 19:51
 How to resize Cube? hungud16-Aug-08 0:00 hungud 16-Aug-08 0:00
 Re: How to resize Cube? VCKicks17-Aug-08 21:31 VCKicks 17-Aug-08 21:31
 Drawing Bitmaps FlaryCZ21-Jul-08 10:52 FlaryCZ 21-Jul-08 10:52
 Re: Drawing Bitmaps VCKicks23-Jul-08 8:29 VCKicks 23-Jul-08 8:29
 Sample works Great, but Sources Don't! schamese9-Jul-08 5:01 schamese 9-Jul-08 5:01
 Re: Sample works Great, but Sources Don't! VCKicks9-Jul-08 7:33 VCKicks 9-Jul-08 7:33
 Last Visit: 31-Dec-99 18:00     Last Update: 26-Sep-17 10:14 Refresh 1