Introduction to 3D Game Programming with DirectX.9.0 - F. D. Luna
.pdf
24 Part I
1 |
0 |
0 |
0 |
|
|
|
|
|
|
T 1, 2, 3 0 1 0 |
0 |
|
||
0 |
0 |
1 |
0 |
|
|
|
3 |
|
|
1 |
2 |
1 |
||
Applying the sequence of transformations in the order scaling, rotating, and translating, we obtain:
|
pS 1, |
0, 0, |
1 p |
|
|
|
Y |
|||
(5) |
p R |
y |
|
.707, |
0, |
.707, |
1 |
p |
||
|
|
|
|
|
|
|
|
|||
|
|
|
1.707, |
2, |
3.707, |
1 |
|
|||
|
p T |
|
||||||||
|
|
|
|
|
|
|
|
|
L |
|
One of the key benefits of matricesFis that we can use matrix multiplication to combine several transformations into one matrix. For
example, let’s reconsider the example at the beginning of this section. |
||||||||||||||||||||
|
|
|
|
|
|
|
|
|
M |
|
|
|
|
|
|
|
|
|
||
Let’s combine the three transformation matrices into one matrix repre- |
||||||||||||||||||||
senting all three throughAmatrix multiplication. Note that the order in |
||||||||||||||||||||
which we multiply the transformations is the order that they are |
|
|
||||||||||||||||||
applied. |
|
|
|
E |
|
|
|
|
|
|
|
|
|
|
|
|||||
T |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
0 |
0 |
|
0 |
.707 |
0 |
.707 |
0 |
|
1 |
0 |
0 |
0 |
|
||
|
|
5 |
|
|||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
SR y T |
0 |
|
0 |
|
0 |
0 |
1 |
0 |
0 0 1 0 0 |
|||||||||||
5 |
||||||||||||||||||||
|
|
|
|
|
|
1 |
|
|
|
.707 |
0 |
.707 |
0 0 |
0 |
1 |
0 |
||||
|
|
|
0 |
|
0 |
|
0 |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
0 |
0 |
|
|
|
|
|
||||||
|
|
|
5 |
|
|
|
|
|
|
|||||||||||
(6) |
|
|
|
|
|
|
0 |
1 1 2 |
3 1 |
|||||||||||
|
|
|
|
0 |
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
0 |
|
1 |
|
|
|
|
|
|
|
|
|
|
||||||
.1414 |
|
0 |
.1414 |
|
0 |
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 |
|
1 |
|
0 |
|
|
|
0 Q |
|
|
|
|
|
|
|
|
|
||
.1414 |
|
0 |
|
.1414 |
|
|
0 |
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
||
|
1 |
|
2 |
|
|
|
1 |
|
|
|
|
|
|
|
|
|
||||
Then pQ = [1.707, 2, –3.707, 1].
The ability to combine transformations has performance implications. Suppose that we need to apply the same scaling, rotation, and translation transformations to a large set of vectors (a common task in 3D graphics). Instead of applying a sequence of transformations, as we did in equation (5), per vector, we can combine all three transformations into one matrix, as we did in equation (6). Then we only have to
Team-Fly®
Mathematical Prerequisites
multiply each vector by one matrix that contains all three transformations combined. This saves a significant amount of vector-matrix multiplication operations.
Some Functions to Transform Vectors
The D3DX library provides the following two functions for transforming points and vectors, respectively. The D3DXVec3TransformCoord function transforms points and assumes the fourth component of the vector is an understood 1. The D3DXVec3TransformNormal function transforms vectors and assumes the fourth component of the vector is an understood 0.
D3DXVECTOR3 *D3DXVec3TransformCoord( |
|
|
D3DXVECTOR3* pOut, |
// Result. |
|
CONST D3DXVECTOR3* pV, |
// The point to transform. |
|
CONST D3DXMATRIX* pM |
// The transformation matrix. |
|
); |
|
|
D3DXMATRIX T(...); |
// initialize a transformation matrix |
|
D3DXVECTOR3 p(...); |
// initialize a point |
|
D3DXVec3TransformCoord( &p, &p, &T); |
// transform the point |
|
D3DXVECTOR3 *WINAPI D3DXVec3TransformNormal( |
||
D3DXVECTOR3 *pOut, |
// Result. |
|
CONST D3DXVECTOR3 *pV, |
// The vector to transform. |
|
CONST D3DXMATRIX *pM |
// The transformation matrix. |
|
); |
|
|
D3DXMATRIX T(...); |
// initialize a transformation matrix |
|
D3DXVECTOR3 v(...); |
// initialize a vector |
|
D3DXVec3TransformNormal( &v, &v, &T); |
// transform the vector |
|
Note: The D3DX library also provides D3DXVec3TransformCoordArray and D3DXVec3TransformNormalArray for transforming an array of points and an array of vectors, respectively.
25
P a r t I
Planes (Optional)
A plane can be described with a vector n and a point on the plane p0. The vector n is called the plane’s normal vector and is perpendicular to the plane (see Figure 11).
Figure 11: A plane defined by a normal vector n and a point on the plane p0
26 Part I
In Figure 12 we see that the graph of a plane is all the points p that satisfy the equation.
(7) n p p0 0
Figure 12: If p0 is a point on the plane, then the point p is also on the plane if the vector formed from (p – p0) is orthogonal to the plane’s normal vector.
When describing a particular plane, the normal n and a known point on the plane p0 are fixed, so it is typical to write equation (7) as:
(8)n p d 0
where d = –n p0.
Note: If the plane’s normal vector n is of unit length, d = –n p0 gives the shortest signed distance from the origin to the plane.
D3DXPLANE
When representing a plane in code, it suffices to store only the normal vector n and the constant d. It is useful to think of this as a 4D vector, which we denote as (n, d). The D3DX library uses the following structure for a plane:
typedef struct D3DXPLANE
{
#ifdef __cplusplus public:
D3DXPLANE() {}
D3DXPLANE( CONST FLOAT* ); D3DXPLANE( CONST D3DXFLOAT16* );
D3DXPLANE( FLOAT a, FLOAT b, FLOAT c, FLOAT d );
//casting operator FLOAT* ();
operator CONST FLOAT* () const;
//unary operators
D3DXPLANE operator + () const;
D3DXPLANE operator - () const;
// binary operators
BOOL operator == ( CONST D3DXPLANE& ) const; BOOL operator != ( CONST D3DXPLANE& ) const;
Mathematical Prerequisites
#endif //__cplusplus FLOAT a, b, c, d;
} D3DXPLANE, *LPD3DXPLANE;
where a, b, and c form the components of the plane’s normal vector n and d is the constant d, from equation (8).
27
P a r t I
Point and Plane Spatial Relation
Equation (8) is primarily useful for testing the location of points relative to the plane. For example, given the plane (n, d), we can test how a particular point p is in relation with the plane:
If n p + d = 0, then p is coplanar with the plane.
If n p + d > 0, then p is in front of the plane and in the plane’s positive half-space.
If n p + d < 0, then p is in back of the plane and in the plane’s negative half-space.
Note: If the plane’s normal vector n is of unit length, then n p + d gives the shortest signed distance from the plane to the point p.
This next D3DX function evaluates n p + d for a particular plane and point:
FLOAT D3DXPlaneDotCoord( |
|
CONST D3DXPLANE *pP, |
// plane. |
CONST D3DXVECTOR3 *pV |
// point. |
); |
|
// Test the locality of a point relative to a plane. D3DXPLANE p(0.0f, 1.0f, 0.0f, 0.0f);
D3DXVECTOR3 v(3.0f, 5.0f, 2.0f);
float x = D3DXPlaneDotCoord( &p, &v );
if( x approximately equals 0.0f ) if( x > 0 )
if( x < 0 )
//v is coplanar to the plane.
//v is in positive half-space.
//v is in negative half-space.
Note: We say “approximately equals” due to floating-point imprecision. See the note in the section titled “Vector Equality.”
Note: Methods similar to D3DXPlaneDotCoord are D3DXPlaneDot and D3DXPlaneDotNormal. See the DirectX documentation for details.
Construction
Besides directly specifying the normal and signed distance of a plane, we can calculate these two components in two ways. Given the normal n and a known point on the plane p0, we can solve for the d component:
28 Part I
n p0 d 0 n p0 dn p0 d
The D3DX library provides the following function to perform this calculation:
D3DXPLANE *D3DXPlaneFromPointNormal(
D3DXPLANE* pOut, |
// Result. |
CONST D3DXVECTOR3* pPoint, |
// Point on the plane. |
CONST D3DXVECTOR3* pNormal |
// The normal of the plane. |
); |
|
The second way that we can construct a plane is by specifying three points on the plane.
Given the points p0, p1, p2, we can form two vectors on the plane:
up1 p0
vp2 p0
From that we can compute the normal of the plane by taking the cross product of the two vectors on the plane. Remember the left hand thumb rule.
n u v
Then, –(n p0) = d.
The D3DX library provides the following function to compute a plane, given three points on the plane:
D3DXPLANE *D3DXPlaneFromPoints( |
|
|
D3DXPLANE* pOut, |
// Result. |
|
CONST D3DXVECTOR3* pV1, |
// Point 1 |
on the plane. |
CONST D3DXVECTOR3* pV2, |
// Point 2 |
on the plane. |
CONST D3DXVECTOR3* pV3 |
// Point 3 |
on the plane. |
); |
|
|
Normalizing a Plane
Sometimes we might have a plane and would like to normalize the normal vector. At first thought, it would seem that we could just normalize the normal vector as we would any other vector. But recall that
d = –n p0 in n p + d = 0. We see that the length of the normal vector
influences the constant d. Therefore, if we normalize the normal vector,
d n 
n


n

Mathematical Prerequisites
Thus, we have the following formula to normalize the normal vector of the plane (n, d):
1 |
|
|
n |
|
d |
|
|
||
|
|
n, |
d |
|
|
, |
|
|
|
|
|
|
|
|
|
||||
|
n |
|
|
n |
|
n |
|
|
|
We can use the following D3DX function to normalize a plane’s normal |
|||||||||
vector: |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
D3DXPLANE *D3DXPlaneNormalize( |
|
||||||||
|
|
D3DXPLANE *pOut, |
|
// Resulting normalized plane. |
|||||
|
|
CONST D3DXPLANE *pP |
// Input plane. |
||||||
); |
|
|
|
|
|
|
|
|
|
Transforming a Plane
Lengyel shows in Mathematics for 3D Game Programming & Computer
|
|
Graphics that we can transform a plane (n, d) by treating it as a 4D vec- |
|
tor and multiplying it by the inverse-transpose of the desired transfor- |
|
mation matrix. Note that the plane’s normal vector must be normalized |
|
first. |
|
We use the following D3DX function to do this: |
|
|
|
D3DXPLANE *D3DXPlaneTransform( |
|
D3DXPLANE *pOut, |
// Result |
CONST D3DXPLANE *pP, |
// Input plane. |
CONST D3DXMATRIX *pM |
// Transformation matrix. |
); |
|
Sample code: |
|
D3DXMATRIX T(...); |
// Init. T to a desired transformation. |
D3DXMATRIX inverseOfT;
D3DXMATRIX inverseTransposeOfT;
D3DXMatrixInverse( &inverseOfT, 0, &T );
D3DXMatrixTranspose( &inverseTransposeOfT, &inverseOfT );
D3DXPLANE p(...); |
// Init. Plane. |
D3DXPlaneNormalize( &p, &p ); // make sure normal is normalized. |
|
D3DXPlaneTransform( &p, &p, &inverseTransposeOfT ); |
|
Nearest Point on a Plane to a Particular Point
Suppose that we have a point p in space and would like to find the point q on the plane (n, d) that is closest to p. Note that the plane’s normal vector is assumed to be of unit length—this simplifies the problem a bit.
29
P a r t I
30 Part I
Figure 13: The point q on the plane (n d) nearest to p. Observe that the shortest signed distance k from p to the plane is positive, since p is in the positive half-space of (n d). If p was behind the plane, then k < 0.
From Figure 13 we can see that q = p + (–kn), where k is the shortest signed distance from p to the plane, which is also the shortest signed distance between the points p and q. Recall that if the plane’s normal vector n is of unit length, then n p + d gives the shortest signed distance from the plane to the point p.
Rays (Optional)
Suppose a player in a game that we are working on fires his gun at an enemy. How would we determine whether the bullet starting from a particular position and aimed in a direction hit the target? One approach would be to model the bullet with a ray and model the enemy with a bounding sphere. (A bounding sphere is simply a sphere that tightly surrounds an object, thus roughly approximating its volume. Bounding spheres are explained more in Chapter 11.) Then mathematically we can determine whether the ray hit the sphere and where. In this section we learn how to model rays mathematically.
Rays
A ray can be described with an origin and a direction. The parametric equation of a ray is:
(9) p t p0 tu
Figure 14: A ray described by an origin p0 and direction u. We can generate points on the ray by plugging in scalars for t that are greater than or equal to zero.
Mathematical Prerequisites
p0 is the origin of the ray, u is the direction of the ray, and t is the parameter. By plugging in different values for t, we compute different points on the ray. The parameter t must be in the interval [0, ) to describe a ray. Values less than zero will generate points behind the ray (that is, on the line that the ray is on). In fact, if we let t (– , ), then we have a line in 3-space.
Ray/Plane Intersection
Given a ray p(t) = p0 + tu and a plane n p + d = 0, we would like to know if the ray intersects the plane and the point of intersection. To do this, we plug the ray into the plane equations and solve for the parameter t that satisfies the plane equation, giving us the parameter that yields the intersection point.
Plugging equation (9) into the plane equation:
31
P a r t I
n p t d 0 |
Plug ray into plane equation |
n p0 tu d 0 |
|
n p0 n tu d 0 n tu d n p0 t n u d n p0
t |
d n p |
0 |
|
n u |
|
|
|
|
|
|
|
Distributive property
Associative property
Solve for t.
If t is not in the interval [0, ), the ray does not intersect the plane.
If t is in the interval [0, ), the intersection point is found by plugging the parameter that satisfies the plane equation into the ray equation:
|
d n p |
|
|
|
d n p |
0 |
|
||
p |
|
0 |
p |
|
|
|
|
u |
|
|
|
0 |
|
|
|
||||
|
n u |
|
|
|
n u |
|
|
|
|
|
|
|
|
|
|
||||
32 Part I
Summary
Vectors are used to model physical quantities that possess a magnitude and direction mathematically. Geometrically, we represent a vector with a directed line segment. A vector is in standard position when it is translated parallel to itself so that its tail coincides with the origin of the coordinate system. A vector in standard position can be described algebraically by specifying the coordinates of its head.
We can use 4 4 matrices to represent transformations and 1 4
homogeneous vectors to describe points and vectors. The vectormatrix product of a 1 4 row vector and a 4 4 transformation matrix results in a new transformed 1 4 row vector. Several transformation matrices can be combined into one transformation matrix through matrix-matrix multiplication.
We use 4D homogeneous vectors to represent both vectors and
points. We specify 0 for the w component to denote a vector and 1 for the w component to denote a point. If w 0 and w 1, then we have a vector (x, y, z, w) in homogeneous space that can be mapped back to 3-space by dividing each component by w:
x |
|
y |
|
z |
|
w x |
|
y |
|
z |
|
|
x |
|
y |
|
z |
|||||
|
|
, |
|
, |
|
, |
|
|
|
|
, |
|
, |
|
, 1 |
|
|
, |
|
, |
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
w w w w |
w w w |
|
w w w |
|||||||||||||||||||
Planes divide 3D space into two parts: a positive half-space, which is the space in front of the plane, and a negative half-space, which is the space behind the plane. Planes are useful for testing the locality of points relative to them (in other words, what half-space a point exists in relative to a particular plane).
Rays are described parametrically with an origin and direction vector. Rays are useful for modeling various physical quantities, such as light rays and projectiles that approximately follow a linear path such as bullets and rockets.
Part II
Direct3D
Fundamentals
In this part, we study fundamental Direct3D concepts and techniques that are used throughout the rest of this book. With these fundamentals mastered, we can move on to writing more interesting applications. A brief description of the chapters in this part follows.
Chapter 1, “Direct3D Initialization”—In this chapter, we learn what Direct3D is about and how to initialize it in preparation for 3D drawing.
Chapter 2, “The Rendering Pipeline”—The first theme of this chapter is to learn, mathematically, how to describe a 3D world and represent a virtual camera that describes the perspective from which the world is viewed. The second theme is to learn the steps necessary to take a 2D “picture” of the 3D world based on what the camera “sees”; these steps as a whole are referred to as the rendering pipeline.
Chapter 3, “Drawing in Direct3D”—This chapter shows how to draw 3D geometry in Direct3D. We learn how to store geometric data in a form that is usable by Direct3D, and we learn the Direct3D drawing commands. In addition, we learn how to configure the way that Direct3D draws geometry using render states.
Chapter 4, “Color”—In this chapter, we learn how color is represented in Direct3D and how to apply color to solid 3D geometric primitives. Finally, we describe two ways that colors specified per vertex can be shaded across a primitive.
Chapter 5, “Lighting”—In this chapter, we learn how to create light sources and define the interaction between light and surfaces. Lighting adds to the scene’s realism and helps depict the solid form and volume of objects.
Chapter 6, “Texturing”—This chapter describes texture mapping. Texture mapping is a technique used to increase the realism of the scene by mapping 2D image data onto a 3D primitive. For example, using texture mapping, we can model a brick wall by applying a 2D brick wall image onto a 3D rectangle.
33
