Environment Maps
Environment mapping was one of the first cool effects people used texture
maps with. The concept is quite simple: You want a polygon to be able to
reflect the scene, as if it were a mirror or shiny surface like chrome. There
are two primary ways to do it that Direct3D supports: spherical environ-
ment maps and cubic environment maps.
Spherical Environment Maps
Spherical environment maps are one of those classic horrible hacks that
happens to look really good in practice. It isn’t a perfect effect, but it’s
more than good enough for most purposes.
The environment mapping maps each vertex into a u,v pair in the
spherical environment map. Once you have the locations in the sphere
map for each vertex, you texture map as normal. The sphere map is called
that because the actual picture looks like the scene pictured on a sphere.
Real photos are taken with a 180-degree field of view camera lens, or
using a ray-tracer to prerender the sphere map. Rendering a texture like
this is complex enough that it is infeasible to try to do it in real time; it
must be done as a preprocessing step. An example of a sphere map texture
appears in Figure 9.19.
446 n Chapter 9: Advanced Direct3D
Figure 9.18:
Quake III: Arena with
light maps
Courtesy of id Software
The region outside of the circle in the above image is black, but it can be
any color; you’re never actually going to be addressing from those coordi-
nates, as you’ll see in a moment.
Note: You can use any texture as a sphere map. Just load it up into Photoshop
and run it through the Polar Coordinates filter.
Once you have the spherical texture map, the only task left to do is gener
ate the texture coordinates for each vertex. Here comes the trick that runs
the algorithm:
The normal for each vertex, when transformed to view space, will vary
along each direction from –1 to 1. What if you took just the x and y com
ponents and mapped them to (0,1)? You could use the following equation:
You know that the radius of the 2D vector <n
> will vary between 0
(when z is 1.0 and the normal is facing directly toward the viewer) and 1
(when z is 0.0 and the normal is perpendicular to the viewer). When n
and n
are 0, you’ll get a u,v pair of <0.5,0.5>. This is exactly what was
Chapter 9: Advanced Direct3D n 447
Figure 9.19:
Courtesy of nVidia Corporation
wanted: The vertex whose normal is pointing directly toward us should
reflect the point directly behind us (the point in the center of the sphere
map). The vertices along the edges (with radius 1.0) should reflect the
regions on the edge of the sphere map. This is exactly what happens.
As you can see in Figure 9.20, this environment mapping method can
give really nice-looking results.
One caveat of this rendering method is that the sphere map must remain
the same, even if the camera moves. Because of this, it often isn’t useful to
reflect certain types of scenes; it’s best suited for bland scenery like
There are some mechanisms used to attempt to interpolate correct
positions for the spherical environment map while the camera is moving,
but they are far from perfect. They suffer from precision issues; while
texels in the center of the sphere map correspond to relatively small
changes in normal direction, near the edges there are big changes, and an
infinite change when you reach the edge of the circle. This causes some
noticeable artifacts, as evidenced in Figure 9.21. Again, these artifacts only
pop up if you try to find the sphere map location while the camera is mov
ing. If your sphere map setup does not change, none of this happens.
448 n Chapter 9: Advanced Direct3D
Figure 9.20:
In a lot of cases
spherical environ-
ment mapping
looks great.
Courtesy of nVidia Corporation
Calculating Spherical Coordinates in HLSL
Check out this code example, which calculates the spherical coordinates
and saves them in vTexCoords2.
VS_OUTPUT result;
float4 vPos = float4(dataIn.vPosition, 1.0f);
float4 vWorldPos = mul(vPos, g_mtxWorld);
float4 vViewPos = mul(vWorldPos, g_mtxView);
float4 vScreenPos = mul(vViewPos, g_mtxProj);
result.vPosition = vScreenPos;
result.vColor = dataIn.vColor;
result.vTexCoords1 = dataIn.vTexCoords1;
float3 vViewNormal =
normalize(mul(mul(dataIn.vNormal, g_mtxWorld), g_mtxView));
result.vNormal = vViewNormal;
float3 vReflection = normalize(reflect(vViewPos, vViewNormal));
Chapter 9: Advanced Direct3D n 449
Figure 9.21:
Warping artifacts
Courtesy of nVidia Corporation

Get Advanced 3D Game Programming with DirectX 10.0 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.