Creating Rendered Cubic Environment Maps
 
 
 

Cubic environment maps provide a fast and attractive way to simulate a one-bounce ray trace. The object to which a cubic environment (sometimes called a cubic reflection) map is applied, appears to reflect its environment. This tutorial will demonstrate a method for creating cubic environment maps for two types of reflections. The first will show how to create the reflection map for a non-planar object in the scene, and the second will show how to create a reflection map for a reflective plane (that is, a floor or a wall).

Road Map

The basic steps involved in creating the reflection map files are as follows:

  1. Copy the original SDL file to a different “special” SDL file.
  2. Edit the special SDL file, remove the object that we are creating the reflection map for.
  3. Change the name of the output file.
  4. Change the eye position, twist, fov, resolution and aspect ratio
  5. Add the animation of the view direction
  6. Finish editing the special SDL file.
  7. Render the special SDL file.
  8. Edit the original SDL file to add the reflection map to the proper shader.
  9. Render the original SDL file.

Reflection Map for a Non-planar Object in the Scene

A cubic environment map requires six pix files that show what is seen along each of the positive and negative axes directions from a spiced point. It is the specification of the point that allows us to create the reflection map for certain types of reflections.

Let us assume that we want to render a cubic reflection map for a sphere that is inside a room:

Sphere to be reflection mapped

In order to create a reflection map of what is seen from the sphere, we must create a special SDL file. This file will have an eye point positioned at the centre of the sphere (or at the center of whatever object we want). This file will NOT contain the sphere, however. This is because if the sphere were in the SDL file, when we render from the centre of the sphere all we will see is the inside of the sphere and not what is around the sphere (its environment). It is important to always remove the object that we are creating the environment map for from this special SDL file.

Once the eye point is placed at the centre of the object, and that object is removed from this special SDL file, we must insert the animation statements for the eye direction.

Let us assume that the centre of our sphere (and thus, our eye) is at (0, 0, 0). The first thing we do is remove the “view” statement from the MODEL section and replace it with a new camera. It is very important to change the field’s fov to 90.0, twist to 0.0, and aspect to 1.0. Our camera section now looks like:

camera (eye = (0, 0, 0),
	view = camera_view,
	fov = 90,
	viewport = (0.0, 255.0, 0.0, 255.0),
	aspect = (1.0)
);

In order to use this camera, it must be defined in the DEFINITION section:

triple camera_view (0.0, 0.0, 0.0);

In order to create the pix files from this little animation, the DEFINITION section must include:

startframe = 1;
endframe = 6;

It is also important to remember that we are creating pix files that are to be used as texture maps, so the resolution should be one of 256, 512, 1024, and so on.

The final step is to add animation to the MODEL section, also as described in this manual:

if (	frame == 1.0 ) camera_view = (1.0, 0.0, 0.0);
else if	(frame == 2.0 ) camera_view = (-1.0, 0.0, 0.0);
else if	(frame == 3.0 ) camera_view = (0.0, 1.0, 0.0);
else if	(frame == 4.0 ) camera_view = (0.0, -1.0, 0.0);
else if	(frame == 5.0 ) camera_view = (0.0, 0.0, -1.0);
else if	(frame == 6.0 ) camera_view = (0.0, 0.0, 1.0);

After rendering this special SDL file, we return to the original SDL file and add the reflection map to the shader that corresponds to the object (in this case, a sphere).

shader AAA ( model = phong,
	diffuse = 0.800000,
	shinyness = 10.000000,
	color = (0.0, 0.0, 0.0),
	specular = (0.800000, 0.800000, 0.800000),
	reflectivity = 1.0,
	reflection = texture(procedure = Cube,
	right = "pix/special.1",
	left = "pix/special.2",
	top = "pix/special.3",
	bottom = "pix/special.4",
	front = "pix/special.6",
	back = "pix/special.5"
	)
 );

The sphere will now have a reflection of the environment on it.

Reflection Map for a Reflective Plane

The first section described how to create and use a reflection map for an object in the scene. Creating reflection maps for planar objects (say a shiny floor) is done in a different manner.

Creating a reflection map for a planar object is easiest if the planar object lies on one of the XY, YZ, or XZ planes. If this is not the case, then calculation of the eye point for the special SDL file is difficult, but it can still be done.

Let’s start with the simplest case. We have a planar object that lies on the XZ plane (see below). For simplicity, we will refer to this planar object as the floor of our modeled room, in a Y-up environment.

Reflection map for planar object

What we will do, in effect, is mirror our eye point in the floor. The equation to do this mirroring for the example above is:

eye_Y' = floor_y – (eye_y – floor_y) (1)

Substituting in our values from the example and solving:

eye_Y' = 2.0 – (5.0 – 2.0)

eye_Y' = 2.0 – (3.0)

eye_Y' = –1.0

So, in our special SDL file, we change only the eye’s Y value to be this new Y' value. We then replace the “view” statement with a new view statement as with the first example. For example, if the CAMERA section was

Camera (
	eye = (3.0, 5.0, –2.0),
	view = (0.3, 1.2, 9.3),
	fov = 40.0,
	aspect = 1.316
);

then we would change it to

camera (
	eye = (3.0, -1.0, –2.0),
	view = camera_view,
	fov = 90,
	viewport = (0.0, 255.0, 0.0, 255.0),
	aspect = (1.0)
);

and, as before, we would change the output pixel resolution to one of 256, 512, 1024, 2048, and so on, and add the animation to the MODEL section for x_dir, y_dir, and z_dir. This special SDL file is rendered and the reflection map is applied to the floor’s surface descriptor in the original SDL file. Remember to remove the floor in the special SDL.

If the planar object is not on the XZ plane, then the modified coordinate can be found by substitution of X for Y in equation (1) if the object lies in the YZ plane or by substituting Z for Y in equation (1) if the object lies in the XY plane.

If the planar object does not lie in one of the above planes, then it becomes more difficult to calculate the new eye point, and it requires a lot more math.

Let’s say that our planar object is described as a face that has the following points in the SDL file:

X Y Z

V1 –0.4183 –4.64 2.5132

V2 –3.905 –1.084 2.5716

V3 0.114 3.2474 –1.6657

V4 4.1738 –0.3513 –2.0018

And assume that the eye is at (0.5, 0.5, 12).

Now, in order to reflect the eye point in this plane, we will need a normal to this plane. To calculate the normal, we need 3 of the vertices of the planar object. Let us arbitrarily choose V1, V2 and V3, which from inspection of the wire frame, we know do not lie in a straight line (in mathematical terms, the points are not co-linear).

DX2 = V2.X – V1.X (2)

DX3 = V3.X – V1.X (3)

DY2 = V2.Y – V1.Y (4)

DY3 = V3.Y – V1.Y (5)

DZ2 = V2.Z – V1.Z (6)

DZ3 = V3.Z – V1.Z (7)

The results of equations (2) through (7) are then used to compute:

L = DY2 *DZ3 – DY3 * DZ2 (8)

M = DX3 * DZ2 – DX2 * DZ3 (9)

N = DX2 * DY3 – DX3 * DY2 (10)

R = L * L + M * M + N * N (11)

R = SQRT(R) (12)

L = L/R (13)

M = M/R (14)

N = N/R (15)

P = L * V1.X + M * V1.Y + N * V1.Z (16)

Now, you might think that all of that is far too much math for one day, but we’re not done yet. (SQRT(R) in equation (12) means that we want the square root of the number represented by R.)

The distance of the eye point from this plane is calculated by:

D = L * EYE_X + M * EYE_Y + N * EYE_Z + P (17)

If D is negative, then the new eye point is given by:

D = 2 * (–D)

EYE_X' = EYE_X + D * L (18)

EYE_Y' = EYE_Y + D * M

EYE_Z' = EYE_Z + D * N

If D is positive, then the new eye point is given by:

D = 2 * D

EYE_X' = EYE_X + D * (–L) (19)

EYE_Y' = EYE_Y + D * (–M)

EYE_Z' = EYE_Z + D * (–N)

If D turns out to be equal to 0.0, then the eye point is on the plane and you should not create a reflection map for this object, because a mirror viewed “side on” does not reflect anything.

Returning to our example and placing the values into equations (2) through (7) we get:

DX2 = –3.905 – –0.4183 = -3.4867

DX3 = 0.114 – –0.4183 = 0.5323

DY2 = –1.084 – –4.64 = 3.556

DY3 = 3.2474 – –4.64 = 7.8874

DZ2 = 2.5716 – 2.5132 = 0.584

DZ3 = –1.6657 – 2.5132 = –4.1789

Placing these values into equations (8) through (10) we get:

L = 3.556 * –4.1789 – 7.8874 * 0.584 = -19.46641

M = 0.5323 * 0.584 – –3.4867 * –4.1789 = –14.2597

N = –3.4867 * 7.8874 – 0.5323 * 3.556 = –29.39385

Using these values in equations (11) and (12) we get:

R = –19.46641 * –19.46641 + –14.2597 * –14.2597 + –29.39385 * –29.39385

= 1446.27858

R = SQRT (1446.27858) = 38.02997

Then applying equations (13) to (15) we get:

L = –19.46641/38.02997 = –0.51187

M = –14.2597/38.02997 = –0.37496

N = –29.39385/38.02997 = –0.77291

Then we take a break to catch our breath and continue by applying equation (16) to these numbers:

P = –0.51187 * –0.4183 + –0.37496 * –4.64 + –0.77291 * 2.5132 = 0.011452

After applying equation (17) we get:

D = –0.51187 * 0.5 + –0.37496 * 0.5 + –0.77291 * 12.0 + 0.011452 = –9.70688

We can see that D is negative, so we apply equation (18):

D = 2 * (– –9.70688) = 2 * 9.70688 = 19.41376

Note that the negative of a negative number is a positive number, and continue with equation (18):

EYE_X' = 0.5 + 19.41376 * –0.51187 = –9.43732

EYE_Y' = 0.5 + 19.41376 * –0.37496 = –6.77938

EYE_Z' = 12.0 + 19.41376 * –0.77291 = –3.0051

Now that we have our new eye point, we go back to our special SDL file, and replace all three eye components:

eye = (–9.43732, –6.77938, –3.0051),

And again, as before, we replace the rest of the camera data, set the proper resolution, add the animation to the MODEL section and render this special SDL file to create the reflection map.

Notes and Limitations

Shadows do not show up on surfaces that get all of their color from a reflection map. In order for a shadow to appear on a reflection-mapped surface, the surface must have a non-zero diffuse value.

A reflection-mapped object does not reflect itself. For example, a teapot will not reflect its spout, but it will reflect the rest of the scene. This is because we have to remove the object which will reflect from the special SDL file we create. To get proper reflections of an object with itself requires ray tracing. This method provides a cheaper alternative to ray tracing.

The methods for creating reflection maps described in this tutorial are for a static object in the “reflection maps for an object” case and for a static object and eye in the “reflection maps for planar surfaces” case. Should you wish to create high quality reflections for a moving object in an animation, then a new reflection map will have to be created for each frame of the animation. In the case of planar objects, some time can be saved by noting that some of the reflection map views do not “see” anything and are therefore black. These views only need to be created once for the entire animation.