Character Animation with Direct3D- P16

Chia sẻ: Cong Thanh | Ngày: | Loại File: PDF | Số trang:20

lượt xem

Character Animation with Direct3D- P16

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Character Animation with Direct3D- P16:This book is primarily aimed at teaching indie and hobby game developers how to create character animation with Direct3D. Also, the seasoned professional game developer may find some interesting things in this book. You will need a solid understanding of the C++ programming language as well as general object-oriented programming skills.

Chủ đề:

Nội dung Text: Character Animation with Direct3D- P16

  1. 286 Character Animation with Direct3D //Calculating the binormal and setting //the tangent binormal and normal matrix float3x3 TBNMatrix = float3x3(tangent, binormal, normal); //Setting the lightVector OUT.lightVec = mul(TBNMatrix, lightDir); OUT.lightHalf = mul(TBNMatrix, vHalf); OUT.tex0 = IN.tex0; return OUT; } //Pixel Shader float4 morphNormalMapPS(VS_OUTPUT IN) : COLOR0 { //Calculate the color and the normal float4 color = tex2D(DiffuseSampler, IN.tex0); //This is how you uncompress a normal map float3 normal = 2.0f * tex2D(NormalSampler, IN.tex0).rgb - 1.0f; //Get specular float4 specularColor = tex2D(SpecularSampler, IN.tex0); //Set the output color float diffuse = max(saturate( dot(normal, normalize(IN.lightVec))), 0.2f); float specular = max(saturate( dot(normal, normalize(IN.lightHalf))), 0.0f); specular = pow(specular, 85.0f) * 0.4f; return color * diffuse + specularColor * specular; } Please purchase PDF Split-Merge on to remove this watermark.
  2. Chapter 12 Wrinkle Maps 287 EXAMPLE 12.2 Example 12.2 contains all the code for implementing specular highlights. Play around with the shininess value in the pixel shader, and if you have good image-editing software, play around with the specular map as well. This example also implements specular highlights for the old diffuse lighting model (used for the eyes in the example, which are not normal mapped). Figure 12.13 shows another screenshot of the Soldier’s face using somewhat “exaggerated” highlights. Note that this isn’t the kind of result you’d actually want for skin. The examples and images in this chapter are a bit exaggerated to emphasize the effect of the specular highlights. ease purchase PDF Split-Merge on to remove this watermark.
  3. 288 Character Animation with Direct3D FIGURE 12.13 Exaggerated highlights. W RINKLE M APS You’ve now arrived at the goal of this chapter: the wrinkle maps. These maps are basically an animated or weighted normal map that is connected to the move- ment of the face. For example, smiling may reveal the dimples in the cheeks of the characters. These small deformations occur as a result of the underlying muscles in the face moving. Another example of this phenomenon is wrinkles that appear (or disappear) on the forehead as a person raises or lowers his or her eyebrows. Please purchase PDF Split-Merge on to remove this watermark.
  4. Chapter 12 Wrinkle Maps 289 The use of wrinkle maps in games is still a recent addition, and most games today don’t bother with it unless the characters are shown in close-up. Figure 12.14 shows a grayscale image of a normal map containing wrinkles for the forehead and dimples. FIGURE 12.14 Wrinkle normal map. Note that the wrinkles in Figure 12.14 have been made somewhat extreme to stand out a bit better (for educational purposes). Normally, wrinkle maps are something you don’t want sticking out like a sore thumb. Rather, they should be a background effect that doesn’t steal too much of the focus. Next, you need to encode which regions of the wrinkle map should be affected by which facial movements. In the upcoming wrinkle map example, I’ve used a separate texture to store masking of the wrinkle map regions. You could, however, also store this data in the vertex color, for example. Figure 12.15 shows the mask used to define the three different regions of the wrinkle map. ease purchase PDF Split-Merge on to remove this watermark.
  5. 290 Character Animation with Direct3D FIGURE 12.15 Wrinkle map mask. In Figure 12.15, three different regions are defined. The Red channel defines the part of the face that isn’t affected by animated wrinkles. The Green channel defines the forehead wrinkles, and the Blue channel defines the two dimple areas at either side of the mouth. To the shader we will upload two blend values (depending on what emotion or shape the character’s face has). These two values are called fore- headWeight and cheekWeight. At each pixel, we sample the blend map, multiply the Green channel with the foreheadWeight and the Blue channel with the cheekWeight. The resulting value is used to fade the normal in/out from the wrinkle normal map. The following code snippet shows how this is done in the pixel shader: //Pixel Shader float4 morphNormalMapPS(VS_OUTPUT IN) : COLOR0 { //Sample color float4 color = tex2D(DiffuseSampler, IN.tex0); //Sample blend from wrinkle mask texture float4 blend = tex2D(BlendSampler, IN.tex0); //Sample normal and decompress float3 normal = 2.0f * tex2D(NormalSampler, IN.tex0).rgb - 1.0f; //Calculate final normal weight float w = blend.r + foreheadWeight * blend.g + cheekWeight * blend.b; Please purchase PDF Split-Merge on to remove this watermark.
  6. Chapter 12 Wrinkle Maps 291 w = min( w, 1.0f ); normal.x *= w; normal.y *= w; //Re-normalize normal = normalize( normal ); //Normalize the light float3 light = normalize(IN.lightVec); //Set the output color float diffuse = max(saturate(dot(normal, light)), 0.2f); return color * diffuse; } EXAMPLE 12.3 Example 12.3 has the full implementation for the wrinkle maps. You can find how the weights for the forehead and dimples are set in the render method of the Face class. ease purchase PDF Split-Merge on to remove this watermark.
  7. 292 Character Animation with Direct3D Figure 12.16 shows the wrinkle maps in action. FIGURE 12.16 Wrinkle maps in action. Thanks to Henrik Enqvist at Remedy Entertainment for the idea of covering wrinkle maps. He also graciously supplied the example code for the wrinkle map example. C ONCLUSIONS This chapter covered all aspects of normal mapping, from the theory of normal maps to how to create them and how to apply them on a real-time character. This base knowledge then allows you to implement the more advanced wrinkle maps as an animated extension to normal maps. I hope you managed to understand all the steps of this somewhat complex process so that you’ll be able to use it in your own projects. The DirectX SDK also has skinned characters with high-quality normal maps, which are excellent to play around with. I also touched briefly on implementing a specular lighting model—something that, together with normal maps, really makes your character “shine.” After the slight sidetrack this chapter has taken, I’ll return to more mainstream character animation again. Next up is how to create crowd simulations. C HAPTER 12 E XERCISES Implement normal mapping for the SkinnedMesh class using the code in the Face class as a base. Please purchase PDF Split-Merge on to remove this watermark.
  8. Chapter 12 Wrinkle Maps 293 Implement normal mapping without supplying the binormal from the mesh, but calculate it on-the-fly in the vertex shader. Implement support for multiple lights (for both normal mapping and specular highlights). F URTHER R EADING [Cloward] Cloward, Ben, “Creating and Using Normal Maps.” Available online at [Gath06] Gath, Jakob, “Derivation of the Tangent Space Matrix.” Available online at matrix_derivation.php, 2006. [Green07] Green, Chris, “Efficient Self-Shadowed Radiosity Normal Mapping.” Available online at 2007_EfficientSelfShadowedRadiosityNormalMapping.pdf, 2007. [Hess02] Hess, Josh, “Object Space Normal Mapping with Skeletal Animation Tutorial.” Available online at:, 2002. [Lengyel01] Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh.” Terathon Software 3D Graphics Library. Available online at, 2001. ease purchase PDF Split-Merge on to remove this watermark.
  9. This page intentionally left blank Please purchase PDF Split-Merge on to remove this watermark.
  10. 13 Crowd Simulation This chapter introduces the concept of crowd simulation and how it can be used in games to control large groups of NPCs. You will first get familiar with the ancestor of crowd simulation—namely, flocking behaviors. With flocking behaviors it is possible to control a large group of entities, giving them a seemingly complex group behavior using only a few simple rules. This idea is then carried over to crowd simulation and extended to create some even more complex behaviors. Here’s what will be covered in this chapter: 295 ease purchase PDF Split-Merge on to remove this watermark.
  11. 296 Character Animation with Direct3D Flocking behaviors “Boids” implementation Basic crowd simulation Crowd simulation and obstacle avoidance F LOCKING B EHAVIORS Let’s start from the beginning. Like many other algorithms in computer science, flocking behaviors (aka swarm behaviors or swarm intelligence) try to emulate what already occurs in nature. Birds, fish, insects, and many other groups of animals seem to exhibit something called emergent behavior. In philosophy, systems theory, and science, emergence is the way complex systems and patterns arise out of a multiplicity of relatively simple interactions. Emergence is central to the theories of integrative levels and of complex systems. -Wikipedia Flocking algorithms have been around a while now, and in theory they are simple to both understand and implement. Flocking algorithms are also lightweight (i.e., not very CPU intensive), which is also a huge plus (especially since some of the flocks can have quite a few entities in them). The theory is to have a set of rules that are evaluated for each entity per frame, to determine where this entity should move. The result from the different individual rules are summed up (and often weighted) to produce the final move direction. One example of this is how ants navigate. If an ant is out on a random hike and finds a source of food, it will leave a trail of pheromones on its way back to the stack, carrying with it a piece of the food. Another ant on its way out from the stack will encounter this trail and then be more likely to follow it to the food source. On its way back, the second ant will lay its own trail of pheromones (reinforcing the first one), making it even more likely that a third ant will follow the first two. Once the food source has been depleted, the ants will stop laying the trail and the pheromones will evaporate with time, stopping ants from wasting time down that trail. So with these seemingly simple rules that each individual follows, the community as a whole still runs a pretty complex operation. This specific example has even spawned its own algorithm called Ant Colony Optimization (ACO), which is used to find good paths through a graph/search space. ACO is an adaptable algorithm, which makes it perfect for changing environments. For example, if a certain ant trail is blocked, the pheromones will evaporate and the ants will start using other trails instead. This tech- nique has been successfully applied to packet routing in networks. Please purchase PDF Split-Merge on to remove this watermark.
  12. Chapter 13 Crowd Simulation 297 BOIDS In 1986, Craig Reynolds made a computer simulation of three simple steering behaviors for a group of creatures he called “Boids.” With only three simple steer- ing rules he managed to show some surprisingly complex emergent behavior. Each Boid just considers a local area around itself and then bases its steering on whatever objects or other Boids are in this area. Separation The first rule is to make the Boids avoid colliding with other Boids and to avoid crowding each other. This rule is named Separation. It calculates a force pointing away from local neighbors, as shown in Figure 13.1. FIGURE 13.1 Separation. Alignment The second rule makes Boids keep the same heading as other Boids. This rule is called Alignment, and it states that a Boid should steer toward the average heading of its local neighbors. This rule is shown in Figure 13.2. ease purchase PDF Split-Merge on to remove this watermark.
  13. 298 Character Animation with Direct3D FIGURE 13.2 Alignment. Cohesion The third and last rule of the Boid steering behaviors is called Cohesion. It keeps the flock together by making a Boid steer toward the center location of its local neighbors. This last rule is shown in Figure 13.3. FIGURE 13.3 Cohesion. Summing Up For each frame, these three rules each produce a force vector according to the location of a Boid’s local neighbors. For now, let’s just consider these three simple rules (later you’ll see how you can add your own rules to create your own custom behaviors). Figure 13.4 shows the three steering behaviors summed up to produce the final force for the Boid. Please purchase PDF Split-Merge on to remove this watermark.
  14. Chapter 13 Crowd Simulation 299 FIGURE 13.4 Summing up the forces. In Figure 13.4, Fs, Fa, and Fc stand for the forces of the Separation, Alignment, and Cohesion rules, respectively. The resulting force F is the force that will be used to update the velocity and position of the Boid. In the upcoming example I’ll use the Boid class to control an individual entity: class Boid { friend class Flock; public: Boid(Flock *pFlock); ~Boid(); void Update(float deltaTime); void Render(bool shadow); private: static Mesh* sm_pBoidMesh; Flock* m_pFlock; D3DXVECTOR3 m_position; D3DXVECTOR3 m_velocity; }; The Boid class contains a pointer to the flock it belongs to as well as a position and a velocity. In the Boid’s Update() function the different steering behaviors and their resulting forces are calculated and used to update the velocity and position of the Boid. To manage a flock of Boids, I’ve created the Flock class like this: ease purchase PDF Split-Merge on to remove this watermark.
  15. 300 Character Animation with Direct3D class Flock { public: Flock(int numBoids); ~Flock(); void Update(float deltaTime); void Render(bool shadow); void GetNeighbors(Boid* pBoid, float radius, vector &neighbors); private: vector m_boids; }; The only special thing about the Flock class is the GetNeighbors() function, which just fills a list of Boids within a radius of the querying Boid: void Flock::GetNeighbors(Boid* pBoid, float radius, vector &neighbors) { for(int i=0; im_position - m_boids[i]->m_position; if(D3DXVec3Length(&(toNeighbor)) < radius) { neighbors.push_back(m_boids[i]); } } } } Note that the GetNeighbors() function has a rather naïve implementation in this example. For very large flocks it would be unnecessary to loop through the entire flock to find the closest neighbors (especially since we need to do this for each of the entities in the flock). A better way of getting the nearest neighbors would be to use a space partitioning tree, such as a KD-tree. See the following URL for a good introduction to KD-trees: Please purchase PDF Split-Merge on to remove this watermark.
  16. Chapter 13 Crowd Simulation 301 Since each Boid object contains a pointer to its flock, it can use the GetNeighbors() function to find any neighboring Boids. Then it is easy to calculate the three rather simple steering behaviors as covered earlier, sum these up, and apply the resulting force to the velocity and position of the Boid. The Boid::Update() function shows you how: void Boid::Update(float deltaTime) { //Tweakable values const float NEIGHBORHOOD_SIZE = 3.5f; const float SEPARATION_LIMIT = 2.5f; const float SEPARATION_FORCE = 15.0f; const float BOID_SPEED = 3.0f; //Get neighboring Boids vector neighbors; m_pFlock->GetNeighbors(this, NEIGHBORHOOD_SIZE, neighbors); //Forces D3DXVECTOR3 acceleration(0.0f, 0.0f, 0.0f); D3DXVECTOR3 separationForce(0.0f, 0.0f, 0.0f); D3DXVECTOR3 alignmentForce(0.0f, 0.0f, 0.0f); D3DXVECTOR3 cohesionForce(0.0f, 0.0f, 0.0f); D3DXVECTOR3 toPointForce(0.0f, 0.0f, 0.0f); D3DXVECTOR3 floorForce(0.0f, 0.0f, 0.0f); if(!neighbors.empty()) { //Calculate neighborhood center D3DXVECTOR3 center(0.0f, 0.0f, 0.0f); for(int i=0; im_position; } center /= (float)neighbors.size(); //RULE 1: Separation for(int i=0; im_position - m_position; float distToNeightbor = D3DXVec3Length(&vToNeighbor); ease purchase PDF Split-Merge on to remove this watermark.
  17. 302 Character Animation with Direct3D if(distToNeightbor < SEPARATION_LIMIT) { //Too close to neighbor float force = 1.0f - (distToNeightbor / SEPARATION_LIMIT); separationForce -= vToNeighbor * SEPARATION_FORCE * force; } } //RULE 2: Alignment for(int i=0; im_velocity; } alignmentForce /= (float)neighbors.size(); //RULE 3: Cohesion float distToCenter = D3DXVec3Length(&(center - m_position)) + 0.01f; cohesionForce = (center - m_position) / distToCenter; } //RULE 4: Steer to point toPointForce = D3DXVECTOR3(0.0f, 15.0f, 0.0f) - m_position; D3DXVec3Normalize(&toPointForce, &toPointForce); toPointForce *= 0.5f; //RULE 5: Dont crash! if(m_position.y < 3.0f) floorForce.y += (3.0f - m_position.y) * 100.0f; //Sum up forces acceleration = separationForce + alignmentForce + cohesionForce + toPointForce + floorForce; //Update velocity & position D3DXVec3Normalize(&acceleration, &acceleration); m_velocity += acceleration * deltaTime * 3.0f; D3DXVec3Normalize(&m_velocity, &m_velocity); m_position += m_velocity * BOID_SPEED * deltaTime; Please purchase PDF Split-Merge on to remove this watermark.
  18. Chapter 13 Crowd Simulation 303 //Cap Y position m_position.y = max(m_position.y, 1.0f); } In addition to the three normal Boid steering behaviors, I have added a steer- toward-point force (for keeping the Boids in the camera’s view frustum) and an avoid-the-floor force, for making sure the Boids don’t crash with the floor. Other than that this function is fairly straightforward and implements the steering behaviors covered earlier. EXAMPLE 13.1 This example shows you a simple implementation of the Boids flocking be- havior. There are plenty of tweakable values available to change the way the flock behaves. For instance, there’s the size of the area in which neighboring Boids will affect each other. There’s also the matter of weighing the different steering behaviors. For example, it might be more important that they avoid colliding with each other (Separation) than it is that they stay together as a group (Cohesion). ease purchase PDF Split-Merge on to remove this watermark.
  19. 304 Character Animation with Direct3D I NTRODUCTION TO C ROWD S IMULATION There’s a lot of academic research being done in the crowd simulation field of computer science. There are several uses for crowd simulations (aside from games). One example is when simulating area or building evacuations. By using crowd simulations it is possible to simulate the time it would take for a crowd to evacuate a building in case of fire, for example. It can also show where any potential choke points are or help to determine where the most efficient place for a fire exit would be, and so on. Another example of using crowd simulation is in civil engineering when simulating pedestrian crossings, sidewalks, city planning, and more. The bottom line is that this is a relatively cheap method of testing all thinkable scenarios and getting a fair idea of how it would play out in reality. As the processing power of today’s computers and consoles are ever increasing, it is suddenly feasible to render a multitude of characters in real time. Many games have recently utilized crowd simulations for “innocent” bystanders—most notable among these games is probably the Grand Theft Auto series. Crowd simulation is basically not that different from flocking algorithms. Usually, crowd simulation takes the steering behaviors used by flocking algorithms to the next level. The entities used in crowd simulation often have much more logic governing their actions, making them much smarter than your average Boid. That is why entities in a crowd simulation are most often referred to as agents instead of entities. An agent may have its own internal state machine. For example, an agent may act differently if it is in the hypothetical “wounded” state compared to the “normal” state. The crowd simulation may also govern which animations to play for the agents. Say, for example, that two agents are heading toward each other on a collision course. Many things could happen in a situation like this. They could stay and talk to each other, or one could step out of the way for the other one, and so on. The most basic addition to a crowd simulation system is that of path finding. Instead of just using a simple point in space and steering toward this as the Boids did, your crowd agent could query the environment for a smart path to reach its goal. The agent follows the path in the same manner as the simple “to-point” steering behavior, but the difference is that the agent steers toward the active waypoint instead. Although a crowd agent usually gets less “smarts” than, say, an enemy opponent character in a first-person shooter game, it still needs to look smart and obey the rules of the environment. At the very least, this means avoiding other crowd members and obstacles placed in the environment. In this section we’ll look at extending the flock- ing steering behaviors to a simple crowd simulation. The following CrowdEntity class governs an entity in the crowd (I still call it an entity instead of an agent since there aren’t yet quite enough brains in this class at the moment to merit an agent status): Please purchase PDF Split-Merge on to remove this watermark.
  20. Chapter 13 Crowd Simulation 305 class CrowdEntity { friend class Crowd; public: CrowdEntity(Crowd *pCrowd); ~CrowdEntity(); void Update(float deltaTime); void Render(); D3DXVECTOR3 GetRandomLocation(); private: static SkinnedMesh* sm_pSoldierMesh; Crowd* m_pCrowd; D3DXVECTOR3 m_position; D3DXVECTOR3 m_velocity; D3DXVECTOR3 m_goal; ID3DXAnimationController* m_pAnimController; }; The CrowdEntity class definition looks very much like the Boid class definition. The only major differences are the additions of an individual goal, a shared skinned mesh (as opposed to a simple static mesh), and the individual animation controller with which to control the skinned mesh. The GetRandomLocation() function is just a simple helper function to generate the goal of a crowd entity. Just as the Boid example had a Flock class, this crowd simulation has the following Crowd class to govern multiple crowd entities: class Crowd { public: Crowd(int numEntities); ~Crowd(); void Update(float deltaTime); void Render(); void GetNeighbors(CrowdEntity* pEntity, float radius, vector &neighbors); private: vector m_entities; }; ease purchase PDF Split-Merge on to remove this watermark.
Đồng bộ tài khoản