Skip to main content

Full text of "Physics For Game Developers 2nd Edition"

See other formats


m 

Game Developers 


Science, Math, a nd Code for Realistic Effects 



O’REILLY 


www.it-ebooks.info 


David M. Bourg 
& Bryan By wale c 





Game Programming 


Physics for Game Developers 

If you want to enrich your game’s experience with physics-based 
realism, the expanded edition of this classic book details physics 
principles applicable to game development. You’ll learn about 
collisions, explosions, sound, projectiles, and other effects used in 
games on Wii, PlayStation, Xbox, smartphones, and tablets. You’ll 
also get a handle on how to take advantage of various sensors such 
as accelerometers and optical tracking devices. 

Authors David Bourg and Bryan Bywalec show you how to develop 
your own solutions to a variety of problems by providing technical 
background, formulas, and a few code examples. This updated 
book is indispensable whether you work alone or as part of a team. 

■ Refresh your knowledge of classical mechanics, including 
kinematics, force, kinetics, and collision response 

■ Explore rigid body dynamics, using real-time 2D and 3D 
simulations to handle rotation and inertia 

■ Apply concepts to real-world problems: model the behavior of 
boats, airplanes, cars, and sports balls 

■ Enhance your games with digital physics, using 
accelerometers, touch screens, GPS, optical tracking devices, 
and 3D displays 

■ Capture 3D sound effects with the OpenAL audio API 


“Physics for Game 
Developers has a wealth 
of information based 
on real world physics 
problems that is 
immediately usable 
in game code.” 

—Paul Zirkle 

Lead Games Engineer 
at Disney Interactive 


David Bourg, owner of MiNO Marine—a Naval architecture and 
marine services firm—also formed a company in the 1990s that 
developed children’s games, casino games, and various PC to Mac 
ports. He’s the co-author of AIfor Game Programmers (O'Reilly). 

Bryan Bywalec is an architect at MiNO Marine, where accurate 
simulation of the physical world is necessary on a daily basis. In 
his passion for physics, he enjoys modding games (like Kerble 
Space Program) that places physics on center stage. 


US$44.99 CAN $47.99 

ISBN: 978-1-449-39251-2 




Twitter: @oreillymedia 
facebook.com/oreilly 


O’REILLY® 

oreilly.com 


www.it-ebooks.info 




















SECOND EDITION 


Physics for Game Developers 


David M. Bourg and Bryan Bywalec 


O’REILLY® 

Beijing • Cambridge • Farnham • Koln • Sebastopol • Tokyo 


www.it-ebooks.info 



Physics for Game Developers, Second Edition 

by David M. Bourg and Bryan Bywalec 

Copyright © 2013 David M. Bourg and Bryan Bywalec. All rights reserved. 

Printed in the United States of America. 

Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. 

O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are 
also available for most titles (http://my.safaribooksonline. com). For more information, contact our corporate/ 
institutional sales department: 800-998-9938 or corporate@oreilly.com. 

Editors: Andy Oram and Rachel Roumeliotis Indexer: Lucie Haskins 

Production Editor: Christopher Hearse Cover Designer: Randy Comer 

Copyeditor: Rachel Monaghan Interior Designer: David Futato 

Proofreader: Amanda Kersey Illustrator: Rebecca Demarest 

April 2013: Second Edition 

Revision History for the Second Edition: 

2013-04-09: First release 

See http://oreilly.com/catalog/errata.csp?isbn=9781449392512 for release details. 

Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly 
Media, Inc. Physics for Game Developers, 2nd Edition, the image of a cat and mouse, and related trade dress 
are trademarks of O’Reilly Media, Inc. 

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as 
trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trade¬ 
mark claim, the designations have been printed in caps or initial caps. 

While every precaution has been taken in the preparation of this book, the publisher and authors assume 
no responsibility for errors or omissions, or for damages resulting from the use of the information contained 
herein. 


ISBN: 978-1-449-39251-2 
[LSI] 


www.it-ebooks.info 


Preface. 

Table of Contents 

. xi 

Part 1. Fundamentals 

1. Basic Concepts. 

. 3 

Newton’s Laws of Motion 

3 

Units and Measures 

4 

Coordinate System 

6 

Vectors 

7 

Derivatives and Integrals 

8 

Mass, Center of Mass, and Moment of Inertia 

9 

Newton’s Second Law of Motion 

20 

Inertia Tensor 

24 

Relativistic Time 

29 

2. Kinematics. 

. 35 

Velocity and Acceleration 

36 

Constant Acceleration 

39 

Nonconstant Acceleration 

41 

2D Particle Kinematics 

42 

3D Particle Kinematics 

45 

X Components 

46 

Y Components 

47 

Z Components 

48 

The Vectors 

48 

Hitting the Target 

49 

Kinematic Particle Explosion 

54 

Rigid-Body Kinematics 

61 

Local Coordinate Axes 

62 


iii 


www.it-ebooks.info 








Angular Velocity and Acceleration 

62 

Force. 

. 71 

Forces 

71 

Force Fields 

72 

Friction 

73 

Fluid Dynamic Drag 

75 

Pressure 

76 

Buoyancy 

77 

Springs and Dampers 

79 

Force and Torque 

80 

Summary 

83 

Kinetics. 

. 85 

Particle Kinetics in 2D 

87 

Particle Kinetics in 3D 

91 

X Components 

94 

Y Components 

95 

Z Components 

95 

Cannon Revised 

95 

Rigid-Body Kinetics 

99 

Collisions. 

.103 

Impulse-Momentum Principle 

104 

Impact 

105 

Linear and Angular Impulse 

112 

Friction 

115 

Projectiles. 

.119 

Simple Trajectories 

120 

Drag 

124 

Magnus Effect 

132 

Variable Mass 

138 


Part II. Rigid-Body Dynamics 


7. Real-Time Simulations. 143 

Integrating the Equations of Motion 144 

Euler’s Method 146 

Better Methods 153 


iv | Table of Contents 


www.it-ebooks.info 









Summary 


159 


8. Particles. 161 

Simple Particle Model 166 

Integrator 169 

Rendering 170 

The Basic Simulator 170 

Implementing External Forces 172 

Implementing Collisions 175 

Particle-to-Ground Collisions 175 

Particle-to-Obstacle Collisions 181 

Tuning 186 

9. 2D Rigid-Body Simulator. 189 

Model 190 

Transforming Coordinates 197 

Integrator 198 

Rendering 200 

The Basic Simulator 201 

Tuning 204 

10. Implementing Collision Response.205 

Linear Collision Response 206 

Angular Effects 213 

11. Rotation in 3D Rigid-Body Simulators. 227 

Rotation Matrices 228 

Quaternions 232 

Quaternion Operations 234 

Quaternions in 3D Simulators 239 

12. 3D Rigid-Body Simulator. 243 

Model 243 

Integration 247 

Flight Controls 250 

13. Connecting Objects. 255 

Springs and Dampers 257 

Connecting Particles 258 

Rope 258 

Connecting Rigid Bodies 265 

Links 265 


Table of Contents | v 


www.it-ebooks.info 









Rotational Restraint 


275 


Physics Engines. 

. 281 

Building Your Own Physics Engine 

281 

Physics Models 

283 

Simulated Objects Manager 

284 

Collision Detection 

285 

Collision Response 

286 

Force Effectors 

287 

Numerical Integrator 

288 


Part III. Physical Modeling 


Aircraft. 

. 293 

Geometry 

294 

Lift and Drag 

297 

Other Forces 

302 

Control 

303 

Modeling 

305 

Ships and Boats. 

. 321 

Stability and Sinking 

323 

Stability 

323 

Sinking 

325 

Ship Motions 

326 

Heave 

327 

Roll 

327 

Pitch 

328 

Coupled Motions 

328 

Resistance and Propulsion 

328 

General Resistance 

328 

Propulsion 

334 

Maneuverability 

335 

Rudders and Thrust Vectoring 

336 

Cars and Hovercraft. 

.339 

Cars 

339 

Resistance 

339 

Power 

340 

Stopping Distance 

341 

Steering 

342 


vi | Table of Contents 


www.it-ebooks.info 








Hovercraft 

345 

How Hovercraft Work 

345 

Resistance 

347 

Steering 

350 

Guns and Explosions. 

. 353 

Projectile Motion 

353 

Taking Aim 

355 

Zeroing the Sights 

357 

Breathing and Body Position 

360 

Recoil and Impact 

361 

Explosions 

362 

Particle Explosions 

363 

Polygon Explosions 

366 

Sports. 

. 369 

Modeling a Golf Swing 

370 

Solving the Golf Swing Equations 

373 

Billiards 

378 

Implementation 

380 

Initialization 

383 

Stepping the Simulation 

386 

Calculating Forces 

388 

Handling Collisions 

393 


Part IV. Digital Physics 


20. Touch Screens.403 

Types of Touch Screens 403 

Resistive 403 

Capacitive 404 

Infrared and Optical Imaging 404 

Exotic: Dispersive Signal and Surface Acoustic Wave 404 

Step-by-Step Physics 404 

Resistive Touch Screens 404 

Capacitive Touch Screens 408 

Example Program 410 

Multitouch 410 

Other Considerations 411 

Haptic Feedback 411 

Modeling Touch Screens in Games 411 


Table of Contents | vii 


www.it-ebooks.info 







Difference from Mouse-Based Input 412 

Custom Gestures 412 

21. Accelerometers. 413 

Accelerometer Theory 414 

MEMS Accelerometers 416 

Common Accelerometer Specifications 417 

Data Clipping 417 

Sensing Orientation 418 

Sensing Tilt 420 

Using Tilt to Control a Sprite 420 

Two Degrees of Freedom 421 

22. Gaming from One Place to Another. 427 

Location-Based Gaming 427 

Geocaching and Reverse Geocaching 428 

Mixed Reality 428 

Street Games 428 

What Time Is It? 429 

Two-Dimensional Mathematical Treatment 429 

Location, Location, Location 433 

Distance 433 

Great-Circle Heading 435 

Rhumb Line 436 

23. Pressure Sensors and Load Cells. 439 

Under Pressure 440 

Example Effects of High Pressure 440 

Button Mashing 442 

Load Cells 444 

Barometers 448 

24. 3D Display.451 

Binocular Vision 451 

Stereoscopic Basics 454 

The Left and Right Frustums 454 

Types of Display 458 

Complementary-Color Anaglyphs 458 

Linear and Circular Polarization 459 

Liquid-Crystal Plasma 462 

Autostereoscopy 463 

Advanced Technologies 465 


viii | Table of Contents 


www.it-ebooks.info 







Programming Considerations 467 

Active Stereoization 467 

Passive Stereoization 469 

25. Optical Tracking. 471 

Sensors and SDKs 472 

Kinect 472 

OpenCV 473 

Numerical Differentiation 474 

26. Sound. 477 

What Is Sound? 477 

Characteristics of and Behavior of Sound Waves 481 

Harmonic Wave 481 

Superposition 483 

Speed of Sound 484 

Attenuation 485 

Reflection 486 

Doppler Effect 488 

3D Sound 489 

How We Hear in 3D 489 

A Simple Example 491 

A. Vector Operations. 495 

B. Matrix Operations. 507 

C. Quaternion Operations. 517 

Bibliography. 529 

Index. 535 


Table of Contents | ix 


www.it-ebooks.info 










www.it-ebooks.info 


Preface 


Who Is This Book For? 

Simply put, this book is targeted at computer game developers who do not have a strong 
mechanics or physics background, charged with the task of incorporating real physics 
in their games. 

As a game developer, and very likely as a gamer yourself, you’ve seen products being 
advertised as “ultra-realistic,” or as using “real-world physics.” At the same time you, or 
perhaps your company’s marketing department, are wondering how you can spice up 
your own games with such realism. Or perhaps you want to try something completely 
new that requires you to explore real physics. The only problem is that you threw your 
college physics text in the lake after final exams and haven’t touched the subject since. 
Maybe you licensed a really cool physics engine, but you have no idea how the underlying 
principles work and how they will affect what you’re trying to model. Or, perhaps you 
are charged with the task of tuning someone else’s physics code but you really don’t 
understand how it works. Well then, this book is for you. 

Sure you could scour the Internet, trade journals, and magazines for information and 
how-to’s on adding physics-based realism to your games. You could even fish out that 
old physics text and start from scratch. However, you’re likely to find that either the 
material is too general to be applied directly, or too advanced requiring you to search 
for other sources to get up to speed on the basics. This book will pull together the 
information you need and will serve as the starting point for you, the game developer, 
in your effort to enrich your game’s content with physics-based realism. 

This book is not a recipe book that simply gives sample code for a miscellaneous set of 
problems. The Internet is full of such example programs (some very good ones we might 
add). Rather than give you a collection of specific solutions to specific problems, our 
aim is to arm you with a thorough and fundamental understanding of the relevant topics 
such that you can formulate your own solutions to a variety of problems. We’ll do this 
by explaining, in detail, the principles of physics applicable to game development, and 


xi 


www.it-ebooks.info 




by providing complimentary hand calculation examples in addition to sample pro¬ 
grams. 

What We Assume You Know 

Although we don’t assume that you are a physics expert, we do assume that you have at 
least a basic college level understanding of classical physics typical of non-physics and 
non-engineering majors. It is not essential that your physics background is fresh in your 
mind as the first several chapters of this book review the subjects relevant to game 
physics. 

We also assume that you are proficient in trigonometry, vector, and matrix math, al¬ 
though we do include reference material in the appendices. Further, we assume that you 
have at least a basic college level understanding of calculus, including integration and 
differentiation of explicit functions. Numerical integration and differentiation is a dif¬ 
ferent story, and we cover these techniques in detail in the later chapters of this book. 

Mechanics 

Most people that we’ve talked to when we was developing the concept for this book 
immediately thought of flight simulators when the phrases “real physics” and “real-time 
simulation” came up. Certainly cutting edge flight simulations are relevant in this con¬ 
text; however, many different types of games, and specific game elements, stand to 
benefit from physics-based realism. 

Consider this example: You’re working on the next blockbuster hunting game complete 
with first-person 3D, beautiful textures, and an awesome sound track to set the mood, 
but something is missing. That something is realism. Specifically, you want the game to 
“feel” more real by challenging the gamer’s marksmanship, and you want to do this by 
adding considerations such as distance to target, wind speed and direction, and muzzle 
velocity, among others. Moreover, you don’t want to fake these elements, but rather, 
you’d like to realistically model them based on the principles of physics. Gary Powell, 
with MathEngine Pic, put it like this “The illusion and immersive experience of the 
virtual world, so carefully built up with high polygon models, detailed textures and 
advanced lighting, is so often shattered as soon as objects start to move and interact.” 1 
“It’s all about interactivity and immersiveness,” says Dr. Steven Collins, CEO of Hav- 
ok.com. 2 We think both these guys or right on target. Why invest so much time and 


1. At the time of this book’s first edition, Gary Powell worked for MathEngine Pic. Their products included 
Dynamics Toolkit 2 and Collision Toolkit 1, which handled single and multiple body dynamics. Currently 
the company operates under the name CM Labs. 

2. At the time of this book’s first edition, Dr. Collins was the CEO of Havok.com. Their technology handled 
rigid body, soft body, cloth, and fluid and particle dynamics. Intel purchased Havok in 2005. 


xii | Preface 


www.it-ebooks.info 



effort making your game world look as realistic as possible, but not take the extra step 
to make it behave just as realistically? 

Here are a few examples of specific game elements that stand to benefit, in terms of 
realism, from the use of real physics: 

• The trajectory of rockets and missiles including the effects of fuel burn off 

• The collision of objects such as billiard balls 

• The effects of gravitation between large objects such as planets and battle stations 

• The stability of cars racing around tight curves 

• The dynamics of boats and other waterborne vehicles 

• The flight path of a baseball after being struck by a bat 

• The flight of a playing card being tossed into a hat 

This is by no means an exhaustive list, but just a few examples to get you in the right 
frame of mind, so to speak. Pretty much anything in your games that bounces around, 
flies, rolls, slides, or isn’t sitting dead still can be realistically modeled to create com¬ 
pelling, believable content for your games. 

So how can this realism be achieved? By using physics, of course, which brings us back 
to the title of this section, the subject of mechanics. Physics is a vast field of science that 
covers many different, but related subjects. The subject most applicable to realistic game 
content is the subject of mechanics, which is really what’s meant by “real physics.” 

By definition, mechanics is the study of bodies at rest and in motion, and of the effect 
of forces on them. The subject of mechanics is subdivided into statics, which specifically 
focuses on bodies at rest, and dynamics, which focuses on bodies in motion. One of the 
oldest and most studied subjects of physics, the formal origins of mechanics can be 
traced back more than 2000 years to Aristotle. An even earlier treatment of the subject 
was formalized in Problems of Mechanics, but the origins of this work are unknown. 
Although some of these early works attributed some physical phenomena to magical 
elements, the contributions of such great minds as Galileo, Kepler, Euler, Lagrange, 
d’Alembert, Newton, and Einstein, to name a few, have helped develop our understand¬ 
ing of this subject to such a degree that we have been able to achieve the remarkable 
state of technological advancement that we see today. 

Because you want your game content to be alive and active, we’ll primarily look at bodies 
in motion and will thus delve into the details of the subject of dynamics. Within the 
subject of dynamics there are even more specific subjects to investigate, namely, kine¬ 
matics, which focuses on the motion of bodies without regard to the forces that act on 
the body, and kinetics, which considers both the motion of bodies and the forces that 
act on or otherwise affect bodies in motion. We’ll take a very close look at these two 
subjects throughout this book. 


Preface | xiii 


www.it-ebooks.info 



Digital Physics 

This book’s first edition focused exclusively on mechanics. More than a decade after its 
release we’ve broadened our definition of game physics to include digital physics not in 
the cosmological sense but in the context of the physics associated with such devices as 
smart phones and their unique user interaction experience. As more platforms such as 
the Wii, PlayStation, X Box and smart phones come out and are expanded developers 
will have to keep up with and understand the new input and sensors technologies that 
accompany these platforms in order to keep producing fresh gaming experiences. But 
you shouldn’t look at this as a burden, and instead look at it as an opportunity to enhance 
the user’s interactive experience with your games. 

Arrangement of This Book 

Physics-based realism is not new to gaming, and in fact many games on the shelves these 
days advertise their physics engines. Also, many 3D modeling and animation tools have 
physics engines built in to help realistically animate specific types of motion. Naturally, 
there are magazine articles that appear every now and then that discuss various aspects 
of physics-based game content. In parallel, but at a different level, research in the area 
of real-time rigid body 3 simulation has been active for many years, and the technical 
j ournals are full of papers that deal with various aspects of this subject. You’ll find papers 
on subjects ranging from the simulation of multiple, connected rigid bodies to the sim¬ 
ulation of cloth. However, while these are fascinating subjects and valuable resources, 
as we hinted earlier, many of them are of limited immediate use to the game developer 
as they first require a solid understanding of the subject of mechanics requiring you to 
learn the basics from other sources. Further, many of them focus primarily on the 
mathematics involved in solving the equations of motion and don’t address the practical 
treatment of the forces acting on the body or system being simulated. 

We asked John Nagle, with Animats, what is, in his opinion, the most difficult part of 
developing a physics-based simulation for games and his response was developing nu¬ 
merically stable, robust code. 4 Gary Powell echoed this when he told me that minimizing 
the amount of parameter tuning to produce stable, realistic behavior was one of the 
most difficult challenges. We agree; speed and robustness in dealing with the mathe¬ 
matics of bodies in motion are crucial elements of a simulator. And on top of that, so 
are completeness and accuracy in representing the interacting forces that initiate and 


3. A rigid body is formally defined as a body, composed of a system of particles, whose particles remain at fixed 
distances from each other with no relative translation or rotation among particles. Although the subject of 
mechanics deals with flexible bodies and even fluids such as water, we’ll focus our attention on bodies that 
are rigid. 

4. At the time of this book’s first edition, John Nagle was the developer of Falling Bodies, a dynamics plug-in 
for Softimage13D. 


xiv | Preface 


www.it-ebooks.info 



perpetuate the simulation in the first place. As you’ll see later in this book, forces govern 
the behavior of objects in your simulation and you need to model them accurately if 
your objects are to behave realistically. 

This prerequisite understanding of mechanics and the real world nature of forces that 
may act on a particular body or system have governed the organization of this book. 
Generally, this book is organized in four parts with each building on the material covered 
in previous parts: 

Part I, Fundamentals 

A mechanics refresher, comprising Chapters 1 through 6. 

Chapter 1, Basic Concepts 

This warm up chapter covers the most basic of principles that are used and referred 
to throughout this book. The specific topics addressed include mass and center of 
mass, Newtons Laws, inertia, units and measures, and vectors. 

Chapter 2, Kinematics 

This chapter covers such topics as linear and angular velocity, acceleration, mo¬ 
mentum, and the general motion of particles and rigid bodies in two and three 
dimensions. 

Chapter 3, Force 

The principles of force and torque are covered in this chapter, which serves as a 
bridge from the subject of kinematics to that of kinetics. General categories of forces 
are discussed including drag forces, force fields, and pressure. 

Chapter 4, Kinetics 

This chapter combines elements of Chapters 2 and 3 to address the subject of ki¬ 
netics and explains the difference between kinematics and kinetics. Further dis¬ 
cussion treats the kinetics of particles and rigid bodies in two and three dimensions. 

Chapter 5, Collisions 

In this chapter we’ll cover particle and rigid body collision response, that is, what 
happens after two objects run in to each other. 

Chapter 6, Projectiles 

This chapter will focus on the physics of simple projectiles laying the ground work 
for further specific modeling treatment in later chapters. 

Part II, Rigid-Body Dynamics 

An introduction to real time simulations, comprising Chapters 7 through 14. 
Chapter 7, Real-Time Simulations 

This chapter will introduce real-time simulations and detail the core of such sim¬ 
ulations—the numerical integrator. Various methods will be presented and cover¬ 
age will include stability and tuning. 


Preface | xv 


www.it-ebooks.info 



Chapter 8, Particles 

Before diving into rigid body simulations, this chapter will show how to implement 
a particle simulation, which will be extended in the next chapter to include rigid 
bodies. 

Chapter 9, 2D Rigid-Body Simulator 

This chapter will extend the particle simulator from the previous chapter showing 
how to implement rigid bodies, which primarily consists of adding rotation and 
dealing with the inertia tensor. 

Chapter 10, Implementing Collision Response 

Collision detection and response will be combined to implement real-time collision 
capabilities in the 2D simulator. 

Chapter 11, Rotation in 3D Rigid-Body Simulators 

This chapter will address how to handle rigid body rotation in 3D including how 
to deal with the inertia tensor. Then we’ll show the reader how to extend the 2D 
simulator to 3D. 

Chapter 12, 3D Rigid-Body Simulator 

Multiple unconnected bodies will be incorporated in the simulator in this chapter. 
Introduction of multiple bodies requires resolution of multiple rigid body colli¬ 
sions, which can be very tricky. Issues of stability and realism will be covered. 

Chapter 13, Connecting Objects 

Taking things a step further, this chapter will show how to join rigid bodies forming 
connected bodies, which may be used to simulate human bodies, complex vehicles 
that may blow apart, among many other game objects. Various connector types will 
be considered. 

Chapter 14, Physics Engines 

In this chapter, specific aspects of automobile performance are addressed, including 
aerodynamic drag, rolling resistance, skidding distance, and roadway banking. 

Part III, Physical Modeling 

A look at some real world problems, comprising Chapters 15 through 19. 

Chapter 15, Aircraft 

This chapter focuses on the elements of flight including propulsor forces, drag, 
geometry, mass, and most importantly lift. 

Chapter 16, Ships and Boats 

The fundamental elements of floating vehicles are discussed in this chapter, in¬ 
cluding floatation, stability, volume, drag, and speed. 

Chapter 17, Cars and Hovercraft 

In this chapter, specific aspects of automobile performance are addressed, including 
aerodynamic drag, rolling resistance, skidding distance, and roadway banking. Ad¬ 
ditionally hovercraft shares some of the same characteristics of both cars and boats. 


xvi | Preface 


www.it-ebooks.info 



This chapter will consider those characteristics that distinguish the hovercraft as a 
unique vehicle. Topics covered include hovering flight, aerostatic lift, and direc¬ 
tional control 

Chapter 18, Guns and Explosions 

This chapter will focus on the physics of guns including power, recoil, and proj ectile 
flight. Since we generally want things to explode when hit with a large projectile, 
this chapter will also address the physics of and modeling explosions. 

Chapter 19, Sports 

This chapter will focus on the physics of ball sports such as baseball, golf, and tennis. 
Coverage will go beyond projectile physics and include such topics as including 
pitching, bat swing, bat-ball impact, golf club swing and club ball impact, plus tennis 
racket swinging and racket/ball impacts. 

Part IV, Digital Physics 

Chapters in this part of the book will explain the physics behind accelerometers, 
touch screens, GPS and other gizmos showing the reader how to leverage these 
elements in their games, comprising Chapters 20 through 26. 

Chapter 20, Touch Screens 

Touch screens facilitate virtual tactile interfaces with mobile device games, such as 
those made for the iPhone. This chapter will explain the physics of touch screen 
and how the reader can leverage this interface in their games particularly with 
respect to virtual physical interaction with game elements through gesturing. 

Chapter 21, Accelerometers 

Accelerometers are now widely used in mobile devices and game controllers al¬ 
lowing virtual physical interaction between players and game objects. This chapter 
will explain how accelerometers work, what data they provide and how that data 
can be manipulated with respect to virtual physical interaction with game elements. 
Topics covered will include, but not be limited to integration of acceleration data 
to derive velocities and displacements and rotations. 

Chapter 22, Gaming from One Place to Another 

Mobile devices commonly have GPS capabilities and this chapter will explain the 
physics of the GPS system including relativistic effects. Further, GPS data will be 
explained and this chapter showing the reader how to manipulate that data for 
virtual interaction with game elements. For example, we’ll show the reader how to 
differentiate GPS data to derive speed and acceleration among other manipulations. 

Chapter 23, Pressure Sensors and Load Cells 

Pressure sensing devices are used in games as a means of allowing players to interact 
with game elements, for example, the Wii balance board uses pressure sensors al¬ 
lowing players to interact with the Wii Fit game. This chapter will explain the physics 
behind such pressure sensors, what data they generate, and how to manipulate that 
data for game interaction. 


Preface | xvii 


www.it-ebooks.info 



Chapter 24, 3D Display 

The new PlayStation Move and Microsoft’s Kinect use optical tracking systems to 
detect the position of players’ game controllers or gestures. This chapter will explain 
the physics behind optical tracking and how to leverage this technology in games. 

Chapter 25, Optical Tracking 

As televisions and handheld game consoles race to implement 3D displays, several 
different technologies are being developed. By understanding the physics of the 
glasses dependent stereoscopic displays, the new “glasses free” autostereoscopic 
displays, and looking forward to holography and volumetric displays, developers 
will be better positioned to leverage these effects in their games. 

Chapter 26, Sound 

Sound is a particularly important part of a game’s immersive experience; however, 
to date no book on game physics addresses the physics of sound. This chapter will 
focus on sound physics including such topics of sound speed and the Doppler Effect. 
Discussions will also include why sound physics is often ignored in games, for 
example, when simulating explosions in outer space. 

Appendix A, Vector Operations 

This appendix shows you how to implement a C++ class that captures all of the 
vector operations that you’ll need to when writing 2D or 3D simulations. 

Appendix B, Matrix Operations 

This appendix implements a class that captures all of the operations you need to 
handle 3x3 matrices. 

Appendix C, Quaternion Operations 

This appendix implements a class that captures all of the operations you need to 
handle quaternions when writing 3D rigid body simulations. 

Part I, Fundamentals focuses on fundamental topics in Newtonian mechanics such as 
kinematics and kinetics. Kinematics deals with the motion of objects. We’ll cover both 
linear and angular velocity and acceleration. Kinetics deals with forces and resulting 
motion. Part I serves as a primer for Part II, Rigid-Body Dynamics that covers rigid 
body dynamics. Readers already versed in classical mechanics can skip Part I, Funda¬ 
mentals without loss of continuity. 

Part II, Rigid-Body Dynamics focuses on rigid body dynamics and development of both 
single and multi-body simulations. This part covers numerical integration, real-time 
simulation of particles and rigid bodies, and connected rigid bodies. Generally, this part 
covers what most game programmers consider elements of a physics engine. 

Part III, Physical Modeling focuses on physical modeling. The aim of this part is to 
provide valuable physical insight for the reader so they can make better judgments on 
what to include in their models and what they can safely leave out without sacrificing 
physical realism. We cannot and do not attempt to cover all the possible things you 


xviii | Preface 


www.it-ebooks.info 



might want to simulate. Instead we cover several typical things you may try to simulate 
in a game such as aircraft, boats, sports balls, among others with the purpose of giving 
you some insight into the physical nature of those things and some of the choices you 
must make when developing suitable models. 

Part IV, Digital Physics covers digital physics in a broad sense. This is an exciting topic 
as it relates to the technologies associated with mobile platforms, such as smart phones 
like the iPhone, and ground breaking game systems such as the Nentendo Wii. Chapters 
in this part of the book will explain the physics behind accelerometers, touch screens, 
GPS and other gizmos showing the reader how to leverage these elements in their games. 
We recognize that these topics are not what most game programmers typically think 
about when they think of game physics; however, the technologies covered play an 
increasingly important role in modern mobile games and we feel it important to explain 
the underlying physics behind them with the hope that you’ll be better able to leverage 
these technologies in your games. 

In addition to resources pertaining to real-time simulations, the Bibliography at the end 
of this book will provide sources of information on mechanics, mathematics, and other 
specific technical subjects, such as books on aerodynamics. 

Conventions Used in This Book 

The following typographical conventions are used in this book: 

Constant width 

Used to indicate command-line computer output, code examples, Registry keys, 
and keyboard accelerators (see “Keyboard Accelerators” later in this book). 

Constant width italic 

Used to indicate variables in code examples. 

Italic 

Introduces new terms and to indicate URLs, variables, filenames and directories, 
commands, and file extensions. 

Bold 

Indicates vector variables. 

« 9 *. 

This icon signifies a tip, suggestion, or general note. 


This icon indicates a warning or caution. 



Preface | xix 


www.it-ebooks.info 








We use boldface type to indicate a vector quantity, such as force, F. When referring to 
the magnitude only of a vector quantity, we use standard type. For example, the mag¬ 
nitude of the vector force, F, is F with components along the coordinate axes, Fx, Fy, 
and Fz. In the code samples throughout the book, we use the * (asterisk) to indicate 
vector dot product, or scalar product, operations depending on the context, and we use 
the A (caret) to indicate vector cross product. 

Using Code Examples 

This book is here to help you get your job done. In general, if this book includes code 
examples, you may use the code in your programs and documentation. You do not need 
to contact us for permission unless you’re reproducing a significant portion of the code. 
For example, writing a program that uses several chunks of code from this book does 
not require permission. Selling or distributing a CD-ROM of examples from O’Reilly 
books does require permission. Answering a question by citing this book and quoting 
example code does not require permission. Incorporating a significant amount of ex¬ 
ample code from this book into your product’s documentation does require permission. 

We appreciate, but do not require, attribution. An attribution usually includes the title, 
author, publisher, and ISBN. For example: “Physics for Game Developers, 2nd Edition 
by David M. Bourg and Bryan Bywalec (O’Reilly). Copyright 2013 David M. Bourgand 
Bryan Bywalec, 978-1-449-39251-2.” 

If you feel your use of code examples falls outside fair use or the permission given above, 
feel free to contact us at permissions@oreilly.com. 


Safari® Books Online 

*+ r Safari Books Online ( www.safaribooksonline.com ) is an on-demand 

Ddldll digital library that delivers expert content in both book and video 
form from the world’s leading authors in technology and business. 


Books Online 


Technology professionals, software developers, web designers, and business and crea¬ 
tive professionals use Safari Books Online as their primary resource for research, prob¬ 
lem solving, learning, and certification training. 

Safari Books Online offers a range of product mixes and pricing programs for organi¬ 
zations, government agencies, and individuals. Subscribers have access to thousands of 
books, training videos, and prepublication manuscripts in one fully searchable database 
from publishers like O’Reilly Media, Prentice Hall Professional, Addison-Wesley Pro¬ 
fessional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John 
Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT 
Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technol- 


xx | Preface 


www.it-ebooks.info 



ogy, and dozens more. For more information about Safari Books Online, please visit us 
online. 

How to Contact Us 

Please address comments and questions concerning this book to the publisher: 

O’Reilly Media, Inc. 

1005 Gravenstein Highway North 
Sebastopol, CA 95472 

800-998-9938 (in the United States or Canada) 

707-829-0515 (international or local) 

707-829-0104 (fax) 

We have a web page for this book, where we list errata, examples, and any additional 
information. You can access this page at http://oreil.ly/Physics-GameDev2. 

To comment or ask technical questions about this book, send email to bookques 
tions@oreilly.com. 

For more information about our books, courses, conferences, and news, see our website 
at http://www.oreilly.com. 

Find us on Facebook: http://facebook.com/oreilly 

Follow us on Twitter: http://twitter.com/oreillymedia 

Watch us on YouTube: http://www.youtube.com/oreillymedia 


Preface | xxi 


www.it-ebooks.info 



Acknowledgments 

We want to thank Andy Oram, the editor of this edition of the book, for his skillful 
review of our writing and his insightful comments and suggestions, not to mention his 
patience. We also want to express my appreciation to O’Reilly for agreeing to take on 
this project giving us the opportunity to expand on the original edition. Furthermore, 
special thanks go to all of the production and technical staff at O’Reilly. 

We’d also like to thank the technical reviewers, Christian Stober and Paul Zirkle, whose 
valuable insight added much to this edition. 

Individually, David would like to thank his loving wife and best friend, Helena, for her 
endless support and encouragement, and his wonderful daughter, Natalia, for making 
every day special. 

Bryan would like to thank his co-author David for the opportunity to help with the 
second edition and would also like to thank his parents, Barry and Sharon, for raising 
him to be curious about the world. Lastly, he would like to thank his fiancee, Anne 
Hasuly, for her support without which many chapters would still be half-finished. 


xxii | Preface 


www.it-ebooks.info 



PARTI 


Fundamentals 


Part I focuses on fundamental topics in Newtonian mechanics such as kinematics and 
kinetics. Kinematics deals with the motion of objects; we’ll cover both linear and angular 
velocity and acceleration. Kinetics deals with forces and resulting motion. Part I serves 
as a primer for Part II, which covers rigid-body dynamics. Readers already versed in 
classical mechanics can skip Part I without loss of continuity. 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 1 


Basic Concepts 


As a warm-up, this chapter will cover the most basic of the principles that will be used 
and referenced throughout the remainder of this book. First, we’ll introduce Newtons 
laws of motion, which are very important in the study of mechanics. Then we’ll discuss 
units and measures, where we’ll explain the importance of keeping track of units in your 
calculations. You’ll also have a look at the units associated with various physical quan¬ 
tities that you’ll be studying. After discussing units, we’ll define our general coordinate 
system, which will serve as our standard frame of reference. Then we’ll explain the 
concepts of mass, center of mass, and moment of inertia, and show you how to calculate 
these quantities for a collection, or combination, of masses. Finally, we’ll discuss New¬ 
ton’s second law of motion in greater detail, take a quick look at vectors, and briefly 
discuss relativistic time. 

Newton's Laws of Motion 

In the late 1600s (around 1687), Sir Isaac Newton put forth his philosophies on me¬ 
chanics in his Philosophiae Naturalis Principia Mathematica. In this work Newton sta¬ 
ted the now-famous laws of motion, which are summarized here: 

Law I 

A body tends to remain at rest or continue to move in a straight line at constant 
velocity unless acted upon by an external force. This is the so-called concept of 
inertia. 

Law 11 

The acceleration of a body is proportional to the resultant force acting on the body, 
and this acceleration is in the same direction as the resultant force. 

Law III 

For every force acting on a body (action) there is an equal and opposite reacting 
force (reaction), where the reaction is collinear to the acting force. 


3 


www.it-ebooks.info 




These laws form the basis for much of the analysis in the field of mechanics. Of particular 
interest to us in the study of dynamics is the second law, which is written: 

F = ma 

where F is the resultant force acting on the body, m is the mass of the body, and a is the 
linear acceleration of the body’s center of gravity. We’ll discuss this second law in greater 
detail later in this chapter, but before that there are some more fundamental issues that 
we must address. 

Units and Measures 

Over years of teaching various engineering courses, we’ve observed that one of the most 
common mistakes students make when performing calculations is using the wrong units 
for a quantity, thus failing to maintain consistent units and producing some pretty wacky 
answers. For example, in the field of ship performance, the most commonly misused 
unit is that for speed: people forget to convert speed in knots to speed in meters per 
second (m/s) or feet per second (ft/s). One knot is equal to 0.514 m/s, and considering 
that many quantities of interest in this field are proportional to speed squared, this 
mistake could result in answers that are as much as 185% off target! So, if some of your 
results look suspicious later on, the first thing you need to do is go back to your formulas 
and check their dimensional consistency. 

To check dimensional consistency, you must take a closer look at your units of measure 
and consider their component dimensions. We are not talking about 2D or 3D type 
dimensions here, but rather the basic measurable dimensions that will make up various 
derived units for the physical quantities that we will be using. These basic dimensions 
are mass, length, and time. 

It is important for you to be aware of these dimensions, as well as the combinations of 
these dimensions that make up the other derived units, so that you can ensure dimen¬ 
sional consistency in your calculations. For example, you know that the weight of an 
object is measured in units of force, which can be broken down into component di¬ 
mensions like so: 


F = (M) (L/T 2 ) 

where M is mass, L is length, and T is time. Does this look familiar? Well, if you consider 
that the component units for acceleration are (L/T 2 ) and let a be the symbol for accel¬ 
eration and m be the symbol for the mass of an object, you get: 

F = ma 


4 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



which is the famous expression of Newtons second law of motion. We will take a closer 
look at this equation later. 

By no means did we just derive this famous formula. What we did was check its di¬ 
mensional consistency (albeit in reverse), and all that means is that any formulas you 
develop to represent a force acting on a body had better come out to a consistent set of 
units in the form (M) ( LIT 2 ). This may seem trivial at the moment; however, when you 
start looking at more complicated formulas for the forces acting on a body, you’ll want 
to be able to break down these formulas into their component dimensions so you can 
check their dimensional consistency. Later we will use actual units, from the SI (le Sys- 
teme international d’unites, or International System of Units) for our physical quantities. 
Of course, there are other unit systems, but unless you want to show these values to 
your gamers, it really does not matter which system you use in your games. Again, what 
is important is consistency. 

To help clarify this point, consider the formula for the friction drag on a body moving 
through a fluid, such as water: 


R f = 1/2 p V 2 S C f 

In this formula, R f represents resistance (a force) due to friction, p is the density of water, 
V is the speed of the moving body, S is the submerged surface area of the body, and C f 
is an empirical (experimentally determined) drag coefficient for the body. Now rewriting 
this formula in terms of basic dimensions instead of variables will show that the di¬ 
mensions on the left side of the formula match exactly the dimensions on the right side. 
Since R f is a force, its basic dimensions are of the form: 

(M) (L/T 2 ) 

as discussed earlier, which implies that the dimensions of all the terms on the right side 
of the equation, when combined, must yield an equivalent form. Considering the basic 
units for density, speed, and surface area: 

• Density: (M)/(L 3 ) 

. Speed: (L)/(T) 

• Area: (L 2 ) 

and combining these dimensions for the terms, p V 2 S, as follows: 

[(M)/(L 3 )] [(L)/(T )] 2 [L 2 ] 

and collecting the dimensions in the numerator and denominator yields the following 
form: 


Units and Measures | 5 


www.it-ebooks.info 



(M L 2 L 2 ) / (L 3 T 2 ) 

Canceling dimensions that appear in both the numerator and denominator yields: 

M (L/T 2 ) 

which is consistent with the form shown earlier for resistance, R ( . This exercise also 
reveals that the empirical term, C f , for the coefficient of friction must be nondimensional 
—that is, it is a constant number with no units. 

With that, let’s take a look at some more common physical quantities that you will be 
using along with their corresponding symbols, component dimensions, and units in 
both the SI and English systems. This information is summarized in Table 1-1. 

Table 1-1. Common physical quantities and units 


Quantity 

Symbol 

Dimensions 

Units, SI 

Units, English 

Acceleration, linear 

A 

L/T 2 

m/s 2 

ft/s 2 

Acceleration, angular 

a 

radian/T 2 

radian/s 2 

radian/s 2 

Density 

P 

M/L 3 

kg/m 3 

slug/ft 3 

Force 

F 

M (L/T 2 ) 

newton, N 

pound, lbs 

Kinematic viscosity 

V 

L 2 /T 

m 2 /s 

ft 2 /s 

Length 

L (or x, y, z) 

L 

meters, m 

feet, ft 

Mass 

m 

M 

kilogram, kg 

slug 

Moment (torque) 

M a 

M (L 2 /T 2 ) 

N-m 

ft-lbs 

Mass Moment of Inertia 

1 

ML 2 

kg-m 2 

lbs-ft-s 2 

Pressure 

P 

M/(LT 2 ) 

N/m 2 

lbs/ft 2 

Time 

T 

T 

seconds, s 

seconds, s 

Velocity, linear 

V 

L/T 

m/s 

ft/s 

Velocity, angular 

w 

radian/T 

radian/s 

radian/s 

Viscosity 

P 

M/(LT) 

Ns/m 2 

lbs • s/ft 2 


a In general, we will use a capital M to represent a moment (torque) acting on a body and a lowercase m to represent the mass of 
a body. If we're referring to the basic dimension of mass in a general sense—that is, referring to the dimensional components of 
derived units of measure—well use a capital M. Usually, the meanings of these symbols will be obvious based on the context in 
which they are used; however, we will specify their meanings in cases where ambiguity may exist. 

Coordinate System 

Throughout this book we will refer to a standard, right-handed Cartesian coordinate 
system when specifying positions in 2D or 3D space. In two dimensions we will use the 
coordinate system shown in Figure 1 -1 (a), where rotations are measured positive coun¬ 
terclockwise. 


6 | Chapter 1: Basic Concepts 


www.it-ebooks.info 







In three dimensions we will use the coordinate system shown in Figure l-l(b), where 
rotations about the x-axis are positive from positive y to positive z, rotations about the 
y-axis are positive from positive z to positive x, and rotations about the z-axis are positive 
from positive x to positive y. 

Vectors 

Let us take you back for a moment to your high school math class and review the concept 
of vectors. Essentially, a vector is a quantity that has both magnitude as well as direction. 
Recall that a scalar, unlike a vector, has only magnitude and no direction. In mechanics, 
quantities such as force, velocity, acceleration, and momentum are vectors, and you 
must consider both their magnitude and direction. Quantities such as distance, density, 
viscosity, and the like are scalars. 

With regard to notation, we’ll use boldface type to indicate a vector quantity, such as 
force, F. When referring to the magnitude only of a vector quantity, we’ll use standard 
type. For example, the magnitude of the vector force, F, is F with components along the 
coordinate axes, F x , F , and F z . In the code samples throughout the book, we’ll use the 
* (asterisk) to indicate vector dot product, or scalar product, operations depending on 
the context, and we’ll use the A (caret) to indicate vector cross product. 

Because we will be using vectors throughout this book, it is important that you refresh 
your memory on the basic vector operations, such as vector addition, dot product, and 
cross product, among others. For your convenience (so you don’t have to drag out that 
old math book), we’ve included a summary of the basic vector operations in Appen¬ 
dix A. This appendix provides code for a Vector class that contains all the important 
vector math functionality. Further, we explain how to use specific vector operations— 
such as the dot-product and cross-product operations—to perform some common and 


Vectors | 7 


www.it-ebooks.info 














useful, calculations. For example, in dynamics you’ll often have to find a vector per¬ 
pendicular, or normal, to a plane or contacting surface; you use the cross-product op¬ 
eration for this task. Another common calculation involves finding the shortest distance 
from a point to a plane in space; you use the dot-product operation here. Both of these 
tasks are described in Appendix A, which we encourage you to review before delving 
too deeply into the example code presented throughout the remainder of this book. 

Derivatives and Integrals 

If you’re not familiar with calculus, or The Calculus, don’t let the use of derivatives and 
integrals in this text worry you. While we’ll write equations using derivatives and inte¬ 
grals, we’ll show you explicitly how to deal with them computationally throughout this 
book. Without going into a dissertation on all the properties and applications of deriv¬ 
atives and integrals, let’s touch on their physical significance as they relate to the material 
we’ll cover. 

You can think of a derivative as the rate of change in one variable with respect to another 
variable, or in other words, derivatives tells you how fast one variable changes as some 
other variable changes. Take speed, for example. A car travels at a certain speed covering 
some distance in a certain period of time. Its speed, on average, is the distance traveled 
over a specific time interval. If it travels a distance of 60 kilometers in one hour, then 
its average speed is 60 kilometers an hour. When we’re doing simulations, the ones you’ll 
see later in this book, we’re interested in what the car is doing over very short time 
intervals. As the time interval gets really small and we consider the distance traveled 
over that very short period of time, we’re looking at instantaneous speed. We usually 
write such relations using symbols like the following: 

Ivl = ds/dt 

where v is the speed, ds is a small distance (a differential distance), and dt is a small, 
differential, period of time. In reality, for our simulations, we’ll never deal with infinitely 
small numbers; we’ll use small numbers, such as time intervals of 1 millisecond, but not 
infinitely small numbers. 

For our purposes, you can think of integrals as the reverse, or the inverse, of derivatives; 
integration is the inverse of differentiation. The symbol J represents integration. You 
can think of integration as a process of adding up a bunch of infinitely small chunks of 
some variable. Here again, we are not going to deal with infinitely small pieces of any¬ 
thing, but instead will consider small, discrete parcels of some variable—for example, 
a small, discrete amount of time, area, or mass. In these cases, we’ll use the Z symbol 
instead of the integration symbol. Consider a loaf of bread that’s sliced into uniformly 
thick slices along its whole length. If you wanted to compute the volume of that loaf of 
bread, you can approximate it by starting at one end and computing the volume of the 
first slice, approximating its volume as though it were a very short, square cylinder; then 


8 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



moving on to the second slice, estimating its volume and adding that to the volume of 
the first slice; and then moving on to the third, and fourth, and so on, aggregating the 
volume of the loaf as you move toward the other end. Integration applies this technique 
to infinitely thin slices of volume to compute the volume of any arbitrary shape. The 
same techniques apply to other computations—for example, computing areas, iner¬ 
tias , masses, and so on, and even aggregating distance traveled over successive small 
slices of time, as you’ll see later. In fact, this latter application is the inverse of the de¬ 
rivative of distance with respect to time, which gives speed. Using integration and dif¬ 
ferentiation in this way allows you to work back and forth when computing speed, 
acceleration, and distance traveled, as you’ll see shortly. In fact, we’ll use these concepts 
heavily throughout the rest of this book. 

Mass, Center of Mass, and Moment of Inertia 

The properties of a body— mass, center of mass, and moment of inertia, collectively called 
mass properties —are absolutely crucial to the study of mechanics, as the linear and 
angular 1 motion of a body and a body’s response to a given force are functions of these 
mass properties. Thus, in order to accurately model a body in motion, you need to know 
or be capable of calculating these mass properties. Let’s look at a few definitions first. 

In general, people think of mass as a measure of the amount of matter in a body. For 
our purposes in the study of mechanics, we can also think of mass as a measure of a 
body’s resistance to motion or a change in its motion. Thus, the greater a body’s mass, 
the harder it will be to set it in motion or change its motion. 

In laymen’s terms, the center of mass (also known as center of gravity) is the point in a 
body around which the mass of the body is evenly distributed. In mechanics, the center 
of mass is the point through which any force can act on the body without resulting in 
a rotation of the body. 

Although most people are familiar with the terms mass and center of gravity, the term 
moment of inertia is not so familiar; however, in mechanics it is equally important. The 
mass moment of inertia of a body is a quantitative measure of the radial distribution of 
the mass of a body about a given axis of rotation. Analogous to mass being a measure 
of a body’s resistance to linear motion, mass moment of inertia (also known as rotational 
inertia) is a measure of a body’s resistance to rotational motion. 

Now that you know what these properties mean, let’s look at how to calculate each. 

For a given body made up of a number of particles, the total mass of the body is simply 
the sum of the masses of all elemental particles making up the body, where the mass of 


1. Linear motion refers to motion in space without regard to rotation; angular motion refers specifically to the 
rotation of a body about any axis (the body may or may not be undergoing linear motion at the same time). 


Mass, Center of Mass, and Moment of Inertia | 9 


www.it-ebooks.info 



each elemental particle is its mass density times its volume. Assuming that the body is 
of uniform density, then the total mass of the body is simply the density of the body 
times the total volume of the body. This is expressed in the following equation: 

m = /pdV = p f dV 

In practice, you rarely need to take the volume integral to find the mass of a body, 
especially considering that many of the bodies we will consider—for example, cars and 
planes—are not of uniform density. Thus, you will simplify these complicated bodies 
by breaking them down into an ensemble of component bodies of known or easily 
calculable mass and simply sum the masses of all components to arrive at the total mass. 

The calculation of the center of gravity of a body is a little more involved. First, divide 
the body into a finite number of elemental masses with the center of each mass specified 
relative to the reference coordinate system axes. Well refer to these elemental masses 
as m r Next, take the first moment of each mass about the reference axes and then add 
up all of these moments. The first moment is the product of the mass times the distance 
along a given coordinate axis from the origin to the center of mass. Finally, divide this 
sum of moments by the total mass of the body, yielding the coordinates to the center of 
mass of the body relative to the reference axes. You must perform this calculation once 
for each dimension—that is, twice when working in 2D and three times when working 
in 3D. Here are the equations for the 3D coordinates of the center of mass of a body: 

x c = { fx 0 dm} / m 

Yc= {/y 0 dm} /m 

z c = {/ z o dm} /m 

where (x, y, z) c are the coordinates of the center of mass for the body and (x, y, z) 0 are 
the coordinates of the center of mass of each elemental mass. The quantities x a dm, y a 
dm, and z a dm represent the first moments of the elemental mass, dm, about each of the 
coordinate axes. 

Here again, don’t worry too much about the integrals in these equations. In practice, 
you will be summing finite numbers of masses and the formulas will take on the friend¬ 
lier forms shown here: 


x c = {E x 0 mj} / {E m;} 
y c = {E y 0 mj} / {Em;} 
z c = {E z 0 nii} / {Emi} 

Note that you can easily substitute weights for masses in these formulas since the con¬ 
stant acceleration due to gravity, g, would appear in both the numerators and denomi- 


10 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



nators, thus dropping out of the equations. Recall that the weight of an object is its mass 
times the acceleration due to gravity, g, which is 9.8 m/s 2 at sea level. 

The formulas for calculating the total mass and center of gravity for a system of discrete 
point masses can conveniently be written in vector notation as follows: 

m t = X mj 

CG=[S (c gi ) ( mi )]/m t 

where m, is the total mass, m i is the mass of each point mass in the system, CG is the 
combined center of gravity, and cgj is the location of the center of gravity of each point 
mass in design, or reference, coordinates. Notice that CG and eg, are shown as vectors 
since they denote position in Cartesian coordinates. This is a matter of convenience 
since it allows you to take care of the x, y, and z components (or just x and y in two 
dimensions) in one shot. 

In the code samples that follow, let’s assume that the point masses making up the body 
are represented by an array of structures where each structure contains the point mass’s 
design coordinates and mass. The structure will also contain an element to hold the 
coordinates of the point mass relative to the combined center of gravity of the rigid 
body, which will be calculated later. 

typedef struct _PointMass 

{ 

float mass; 

Vector designPosition; 

Vector correctedPosition; 

} PointMass; 

// Assume that _NUMELEMENTS has been defined 
PointMassElements[_NUMELEMENTS]; 

Here’s some code that illustrates how to calculate the total mass and combined center 
of gravity of the elements: 

int i; 

float TotalMass; 

Vector CombinedCG; 

Vector FlrstMoment; 

TotalMass = 0; 

for(i=0; i<_NUMELEMENTS; i++) 

TotalMass FAC+= Elements[i].mass; 

FlrstMoment = Vector(0, 0, 0); 
for(l=0; i<_NUMELEMENTS; i++) 

{ 

FlrstMoment += Element[i].mass * Element[i].designPosttion; 


Mass,CenterofMass,andMomentoflnertia | 11 


www.it-ebooks.info 



} 

ConblnedCG = FlrstMonent / TotalMass; 

Now that the combined center of gravity location has been found, you can calculate the 
relative position of each point mass as follows: 

for(t=0; i<_NUMELEMENTS; i++) 

{ 

Elenentfi].correctedPosition = Elenentfi].designPosition - 
ComblnedCG; 

} 

To calculate mass moment of inertia, you need to take the second moment of each 
elemental mass making up the body about each coordinate axis. The second moment 
is then the product of the mass times distance squared. That distance is not the distance 
to the elemental mass centroid along the coordinate axis as in the calculation for center 
of mass, but rather the perpendicular distance from the coordinate axis, about which 
we want to calculate the moment of inertia, to the elemental mass centroid. 

Referring to Figure 1-2 for an arbitrary body in three dimensions, when calculating 
moment of inertia about the x-axis, / xx , this distance, r, will be in the yz-plane such that 
r 2 = y 2 + z 2 . Similarly, for the moment of inertia about the y-axis, / yy , r 2 = z 2 + x 2 , and 
for the moment of inertia about the z-axis, / zz , r 2 = x 2 + y 2 . 





Figure 1-2. Arbitrary body in 3D 


The equations for mass moment of inertia about the coordinate axes in 3D are: 

Ixx = /r x 2 dm = /(y 2 + z 2 ) dm 
lyy = fr y 2 dm = /(z 2 + x 2 ) dm 
Izz = /r z 2 dm = / (x 2 + y 2 ) dm 

Let’s look for a moment at a common situation that arises in practice. Say you are given 
the moment of inertia, I a , of a body about an axis, called the neutral axis, passing through 


12 | Chapter 1: Basic Concepts 


www.it-ebooks.info 


















the center of mass of the body, but you want to know the moment of inertia, I, about an 
axis some distance from but parallel to this neutral axis. In this case, you can use the 
transfer of axes, or parallel axis theorem, to determine the moment of inertia about this 
new axis. The formula to use is: 


T = I 0 + md 2 

where m is the mass of the body and d is the perpendicular distance between the parallel 
axes. 

There is an important practical observation to make here: the new moment of inertia 
is a function of the distance separating the axes squared. This means that in cases where 
I a is known to be relatively small and d relatively large, you can safely ignore /„, since 
the md 2 term will dominate. You must use your best judgment here, of course. This 
formula for transfer of axes also indicates that the moment of inertia of a body will be 
at its minimum when calculated about an axis passing through the body’s center of 
gravity. The body’s moment of inertia about any parallel axis will always increase by an 
amount, md 2 , when calculated about an axis not passing through the body’s center of 
mass. 

In practice, calculating mass moment of inertia for all but the simplest shapes of uniform 
density is a complicated endeavor, so we will often approximate the moment of inertia 
of a body about axes passing through its center of mass by using simple formulas for 
basic shapes that approximate the object. Further, we will break down complicated 
bodies into smaller components and take advantage of the fact that I a may be negligible 
for certain components considering its md 2 contribution to the total body’s moment of 
inertia. 

Figure 1-3 through Figure 1-7 show some simple solid geometries for which you can 
easily calculate mass moments of inertia. The mass moment of inertia formulas for each 
of these simple geometries of homogenous density about the three coordinate axes are 
shown in the figure captions. You can readily find similar formulas for other basic ge¬ 
ometries in college-level dynamics texts (see the Bibliography at the end of this book 
for a few sources). 


Mass, Center of Mass, and Moment of Inertia | 13 


www.it-ebooks.info 





Figure 1-5. Rectangular cylinder: I xx = (1/12) m(a 2 + l 2 ); l yy = (1/12) m(b 2 + l 2 ); I z: = 
(1/12) m(a 2 + b 2 ) 


14 | Chapter 1: Basic Concepts 


www.it-ebooks.info 










; 

< 

Figure 1-6. Sphere: 1^ = I yy = I zz = (2/5) mr 

; 

Z'^^' 

..■V Xy 


Figure 1-7. Spherical shell: I xx = I = I zz = (2/3) mr 2 


As you can see, these formulas are relatively simple to implement. The trick here is to 
break up a complex body into a number of smaller, simpler representative geometries 
whose combination will approximate the complex body’s inertia properties. This exer¬ 
cise is largely a matter of judgment considering the desired level of accuracy. 

Let’s look at a simple 2D example demonstrating how to apply the formulas discussed 
in this section. Suppose you’re working on a top-down-view auto racing game where 
you want to simulate the automobile sprite based on 2D rigid-body dynamics. At the 
start of the game, the player’s car is at the starting line, full of fuel and ready to go. Before 
starting the simulation, you need to calculate the mass properties of the car, driver, and 
fuel load at this initial state. In this case, the body is made up of three components: the 
car, driver, and full load of fuel. Later during the game, however, the mass of this body 
will change as fuel burns off and the driver gets thrown after a crash! For now, let’s focus 
on the initial condition, as illustrated in Figure 1-8. 


Mass,CenterofMass,andMomentoflnertia | 15 


www.it-ebooks.info 









The properties of each component in this example are given in Table 1-2. Note that 
length is measured along the x-axis, width along the y-axis, and height would be coming 
out of the screen. Also note that the coordinates—in the form (x,y )—to the centroid of 
each component are referenced to the global origin. 


Table 1-2. Example properties 


1 Car 

Driver (seated) 

Fiicl 1 

Length = 4.70 m 

Length = 0.90 m 

Length = 0.50 m 

Width = 1.80 m 

Width = 0.50 m 

Width = 0.90 m 

Height = 1.25 m 

Height= 1.10 m 

Height = 0.30 m 

Weight = 17,500 N 

Weight = 850 N 

Density of fuel = 750 kg/m 3 

Centroid = (30.5,30.5) m 

Centroid = (31.50,31.00) m 

Centroid = (28.00,30.50) m 


The first mass property we want to calculate is the mass of the body. This is a simple 
calculation since we are already given the weight of the car and the driver. The only 
other component of weight we need is that of the fuel. Since we are given the mass 
density of the fuel and the geometry of the tank, we can calculate the volume of the tank 
and multiply by the density and the acceleration due to gravity to get the weight of the 
fuel in the tank. This yields 920.6 N of fuel, as shown here: 

Wfuei = pvg = (750 kg/m 3 ) (0.50 m) (0.90 m) (0.30 m) (9.81 m/s 2 ) 

= 993 N 


- 

0 % 

•>' 4 », 

a ,4 * 


Acceleration due to gravity is the acceleration of a falling object as it 
falls toward the earth. The weight of an object is equal to its mass times 
the acceleration due to gravity. The symbol g is used to represent the 
acceleration due to gravity, and on Earth the value ofgis approximately 
9.8 m/s 2 at sea level. Units for weight in the metric system are Newtons, 


N. 


16 | Chapter 1: Basic Concepts 


www.it-ebooks.info 












Now, the total weight of the body is: 

Wtotal = W car + Wjj-j ver + Wf ue i 
Wtotal = 17,500 N + 850 N + 993 N = 19,343 N 

To get the mass of the body, you simply divide the weight by the acceleration due to 
gravity. 


Mtotal = Wt 0 tai/g = 19,343 N /(9.81 m/s 2 ) = 1972 kg 

The next mass property we want is the location of the center of gravity of the body. In 
this example we will calculate the centroid relative to the global origin. We will also apply 
the first moment formula twice, once for the x coordinate and again for they coordinate: 

X C g body = {( x cg car)(W ca r) + (x C g driverX^driver) + (x C g fuel) 

(Wfuel)} / Wtotal 

X C g body = {(30.50 m)( 17,500 N) + (31.50 m)(850 N) + (28.00 m) 

(993 N)} / 19,343 N 
Xcg body = 30.42 m 

Ycg body = {(y C g car)(W ca r) + (Ycg driver)(^driver) + (Ycg fuel) 

(Wfuei)} /Wt 0 tal 

Y cg body = {(30.50 m)(17,500 N) + (31.00 m)(850 N) + (30.50 m) 

(993 N)} / 19,343 N 
Ycg body = 30.52 m 

Notice that we used weight in these equations instead of mass. Remember we can do 
this because the acceleration due to gravity built into the weight value is constant and 
appears in both the numerator and denominator, thus canceling out. 

Now it’s time to calculate the mass moment of inertia of the body. This is easy enough 
in this 2D example since we have only one rotational axis, coming out of the paper, and 
thus need only perform the calculation once. The first step is to calculate the local 
moment of inertia of each component about its own neutral axis. Given the limited 
information we have on the geometry and mass distribution of each component, we 
will make a simplifying approximation by assuming that each component can be rep¬ 
resented by a rectangular cylinder, and will thus use the corresponding formula for 
moment of inertia from Figure 1-5. In the equations to follow, we’ll use a lowercase w 
to represent width so as to not confuse it with weight, where we’ve been using a capital 
W. 


I 0 car = (m/12) (W 2 + L 2 ) 


Mass,CenterofMass,andMomentoflnertia | 17 


www.it-ebooks.info 



Io car = ((17,500 N / 9.81 m/s 2 ) / 12 ) ((1.80 m) 2 + (4.70 m) 2 ) = 
3765.5 N - s 2 - m 
I 0 driver = (m/12) (w 2 + L 2 ) 

Io driver = ((850 N / 9.81 m/s 2 ) / 12) ((0.50 m) 2 + (0.90 m) 2 ) = 7.7 

N - s 2 - m 

Io fuel = (m/12) (w 2 + L 2 ) 

Io fuel = ((993 N / 9.81 m/s 2 ) / 12) ((0.90 m) 2 + (0.50 m) 2 ) = 8.9 N 

- s 2 - m 


Since these are the moments of inertia of each component about its own neutral axis, 
we now need to use the parallel axis theorem to transfer these moments to the neutral 
axis of the body, which is located at the body center of gravity that we recently calculated. 
To do this, we must find the distance from the body center of gravity to each component’s 
center of gravity. The distances squared from each component to the body center of 
gravity are: 


d“car — ( x cg car X C g) _ + (Ycg car Y C g) _ 

d 2 car = (30.50 m - 30.42 m) 2 + (30.50 m - 30.53 m) 2 = 0.01 m 2 


)“ + (y C g driver Y C g) 2 
d 2 driver = (31.50 m - 30.42 m) 2 + (31.25 m - 30.53 m) 2 = 1.68 


^“driver — ( x cg driver X C g)“ + (ycg driver ^cg)" 


m- 


2 fuel = 


( x cg fuel X cg )- + (ycg fuel 5f C g) 


d 2 f U ei = (28.00 m - 30.42 m) 2 + (30.50 m - 30.53 m) 2 = 5.86 m 2 


Now we can apply the parallel axis theorem as follows: 

leg car = Io + md“ 

leg car = 3765.5 N - s 2 - m + (17,500 N / 9.81 m/s 2 ) (0.01 m 2 ) = 
3783.34 N-s 2 -m 

leg driver = Io + md - 

Icg driver = 7.7 N - s 2 - m + (850 N / 9.81 m/s 2 ) (1.68 m 2 ) = 
153.27 N - s 2 - m 

leg fuel = Io + md“ 

leg fuel = 8.9 N - s 2 - m + (993 N / 9.81 m/s 2 ) (5.86 m 2 ) = 
602.07 N - s 2 - m 


18 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



Notice how the calculations for the I cg of the driver and the fuel are dominated by their 
md 2 terms. In this example, the local inertia of the driver and fuel is only 2.7% and 2.1%, 
respectively, of their corresponding md 2 terms. 

Finally, we can obtain the total moment of inertia of the body about its own neutral axis 
by summing the I cg contributions of each component as follows: 

leg total = leg car + leg driver + ^cg fuel 

leg total = 3783.34 N - s 2 - m + 153.27 N - s 2 - m + 602.07 N - 
s 2 - m = 4538.68 N - s 2 - m 

The mass properties of the body—that is, the combination of the car, driver, and full 
tank of fuel—are shown in Table 1-3. 

Table 1-3. Example summary of mass properties 


Property Computed value 


Total mass (weight) 1972 kg (19,343 N) 

Combined center of mass location (x,y) = (30.42 m, 30.53 m) 

Mass moment of inertia 4538.68 N - s 2 - m 

It is important that you understand the concepts illustrated in this example well because 
as we move on to more complicated systems and especially to general motion in 3D, 
these calculations are only going to get more complicated. Moreover, the motion of the 
bodies to be simulated are functions of these mass properties, where mass will determine 
how these bodies are affected by forces, center of mass will be used to track position, 
and mass moment of inertia will determine how these bodies rotate under the action of 
noncentroidal forces. 

So far, we have looked at moments of inertia about the three coordinate axes in 3D space. 
However, in general 3D rigid-body dynamics, the body may rotate about any axis—not 
necessarily one of the coordinate axes, even if the local coordinate axes pass through 
the body center of mass. This complication implies that we must add a few more terms 
to our set of Is for a body to handle this generalized rotation. We will address this topic 
further later in this chapter, but before we do that we need to go over Newton’s second 
law of motion in detail. 


Mass,CenterofMass,andMomentoflnertia | 19 


www.it-ebooks.info 






Newton's Second Law of Motion 

As we stated in the first section of this chapter, Newton’s second law of motion is of 
particular interest in the study of mechanics. Recall that the equation form of Newtons 
second law is: 


F = ma 

where F is the resultant force acting on the body, m is the mass of the body, and a is the 
linear acceleration of the body center of gravity. 

If you rearrange this equation as follows: 

F/m = a 

you can see how the mass of a body acts as a measure of resistance to motion. Observe 
here that as mass increases in the denominator for a constant applied force, then the 
resulting acceleration of the body will decrease. You could say that the body of greater 
mass offers greater resistance to motion. Similarly, as the mass decreases for a constant 
applied force, then the resulting acceleration of the body will increase, and you could 
say that the body of smaller mass offers lower resistance to motion. 

Newton’s second law also states that the resulting acceleration is in the same direction 
as the resultant force on the body; thus, force and acceleration must be treated as vector 
quantities. In general, there may be more than one force acting on the body at a given 
time, which means that the resultant force is the vector sum of all forces acting on the 
body. So, you can now write: 


Yj F = ma 


where a represents the acceleration vector. 

In 3D, the force and acceleration vectors will have x,y, and z components in the Cartesian 
reference system. In this case, the component equations of motion are written as follows: 

Z F x = ma x 
Z Fy = may 
ZF z = ma z 

An alternative way to interpret Newton’s second law is that the sum of all forces acting 
on a body is equal to the rate of change of the body’s momentum over time, which is 
the derivative of momentum with respect to time. Momentum equals mass times ve¬ 
locity, and since velocity is a vector quantity, so is momentum. Thus: 


20 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



G = mv 


where G is linear momentum of the body, m is the body’s mass, and v is velocity of the 
center of gravity of the body. The time rate of change of momentum is the derivative of 
momentum with respect to time: 


dG/dt = d/dt (mv) 

Assuming that the body mass is constant (for now), you can write: 

dG/dt = m dv/dt 

Observing that the time rate of change of velocity, dv/dt, is acceleration, we arrive at: 

dG/dt = ma 


and: 


Yj F = dG/dt = ma 

So far we have considered only translation of the body without rotation. In generalized 
3D motion, you must account for the rotational motion of the body and will thus need 
some additional equations to fully describe the body’s motion. Specifically, you will 
require analogous formulas relating the sum of all moments (torque) on a body to the 
rate of change in its angular momentum over time, or the derivative of angular mo¬ 
mentum with respect to time. This gives us: 

I M cg = d/dt (H cg ) 

where X M cg is the sum of all moments about the body center of gravity, and H is the 
angular momentum of the body. M cg can be expressed as: 

M cg = r x F 

where F is a force acting on the body, and r is the distance vector from F, perpendicular 
to the line of action of F (i.e., perpendicular to the vector F), to the center of gravity of 
the body, and x is the vector cross-product operator. 

The angular momentum of the body is the sum of the moments of the momentum of 
all particles in the body about the axis of rotation, which in this case we assume passes 
through the center of gravity of the body. This can be expressed as: 

H cg = 2 rj x mj (to x rj) 


Newton's Second Law of Motion | 21 


www.it-ebooks.info 



where i represents the zth particle making up the body, to is the angular velocity of the 
body about the axis under consideration, and (r ; x m { (to x r,)) is the angular momentum 
of the zth particle, which has a magnitude of m^r 2 . For rotation about a given axis, this 
equation can be rewritten in the form: 

H cg = /tor dm 

Given that the angular velocity is the same for all particles making up the rigid body, 
we have: 


H cg = to Jr 2 dm 

and recalling that moment of inertia, I, equals / r 2 dm, we get: 

H cg = Ito 

Taking the derivative with respect to time, we obtain: 

dH cg /dt = d/dt (Ito) = I dto/dt = la 

where a is the angular acceleration of the body about a given axis. 
Finally, we can write: 

S M cg = la 


As we stated in our discussion on mass moment of inertia, we will have to further 
generalize our formulas for moment of inertia and angular moment to account for 
rotation about any body axis. Generally, M and a will be vector quantities, while I will 
be a tensor 2 since the magnitude of moment of inertia for a body may vary depending 
on the axis of rotation (see the sidebar “Tensors” on page 22). 


Tensors 

A tensor is a mathematical expression that has magnitude and direction, but its mag¬ 
nitude may not be unique depending on the direction. Tensors are typically used to 
represent properties of materials where these properties have different magnitudes in 
different directions. Materials with properties that vary depending on direction are 
called anisotropic (isotropic implies the same magnitude in all directions). For example, 
consider the elasticity (or strength) of two common materials, a sheet of plain paper 


2. In this case, I will be a second-rank tensor, which is essentially a 3x3 matrix. A vector is actually a tensor of 
rank one, and a scalar is actually a tensor of rank zero. 


22 | Chapter 1: Basic Concepts 


www.it-ebooks.info 





and a piece of woven or knitted cloth. Take the sheet of paper and, holding it flat, pull 
on it softly from opposing ends. Try this length-wise, width-wise, and along a diagonal. 
You should observe that the paper seems just as strong, or stretches about the same, in 
all directions. It is isotropic; therefore, only a single scalar constant is required to rep¬ 
resent its strength for all directions. 

Now, try to find a piece of cloth with a simple, relatively loose weave where the threads 
in one direction are perpendicular to the threads in the other direction. Most neckties 
will do. Try the same pull test that you conducted with the sheet of paper, pulling the 
cloth along each thread direction and then at a diagonal to the threads. You should 
observe that the cloth stretches more when you pull it along a diagonal to the threads 
as opposed to pulling it along the direction of the run of the threads. The cloth is ani¬ 
sotropic in that it exhibits different elastic (or strength) properties depending on the 
direction of pull; thus, a collection of vector quantities (a tensor) is required to represent 
its strength for all directions. 

In the context of this book, the property under consideration is a body’s moment of 
inertia, which in 3D requires nine components to fully describe it for any arbitrary 
rotation. Moment of inertia is not a strength property as in the paper and cloth example, 
but it is a property of the body that varies with the axis of rotation. Since nine components 
are required, moment of inertia will be generalized in the form of a 3x3 matrix (i.e., a 
second-rank tensor) later in this book. 


We need to mention a few things at this point regarding coordinates, which will become 
important when you’re writing your real-time simulator. Both of the equations of mo¬ 
tion have, so far, been written in terms of global coordinates and not body-fixed coor¬ 
dinates. That’s OK for the linear equation of motion, where you can track the body’s 
location and velocity in the global coordinate system. However, from a computational 
point of view, you don’t want to do that for the angular equation of motion for bodies 
that rotate in three dimensions. 3 The reason is because the moment of inertia term, 
when calculated with respect to global coordinates, actually changes depending on the 
body’s position and orientation. This means that during your simulation you’ll have to 
recalculate the inertia matrix (and its inverse) a lot, which is computationally inefficient. 
It’s better to rewrite the equations of motion in terms of local (attached to the body) 
coordinates so you have to calculate the inertia matrix (and its inverse) only once at the 
start of your simulation. 

In general, the time derivative of a vector, V, in a fixed (nonrotating) coordinate system 
is related to its time derivative in a rotating coordinate system by the following: 

(dV/dt) fixed = (dV/dt) rot + (® X V) 


3. In two dimensions, its OK to leave the angular equation of motion as its shown here since the moment of 
inertia term is simply a constant scalar quantity. 


Newton's Second Law of Motion | 23 


www.it-ebooks.info 





The (to x V) term represents the difference between Vs time derivative as measured in 
the fixed coordinate system and V’s time derivative as measured in the rotating coor¬ 
dinate system. We can use this relation to rewrite the angular equation of motion in 
terms of local, or body-fixed, coordinates. Further, the vector to consider is the angular 
momentum vector H cg . Recall that H cg = I to and its time derivative are equal to the sum 
of moments about the body’s center of gravity. These are the pieces you need for the 
angular equation of motion, and you can get to that equation by substituting H cg in place 
of V in the derivative transform relation as follows: 

£ M cg = dH cg /dt = I (doo/dt) + (<d X (I ©)) 

where the moments, inertia tensor, and angular velocity are all expressed in local (body) 
coordinates. Although this equation looks a bit more complicated than the one we 
showed you earlier, it is much more convenient to use since I will be constant throughout 
your simulation (unless your body’s mass or geometry changes for some reason during 
your simulation), and the moments are relatively easy to calculate in local coordinates. 
You’ll put this equation to use in Chapter 15 when we show you how to develop a simple 
3D rigid-body simulator. 

Inertia Tensor 

Take another look at the angular equation of motion and notice that we set the inertia 
term, I, in bold, implying that it is a vector. You’ve already seen that, for two-dimensional 
problems, this inertia term reduces to a scalar quantity representing the moment of 
inertia about the single axis of rotation. However, in three dimensions there are three 
coordinate axes about which the body can rotate. Moreover, in generalized three di¬ 
mensions, the body can rotate about any arbitrary axis. Thus, for three-dimensional 
problems, I is actually a 3x3 matrix—a second-rank tensor. 

To understand where this inertia matrix comes from, you must look again at the angular 
momentum equation: 


H cg = /(r x (<d x r)) dm 

where to is the angular velocity of the body; r is the distance from the body’s center of 
gravity to each elemental mass, dm; and (r x (to x r ))dm is the angular momentum of 
each elemental mass. The term in parentheses is called a triple vector product and can 
be expanded by taking the vector cross products, r and to are vectors that can be written 
as follows: 


r = xi + yj + zk 

(O = (% i + (Dy j + co z k 


24 [ Chapter 1: Basic Concepts 


www.it-ebooks.info 



Expanding the triple vector product term yields: 

H cg = / { [(y 2 + z 2 )o) x - xyo) y - xzm z ] i + 

[ -yxw x + (z 2 + x 2 )(o y - yzo) z ] j + 

[-zxo) x - zytOy + (x 2 + y 2 )coz] k} dm 

To simplify this equation, let’s replace a few terms by letting: 

Ixx = / (y 2 + z 2 ) dm 

lyy = /(Z 2 + X 2 ) dm 

Izz = /(x 2 + y 2 ) dm 
Ixy = Jyx = /( x Y) dm 
I xz — Izx = /( xz ) dm 
lyz = Izy = / (yz) dm 

Substituting these I variables, some of which should look familiar to you, back into the 
expanded equation yields: 

H C g = [I xx <«>x — Ixy ®y — Ixz ®z] I + 

[— Iyx w x + lyy ©y — lyz (l, zl j + 

L — Izx ©X — Izy ©y + Izz ©zl ^ 

Simplifying this a step further by letting I be a matrix: 

Ixx — Ixy — Ixz 

I = — lyx lyy — lyz 

— Izx — Izy Izz 

yields the following equation: 

H cg = I © 


Inertia Tensor | 25 


www.it-ebooks.info 



You already know that I represents the moment of inertia, and the terms that should 
look familiar to you already are the moment of inertia terms about the three coordinate 
axes, 1xx, Iyy, and f zz . The other terms are called products of inertia (see Figure 1-9): 

Ixy = Iy x = / (xy) dm 
I xz — Izx = /( xz ) dm 
lyz = Izy = / (yz) dm 



Figure 1-9. Products of inertia 


Just like the parallel axis theorem, there’s a similar transfer of axis formula that applies 
to products of inertia: 


Ixy = lo(xy) + m d x dy 
Ixz = lo(xz) + m d x d z 
lyz = lo(yz) + m dy d z 

where the I 0 terms represent the local products of inertia (that is, the products of inertia 
of the object about axes that pass through its own center of gravity), m is the object’s 
mass, and the d terms are the distances between the coordinate axes that pass through 
the object’s center of gravity and a parallel set of axes some distance away (see 
Figure 1-10). 

You’ll notice that we did not give you any product of inertia formulas for the simple 
shapes shown earlier in Figure 1-3 through Figure 1-7. The reason is that the given 
moments of inertia were about the principal axes for these shapes. For any body, there 
exists a set of axes—called the principal axes—oriented such that the product of inertia 
terms in the inertia tensor are all zero. 


26 | Chapter 1: Basic Concepts 


www.it-ebooks.info 












y 0 



Figure 1-10. Transfer of axes 

For the simple geometries shown earlier, each coordinate axis represented a plane of 
symmetry, and products of inertia go to zero about axes that represent planes of sym¬ 
metry. You can see this by examining the product of inertia formulas, where, for ex¬ 
ample, all of the (xy) terms in the integral will be cancelled out by each corresponding 
-(xy) term if the body is symmetric about the y-axis, as illustrated in Figure 1-11. 


- 

/ 

dm -x 

X 

dm 

y 



y 




Figure 1-11. Symmetry 

For composite bodies, however, there may not be any planes of symmetry, and the 
orientation of the principal axes will not be obvious. Further, you may not even want to 
use the principal axes as your local coordinate axes for a given rigid body since it may 


Inertia Tensor | 27 


www.it-ebooks.info 















be awkward to do so. For example, consider the airplane from the FlightSim discussion 
in Chapter 7, where you’ll have the local coordinate design axes running, relative to the 
pilot, fore and aft, up and down, and left and right. This orientation is convenient for 
locating the parts of the wings, tail, elevators, etc. with respect to one another, but these 
axes don’t necessarily represent the principal axes of the airplane. The end result is that 
you’ll use axes that are convenient and deal with the nonzero products of inertia (which, 
by the way, can be either positive or negative). 

We already showed you how to calculate the combined moments of inertia for a com¬ 
posite body made up of a few smaller elements. Accounting for the product of inertia 
terms follows the same procedure except that, typically, your elements are such that 
their local product of inertia terms are zero. This is the case only if you represent your 
elements by simple geometries such as point masses, spheres, rectangles, etc. That being 
the case, the main contribution to the rigid body’s products of inertia will be due to the 
transfer of axes terms for each element. 

Before looking at some sample code, let’s first revise the element structure to include a 
new term to hold the element’s local moment of inertia as follows: 

typedef struct _PointMass 

1 

float mass; 

Vector designPositlon; 

Vector correctedPositlon; 

Vector locallnertla; 

} PointMass; 

Here we’re using a vector to represent the three local moment of inertia terms and we’re 
also assuming that the local products of inertia are zero for each element. 

The following code sample shows how to calculate the inertia tensor given the compo¬ 
nent elements: 

float Ixx, Iyy, Izz, Ixy, Ixz, Iyz; 

Matrix3x3 InertiaTensor; 

Ixx = 0; Iyy = 0; Izz = 0; 

Ixy = 0; Ixz = 0; Iyz = 0; 

for (i = 0; i<_NUMELEMENTS; 1++) 

1 

Ixx += Elenentfl].Locallnertla.x + 

Elenentfl].mass * (Elementfi].correctedPositlon.y * 

Elementfl].correctedPositlon.y + 

Elementfi].correctedPositlon.z * 

Element[i].correctedPositlon.z); 

Iyy += Elementfl].Locallnertla.y + 

Elementfi].mass * (Elementfi].correctedPositlon.z * 

Elementfi].correctedPositlon.z + 


28 | Chapter 1: Basic Concepts 


www.it-ebooks.info 



Elemental] .correctedPosition.x * 

Element[i].correctedPosition.x); 

Izz += Element[i].Locallnertia.z + 

Elementfl].mass * (Element[i].correctedPosition.x * 

Element[i].correctedPosition.x + 

Element[i].correctedPosition.y * 

Element[i].correctedPosition.y); 

Ixy += Element[i].mass * (Element[i].correctedPosition.x * 

Element[i].correctedPosition.y); 

Ixz += Element[i].mass * (Element[i].correctedPosition.x * 

Element[i].correctedPosition.z); 

Iyz += Element[i].mass * (Element[i].correctedPosition.y * 

Element[i].correctedPosition.z); 

} 

// ell stands for element on row 1 column 1, el2 for row 1 column 2, etc. 

InertiaTensor.ell = Ixx; 

InertiaTensor,el2 = -Ixy; 

InertiaTensor.el3 = -Ixz; 

InertiaTensor,e21 = -Ixy; 

InertiaTensor,e22 = Iyy; 

InertiaTensor.e23 = -Iyz; 

InertiaTensor,e31 = -Ixz; 

InertiaTensor,e32 = -Iyz; 

InertiaTensor.e33 = Izz; 

Note that the inertia tensor is calculated about axes that pass through the combined 
center of gravity for the rigid body, so be sure to use the corrected coordinates for each 
element relative to the combined center of gravity when applying the transfer of axes 
formulas. 

We should also mention that this calculation is for the inertia tensor in body-fixed 
coordinates, or local coordinates. As we discussed earlier in this chapter, it is better to 
rewrite the angular equation of motion in terms of local coordinates and use the local 
inertia tensor to save some number crunching in your real-time simulation. 

Relativistic Time 

To allow for a thorough understanding of how advanced space vehicles work as well as 
give you a mechanism by which to alter time in your games, we would like to offer a 
brief introduction to the theory of relativity, and particularly its effect on time. In our 
everyday experience, it is safe to assume that the clock on your wall is ticking at the same 
rate as the clock on our wall as we write this. However, the reason we all know the name 


Relativistic Time | 29 


www.it-ebooks.info 



Albert Einstein is that he had the foresight to abandon time as a constant. Instead he 
postulated that light travels at the same speed regardless of the motion of the source. 

That is to say, if you shine a flashlight in a vacuum, the electromagnetic radiation it emits 
in the form of visible light travels at a set velocity of c (299,792,458 m/s). Now, if you 
take that same flashlight and put it on the nose of a rocket traveling at half that speed 
directly at you, you might expect that light is traveling at you with a velocity of 1.5c. Yet, 
the rocket-powered flashlight would still be observed as emitting light at a velocity of 
c. As Einstein’s theory of special relativity matured, the postulate has been reformulated 
to state that there is a maximum speed at which information can be transferred in the 
space-time continuum, a principal called locality. As electromagnetic radiation has no 
mass, 4 it travels at this maximum speed in a vacuum. 

The most startling consequence of the theory is that time is no longer absolute. The 
postulate that the speed of light is constant for all frames of reference requires that time 
slow down, or dilate, as velocity increases. It is actually fairly easy to demonstrate this 
result. 

The following example depicts a conceptual clock. A beam of light is bouncing between 
two mirrors. The time it takes for the beam of light to start from one mirror, bounce off 
the second, and return to the first constitutes one “tick” of this clock. That tick can be 
calculated as: 


At = 2L/c 

Where L is the distance between the mirrors and c is the speed of light. Figure 1-12 
shows what the clock would look like if you were above it traveling at its velocity. 


Mirror A 

-—-r 


" A 


L 


___ ±. 

Mirror B 


Figure 1-12. Traveling with the clock 


4. Photons, the particle form of electromagnetic radiation, can have relativistic mass but are hypothesized to 
have no “rest mass.” To avoid getting into quantum electrodynamics, here we’ll just consider them without 
mass. 


30 | Chapter 1: Basic Concepts 


www.it-ebooks.info 









Now suppose that you are above the mirrors as they speed past you to the right. Then 
the clock would look something like Figure 1-13. 



One tick of the clock is now defined as twice the distance of the hypotenuse over the 
speed of light. Clearly H must be larger than L, so we see that the clock with the relative 
velocity will take longer to tick than if you were moving with the clock. 

If this isn’t clear, we can also come to the same conclusion a different way. If we define 
the speed of light as the amount of time it takes for the light beam to travel the distance 
between the mirrors divided by the time it took to travel that distance, we see that: 

c = 2L/At 

but because the speed of light must be held constant in all frames of reference via locality, 
we also have: 


c = 2H/At 

For the two preceding equations to be equivalent, At must be different for each system. 

This means that if I were in a rocket moving at high velocity past you as you read this 
book, you would look at the clock on my rocket wall and see it ticking more slowly than 
your clock. Now, it may seem as though I would look out of my rocket and see your 
clock running fast, but in fact the opposite is true. I would consider myself at rest and 
you speeding past me such that I would say your clock is running slowly. This may seem 
counterintuitive, but think of it in the same way as visual perspective. If you are at a 
great distance from me, then you appear to be small. That doesn’t imply that I would 
appear to be huge to you! 

Now the amount of dilation for a given velocity v is given by the Lorentz transformation: 


Relativistic Time | 31 


www.it-ebooks.info 











At’ = yAt 


where: 


Y = 



is called the Lorentzfactor. 

For velocities approaching the speed of light, the effect of time dilation is dramatic. 
Imagine if you had a twin sister. She boards a spaceship and is accelerated to three- 
fourths the speed of light relative to you on Earth. Upon her return, according to her 
clock, 20 years have elapsed since she left. However, due to time dilation you will have 
aged 30 years. While this seems paradoxical given that you both will have observed each 
other’s time as running slowly compared to your own, the paradox is resolved by the 
fact that special relativity claims only that inertial frames of reference are identical. For 
the spaceship to return to Earth, it must accelerate by changing directions or, in other 
words, become a noninertial frame of reference. Once the ship is no longer an inertial 
frame of reference, there will appear to be a jump in the stay-at-home twin’s age. Strange 
but true! 

In addition to time dilation due to relative velocity, time also slows down in the presence 
of strong gravitational fields as a result of Einstein’s theory of general relativity. This sort 
of time dilation is not relative in the sense that if I were closer to a black hole than you, 
we’d both agree that my clock is ticking less often than yours. However, given that all 
physical processes would be slower, there is no way to establish which clock is “faster” 
and which is “slower.” It is all relative! 

As some games require a way to speed up or slow down time, the applications of time 
dilation allow for a physical phenomenon to enable time manipulation. Imagine your 
character needing to be sent to the future to complete some task. That character could 
be put into a centrifuge and accelerated near the speed of light. Upon exiting the cen¬ 
trifuge, he would essentially have time-traveled into the future. However, if you plan to 
stay within the limits of physics, then it is a one-way trip: there is no way to reverse time 
in relativity! Additionally, if you would like to send a character to a nearby star, you can 
do so within the limits of physics as well. By accelerating a spaceship, a human being 
would be able to travel a great distance in a lifetime. In fact, with a constant acceleration 
of 9.8 m/s 2 , which would make the astronauts feel like they were on Earth, you could 
travel the entire visible galaxy. However, you would have essentially time-traveled bil¬ 
lions of years into the future. We are sure that you can imagine any number of scenarios 
where such a mechanism might make your game more interesting while always re¬ 
maining in the realm of the physically possible! 


32 | Chapter 1: Basic Concepts 


www.it-ebooks.info 





Now, besides those implications to games involving space flight or high-velocity travel, 
time dilation is also important to some surprising digital electronic applications. For 
instance, the Global Positioning System (GPS), described in detail in Chapter 22, must 
take relativistic time dilation into account when calculating position. The satellite’s high 
speed slows the clock compared to your watch on Earth; however, being farther up the 
Earth’s gravity causes it to tick faster than a terrestrial clock. The specifics of this com¬ 
bined effect are discussed in Chapter 22. 

Another point you might find interesting is that it is now easy to see how the “you can’t 
travel faster than light” rule is a result of the theory of relativity. Should you accelerate 
such that your velocity, v, is equal to c, the Lorentz transformation attempts to divide 
by zero. For games where faster-than-light travel is a practical necessity, you will have 
to imagine a mechanism to prevent this but be able to break the rules with style. 


Relativistic Time | 33 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 2 


Kinematics 


In this chapter we’ll explain the fundamental aspects of the subject of kinematics. 
Specifically, we’ll explain the concepts of linear and angular displacement, velocity, and 
acceleration. We’ve prepared an example program for this chapter that shows you how 
to implement the kinematic equations for particle motion. After discussing particle 
motion, we go on to explain the specific aspects of rigid-body motion. This chapter, 
along with the next chapter on force, is prerequisite to understanding the subject of 
kinetics, which you’ll study in Chapter 4. 

In the preface, we told you that kinematics is the study of the motion of bodies without 
regard to the forces acting on the body. Therefore, in kinematics, attention is focused 
on position, velocity, and acceleration of a body, how these properties are related, and 
how they change over time. 

Here you’ll look at two types of bodies, particles and rigid bodies. A rigid body is a 
system of particles that remain at fixed distances from one another with no relative 
translation or rotation among them. In other words, a rigid body does not change its 
shape as it moves—or any changes in its shape are so small or unimportant that they 
can safely be neglected. When you are considering a rigid body, its dimensions and 
orientation are important, and you must account for both the body’s linear motion and 
its angular motion. 

A particle, on the other hand, is a body that has mass but whose dimensions are negli¬ 
gible or unimportant in the problem being investigated. For example, when considering 
the path of a projectile or a rocket over a great distance, you can safely ignore the body’s 
dimensions when analyzing its trajectory. When you are considering a particle, its linear 
motion is important, but the angular motion of the particle itself is not. Think of it this 
way: when looking at a particle, you are zooming way out to view the big picture, so to 
speak, as opposed to zooming in as you do when looking at the rotation of rigid bodies. 


35 


www.it-ebooks.info 




Whether you are looking at problems involving particles or rigid bodies, there are some 
important kinematic properties common to both. These are, of course, the objects po¬ 
sition, velocity, and acceleration. The next section discusses these properties in detail. 

Velocity and Acceleration 

In general, velocity is a vector quantity that has magnitude and direction. The magnitude 
of velocity is speed. Speed is a familiar term—it’s how fast your speedometer says you’re 
going when driving your car down the highway. Formally, speed is the rate of travel, or 
the ratio of distance traveled to the time it took to travel that distance. In math terms, 
you can write: 


v = As/At 

where v is speed, the magnitude of velocity v, and As is distance traveled over the time 
interval At. Note that this relation reveals that the units for speed are composed of the 
basic dimension’s length divided by time, LIT. Some common units for speed are meters 
per second, m/s; feet per second, ft/sec; and miles per hour, mi/hr. 

Here’s a simple example (illustrated in Figure 2-1): a car is driving down a straight road 
and passes marker one at time t l and marker two at time f 2 , where t 1 equals 0 seconds 
and t 2 equals 1.136 seconds. The distance between these two markers, s, is 30 m. Calculate 
the speed of the car. 


1 1 


V 

CL 


© 

o 


Figure 2-1. Example car speed 


You are given that s equals 30 m; therefore, As equals 30 m and A, equals t 2 - f, or 1.136 
seconds. The speed of the car over this distance is: 

v = As/At = 30 m/1.136 sec = 26.4 m/sec 

which is approximately 60 mi/hr. This is a simple one-dimensional example, but it brings 
up an important point, which is that the speed just calculated is the average speed of the 
car over that distance. You don’t know anything at this point about the car’s acceleration, 


36 | Chapter 2: Kinematics 


www.it-ebooks.info 








or whether or not it is traveling at a constant 60 mi/hr. It could very well be that the car 
was accelerating (or decelerating) over that 30 m distance. 

To more precisely analyze the motion of the car in this example, you need to understand 
the concept of instantaneous velocity. Instantaneous velocity is the specific velocity at 
a given instant in time, not over a large time interval as in the car example. This means 
that you need to look at very small At s. In math terms, you must consider the limit as 
At approaches 0—that is, as At gets infinitesimally small. This is written as follows: 

v = limAt-»o (As/At) 

In differential terms, velocity is the derivative of displacement (change in position) with 
respect to time: 


v = ds/dt 

You can rearrange this relationship and integrate over the intervals from s, to s 2 and f, 
to t 2 , as shown here: 


v dt = ds 

/(si to s2) ds = /(ti to t2) V dt 
s2 - si = As = / (tl t o t2) v dt 


This relation shows that displacement is the integral of velocity over time. This gives 
you a way of working back and forth between displacement and velocity. 

Kinematics makes an important distinction between displacement and distance trav¬ 
eled. In one dimension, displacement is the same as distance traveled; however, with 
vectors in space, displacement is actually the vector from the initial position to the final 
position without regard to the path traveled, while displacement is the difference be¬ 
tween the starting position coordinates and the ending position coordinates. Thus, you 
need to be careful when calculating average velocity given displacement if the path from 
the starting position to the final position is not a straight line. When At is very small (as 
it approaches 0), displacement and distance traveled are the same. 

Another important kinematic property is acceleration, which should also be familiar to 
you. Referring to your driving experience, you know that acceleration is the rate at which 
you can increase your speed. Your friend who boasts that his brand new XYZ 2011 can 
go from 0 to 60 in 4.2 seconds is referring to acceleration. Specifically, he is referring to 
average acceleration. 

Formally, average acceleration is the rate of change in velocity, or Av over At: 

a = Av/At 


Velocity and Acceleration | 37 


www.it-ebooks.info 



Taking the limit as A t goes to 0 gives the instantaneous acceleration: 


a = limAt-^o Av/At 
a = dv/dt 

Thus, acceleration is the time rate of change in velocity, or, the derivative of velocity 
with respect to time. 

Multiplying both sides by dt and integrating yields: 

dv = a dt 

/(vl to v2) dv = / (t i to t2) a dt 

v2 - vl = Av = /(u to t2) a dt 

This relationship provides a means to work back and forth between velocity and accel¬ 
eration. 

Thus, the relationships between displacement, velocity, and acceleration are: 

a = dv/dt = d 2 s/dt 2 


and: 


v dv = a ds 

This is the kinematic differential equation of motion (see the sidebar “Second Deriva¬ 
tives” on page 38 for some helpful background). In the next few sections you’ll see some 
examples of the application of these equations for some common classes of problems 
in kinematics. 


Second Derivatives 

In Chapter 1, we explained that you need not worry about the use of derivatives and 
integrals in this book if you’re unfamiliar with calculus since we’ll show you how to 
implement the code to take care of them computationally. That still applies, but here 
we’ve introduced new notation: 

d 2 s/dt 2 

which is an equation representing acceleration as the second derivative of distance trav¬ 
eled with respect to time. You can think of second derivatives as just two successive 
derivatives in the manner we explained in Chapter 1. In the case of distance traveled, 
velocity, and acceleration, the first derivative of distance traveled with respect to time is 


38 | Chapter 2: Kinematics 


www.it-ebooks.info 





velocity and the second derivative of distance traveled with respect to time is accelera¬ 
tion, which is the same as the first derivative of velocity with respect to time. 


Constant Acceleration 

One of the simplest classes of problems in kinematics involves constant acceleration. A 
good example of this sort of problem involves the acceleration due to gravity, g, on 
objects moving relatively near the earth’s surface, where the gravitational acceleration 
is a constant 9.81 m/s 2 . Having constant acceleration makes integration over time rel¬ 
atively easy since you can pull the acceleration constant out of the integrand, leaving 
just dt. 

Integrating the relationship between velocity and acceleration described earlier when 
acceleration is constant yields the following equation for instantaneous velocity: 

/(vl to v2) dv = /(ti to t2) a dt 
/(vl to v2) dv = a /(ti to t2) dt 
v 2 — v i = a /(ti to t 2 ) dt 
v 2 -vi = a (t 2 - t|) 
v 2 = a t 2 — a ti + vi 

When t l equals 0, you can rewrite this equation in the following form: 

v 2 = a t 2 + V! 
v 2 = vi + a t 2 

This simple equation allows you to calculate the instantaneous velocity at any given time 
by knowing the elapsed time, the initial velocity, and the constant acceleration. 

You can also derive an equation for velocity as a function of displacement instead of 
time by considering the kinematic differential equation of motion: 

v dv = a ds 

Integrating both sides of this equation yields the following alternative function for in¬ 
stantaneous velocity: 

/(vl to v2) v dv = a / s i s2) ds 
(v 2 2 - vi 2 ) / 2 = a (s 2 - si) 
v 2 2 = 2a (s 2 - si) + vi 2 


Constant Acceleration | 39 


www.it-ebooks.info 






You can derive a similar formula for displacement as a function of velocity, acceleration, 
and time by integrating the differential equation: 

v dt = ds 

with the formula derived earlier for instantaneous velocity: 

v 2 — v i + at 

substituted for v. Doing so yields the formula: 

s 2 = s l + v i t + (a t 2 ) /2 

In summary, the three preceding kinematic equations derived are: 

v 2 = vi + a t 2 
v 2 2 = 2a (s 2 - si) + vi 2 
s 2 = si + vi t + (a t 2 ) / 2 

Remember, these equations are valid only when acceleration is constant. Note that ac¬ 
celeration can be 0 or even negative in cases where the body is decelerating. 

You can rearrange these equations by algebraically solving for different variables, and 
you can also derive other handy equations using the approach that we just demonstrated. 
For your convenience, we’ve provided some other useful kinematic equations for con¬ 
stant acceleration problems in Table 2-1. 

Table 2-1. Constant acceleration kinematic formulas 


To find: 

Given these: 

Use this: 

a 

At, v 1( v 2 

a = (v 2 —v n ) / At 

a 

At, v 1( As 

a = (2 As — 2 v 2 At) / (At) 2 

a 

v-i, v 2 , As 

a = (v 2 2 — v 2 2 ) / (2 As) 

As 

a,v„v 2 

As = (v 2 2 - v 2 2 ) / (2a) 

As 

At, v,, v 2 

As = (At/2) (v, + v 2 ) 

At 

a,v„v 2 

At = (v 2 -v,)/a 

At 

a, v„ As 

At = 

[fvf + laAs - vj la 

At 

v„ v 2 , As 

At=(2As)/(v 1 + v 2 ) 

Vl 

At, a, v 2 

v n = v 2 — aAt 

Vl 

At, a, As 

v, = As/At - (aAt)/2 


40 | Chapter 2: Kinematics 


www.it-ebooks.info 






To find: Given these: Use this: 


Vi a, v 2 , As v,=_ 

Jvf-2aAs 


In cases where acceleration is not constant, but is some function of time, velocity, or 
position, you can substitute the function for acceleration into the differential equations 
shown earlier to derive new equations for instantaneous velocity and displacement. The 
next section considers such a problem. 

Nonconstant Acceleration 

A common situation that arises in real-world problems is when drag forces act on a 
body in motion. Typically, drag forces are proportional to velocity squared. Recalling 
the equation of Newton’s second law of motion, F = ma, you can deduce that the accel¬ 
eration induced by these drag forces is also proportional to velocity squared 

Later we’ll show you some techniques to calculate this sort of drag force, but for now 
let the functional form of drag-induced acceleration be: 

a = -kv 2 

where k is a constant and the negative sign indicates that this acceleration acts in the 
direction opposing the body’s velocity. Now substituting this formula for acceleration 
into the previous equation and then rearranging yields: 

a = dv/dt 
-kv 2 = dv/dt 
-k dt = dv/v 2 

If you integrate the right side of this equation from v x to v 2 and the left side from 0 to 
t, and then solve for v 2 , you’ll get this formula for the instantaneous velocity as a function 
of the initial velocity and time: 


-k /(o to t) dt = /(vi to v2) (1/v 2 ) dv 
-k t = 1/vj - 1 /V 2 
v 2 = vi /(I + vikt) 

If you substitute this equation for v in the relation v = ds/dt and integrate again, you’ll 
end up with a new equation for displacement as a function of initial velocity and time; 
see the following procedure: 

v dt = ds; where v = vj / (1 + vjk t) 


Nonconstant Acceleration | 41 


www.it-ebooks.info 







If s t equals 0, then: 


/( 0 to t) v dt = /(si to s2) ds 
/(0 to t) [vi / (1 + vik t)] dt = /( S i t0 s 2 ) ds 
ln(l + vi k t) / k = S 2 - si 


s = ln(l + vi k t) /k 

Note that in this equation, In is the natural logarithm operator. 

This example demonstrates the relative complexity of nonconstant acceleration prob¬ 
lems versus constant acceleration problems. It’s a fairly simple example where you are 
able to derive closed-form equations for velocity and displacement. In practice, however, 
there may be several different types of forces acting on a given body in motion, which 
could make the expression for induced acceleration quite complicated. This complexity 
would render a closed-form solution like the preceding one impossible to obtain unless 
you impose some simplifying restrictions on the problem, forcing you to rely on other 
solution techniques like numerical integration. We’ll talk about this sort of problem in 
greater depth in Chapter 11. 

2D Particle Kinematics 

When we are considering motion in one dimension—that is, when the motion is re¬ 
stricted to a straight line—it is easy enough to directly apply the formulas derived earlier 
to determine instantaneous velocity, acceleration, and displacement. However, in two 
dimensions, with motion possible in any direction on a given plane, you must consider 
the kinematic properties of velocity, acceleration, and displacement as vectors. 

Using rectangular coordinates in the standard Cartesian coordinate system, you must 
account for the x and y components of displacement, velocity, and acceleration. Essen¬ 
tially, you can treat the x and y components separately and then superimpose these 
components to define the corresponding vector quantities. 

To help keep track of these x and y components, let i and j be unit vectors in the x- and 
y-directions, respectively. Now you can write the kinematic property vectors in terms 
of their components as follows: 


V = v x i +Vyj 
a = a x i + a y j 

If x is the displacement in the x-direction and y is the displacement in the y-direction, 
then the displacement vector is: 


s = x i + y j 


42 | Chapter 2: Kinematics 


www.it-ebooks.info 



It follows that: 


v = ds/dt = dx/dt i + dy/dt j 
a = dv/dt = d 2 s/dt 2 = d 2 x/dt 2 i + d 2 y/dt 2 j 


Consider a simple example where you’re writing a shooting game and you need to figure 
out the vertical drop in a fired bullet from its aim point to the point at which it actually 
hits the target. In this example, assume that there is no wind and no drag on the bullet 
as it flies through the air (we’ll deal with wind and drag on projectiles in Chapter 6). 
These assumptions reduce the problem to one of constant acceleration, which in this 
case is that due to gravity. It is this gravitational acceleration that is responsible for the 
drop in the bullet as it travels from the rifle to the target. Figure 2-2 illustrates the 
problem. 


^ I Aim point 



—.c 

f rj 


Hit point 

-- n -H 

1 


Figure 2-2. A 2D kinematics example problem 


tfi* 

- 

While we’re talking about guns and shooting here, we should point out 
*<?; j that these techniques can be applied just as easily to simulating the flight 

— . of angry birds in Angry Birds being shot from oversized slingshots, as 
in the very popular iPhone app. Heck, you can use these techniques to 
simulate flying monkeys, ballistic shoes, or coconuts being hurled at 
Navy combatants! This particle kinematic stuff is perfect for diversion¬ 
ary smartphone apps. 


Let the origin of the 2D coordinate system be at the end of the rifle with the x-axis 
pointing toward the target and the y-axis pointing up. Positive displacements along the 
x-axis are toward the target, and positive displacements along the y-axis are upward. 
This implies that the gravitational acceleration will act in the negative y-direction. 

Treating the x and y components separately allows you to break up the problem into 
small, easy-to-manage pieces. Looking at the x component first, you know that the bullet 
will leave the rifle with an initial muzzle velocity v m in the x-direction, and since we are 
neglecting drag, this speed will be constant. Thus: 


2D Particle Kinematics | 43 


www.it-ebooks.info 













a x = 0 
v x = v m 
X = v x t = v m t 

Now looking at they component, you know that the initial speed in the y-direction, as 
the bullet leaves the rifle, is 0, but the y-acceleration is -g (due to gravity). Thus: 

a y = -g = dv y /dt 
v y = a y t = —g t 
y = (1/2) a y t 2 = -(1/2) g t 2 

The displacement, velocity, and acceleration vectors can now be written as: 

s = (v m t) i — (1/2 g t 2 ) j 
v = (v m ) i - (g t) j 
a = - (g) j 

These equations give the instantaneous displacement, velocity, and acceleration for any 
given instant between the time the bullet leaves the rifle and the time it hits the target. 
The magnitudes of these vectors give the total displacement, velocity, and acceleration 
at a given time. For example: 

S = J(v m t)~ + (l/2gt 2 ) 2 


V = V(v m ) 2 + (gt) 2 

a = 4g~ 2 = g 

To calculate the bullets vertical drop at the instant the bullet hits the target, you must 
first calculate the time required to reach the target; then, you can use that time to cal¬ 
culate they component of displacement, which is the vertical drop. Here are the formulas 
to use: 


thit = XhiAm = n/v m 
d = Yhit = -(1/2) g (thit) 2 

where n is the distance from the rifle to the target and d is the vertical drop of the bullet 
at the target. 


44 | Chapter 2: Kinematics 


www.it-ebooks.info 





If the distance to the target, n, equals 500 m and the muzzle velocity, v m , equals 800 m/ 
sec, then the equations for ^hit and d give: 

thit = 0.625 sec 
d = 1.9 m 

These results tell you that in order to hit the intended target at that range, you’ll need 
to aim for a point about 2 m above it. 

3D Particle Kinematics 

Extending the kinematic property vectors to three dimensions is not very difficult. It 
simply involves the addition of one more component to the vector representations 
shown in the previous section on 2D kinematics. Introducing k as the unit vector in the 
z-direction, you can now write: 


s = xi + yj + zk 

v = ds/dt = dx/dt i + dy/dt j + dz/dt k 
a = d 2 s/dt 2 = d 2 x/dt 2 i + d 2 y/dt 2 j + d 2 z/dt 2 k 

Instead of treating two components separately and then superimposing them, you now 
treat three components separately and superimpose these. This is best illustrated by an 
example. 

Suppose that instead of a hunting game, you’re now writing a game that involves the 
firing of a cannon from, say, a battleship to a target some distance away—for example, 
another ship or an inland target like a building. To add complexity to this activity for 
your user, you’ll want to give her control of several factors that affect the shell’s trajectory 
—namely, the firing angle of the cannon, both horizontal and vertical angles, and the 
muzzle velocity of the shell, which is controlled by the amount of powder packed behind 
the shell when it’s loaded into the cannon. The situation is set up in Figure 2-3. 



Figure 2-3. A 3D kinematics example problem 


3D Particle Kinematics | 45 


www.it-ebooks.info 








We’ll show you how to set up the kinematic equations for this problem by treating each 
vector component separately at first and then combining these components. 

X Components 

The x components here are similar to those in the previous section’s rifle example in 
that there is no drag force acting on the shell; thus, the x component of acceleration is 
0, which means that the x component of velocity is constant and equal to the x compo¬ 
nent of the muzzle velocity as the shell leaves the cannon. Note that since the cannon 
barrel may not be horizontal, you’ll have to compute the x component of the muzzle 
velocity, which is a function of the direction in which the cannon is aimed. 

The muzzle velocity vector is: 

v m = v mx i + v my j + v mz k 

and you are given only the direction of v m as determined by the direction in which the 
user points the cannon, and its magnitude as determined by the amount of powder the 
user packs into the cannon. To calculate the components of the muzzle velocity, you 
need to develop some equations for these components in terms of the direction angles 
of the cannon and the magnitude of the muzzle velocity. 

You can use the direction cosines of a vector to determine the velocity components as 
follows: 


cos 0 X = Vmx/Vm 

COS 0y = V m y/v m 

cox 9 Z = v mz /v m 

Refer to Appendix A for a description and illustration of vector direction cosines. 

Since the initial muzzle velocity vector direction is the same as the direction in which 
the cannon is aimed, you can treat the cannon as a vector with a magnitude of L, its 
length, and pointing in a direction defined by the angles given in this problem. Using 
the cannon length, L, and its components instead of muzzle velocity in the equations 
for direction cosines gives: 


cos 0 X = L x /L 

COS 9y = Ly/L 

cos 0 Z = L z /L 

In this example, you are given the angles a and y (see Figure 2-4) that define the cannon 
orientation. 


46 | Chapter 2: Kinematics 


www.it-ebooks.info 




Figure 2-4. Cannon orientation 


Using these angles, it follows that the projection, b, of the cannon length, L, onto the x- 
z plane is: 


b = L cos(90° - a) 

and the components of the cannon length, L, on each coordinate axis are: 

Lx = b cos y 
Ly = L cos a 
Lz = b sin y 

Now that you have the information required to compute direction cosines, you can write 
equations for the initial muzzle velocity components as follows: 

v mx = v m cos 0 X 

v my = v m cos 9y 
v mz = v m cos 

Finally, you can write the x components of displacement, velocity, and acceleration as 
follows: 


a x = 0 

v x = v mx = v m cos 0 X 
x = v x t = (v m cos 0 X ) t 


Y Components 

They components are just like the previous rifle example, again with the exception here 
of the initial velocity in the y-direction: 


3D Particle Kinematics | 47 


www.it-ebooks.info 






Vmy = v m COS 0 y 


Thus: 


a y — -g 

v y = v my + a t = (v m cos 0 y ) - g t 

Before writing the equation for they component of displacement, you need to consider 
the elevation of the base of the cannon, plus the height of the end of the cannon barrel, 
in order to calculate the initial y component of displacement when the shell leaves the 
cannon. Let y h be the elevation of the base of the cannon, and let L be the length of the 
cannon barrel; then the initial y component of displacement, y Q , is: 

y 0 = Yb + L cos a 

Now you can write the equation for y as: 

y = y 0 + v my t + (1/2) at 2 
y = (yb + L cos a) + (v m cos 0 y ) t - (1/2) g t 2 


Z Components 

The z components are largely analogous to the x components and can be written as 
follows: 


a z = 0 

v z = V m z = v m COS 0 Z 
Z = V z t = (v m COS 0 Z ) t 


The Vectors 

With the components all worked out, you can now combine them to form the vector 
for each kinematic property. Doing so for this example gives the displacement, velocity, 
and acceleration vectors shown here: 

s = [(v m cos 0 X ) t] i + [(yb + L cos a) + (v m cos 0 y ) t - (1/2) g t 2 ] 
j + [(v m cos 0 Z ) t ] k 

v = [v m cos 0 X ] i + [(v m cos 0 y ) - g t ] j + [v m cos 0 Z ] k 

a — -g j 


48 | Chapter 2: Kinematics 


www.it-ebooks.info 



Observe here that the displacement vector essentially gives the position of the shells 
center of mass at any given instant in time; thus, you can use this vector to plot the shells 
trajectory from the cannon to the target. 

Hitting the Target 

Now that you have the equations fully describing the shell’s trajectory, you need to 
consider the location of the target in order to determine when a direct hit occurs. To 
show you how to do this, we’ve prepared a sample program that implements these 
kinematic equations along with a simple bounding box collision detection method for 
checking whether or not the shell has struck the target. Basically, at each time step where 
we calculate the position of the shell after it has left the cannon, we check to see if this 
position falls within the bounding dimensions of the target obj ect represented by a cube. 

The sample program is set up such that you can change all of the variables in the sim¬ 
ulation and view the effects of your changes. Figure 2-5 shows the main screen for the 
cannon example program, with the governing variables shown on the left. The upper 
illustration is a bird’s-eye view looking down on the cannon and the target, while the 
lower illustration is a profile (side) view. 



Figure 2-5. Cannon sample program main window 


3D Particle Kinematics | 49 


www.it-ebooks.info 










































You can change any of the variables shown on the main window and press the Fire 
button to see the resulting flight path of the shell. A message box will appear when you 
hit the target or when the shell hits the ground. The program is set up so you can 
repeatedly change the variables and press Fire to see the result without erasing the 
previous trial. This allows you to gauge how much you need to adjust each variable in 
order to hit the target. Press the Refresh button to redraw the views when they get too 
cluttered. 

Figure 2-6 shows a few trial shots that we made before finally hitting the target. 


in 




* * 


Figure 2-6. Trial shots (profile view) 

The code for this example is really quite simple. Aside from the overhead of the window, 
controls, and illustrations setup, all of the action takes place when the Fire button is 
pressed. In pseudocode, the Fire button’s pressed event handler looks something like 
this: 

FIRE BUTTON PRESSED EVENT: 


Fetch and store user input values for global variables, 

Vn, Alpha, Ganna, L, Yb, X, Y, Z, Length, Width, Height... 

Initialize the tine and status variables... 

status = 0; 
tine = 0; 

Start stepping through tine for the sinulation 
until the target is hit, the shell hits 
the ground, or the sinulation tines out... 

while(status == 0) 

{ 

//do the next tine step 
status = DoSinulationQ; 


50 | Chapter 2: Kinematics 


www.it-ebooks.info 





Update the display... 


} 

// Report results 
if (status == 1) 

Display DIRECT HIT message to the user... 
if (status == 2) 

Display MISSED TARGET message to the user... 
if (status == 3) 

Display SIMULATION TIMED OUT message to the user... 

The first task is to simply get the new values for the variables shown on the main window. 
After that, the program enters a while loop, stepping through increments of time and 
recalculating the position of the shell projectile using the formula for the displacement 
vector, s, shown earlier. The shell position at the current time is calculated in the function 
DoSirnulation. Immediately after calling DoSimulation, the program updates the il¬ 
lustrations on the main window, showing the shell’s trajectory. DoSimulation returns 
0, keeping the while loop going, if there has not yet been a collision or if the time has 
not yet reached the preset time-out value. 

Once the while loop terminates by DoSimulation returning nonzero, the program 
checks the return value from this function call to see if a hit has occurred between the 
shell and the ground or the shell and the target. Just so the program does not get stuck 
in this while loop, DoSimulation will return a value of 3, indicating that it is taking too 
long. 

Now let’s look at what’s happing in the function DoSimulation (we’ve also included here 
the global variables that are used in DoSimulation). 

//-.// 

// Define a custom type to represent 
// the three components of a 3D vector, where 
// i represents the x component, j represents 
// the y component, and k represents the z 
// component 

//- ... // 

typedef struct TVectorTag 

{ 

double i; 
double j; 
double k; 

} TVector; 


//.// 

// Now define the variables required for this simulation 

//.// 

double Vm; // Magnitude of muzzle velocity, m/s 


3D Particle Kinematics | 51 


www.it-ebooks.info 








double 

Alpha; 

// 



// 



// 



// 

double 

Gamma; 

// 



// 



// 



// 

double 

L; 

// 

double 

Yb; 

// 

double 

X; 

// 

double 

Y; 

// 

double 

Z; 

// 

double 

Length: 

; // 

double 

Width; 

// 

double 

Height: 

; // 

TVector 

s; 

// 

double 

time; 

// 



// 

double 

tine; 

// 



// 

double 

g; 

// 


Angle from y-axls (upward) to the cannon. 

When this angle is 0, the cannon is pointing 
straight up, when it is 90 degrees, the cannon 
is horizontal 

Angle from x-axis, in the x-z plane to the cannon. 

When this angle is 0, the cannon is pointing in 

the positive x-direction, positive values of this angle 

are toward the positive z-axis 

This is the length of the cannon, m 

This is the base elevation of the cannon, m 

The x-position of the center of the target, m 

The y-position of the center of the target, m 

The z-position of the center of the target, m 

The length of the target measured along the x-axis, m 

The width of the target measured along the z-axis, m 
The height of the target measure along the y-axis, m 

The shell position (displacement) vector 

The time from the instant the shell leaves 
the cannon, seconds 

The time increment to use when stepping through 
the simulation, seconds 

acceleration due to gravity, m/s A 2 


//.-// 

// This function steps the simulation ahead in time. This is where the kinematic 
// properties are calculated. The function will return 1 when the target is hit, 
// and 2 when the shell hits the ground (x-z plane) before hitting the target; 

// otherwise, the function returns 0. 


//.-// 

int DoSimulation(void) 

//.-// 

{ 

double cosX; 

double cosY; 

double cosZ; 

double xe, ze; 

double b. Lx, Ly, Lz; 

double txl, tx2, tyl, ty2, tzl, tz2; 


// step to the next time in the simulation 
time+=tlnc; 


// First calculate the direction cosines for the cannon orientation. 

// In a real game, you would not want to put this calculation in this 
// function since it is a waste of CPU time to calculate these values 
// at each time step as they never change during the sim. We only put them 
// here in this case so you can see all the calculation steps in a single 
// function. 


52 | Chapter 2: Kinematics 


www.it-ebooks.info 






b = L * cos((90-Alpha) *3.14/180); // projection of barrel onto x-z plane 

Lx = b * cos(Gamma * 3.14/180); // x-component of barrel length 

Ly = L * cos(Alpha * 3.14/180); // y-component of barrel length 

Lz = b * sin(Gamma * 3.14/180); // z-conponent of barrel length 

cosX = Lx/L; 
cosY = Ly/L; 
cosZ = Lz/L; 

// These are the x and z coordinates of the very end of the cannon barrel 
// we'll use these as the initial x and z displacements 
xe = L * cos((90-Alpha) *3.14/180) * cos(Gamma * 3.14/180); 

ze = L * cos((90-Alpha) *3.14/180) * sin(Gamma * 3.14/180); 

// Now we can calculate the position vector at this time 
s.i = Vm * cosX * time + xe; 

s.j = (Yb + L * cos(Alpha*3.14/180)) + (Vm * cosY * time) - 

(0.5 * g * time * time); 

s.k = Vm * cosZ * time + ze; 

// Check for collision with target 

// Get extents (bounding coordinates) of the target 

txl = X - Length/2; 

tx2 = X + Length/2; 

tyl = Y - Height/2; 

ty2 = Y + Height/2; 

tzl = Z - Width/2; 

tz2 = Z + Width/2; 

// Now check to see if the shell has passed through the target 
// We're using a rudimentary collision detection scheme here where 
// we simply check to see if the shell's coordinates are within the 
// bounding box of the target. This works for demo purposes, but 

// a practical problem is that you may miss a collision if for a given 

// time step the shell's change in position is large enough to allow 
// it to "skip" over the target. 

// A better approach is to look at the previous time step's position data 
// and to check the line from the previous position to the current position 
// to see if that line intersects the target bounding box. 
if( (s.i >= txl && s.i <= tx2) && 

(s.j >= tyl && s.j <= ty2) && 

(s.k >= tzl && s.k <= tz2) ) 

return 1; 

// Check for collision with ground (x-z plane) 
if(s.j <= 0) 
return 2; 

// Cut off the simulation if it's taking too long 
// This is so the program does not get stuck in the while loop 
if(time>3600) 
return 3; 


3D Particle Kinematics | 53 


www.it-ebooks.info 



return 0; 

} 

We’ve commented the code so that you can readily see what’s going on. This function 
essentially does four things: 1) increments the time variable by the specified time in¬ 
crement, 2) calculates the initial muzzle velocity components in the x-, y-, and z- 
directions, 3) calculates the shell’s new position, and 4) checks for a collision with the 
target using a bounding box scheme or the ground. 

Here’s the code that computes the shell’s position: 

// Now we can calculate the position vector at this tine 
s.i = Vm * cosX * tine + xe; 

s.j = (Yb + L * cos(Alpha*3.14/180)) + (Vn * cosY * tine) - 
(0.5 * g * tine * tine); 
s.k = Vn * cosZ * tine + ze; 

This code calculates the three components of the displacement vector, s, using the for¬ 
mulas that we gave you earlier. If you wanted to compute the velocity and acceleration 
vectors as well, just to see their values, you should do so in this section of the program. 
You can set up a couple of new global variables to represent the velocity and acceleration 
vectors, just as we did with the displacement vector, and apply the velocity and accel¬ 
eration formulas that we gave you. 

That’s all there is to it. It’s obvious by playing with this sample program that the shell’s 
trajectory is parabolic in shape, which is typical projectile motion. We’ll take a more 
detailed look at this sort of motion in Chapter 6. 

Even though we put a comment in the source code, we must reiterate a warning here 
regarding the collision detection scheme that we used in this example. Because we’re 
checking only the current position coordinate to see if it falls within the bounding 
dimensions of the target cube, we run the risk of skipping over the target if the change 
in position is too large for a given time step. A better approach would be to keep track 
of the shell’s previous position and check to see if the line connecting the previous 
position to the new one intersects the target cube. 

Kinematic Particle Explosion 

At this point you might be wondering how particle kinematics can help you create 
realistic game content unless you’re writing a game that involves shooting a gun or a 
cannon. If so, let us offer you a few ideas and then show you an example. Say you’re 
writing a football simulation game. You can use particle kinematics to model the tra¬ 
jectory of the football after it’s thrown or kicked. You can also treat the wide receivers 
as particles when calculating whether or not they’ll be able to catch the thrown ball. In 
this scenario you’ll have two particles—the receiver and the ball—traveling independ¬ 
ently, and you’ll have to calculate when a collision occurs between these two particles, 


54 | Chapter 2: Kinematics 


www.it-ebooks.info 



indicating a catch (unless, of course, your player is all thumbs and fumbles the ball after 
it hits his hands). You can find similar applications for other sports-based games as well. 

What about a 3D “shoot ’em up” game? How could you use particle kinematics in this 
genre aside from bullets, cannons, grenades, and the like? Well, you could use particle 
kinematics to model your player when she jumps into the air, either from a run or from 
a standing position. For example, your player reaches the middle of a catwalk only to 
find a section missing, so you immediately back up a few paces to get a running head 
start before leaping into the air, hoping to clear the gap. This long-jump scenario is 
perfect for using particle kinematics. All you really need to do is define your players 
initial velocity, both speed and take-off angle, and then apply the vector formula for 
displacement to calculate whether or not the player makes the jump. You can also use 
the displacement formula to calculate the player’s trajectory so that you can move the 
player’s viewpoint accordingly, giving the illusion of leaping into the air. You may in fact 
already be using these principles to model this action in your games, or at least you’ve 
seen it done if you play games of this genre. If your player happens to fall short on the 
j ump, you can use the formulas for velocity to calculate the player’s impact velocity when 
she hits the ground below. Based on this impact velocity, you can determine an appro¬ 
priate amount of damage to deduct from the player’s health score, or if the velocity is 
over a certain threshold, you can say goodbye to your would-be adventurer! 

Another use for simple particle kinematics is for certain special effects like particle 
explosions. This sort of effect is quite simple to implement and really adds a sense of 
realism to explosion effects. The particles don’t just fly off in random, straight-line tra¬ 
jectories. Instead, they rise and fall under the influence of their initial velocity, angle, 
and the acceleration due to gravity, which gives the impression that the particles have 
mass. 

So, let’s explore an example of a kinematic particle explosion. The code for this example 
is taken from the cannon example discussed previously, so a lot of it should look familiar 
to you. Figure 2-7 shows this example program’s main window. 


Kinematic Particle Explosion | 55 


www.it-ebooks.info 




Figure 2-7. Particle explosion example program 

The explosion effect takes place in the large rectangular area on the right. While the 
black dots representing exploding particles are certainly static in the figure, we assure 
you they move in the most spectacular way during the simulation. 

In the edit controls on the left, you specify an x- and y-position for the effect, along with 
the initial velocity of the particles (which is a measure of the explosion’s strength), a 
duration in milliseconds, a gravity factor, and finally an angle. The angle parameter can 
be any number between 0 and 360 degrees or 999. When you specify an angle in the 
range of 0 to 360 degrees, all the particles in the explosion will be launched generally in 
that direction. If you specify a value of999, then all the particles will shoot off in random 
directions. The duration parameter is essentially the life of the effect. The particles will 
fade out as they approach that life. 

The first thing you need to do for this example is set up some structures and global 
variables to represent the particle effect and the individual particles making up the effect 
along with the initial parameters describing the behavior of the effect as discussed in 
the previous paragraph. Here’s the code: 


//.// 

// Define a custom type to represent each particle in the effect. 

//.// 

typedef struct _TParticle 
{ 

float x; // x coordinate of the particle 


56 | Chapter 2: Kinematics 


www.it-ebooks.info 

































float 

y; 

// y coordinate of the particle 

float 

vi; 

// initial velocity 

float 

angle; 

// initial trajectory (direction) 

int 

life; 

// duration in milliseconds 

int 

r; 

// red component of particle's color 

int 

g; 

// green component of particle's color 

int 

b; 

// blue component of particle's color 

int 

time; 

// keeps track of the effect's time 

float 

gravity; 

// gravity factor 

BOOL 

Active; 

// indicates whether this particle 
// is active or dead 


} TPartlcle; 

#define _MAXPARTICLES 50 


typedef struct -TParticleExplosion 


{ 

TPartlcle p[_MAXPARTICLES]; // list of particles 

// making up this effect 

int V0; // initial velocity, or strength, of the effect 

int x; // initial x location 

int y; // initial y location 

BOOL Active; // indicates whether this effect is 

//active or dead 

} TParticleExplosion; 

//.// 

// Now define the variables required for this simulation 

//...// 

TParticleExplosion Explosion; 

int xc; // x coordinate of the effect 

int yc; // y coordinate of the effect 

int V0; // initial velocity 

int Duration; // life in milliseconds 

float Gravity; // gravity factor (acceleration) 

float Angle; // indicates particles' direction 


You can see from this code that the particle explosion effect is made up of a collection 
of particles. The behavior of each particle is determined by kinematics and the initial 
parameters set for each particle. 

Whenever you press the Go button, the initial parameters that you specified are used 
to initialize the particle explosion (if you press the Random button, the program ran¬ 
domly selects these initial values for you). This takes place in the function called Crea 
teParticleExplosion: 

///////////////////////////////////////////////////////////////////// 

/* This function creates a new particle explosion effect. 

x,y: starting point of the effect 

Vinit: a measure of how fast the particles will be sent flying 


Kinematic Particle Explosion | 57 


www.it-ebooks.info 






(it's actually the initial velocity of the particles) 
life: life of the particles in milliseconds; particles will 

fade and die out as they approach 
their specified life 

gravity: the acceleration due to gravity, which controls the 
rate at which particles will fall 

as they fly 

angle: initial trajectory angle of the particles, 

specify 999 to create a particle explosion 
that emits particles in all directions; otherwise, 

0 right, 90 up, 180 left, etc... 

*/ 

void CreateParticleExplosion(int x, int y, int Vinit, int life, 

float gravity, float angle) 

{ 

int i; 
int m; 
float f; 

Explosion.Active = TRUE; 

Explosion.x = x; 

Explosion.y = y; 

Explosion.V0 = Vinit; 

for(i=0; i<_MAXPARTICLES; i++) 

{ 

Explosion.p[i].x = 0; 

Explosion.p[i].y = 0; 

Explosion.p[i].vi = tb_Rnd(Vinit/2, Vinit); 

tf(angle < 999) 

{ 

if(tb_Rnd(0,l) == 0) 
m = -1; 

else 

m = 1; 

Explosion.p[i].angle = -angle + m * tb_Rnd(0,10); 

} else 

Explosion.p[i].angle = tb_Rnd(0,360); 

f = (float) tb_Rnd(80, 100) / 100.0f; 

Explosion.p[i].life = tb_Round(life * f); 

Explosion.p[i].r = 255;//tb_Rnd(225, 255); 

Explosion.p[i].g = 255;//tb_Rnd(85, 115); 

Explosion.p[i].b = 255;//tb_Rnd(15, 45); 

Explosion.p[i].time = 0; 

Explosion.p[i].Active = TRUE; 

Explosion.p[i].gravity = gravity; 

} 


} 


58 | Chapter 2: Kinematics 


www.it-ebooks.info 



Here you can see that all the particles are set to start off in the same position, as specified 
by the x andy coordinates that you provide; however, you’ll notice that the initial velocity 
of each particle is actually randomly selected from a range of Vinit/2 to Vinit. We do 
this to give the particle behavior some variety. We do the same thing for the life param¬ 
eter of each particle so they don’t all fade out and die at the exact same time. 

After the particle explosion is created, the program enters a loop to propagate and draw 
the effect. The loop is a while loop, as shown here in pseudocode: 

whlle(status) 

{ 

Clear the off screen buffer... 
status = DrawParticleExplosion( ); 

Copy the off screen buffer to the screen... 

} 

The while loop continues as long as status remains true, which indicates that the 
particle effect is still alive. After all the particles in the effect reach their set life, then the 
effect is dead and status will be set to false. All the calculations for the particle behavior 
actually take place in the function called DrawParticleExploslon; the rest of the code 
in this while loop is for clearing the off-screen buffer and then copying it to the main 
window. 

DrawParticleExploslon updates the state of each particle in the effect by calling an¬ 
other function, UpdateParticleState, and then draws the effect to the off-screen buffer 
passed in as a parameter. Here’s what these two functions look like: 

//-.// 

// Draws the particle system and updates the state of each particle. 

// Returns false when all of the particles have died out. 

//-.// 

BOOL DrawParticleExplosion(void) 

{ 

int i; 

BOOL finished = TRUE; 

float r; 

if(Explosion.Active) 

for(i=0; i<_MAXPARTICLES; i++) 

{ 

if(Explosion.p[i].Active) 

{ 

finished = FALSE; 

// Calculate a color scale factor to fade the particle's color 
// as its life expires 
r = ((float)(Explosion.p[i].Life- 

Explosion .p[i].time)/(float)(Explosion.p[i].life)); 


Kinematic Particle Explosion | 59 


www.it-ebooks.info 







Draw the particle as a small circle... 


} 


} 


Explosion.p[l].Active = UpdatePartlcleState(&(Exploslon.p[l]), 

10 ); 


If(finished) 

Explosion.Active = FALSE; 


return !finished; 

} 


//.// 

/* This Is generic function to update the state of a given particle, 
p: pointer to a particle structure 

dtlme: time Increment In milliseconds to 

advance the state of the particle 


If the total elapsed time for this particle has exceeded the particle's 
set life, then this function returns FALSE, Indicating that the particle 
should expire. 

*/ 

BOOL UpdatePartlcleState(TPartlcle* p, Int dtlme) 

{ 

BOOL retval; 
float t; 


p->tlme+=dtlme; 

t = (float)p->tlme/1000.0f; 

p->x = p->vl * cos(p->angle*PI/180.0f) * t; 

p->y = p->vl * sln(p->angle*PI/180.0f) * t + (p->gravlty*t*t)/2.0f; 

If (p->tlme >= p->llfe) 
retval = FALSE; 

else 

retval = TRUE; 
return retval; 

} 

UpdateParticleState uses the kinematic formulas that we’ve already shown you to 
update the particle’s position as a function of its initial velocity, time, and the acceleration 
due to gravity. After UpdateParticleState is called, DrawParticleExplosion scales 
down each particle’s color, fading it to black, based on the life of each particle and elapsed 
time. The fade effect is simply to show the particles dying slowly over time instead of 
disappearing from the screen. The effect resembles the behavior of fireworks as they 
explode in the night sky. 


60 | Chapter 2: Kinematics 


www.it-ebooks.info 




Rigid-Body Kinematics 

The formulas for displacement, velocity, and acceleration discussed in the previous 
sections apply equally well for rigid bodies as they do for particles. The difference is that 
with rigid bodies, the point on the rigid body that you track, in terms of linear motion, 
is the body’s center of mass (gravity). 

When a rigid body translates with no rotation, all of the particles making up the rigid 
body move on parallel paths since the body does not change its shape. Further, when a 
rigid body does rotate, it generally rotates about axes that pass through its center of 
mass, unless the body is hinged at some other point about which it’s forced to rotate. 
These facts make the center of mass a convenient point to use to track its linear motion. 
This is good news for you since you can use all of the material you learned on particle 
kinematics here in your study of rigid-body kinematics. 

The procedure for dealing with rigid bodies involves two distinct aspects: 1) tracking 
the translation of the body’s center of mass, and 2) tracking the body’s rotation. The first 
aspect is old hat by now—just treat the body as a particle. The second aspect, however, 
requires you to consider a few more concepts—namely, local coordinates, angular dis¬ 
placement, angular velocity, and angular acceleration. 

For most of the remainder of this chapter, we’ll discuss plane kinematics of rigid bodies. 
Plane motion simply means that the body’s motion is restricted to a flat plane in space 
where the only axis of rotation about which the body can rotate is perpendicular to the 
plane. Plane motion is essentially two-dimensional. This allows us to focus on the new 
kinematic concepts of angular displacement, velocity, and acceleration without getting 
lost in the math required to describe arbitrary rotation in three dimensions. 

You might be surprised by how many problems lend themselves to plane kinematic 
solutions. For example, in some popular 3D “shoot ’em up” games, your character is able 
to push objects, such as boxes and barrels, around on the floor. While the game world 
here is three dimensions, these particular objects may be restricted to sliding on the 
floor—a plane—and thus can be treated like a 2D problem. Even if the player pushes 
on these objects at some angle instead of straight on, you’ll be able to simulate the sliding 
and rotation of these objects using 2D kinematics (and kinetics) techniques. 


Rigid-Body Kinematics | 61 


www.it-ebooks.info 



Local Coordinate Axes 

Earlier, we defined the Cartesian coordinate system to use for your fixed global refer¬ 
ence, or world coordinates. This world coordinate system is all that’s required when 
treating particles; however, for rigid bodies you’ll also use a set of local coordinates fixed 
to the body. Specifically, this local coordinate system will be fixed at the body’s center- 
of-mass location. You’ll use this coordinate system to track the orientation of the body 
as it rotates. 

For plane motion, we require only one scalar quantity to describe the body’s orientation. 
This is illustrated in Figure 2-8. 



Figure 2-8. Local coordinate axes 

Here the orientation, Cl, is defined as the angular difference between the two sets of 
coordinate axes: the fixed world axes and the local body axes. This is the so-called Euler 
angle. In general 3D motion there is a total of three Euler angles, which are usually called 
yaw, pitch, and roll in aerodynamic and hydrodynamic jargon. While these angular 
representations are easy to visualize in terms of their physical meaning, they aren’t so 
nice from a numerical point of view, so you’ll have to look for alternative representations 
when writing your 3D real-time simulator. These issues are addressed in Chapter 9. 

Angular Velocity and Acceleration 

In two-dimensional plane motion, as the body rotates, Cl will change, and the rate at 
which it changes is the angular velocity, w. Likewise, the rate at which to changes is the 
angular acceleration, a. These angular properties are analogous to the linear properties 
of displacement, velocity, and acceleration. The units for angular displacement, velocity, 


62 | Chapter 2: Kinematics 


www.it-ebooks.info 








and acceleration are radians (rad), radians per sec (rad/s), and radians per second- 
squared (rad/s 2 ), respectively. 

Mathematically, you can write these relations between angular displacement, angular 
velocity, and angular acceleration as: 


co = d£2/dt 

a = dco/dt = d 2 £2/dt 2 
co = fa dt 
Cl = ft o dt 
co dco = a d£2 

In fact, you can substitute the angular properties Cl, co, and a for the linear properties 
s, v, and a in the equations derived earlier for particle kinematics to obtain similar 
kinematic equations for rotation. For constant angular acceleration, you’ll end up with 
the following equations: 


(02 = ®i + a t 
tt> 2 2 = uq 2 + 2 a (£^2 - Qi) 

Cl 2 = + cojt + (1/2) a t“ 

When a rigid body rotates about a given axis, every point on the rigid body sweeps out 
a circular path around the axis of rotation. You can think of the body’s rotation as causing 
additional linear motion of each particle making up the body—that is, this linear motion 
is in addition to the linear motion of the body’s center of mass. To get the total linear 
motion of any particle or point on the rigid body, you must be able to relate the angular 
motion of the body to the linear motion of the particle or point as it sweeps its circular 
path about the axis of rotation. 

Before we show you how to do this, we’ll explain why you would even want to perform 
such a calculation. Basically, in dynamics, knowing that two objects have collided is not 
always enough, and you’ll often want to know how hard, so to speak, these two objects 
have collided. When you’re dealing with interacting rigid bodies that may at some point 
make contact with one another or with other fixed objects, you need to determine not 
only the location of the points of contact, but also the relative velocity or acceleration 
between the contact points. This information will allow you to calculate the interaction 
forces between the colliding bodies. 

The arc length of the path swept by a particle on the rigid body is a function of the 
distance from the axis of rotation to the particle and the angular displacement, Cl. We’ll 
use c to denote arc length and r to denote the distance from the axis of rotation to the 
particle, as shown in Figure 2-9. 


Angular Velocity and Acceleration | 63 


www.it-ebooks.info 




Figure 2-9. Circular path of particles making up a rigid body 
The formula relating arc length to angular displacement is: 

c = r £2 

where Cl must be in radians, not degrees. If you differentiate this formula with respect 
to time: 


dc/dt = r d£2/dt 

you get an equation relating the linear velocity of the particle as it moves along its circular 
path to the angular velocity of the rigid body. This equation is written as follows: 


v = r co 


This velocity as a vector is tangent to the circular path swept by the particle. Imagine 
this particle as a ball at the end of a rod where the other end of the rod is fixed to a 
rotating axis. If the ball is released from the end of the rod as it rotates, the ball will fly 
off in a direction tangent to the circular path it was taking when attached to the rod. 
This is in the same direction as the tangential linear velocity given by the preceding 
equation. Figure 2-10 illustrates the tangential velocity. 


64 | Chapter 2: Kinematics 


www.it-ebooks.info 







Figure 2-10. Linear velocity due to angular velocity 
Differentiating the equation, v = r to: 

dv/dt = r dco/dt 

yields this formula for the tangential linear acceleration as a function of angular accel¬ 
eration: 


a t = r a 


Note that there is another component of acceleration for the particle that results from 
the rotation of the rigid body. This component—the centripetal acceleration—is normal, 
or perpendicular, to the circular path of the particle and is always directed toward the 
axis of rotation. Remember that velocity is a vector and since acceleration is the rate of 
change in the velocity vector, there are two ways that acceleration can be produced. One 
way is by a change in the magnitude of the velocity vector—that is, a change in speed 
—and the other way is a change in the direction of the velocity vector. The change in 
speed gives rise to the tangential acceleration component, while the direction change 
gives rise to the centripetal acceleration component. The resultant acceleration vector 
is the vector sum of the tangential and centripetal accelerations (see Figure 2-11). Cen¬ 
tripetal acceleration is what you feel when you take your car around a tight curve even 
though your speed is constant. 


Angular Velocity and Acceleration | 65 


www.it-ebooks.info 







Figure 2-11. Tangential and centripetal acceleration 

The formula for the magnitude of centripetal acceleration, a n , is: 


where v is the tangential velocity. Substituting the equation for tangential velocity into 
this equation for centripetal acceleration gives the following alternative form: 

a n = r co 2 

In two dimensions you can easily get away with using these scalar equations; however, 
in three dimensions you’ll have to use the vector forms of these equations. Angular 
velocity as a vector is parallel with the axis of rotation. In Figure 2-10 the angular velocity 
would be pointing out of the page directly at you. Its sense, or direction of rotation, is 
determined by the right hand rule. If you curl the fingers of your right hand in an arc 
around the axis of rotation with your fingers pointing toward the direction in which 
the body is rotating, then your thumb will stick up in the direction of the angular velocity 
vector. 

If you take the vector cross product (refer to the sidebar “Vector Cross Product” on page 
67 for background and to Appendix A for a review of vector math) of the angular velocity 
vector and the vector from the axis of rotation to the particle under consideration, you’ll 
end up with the linear, tangential velocity vector. This is written as follows: 

v = (o X r 


66 | Chapter 2: Kinematics 


www.it-ebooks.info 






Note that this gives both the magnitude and direction of the linear, tangential velocity. 
Also, be sure to preserve the order of the vectors when taking the cross product—that 
is, to cross r, and not the other way around, which would give the wrong direction for v. 


Vector Cross Product 

Given any two vectors A and B, the cross product A x B is defined by a third vector C 
with a magnitude equal to AB sin 0, where 0 is the angle between the two vectors A and 
B, as illustrated in the following figure. 



C = A x B 
C = AB sin 0 

The direction of C is determined by the right hand rule. As noted previously, the right 
hand rule is a simple trick to help you keep track of vector directions. Assume that A 
and B lie in a plane and let an axis of rotation extend perpendicular to this plane through 
a point located at the tail of A. Pretend to curl the fingers of your right hand around the 
axis of rotation from vector A toward B. Now extend your thumb (as though you are 
giving a thumbs up) while keeping your fingers curled around the axis. The direction 
that your thumb is pointing indicates the direction of vector C. 

In the preceding figure, a parallelogram is formed by A and B (the shaded region). The 
area of this parallelogram is the magnitude of C, which is AB sin 0. 


There are two equations that you’ll need in order to determine the vectors for tangential 
and centripetal acceleration. They are: 

a n = (o X (w X r) 
a t = a x r 

Another way to look at the quantities v, a n , and a t is that they are the velocity and 
acceleration of the particle under consideration, on the rigid body, relative to the point 
about which the rigid body is rotating—for example, the body’s center-of-mass location. 
This is very convenient because, as we said earlier, you’ll want to track the motion of 
the rigid body as a particle when viewing the big picture without having to worry about 


Angular Velocity and Acceleration | 67 


www.it-ebooks.info 








what each particle making up the rigid body is doing all the time. Thus, you treat the 
rigid body’s linear motion and its angular motion separately. When you do need to take 
a close look at specific particles of—or points on—the rigid body, you can do so by taking 
the motion of the rigid body as a particle and then adding to it the relative motion of 
the point under consideration. 

Figure 2-12 shows a rigid body that is traveling at a speed v cg , where v cg is the speed of 
the rigid body’s center of mass (or center of gravity). Remember, the center of mass is 
the point to track when treating a rigid body as a particle. This rigid body is also rotating 
with an angular velocity to about an axis that passes through the body’s center of mass. 
The vector r is the vector from the rigid body’s center of mass to the particular point of 
interest, P, located on the rigid body. 



In this case, we can find the resultant velocity of the point, P, by taking the vector sum 
of the velocity of the body’s center of mass and the tangential velocity of point P due to 
the body’s angular velocity to. Here’s what the vector equation looks like: 


Vr = v cg + v t 


or: 


VR = V cg + (to x r) 

You can do the same thing with acceleration to determine point P’s resultant accelera¬ 
tion. Here you’ll take the vector sum of the acceleration of the rigid body’s center of 


68 | Chapter 2: Kinematics 


www.it-ebooks.info 






mass, the tangential acceleration due to the body’s angular acceleration, and the cen¬ 
tripetal acceleration due to the change in direction of the tangential velocity. In equation 
form, this looks like: 


a R — a cg + a n + a t 

Figure 2-13 illustrates what’s happening here. 



You can rewrite the equation for the resultant acceleration in the following form: 
a R = a c „ + (w x (to x r)) + (a x r) 

As you can see, using these principles of relative velocity and acceleration allows you to 
calculate the resultant kinematic properties of any point on a rigid body at any given 
time by determining what the body’s center of mass is doing along with how the body 
is rotating. 


Angular Velocity and Acceleration | 69 


www.it-ebooks.info 






www.it-ebooks.info 


CHAPTER 3 

Force 


This chapter is a prerequisite to Chapter 4, which addresses the subject of kinetics. The 
aim here is to provide you with enough of a background on forces so you can readily 
appreciate the subject of kinetics. This chapter is not meant to be the final word on the 
subject of force. In fact, we feel that the subject of force is so important to realistic 
simulations that we’ll revisit it several times in various contexts throughout the re¬ 
mainder of this book. In this chapter, we’ll discuss the two fundamental categories of 
force and briefly explain some important specific types of force. We’ll also explain the 
relationship between force and torque. 

Forces 

As we mentioned in Chapter 2, you need to understand the concept of force before you 
can fully understand the subject of kinetics. Kinematics is only half the battle. You are 
already familiar with the concept of force from your daily experiences. You exert a force 
on this book as you hold it in your hands, counteracting gravity. You exert force on your 
mouse as you move it from one point to another. When you play soccer, you exert force 
on the ball as you kick it. In general, force is what makes an object move, or more 
precisely, what produces an acceleration that changes the velocity. Even as you hold this 
book, although it may not be moving, you’ve effectively produced an acceleration that 
cancels the acceleration from gravity. When you kick that soccer ball, you change its 
velocity from, say, 0 when the ball is at rest to some positive value as the ball leaves your 
foot. These are some examples of externally applied contact forces. 

There’s another broad category of forces, in addition to contact forces, called field forces 
or sometimes/orces at a distance. These forces can act on a body without actually having 
to make contact with it. A good example is the gravitational attraction between objects. 
Another example is the electromagnetic attraction between charged particles. The con¬ 
cept of a force field was developed long ago to help us visualize the interaction between 
objects subject to forces at a distance. You can say that an object is subjected to the 


71 


www.it-ebooks.info 




gravitational field of another object. Thinking in terms of force fields can help you grasp 
the fact that an object can exert a force on another object without having to physically 
touch it. 

Within these two broad categories of forces, there are specific types of forces related to 
various physical phenomena—forces due to friction, buoyancy, and pressure, among 
others. We’ll discuss idealizations of several of these types of forces in this chapter. Later 
in this book, we’ll revisit these forces from a more practical point of view. 

Before going further, we need to explain the implications of Newton’s third law as in¬ 
troduced in Chapter 1. Remember, Newton’s third law states that for every force acting 
on a body, there is an equal and opposite reacting force. This means that forces must 
exist in pairs—a single force can’t exist by itself. 

Consider the gravitational attraction between the earth and yourself. The earth is ex¬ 
erting a force—your weight—on you, accelerating you toward its center. Likewise, you 
are exerting a force on the earth, accelerating it toward you. The huge difference between 
your mass and the earth’s makes the acceleration of the earth in this case so small that 
it’s negligible. Earlier we said you are exerting a force on this book to hold it up; likewise, 
this book is exerting a force on your hands equal in magnitude but opposite in direction 
to the force you are exerting on it. You feel this reaction force as the book’s weight. 

This phenomenon of action-reaction is the basis for rocket propulsion. A rocket engine 
exerts force on the fuel molecules that are accelerated out of the engine exhaust nozzle. 
The force required to accelerate these molecules is exerted back against the rocket as a 
reaction force called thrust. Throughout the remainder of this book, you’ll see many 
other examples of action-reaction, which is an important phenomenon in rigid-body 
dynamics. It is especially important when we are dealing with collisions and objects in 
contact, as you’ll see later. 

Force Fields 

The best example of a force field or force at a distance is the gravitational attraction 
between objects. Newton’s law of gravitation states that the force of attraction between 
two masses is directly proportional to the product of the masses and inversely propor¬ 
tional to the square of the distances separating the centers of each mass. Further, this 
law states that the line of action of the force of attraction is along the line that connects 
the centers of the two masses. This is written as follows: 

F a = (Gm 1 m 2 )/r 2 

where G is the gravitational constant, Newton’s so-called universal constant. G was first 
measured experimentally by Sir Henry Cavendish in 1798 and equals 6.673x10 11 (N- 
m 2 )/kg 2 in metric units or 3.436x10 s ft 4 /(lb-s 4 ) in English units. 


72 | Chapter 3:Force 


www.it-ebooks.info 



So far in this book, I’ve been using the acceleration due to gravity, g, as a constant 9.8 
m/s 2 (32.174 ft/s 2 ). This is true when you are near the earths surface—for example, at 
sea level. In reality, g varies with altitude—maybe not by much for our purposes, but it 
does. Consider Newton’s second law along with the law of gravitation for a body near 
the earth. Equating these two laws, in equation form, yields: 

m a = (G M e m) / (R e + h ) 2 

where m is the mass of the body, a is the acceleration of the body due to the gravitational 
attraction between it and the earth, M e is the earth’s mass, R e is the radius of the earth, 
and h is the altitude of the body. If you solve this equation for a, you’ll have a formula 
for the acceleration due to gravity as a function of altitude: 

a = g’ = (G M e ) / (R e + h ) 2 

The radius of the earth is approximately 6.38xl0 6 m, and its mass is about 5.98xl0 24 
kgs. Substituting these values in the preceding equation and assuming 0 altitude (sea 
level) yields the constant g that we’ve been using so far—that is, g at sea level equals 9.8 
m/s 2 . 

Friction 

Frictional forces (friction) always resist motion and are due to the interaction between 
contacting surfaces. Thus, friction is a contact force. Friction is always parallel to the 
contacting surfaces at the point of contact—that is, friction is tangential to the contacting 
surfaces. The magnitude of the frictional force is a function of the normal force between 
the contacting surfaces and the surface roughness. 

This is easiest to visualize by looking at a simple block on a horizontal surface, as shown 
in Figure 3-1. 



Friction | 73 


www.it-ebooks.info 











In Figure 3-1, the block is resting on the horizontal surface with a small force, F a , applied 
to the block on a line of action through the blocks center of mass. As this applied force 
increases, a frictional force will develop between the block and the horizontal surface, 
tending to resist the motion of the block. The maximum value of this frictional force is: 

Ffmax = Ms N 

where p s is the experimentally determined coefficient of static 1 friction and N is the 
normal (perpendicular) force between the block and the surface, which equals the 
weight of the block in this case. As the applied force increases but is still less than F [max , 
the block will remain static and F { will be equal in magnitude to the applied force. The 
block is in static equilibrium. When the applied force becomes greater than F' fmax , the 
frictional force can no longer impede the block’s motion and the block will accelerate 
under the influence of the applied force. Immediately after the block starts its motion, 
the frictional force will decrease from F fmax to F fk , where is: 

Ffk = Pk N 

Here k means kinetic since the block is in motion, and p k , the coefficient of kinetic 
friction, 2 is less than p s . Like the static coefficient of friction, the kinetic coefficient of 
friction is determined experimentally. Table 3 -1 shows typical coefficients of friction for 
several surfaces in contact. 


Table 3-1. Coefficients of friction of common surfaces 


1 Surface condition 


M u 

% difference I 

Dry glass on glass 

0.94 

0.4 

54% 

Dry iron on iron 

1.1 

0.15 

86% 

Dry rubber on pavement 

0.55 

0.4 

27% 

Dry steel on steel 

0.78 

0.42 

46% 

Dry Teflon on Teflon 

0.04 

0.04 

— 

Dry wood on wood 

0.38 

0.2 

47% 

Ice on ice 

0.1 

0.03 

70% 

Oiled steel on steel 

0.10 

0.08 

20% 


The data in Table 3 -1 is provided here to show you the magnitude of some typical friction 
coefficients and the relative difference between the static and kinetic coefficients for 
certain surface conditions. Other data is available for these and other surface conditions 


1. Static here implies that there is no motion; the block is sitting still with all forces balancing. 

2. The term dynamic is sometimes used here instead of kinetic. 


74 | Chapter 3: Force 


www.it-ebooks.info 






in the technical literature (see the Bibliography for sources). Note that experimentally 
determined friction coefficient data will vary, even for the same surface conditions, 
depending on the specific condition of the material used in the experiments and the 
execution of the experiment itself. 

Fluid Dynamic Drag 

Fluid dynamic drag forces oppose motion like friction. In fact, a major component of 
fluid dynamic drag is friction that results from the relative flow of the fluid over (and 
in contact with) the body’s surface. Friction is not the only component of fluid dynamic 
drag, though. Depending on the shape of the body, its speed, and the nature of the fluid, 
fluid dynamic drag will have additional components due to pressure variations in the 
fluid as it flows around the body. If the body is located at the interface between two fluids 
(like a ship on the ocean where the two fluids are air and water), an additional compo¬ 
nent of drag will exist due to the wave generation. 

In general, fluid dynamic drag is a complicated phenomenon that is a function of several 
factors. We won’t go into detail in this section on all these factors, since we’ll revisit this 
subject later. However, we do want to discuss how the viscous (frictional) component of 
these drag forces is typically idealized. 

Ideal viscous drag is a function of velocity and some experimentally determined drag 
coefficient that’s supposed to take into account the surface conditions of the body, the 
fluid properties (density and viscosity), and the flow conditions. You’ll typically see a 
formula for viscous drag force in the form: 

F v — -C f v 

where C f is the drag coefficient, v is the body’s speed, and the minus sign means that the 
force opposes motion. This formula is valid for slow-moving objects in a viscous fluid. 
“Slow moving” implies that the flow around the body is laminar, which means that the 
flow streamlines are undisturbed and parallel. 

For fast-moving objects, you’ll use the formula for F v written as a function of speed 
squared as follows: 


F v = -C f v 2 

“Fast moving” implies that the flow around the object is turbulent, which means that 
the flow streamlines are no longer parallel and there is a sort of mixing effect in the flow 
around the object. Note that the values of C f are generally not the same for these two 
equations. In addition to the factors mentioned earlier, C f depends significantly on 
whether the flow is laminar or turbulent. 


Fluid Dynamic Drag | 75 


www.it-ebooks.info 



Both of these equations are very simplified and inadequate for practical analysis of fluid 
flow problems. However, they do offer certain advantages in computer game simula¬ 
tions. Most obviously, these formulas are easy to implement—you need only know the 
velocity of the body under consideration, which you get from your kinematic equations, 
and an assumed value for the drag coefficient. This is convenient, as your game world 
will typically have many different types of objects of all sizes and shapes that would make 
rigorous analysis of each of their drag properties impractical. If the illusion of realism 
is all you need, not real-life accuracy, then these formulas may be sufficient. 

Another advantage of using these idealized formulas is that you can tweak the drag 
coefficients as you see fit to help reduce numerical instabilities when solving the equa¬ 
tions of motion, while maintaining the illusion of realistic behavior. If real-life accuracy 
is what you’re going for, then you’ll have no choice but to consider a more involved 
(read: complicated) approach for determining fluid dynamic drag. We’ll talk more about 
drag in Chapter 6 through Chapter 10. 

Pressure 

Many people confuse pressure with force. You have probably heard people say, when 
explaining a phenomenon, something like, “It pushed with a force of 100 pounds per 
square inch.” While you understand what they mean, they are technically referring to 
pressure, not force. Pressure is force per unit area, thus the units pounds per square 
inch (psi) or pounds per square foot (psf) and so on. Given the pressure, you’ll need to 
know the total area acted on by this pressure in order to determine the resultant force. 
Force equals pressure times area: 


F = PA 

This formula tells you that for constant pressure, the greater the area acted upon, the 
greater the resultant force. If you rearrange this equation solving for pressure, you’ll see 
that pressure is inversely proportional to area—that is, the greater the area for a given 
applied force, the smaller the resulting pressure and vice versa. 

P = F/A 

An important characteristic of pressure is that it always acts normally (perpendicularly) 
to the surface of the body or object it is acting on. This fact gives you a clue as to the 
direction of the resultant force vector. 

We wanted to mention pressure here because you’ll be working with it to calculate forces 
when you get to the chapters in this book that cover the mechanics of ships, boats, and 
hovercraft. There, the pressures that you’ll consider are hydrostatic pressure (buoyancy) 
and aerostatic lift. We’ll take a brief look at buoyancy next. 


76 | Chapter 3:Force 


www.it-ebooks.info 



Buoyancy 

You’ve no doubt felt the effects of buoyancy when immersing yourself in the bathtub. 
Buoyancy is why you feel lighter in water than you do in air and why some people can 
float on their backs in a swimming pool. 

Buoyancy is a force that develops when an object is immersed in a fluid. It’s a function 
of the volume of the object and the density of the fluid and results from the pressure 
differential between the fluid just above the object and the fluid just below the object. 
Pressure increases the deeper you go in a fluid, thus the pressure is greater at the bottom 
of an object of a given height than it is at the top of the object. Consider the cube shown 
in Figure 3-2. 



n n 


u n 


Figure 3-2. Immersed cube 


Let s denote the cube’s length, width, and height, which are all equal. Further, let h t 
denote the depth to the top of the cube and h b the depth to the bottom of the cube. The 
pressure at the top of the cube is P t = p g h t , which acts over the entire surface area of 
the top of the cube, normal to the surface in the downward direction. The pressure at 
the bottom of the cube is P b = p g h b , which acts over the entire surface area of the bottom 
of the cube, normal to the surface in the upward direction. Note that the pressure acting 
on the sides of the cube increases linearly with submergence, from P t to P b . Also, note 
that since the side pressure is symmetric, equal and opposite, the net side pressure is 0, 
which means that the net side force (due to pressure) is also 0. The same is not true of 
the top and bottom pressures, which are obviously not equal, although they are opposite. 

The force acting down on the top of the cube is equal to the pressure at the top of the 
cube times the surface area of the top. This can be written as follows: 

Ft = Pt A t 


Buoyancy | 77 


www.it-ebooks.info 




























F t = (p g h t ) (s 2 ) 


Similarly, the force acting upward on the bottom of the cube is equal to the pressure at 
the bottom times the surface area of the bottom. 

Fb = Pb A b 
Fb = (P g h b ) (s 2 ) 

The net vertical force (buoyancy) equals the difference between the top and bottom 
forces: 


Fb = Fb - F t 

Fb = (P g hb) (s 2 ) - (p g hj) (s 2 ) 

Fb = (P g) (s 2 ) (hb - ht) 

This formula gives the magnitude of the buoyancy force. Its direction is straight up, 
counteracting the weight of the object. 

There is an important observation we need to make here. Notice that ( h b - h t ) is simply 
the height of the cube, which is s in this case. Substituting s in place of ( h b - h t ) reveals 
that the buoyancy force is a function of the volume of the cube. 

F B — (p g) (s 3 ) 

This is great since it means that all you need to do in order to calculate buoyancy is to 
first calculate the volume of the object and then multiply that volume by the specific 
weight 3 (p g) of the fluid. In truth, that’s a little easier said than done for all but the 
simplest geometries. If you’re dealing with spheres, cubes, cylinders, and the like, then 
calculating volume is easy. However, if you’re dealing with any arbitrary geometry, then 
the volume calculation becomes more difficult. There are two ways to handle this dif¬ 
ficulty. The first way is to simply divide the object into a number of smaller objects of 
simpler geometry, calculate their volumes, and then add them all up. The second way 
is to use numerical integration techniques to calculate volume by integrating over the 
surface of the object. 

You should also note that buoyancy is a function of fluid density, and you don’t have to 
be in a fluid as dense as water to experience the force of buoyancy. In fact, there are 
buoyant forces acting on you right now, although they are very small, due to the fact 
that you are immersed in air. Water is many times more dense than air, which is why 
you notice the force of buoyancy when in water and not in air. Keep in mind, though, 


3. Specific weight is density times the acceleration due to gravity. Typical units are lbs/ft 3 and N/m 3 . 


78 | Chapter 3:Force 


www.it-ebooks.info 



that for very light objects with relatively large volumes, the buoyant forces in air may 
be significant. For example, consider simulating a large balloon. 

Springs and Dampers 

Springs are structural elements that, when connected between two objects, apply equal 
and opposite forces to each object. This spring force follows Hooke s law and is a func¬ 
tion of the stretched or compressed length of the spring relative to the rest length of the 
spring and the spring constant of the spring. Hooke’s law states that the amount of stretch 
or compression is directly proportional to the force being applied. The spring constant 
is a quantity that relates the force exerted by the spring to its deflection: 


F s = k s (L-r) 


Here, F s is the spring force, k s is the spring constant, L is the stretched or compressed 
length of the spring, and r is the rest length of the spring. In the metric system of units, 
F s would be measured in newtons (1 N = 1 kg-m/s 2 ), L and r in meters, and k s in kg/s 2 . 
If the spring is connected between two objects, it exerts a force of F s on one object and 
-F s on the other; these are equal and opposite forces. 

Dampers are usually used in conjunction with springs in numerical simulations. They 
act like viscous drag in that they act against velocity. In this case, if the damper is con¬ 
nected between two obj ects that are moving toward or away from each other, the damper 
acts to slow the relative velocity between the two objects. The force developed by a 
damper is proportional to the relative velocity of the connected objects and a damping 
constant, k d , that relates relative velocity to damping force. 

F d = k d (vi - v 2 ) 

This equation shows the damping force, F d , as a function of the damping constant and 
the relative velocity of the connected points on the two connected bodies. In metric 
units, where the damping force is measured in newtons and velocity in m/s, k d has units 
of kg/s. 

Typically, springs and dampers are combined into a single spring-damper element, 
where a single formula represents the combined force. Using vector notation, we can 
write the formula for a spring-damper element connecting two bodies as follows: 

Fi = -{k s (L - r) + k d (( Vl - v 2 ) • L)/L} L/L 

Here, is the force exerted on body 1, while the force, F 2 , exerted on body 2 is: 


F 2 = -Ft 


Springs and Dampers | 79 


www.it-ebooks.info 



L is the length of the spring-damper ( L , not in bold print, is the magnitude of the vector 
L), which is equal to the vector difference in position between the connected points on 
bodies 1 and 2. If the connected objects are particles, then L is equal to the position of 
body 1 minus the position of body 2. Similarly, v : and v 2 are the velocities of the con¬ 
nected points on bodies 1 and 2. The quantity (v, - v 2 ) represents the relative velocity 
between the connected bodies. 

Springs and dampers are useful when you want to simulate collections of connected 
particles or rigid bodies. The spring force provides the structure, or glue, that holds the 
bodies together (or keeps them separated by a certain distance), while the damper helps 
smooth out the motion between the connected bodies so it’s not too jerky or springy. 
These dampers are also very important from a numerical stability point of view in that 
they help keep your simulations from blowing up. We’re getting a little ahead of ourselves 
here, but we’ll show you how to use these spring-dampers in real-time simulations in 
Chapter 13. 

Force and Torque 

We need to make the distinction here between force and torque. 4 Force is what causes 
linear acceleration, while torque is what causes rotational acceleration. Torque is force 
times distance. Specifically, to calculate the torque applied by a force acting on an object, 
you need to calculate the perpendicular distance from the axis of rotation to the line of 
action of the force and then multiply this distance by the magnitude of the force. 

This calculation gives the magnitude of the torque. Typical units for force are pounds, 
newtons, and tons. Since torque is force times a distance, its units take the form of a 
length unit times a force unit (e.g., foot-pounds, newton-meters, or foot-tons). 

Since both force and torque are vector quantities, you must also determine the direction 
of the torque vector. The force vector is easy to visualize: its line of action passes through 
the point of application of the force, with its direction determined by the direction in 
which the force is applied. As a vector, the torque’s line of action is along the axis of 
rotation, with the direction determined by the direction of rotation and the right hand 
rule (see Figure 3-3). As noted in Chapter 2, the right hand rule is a simple trick to help 
you keep track of vector directions—in this case, the torque vector. Pretend to curl the 
fingers of your right hand around the axis of rotation with your fingertips pointing in 
the direction of rotation. Now extend your thumb, as though you are giving a thumbs 
up, while keeping your fingers curled around the axis. The direction that your thumb 
is pointing indicates the direction of the torque vector. Note that this makes the torque 
vector perpendicular to the applied force vector, as shown in Figure 3-3. 


4. Another common term for torque is moment. 


80 | Chapter 3:Force 


www.it-ebooks.info 




Figure 3-3. Force and torque 

We said earlier that you find the magnitude of torque by multiplying the magnitude of 
the applied force times the perpendicular distance between the axis of rotation and the 
line of action of the force. This calculation is easy to perform in two dimensions where 
the perpendicular distance (d in Figure 3-3) is readily calculable. 

However, in three dimensions you’ll want to be able to calculate torque by knowing only 
the force vector and the coordinates of its point of application on the body relative to 
the axis of rotation. You can accomplish this by using the following formula: 

M = r x F 

The torque, M, is the vector cross product of the position vector, r, and the force vector, 

F. 

In rectangular coordinates you can write the distance, force, and torque vectors as fol¬ 
lows: 


r = xi + yj + zk 
F = F x i + F y j + F z k 
M = M x i + M y j + M z k 

The scalar components of r (x, y, and z) are the coordinate distances from the axis of 
rotation to the point of application of the force, F. The scalar components of the torque 
vector, M, are defined by the following: 


M x = y F z - z F y 
My = z F x - x F z 


Force and Torque | 81 


www.it-ebooks.info 






M z = x Fy - y F x 

Consider the rigid body shown in Figure 3-4 acted upon by the force F at a point away 
from the body’s center of mass. 



Figure 3-4. Torque example 

In this example F, a, and b are given and are as follows: 

F = (-90 lbs) i + (156 lbs) j + (0) k 
a = 0.66 ft 
b = 0.525 ft 

Calculate the torque about the body’s center of mass due to the force F. 

The first step is to put together the distance vector from the point of application of F to 
the body’s center of mass. Since the local coordinates a and b are given, r is simply: 

r = (0.66 ft) i + (0.525 ft) j + (0) k 

Now using the formula M = r x F (or the formulas for the components of the torque 
vector shown earlier), you can write: 

M = [(0.66 ft) i + (0.525 ft) j + (0) k] x [(-90 lbs) i + (156 lbs) j 

+ (0) k] 

M = [(0.66 ft) (156 lbs) - (0.525 ft) (-90 lbs)] k 
M = (150.2 ft-lbs) k 


82 | Chapter 3:Force 


www.it-ebooks.info 









Note that the x and y components of the torque vector are 0; thus, the torque moment 
is pointing directly along the z-axis. The torque vector would be pointing out of the 
page of this book in this case. 

In dynamics you need to consider the sum, or total, of all forces acting on an object 
separately from the sum of all torques acting on a body. When summing forces, you 
simply add, vectorally, all of the forces without regard to their point of application. 
However, when summing torques you must take into account the point of application 
of the forces to calculate the torques, as shown in the previous example. Then you can 
take the vector sum of all torques acting on the body. 

When you are considering rigid bodies that are not physically constrained to rotate 
about a fixed axis, any force acting through the body’s center of mass will not produce 
a torque on the body about its center of gravity. In this case, the axis of rotation passes 
through the center of mass of the body and the vector r would be 0 (all components 0). 
When a force acts through a point on the body some distance away from its center of 
mass, a torque on the body will develop, and the angular motion of the body will be 
affected. Generally, field forces, which are forces at a distance, are assumed to act 
through a body’s center of mass; thus, only the body’s linear motion will be affected 
unless the body is constrained to rotate about a fixed point. Other contact forces, how¬ 
ever, generally do not act through a body’s center of mass (they could but aren’t neces¬ 
sarily assumed to) and tend to affect the body’s angular motion as well as its linear 
motion. 

Summary 

As we said earlier, this chapter on forces is your bridge from kinematics to kinetics. Here 
you’ve looked at the major force categories—contact forces and force fields—and some 
important specific types of forces. This chapter was meant to give you enough theoretical 
background on forces so you can fully appreciate the subject of kinetics that’s covered 
in the next chapter. In Chapter 15 through Chapter 19, you’ll revisit the subject of forces 
from a much more practical point of view when we investigate specific real-life prob¬ 
lems. We’ll also introduce some new specific types of force in those chapters that we 
didn’t cover here. 


Summary | 83 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 4 


Kinetics 


Recall that kinetics is the study of the motion of bodies, including the forces that act on 
them. It’s now time that we combine the material presented in the earlier chapters— 
namely, kinematics and forces—to study the subject of kinetics. As in Chapter 2 on 
kinematics, we’ll first discuss particle kinetics and then go on to discuss rigid-body 
kinetics. 

In kinetics, the most important equation that you must consider is Newton’s second law: 

F = ma 

When rigid bodies are involved, you must also consider that the forces acting on the 
body will tend to cause rotation of the body in addition to translation. The basic rela¬ 
tionship here is: 


M cg = I a 

where M cg is the vector sum of all moments (torques) acting on the body, I is the body 
moment of inertia tensor, and a is the angular acceleration. 

Collectively, these two equations are referred to as the equations of motion. 

There are two types of problems that you will encounter in kinetics. One type is where 
you know the force(s) acting on the body, or you can estimate them, and you must solve 
for the resulting acceleration of the body (and subsequently its velocity and displace¬ 
ment) . Another type is where you know the body’s acceleration, or can readily determine 
it using kinematics, and you must solve for the force(s) acting on the body. 


85 


www.it-ebooks.info 




This chapter will primarily discuss the first type of problem, where you know the force(s) 
acting on the body, which is more common to in-game physics. The second type of 
problem has become important with the advent of motion-based controllers such as the 
Sony SixAxis and Nintendo Wii Remote. These controllers rely on digital accelerome¬ 
ters to directly measure the acceleration of a controller. While this is most often used to 
find the controller’s orientation, it is also possible to integrate the time history of these 
sensor values to determine velocity and position. Additionally, if you know the mass of 
the controller or device, you can find the force. Accelerometers are found in most 
smartphones as well, which also allows for the use of kinematic-based input. So as to 
not confuse the two types of problems, we’ll discuss the second type, with the acceler¬ 
ation as input, in detail in Chapter 21. 

Let us stress that you must consider the sum of all of the forces acting on the body when 
solving kinetics problems. These include all applied forces and all reaction forces. Aside 
from the computational difficulties of solving the equations of motion, one of the more 
challenging aspects of kinetics is identifying and properly accounting for all of these 
forces. In later chapters, you’ll look at specific problems where we’ll investigate the 
particular forces involved. For now, and for the purpose of generality, let’s stick with the 
idealized forces introduced in the previous chapter. 

Here is the general procedure for solving kinetics problems of interest to us: 

1. Calculate the body’s mass properties (mass, center of mass, and moment of inertia). 

2. Identify and quantify all forces and moments acting on the body. 

3. Take the vector sum of all forces and moments. 

4. Solve the equations of motion for linear and angular accelerations. 

5. Integrate with respect to time to find linear and angular velocity. 

6. Integrate again with respect to time to find linear and angular displacement. 

This outline makes the solution to kinetics problems seem easier than it actually is 
because there are a number of complicating factors that you’ll have to overcome. For 
example, in many cases the forces acting on a body are functions of displacement, ve¬ 
locity, or acceleration. This means that you’ll have to use iterative techniques in order 
to solve the equations of motion. Further, since you most likely will not be able to derive 
closed-form solutions for acceleration, you’ll have to numerically integrate in order to 
estimate velocity and displacement at each instant of time under consideration. These 
computational aspects will be addressed further in Chapter 7 through Chapter 13. 


86 | Chapter 4: Kinetics 


www.it-ebooks.info 



Particle Kinetics in 2D 

As in particle kinematics, in particle kinetics you need to consider only the linear motion 
of the particle. Thus, the equations of motion will consist of equations of the form F = 
ma, where motion in each coordinate direction will have its own equation. The equa¬ 
tions for 2D particle motion are: 


XF x = m a x 
XF y = m a y 

where XF x means the sum of all forces in the x-direction, XF y means the sum of all forces 
in the y-direction, a x is the acceleration in the x-direction, and a y is the acceleration in 
the y-direction. 

The resultant force and acceleration vectors are: 

a = a x i + a y j 

a — + a y 

XF = XF x i + XF y j 
IF = ^(ZF,f + (ZF,f 

Let’s look at an example that appears simple but demonstrates the complexity of finding 
closed-form solutions. A ship floating in water, initially at rest, starts up its propeller 
generating a thrust, T, which starts the ship moving forward. Assume that the ship’s 
forward speed is slow and the resistance to its motion can be approximated by: 

R = -C v 

where R is the total resistance, C is a drag coefficient, v is the ship speed, and the minus 
sign indicates that this resistive force opposes the forward motion of the ship. Find 
formulas for the ship’s speed, acceleration, and distance traveled as functions of time, 
assuming that the propeller thrust and resistance force vectors act on a line of action 
passing through the ship’s center of gravity. This assumption lets you treat the ship as a 
particle instead of a rigid body. 

The first step in solving this problem is to identify all of the forces acting on the ship. 
Figure 4-1 shows a free-body diagram of the ship with all of the forces acting on it— 
namely, the propeller thrust, T; resistance, R; the ship’s weight, W; and buoyancy, B. 


Particle Kinetics in 2D | 87 


www.it-ebooks.info 






J 

i 

f 

B 

T -► < 

>-x < - R 

1 

1/ 


Figure 4-1. Free-body diagram of ship 


Notice here that the buoyancy force is exactly equal in magnitude to the ship’s weight 
and opposite in direction; thus, these forces cancel each other out and there will be no 
motion in the y-direction. This must be the case if the ship is to stay afloat. This obser¬ 
vation effectively reduces the problem to a one-dimensional problem with motion in 
the x-direction, only where the forces acting in the x-direction are the propeller thrust 
and resistance. 

Now you can write the equation (for motion in the x-direction) using Newton’s second 
law, as follows: 


£F = m a 
T - R = m a 
T - (C v) = m a 

Where a is the acceleration in the x-direction, and v is the speed in the x-direction. 

The next step is to integrate this equation of motion in order to derive a formula for the 
speed of the ship as a function of time. To do this, you must make the substitution a = 
dv/dt, rearrange, integrate, and then solve for speed as follows: 

T - (C v) = m (dv/dt) 
dt = (m / (T-Cv)) dv 
/(0 to t) dt = /(v i to v2) (m / (T-Cv)) dv 
t - 0 = -(m/C) ln(T-Cv) I (vl t0 v2) 
t = -(m/C) ln(T-Cv 2 ) + (m/C) ln(T-Cvi) 
t = (m/C) [ln(T-Cv!) - ln(T-Cv 2 )] 

(C/m) t = In [(T-C Vl )/(T-Cv 2 )] 
e (C/m) t _ e In [(T-Cvl) / (T-Cv2)] 

e (C/m) t = (T-CvO / (T-Cv 2 ) 

(T-Cv 2 ) = (T-Cvi) 


88 | Chapter 4: Kinetics 


www.it-ebooks.info 









V 2 = (T/C) - e-( c/m > 1 (T/C - vi) 

where v 1 is the initial ship speed (which is constant) and v 2 is the ship speed at time t. 
v 2 is what you’re after here, since it tells you how fast the ship is traveling at any instant 
of time. 

Now that you have an equation for speed as a function of time, you can derive an 
equation for displacement (distance traveled, in this case) as a function of time. Here, 
you’ll have to recall the formula v dt = ds, substitute the previous formula for speed, 
integrate, rearrange, and solve for distance traveled. These steps are shown here: 

v dt = ds 
v 2 dt = ds 

((T/C) - e-( c/m > 1 (T/C - vO) dt = ds 
/(0 to t) (T/C) - e-( c/m > 1 (T/C - Vl ) dt = / (sl t0 s2) ds 
(T/C) / ( o to t) dt - (T/C - Vl ) / ( o to t) e- (C/m) 1 dt = s 2 - Sl 
[(T/C) t + ((T/C) - vtXm/C) e-( c/m > l ] (010 1 ) = s 2 - si 
[(T/C) t + ((T/C) - vi)(m/C) e-( c/m ) l ] - [0 + ((T/C) - vi)(m/C)] = 

S2-N 

(T/C) t + (T/C - vi) (m/C) e-( c/m > 1 - (T/C - vi) (m/C) = s 2 -s, 
s 2 = Sl + (T/C) t + (T/C - vO (m/C) e -( c/m > 1 - (T/C - vi) (m/C) 

Finally you can write an equation for acceleration by going back to the original equation 
of motion and solving for acceleration: 

T - (C v) = m a 
a = (T - (C v)) / m 


where: 


v = v 2 = (T/C) - e -( c/m ) 1 (T/C - vi) 

In summary, the equations for velocity, distance traveled, and acceleration are as follows: 

v 2 = (T/C) - e-( c/m > 1 (T/C - vi) 

s 2 = Sj + (T/C) t + (T/C - vi) (m/C) e -( c/m ) 1 - (T/C - vi) (m/C) 
a = (T - (C v)) / m 

To illustrate the motion of the ship further, we’ve plotted the ship’s speed, distance trav¬ 
eled, and acceleration versus time, as shown in Figure 4-2, Figure 4-3, and Figure 4-4. 
To facilitate these illustrations, we’ve assumed the following: 


Particle Kinetics in 2D | 89 


www.it-ebooks.info 



• The initial ship speed and displacement are 0 at time 0. 

• The propeller thrust is 20,000 thrust units. 

• The ship’s mass is 10,000 mass units. 

• The drag coefficient is 1,000. 



1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 

Time 


Figure 4-2. Speed versus time 



Time 


Figure 4-3. Distance versus time 


90 | Chapter 4: Kinetics 


www.it-ebooks.info 































1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 

Time 


Figure 4-4. Acceleration versus time 

You’ll notice that the ship’s speed approaches the steady state speed of 20 speed units, 
assuming that the propeller thrust remains constant. This corresponds to a reduction 
in acceleration from a maximum acceleration at time 0 to no acceleration once the steady 
speed is achieved. 

This example illustrates how to set up the differential equations of motion and integrate 
them to find velocity, displacement, and acceleration. In this case, you were able to find 
a closed-form solution—that is, you were able to integrate the equations symbolically 
to derive new ones. You could do this because we imposed enough constraints on the 
problem to make it manageable. But you can readily see that if there were more forces 
acting on the ship, or if the thrust were not held constant but was some function of 
speed, or if the resistance were a function of speed squared, and so on, the problem gets 
increasingly complicated—making a closed-form solution much more difficult, if not 
impossible. 

Particle Kinetics in 3D 

As in kinematics, extending the equations of motion for a particle to three dimensions 
is easy to do. You simply need to add one more component and will end up with three 
equations as follows: 


SF X = m a x 
SF y = m a y 


Particle Kinetics in 3D | 91 


www.it-ebooks.info 


















XF Z = m a z 


The resultant force and acceleration vectors are now: 

a = a x i + a y j + a z k 

a = + ciy + dj 

XF = XF x i + XFy j + XF Z k 

zf = ^(SF I f + (SF y f + (SF.f 

To hammer these concepts home, we want to present another example. 

Let’s go back to the cannon example program discussed in Chapter 2. In that example, 
we made some simplifying assumptions so we could focus on the kinematics of the 
problem without complicating it too much. One of the more significant assumptions 
we made was that there was no drag acting on the projectile as it flew through the air. 
Physically, this would be valid only if the projectile were moving through a vacuum, 
which, of course, is unlikely here on Earth. Another significant assumption we made 
was that there was no wind to act on the projectile and affect its course. These two 
considerations, drag and wind, are important in real-life projectile problems, so to make 
this example a little more interesting—and more challenging to the user if this were an 
actual game—we’ll add these two considerations now. 

First, assume that the projectile is a sphere and the drag force acting on it as it flies 
through the air is a function of some drag coefficient and the speed of the projectile. 
This drag force can be written as follows: 


F d = -C d v 

Fd = — C d v x i - C d Vy j — c-d v z k 

where C d is the drag coefficient, v is the velocity of the projectile (v x , v y , and v z are its 
components), and the minus sign means that this drag force opposes the projectile’s 
motion. Actually, we’re cheating a bit here since in reality the fluid dynamic drag would 
be more a function of speed squared. We’re doing this here to facilitate a closed-form 
solution. Also, the drag coefficient here would be determined experimentally for each 
shape. Later, we’ll discuss how experimental data is used on basic shapes to give data for 
similar ships. 

Second, assume that the projectile is subjected to a blowing wind, the force of which is 
a function of some drag coefficient and the wind speed. This force can be written as 
follows: 


F w — C w v w 

F w = — C w v wx 1 — C w v wz k 


92 | Chapter 4: Kinetics 


www.it-ebooks.info 





where C w is the drag coefficient, v w is the wind speed, and the minus sign means that 
this force opposes the projectiles motion when the wind is blowing in a direction op¬ 
posite of the projectile’s direction of motion. When the wind is blowing with the pro¬ 
jectile—say, from behind it—then the wind will actually help the projectile along instead 
of impede its motion. In general, C w is not necessarily equal to the C d shown in the drag 
formula. Referring to Figure 2-3, we’ll define the wind direction as measured by the 
angle y. The x and z components of the wind force can now be written in terms of the 
wind direction, y, as follows: 

F\vx = F w cos y = —(C w v w ) cos y 
Fwz = F w sin y = -(C w v w ) sin y 

We ignored the y-direction as we assume the wind is flowing parallel to the ground. 
Finally, let’s apply a gravitational force to the projectile instead of specifying the effect 
of gravity as a constant acceleration, as we did in Chapter 2. This allows you to include 
the force due to gravity in the equations of motion. Assuming that the projectile is 
relatively close to sea level, the gravitational force can be written as: 

F g = -m g j 

where the minus sign indicates that it acts in the negative y-direction (pulling the pro¬ 
jectile toward the earth), and yon the righthand side of this equation is the acceleration 
due to gravity at sea level. 

Now that all of the forces have been identified, you can write the equations of motion 
in each coordinate direction: 

£F X = F wx + F dx = m (dv x /dt) 

SFy = F dy + F gy = m (dvy/dt) 

SF Z = F wz + F dz = m (dv z /dt) 

Note here that we already made the substitution dv/dt for acceleration in each equation. 
Following the same procedure shown in the previous section, you now need to integrate 
each equation of motion twice—once to find an equation for velocity as a function of 
time, and another to find an equation for displacement as a function of time. As before, 
we’ll show you how this is done component by component. 

You might be asking yourself, where’s the thrust force from the cannon that propels the 
projectile in the first place? In this example, we’re looking specifically at the motion of 
the projectile after it has left the muzzle of the cannon, where there is no longer a thrust 
force acting on the projectile; it isn’t self-propelled. To account for the effect of the 
cannon thrust force, which acts over a very short period of time while the projectile is 
within the cannon, you have to consider the muzzle velocity of the projectile when it 
initially leaves the cannon. The components of the muzzle velocity in the coordinate 


Particle Kinetics in 3D | 93 


www.it-ebooks.info 



directions will become initial velocities in each direction, and they will be included in 
the equations of motion once they’ve been integrated. The initial velocities will show 
up in the velocity and displacement equations just like they did in the example in 
Chapter 2. You’ll see this in the following sections. 

X Components 

The first step is to make the appropriate substitutions for the force terms in the equation 
of motion, and then integrate to find an equation for velocity. 

-F wx - Fdx = m(dv x /dt) 

-(C w v w cos y) - C d v x = m dv x /dt 
dt = m dv x / [-(C w v w cos y) - C d v x ] 

/(0 to t) dt = /(vx 1 to vx2) —m / [(C w v w cos y) + C d v x ] dv x 
t = — (m/C d ) ln((C w v w cos y) + C d v x )l ( vx j to vx2) 
t = -(m/C d ) ln((C w v w cos y) + C d v x2 ) + (m/C d ) ln((C w v w cos y) 

+ Cd v x i) 

(C d /m) t = ln[((C w v w cos y) + C d v x! ) / ((C w v w cos y) + C d v x2 )] 

P (C , /m) t _ P ln[((C v cos y) + Cd v ) / ((Cw vw cos y) + C , v .)] 
c d —c ww xl dx2 

e (Cd/m) t = ( '( Cw Vw cos + Cd Vxl ) / ((C w V w cos y) + C d v x2 ) 

((C w v w cos y) + C d v x2 ) = ((C w v w cos y) + C d v xl ) e-( c d /m) 1 
v x2 = (1/C d ) [ eC c d /m > 1 (c w v w cos y + C d v xl ) - (C w v w cos y)] 

To get an equation for displacement as a function of time, you need to recall the equation 
v dt= ds, make the substitution for v (using the preceding equation) and then integrate 
one more time. 


v x2 dt = ds x 

(1/C d ) [et -C d /m ) 1 (c w v w cos y + C d v x i) - (c w v w cos y)] dt = ds x 
/(0 to t) (1/Cd) [e ( “ c d /m > 1 (c w v w cos y + C d v x! ) - (c w v w cos y)] dt 

= /sxl to sx2) ds x 

s x 2 = [(m/C d ) el- 0 /™! 1 (-(C w v w cos y) / C d - v xl ) - ((C w v w cos 

y)/c d ) t]- 

[(m/C d ) (-(C w v w cos y) / C d - v xl )] + s xl 

Yes, these equations are ugly. Just imagine if we hadn’t made the simplifying assumption 
that drag is proportional to speed and not speed squared! You would have ended up 
with some really nice equations with an arctan term or two thrown in. 


94 | Chapter 4: Kinetics 


www.it-ebooks.info 



Y Components 

For the y components, you need to follow the same procedure shown earlier for the x 
components, but with the appropriate y-direction forces. Here’s what it looks like: 

-F dy - F gy = m (dvy/dt) 

—C d v y - m g = m (dvy/dt) 
f (0 to t) dt = —m /(vyi to vy2) l/(C d v y + m g) dvy 

v y2 = (l/c d ) (C d v yl + m g) - (m g)/C d 

Now that you have an equation for velocity, you can proceed to get an equation for 
displacement as before: 


v y 2 dt = ds y 

[(1/C d ) e(- c d /m ) 1 (Q v yl + m g) - (m g)/C d ] dt = ds y 
/(0 to t) t(l/Cd) e ( -- c d /m - >t (C d vyi + m g) - (m g)/C d ] dt = / (sy i t0 

sy2) dSy 

Sy2 = Syl + [ (v y i + (m g)/Cd) (m/C d ) e(- c d /m)t - t (m g)/C d ] + 
[(m/C d )(v y i + (m g)/C d )] 

OK, that’s two down and only one more to go. 

Z Components 

With the z component, you get a break. You’ll notice that the equations of motion for 
the x and z components look almost the same with the exception of the x and z subscripts 
and the sine versus cosine terms. Taking advantage of this fact, you can simply copy the 
x component equations and replace the x subscript with a z and the cosine terms with 
sines and be done with it: 

v z2 = (1/C d ) [e ( - c d /m)t (c w v w sin y + C d v z! ) - (c w v w sin y)] 
s z2 = [(m/C d ) e(- c d /m)t (-(C w v w sin y) / C d - v z i) - ((C w v w sin 

y)/c d ) t] - 

[(m/C d ) (-(C w v w sin y)/C d - v z i)] + s z! 


Cannon Revised 

Now that you have some new equations for the projectile’s displacement in each coor¬ 
dinate direction, you can go to the cannon example source code and replace the old 
displacement calculation formulas with the new ones. Make the changes in the DoSimu 
lation function as follows: 


Particle Kinetics in 3D | 95 


www.it-ebooks.info 



//.-// 

Int DoSinulation(void) 

//.-// 

{ 


// new local variables: 
double sxl, vxl; 

double syl, vyl; 

double szl, vzl; 


// Now we can calculate the position vector at this tine 

// Old position vector connented out: 

//s.i = Vn * cosX * tine + xe; 

//s.j = (Yb + L * cos(Alpha*3.14/180)) + (Vn * cosY * tine) - 
(0.5 * g * tine * tine); 

//s.k = Vn * cosZ * tine + ze; 

// New position vector calculations: 

sxl = xe; 

vxl = Vn * cosX; 

syl = Yb + L * cos(Alpha * 3.14/180); 

vyl = Vn * cosY; 

szl = ze; 

vzl = Vn * cosZ; 

s.i =((n/Cd) * exp(-(Cd * tine)/n) * ((-Cw * Vw * cos(GannaW * 3.14/180))/Cd - 
vxl) - (Cw * Vw * cos(GannaW * 3.14/180) * tine) / Cd ) - 
( (n/Cd) * ((-Cw * Vw * cos(GannaW * 3.14/180))/Cd - vxl) ) + sxl; 

s.j = syl + ( -(vyl + (n * g)/Cd) * (n/Cd) * exp(-(Cd*tine)/n) - 

(n * g * tine) / Cd ) + ( (n/Cd) * (vyl + (n * g)/Cd) ); 

s.k =((n/Cd) * exp(-(Cd * tine)/n) * ((-Cw * Vw * sin(GannaW * 3.14/180))/Cd - 

vzl) - (Cw * Vw * sin(GannaW * 3.14/180) * tine) / Cd ) - 
( (n/Cd) * ((-Cw * Vw * sin(GannaW * 3.14/180))/Cd - vzl) ) + szl; 


} 

To take into account the cross wind and drag, you’ll need to add some new global 
variables to store the wind speed and direction, the mass of the projectile, and the drag 


96 | Chapter 4: Kinetics 


www.it-ebooks.info 





coefficients. You’ll also have to add some controls in the dialog window so that you can 
change these variables when you run the program. Figure 4-5 shows how we added 
these interface controls in the upper-right corner of the main window. 



Figure 4-5. Revised cannon example screenshot 

We also added these lines to the DemoDlgProc function to handle the new wind speed 
and direction values: 

//-.// 

LRESULT CALLBACK DemoDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM IParam) 

//-.// 

{ 


case WM INITDIALOG: 


// New variables: 
sprintf( str, "%f", m ); 
SetDlgItemText(hDlg, IDC_M, str); 

sprintf( str, "%f", Cd ); 
SetDlgItemText(hDlg, IDC_CD, str); 


Particle Kinetics in 3D | 97 


www.it-ebooks.info 



































sprintf( str, "%f", Vw ); 
SetDlgItemText(hDlg, IDC_VW, str); 

sprintf( str, "%f", GannaW ); 
SetDlgItemText(hDlg, IDC_GAMMAW, str); 

sprintf( str, "%f", Cw ); 
SetDlgItenText(hDlg, IDC_CW, str); 


case IDC_REFRESH: 


// New variables: 

GetDlgItenText(hDlg, IDC_M, str, 15); 
m = atof(str); 

GetDlgItenText(hDlg, IDC_CD, str, 15); 

Cd = atof(str); 

GetDlgItemText(hDlg, IDC_VW, str, 15); 

Vw = atof(str); 

GetDlgItemText(hDlg, IDC_GAMMAW, str, 15); 
GammaW = atof(str); 


GetDlgItenText(hDlg, IDC_CW, str, 15); 
Cw = atof(str); 


case IDC FIRE: 


// New variables: 

GetDlgItemText(hDlg, IDC_M, str, 15); 
m = atof(str); 

GetDlgItemText(hDlg, IDC_CD, str, 15); 

Cd = atof(str); 

GetDlgItemText(hDlg, IDC_VW, str, 15); 

Vw = atof(str); 

GetDlgItenText(hDlg, IDC_GAMMAW, str, 15); 
GammaW = atof(str); 


98 | Chapter 4: Kinetics 


www.it-ebooks.info 



GetDlgItemText(hDlg, IDC_Ckl, str, 15); 
Cw = atof(str); 


} 

After playing with this example program, you should readily see that the trajectory of 
the projectile is noticeably different from that typically obtained in the original example. 
By adjusting the values of the wind speed, direction, and drag coefficients, you can 
dramatically affect the projectile’s trajectory. If you set the wind speed to 0 and the drag 
coefficients to 1, the trajectory will look like that obtained in the original example, where 
wind and drag were not taken into account. Be careful, though: don’t set the drag co¬ 
efficient to 0 because this will result in a “divide by zero” error. We didn’t put the ex¬ 
ception handler in the program, but you can see that it will happen by looking at the 
displacement vector formulas where the drag coefficient appears in the denominator of 
several terms. 

From a user’s perspective, if this were a video game, the problem of hitting the target 
becomes much more challenging when wind and drag are taken into account. The wind 
element is particularly interesting because you can change the wind speed and direction 
during game play, forcing the user to pay careful attention to the wind in order to 
accurately hit the target. 

Rigid-Body Kinetics 

You already know from your study of kinematics in Chapter 2 that dealing with rigid 
bodies adds rotation, or angular motion, into the mix of things to consider. As we stated 
earlier, the equations of motion now consist of a set of equations that relate forces to 
linear accelerations and another set of equations that relate moments to angular accel¬ 
erations. Alternatively, you can think of the equations of motion as relating forces to 
the rate of change in linear momentum, and moments to the rate of change in angular 
momentum, as discussed in Chapter 1. 

As in kinematics, the procedure for dealing with rigid-body kinetics problems involves 
two distinct aspects: 1) tracking the translation of the body’s center of mass, where the 
body is treated as a particle, and 2) tracking the body’s rotation, where you’ll utilize the 
principles of local coordinates and relative angular velocity and acceleration, as dis¬ 
cussed in Chapter 2. Really, the only difference between rigid-body kinematics and 
kinetics problems is that in kinetics problems we have forces to consider (including 
their resulting moments). 

The vector equations are repeated here for convenience: 

F = ma 
M cg = I a 


Rigid-Body Kinetics | 99 


www.it-ebooks.info 



where in two dimensions: 


XF = XF x i + XFy j 

£F = <J(ZF x f + {ZF,f 

Going from two-dimensional particle problems to two-dimensional rigid-body prob¬ 
lems involves only the addition of one more equation. This equation is, of course, the 
moment equation relating the sum of all moments acting on the body to the body’s 
moment of inertia and its angular acceleration. In plane motion, the axis of rotation of 
the rigid body is always perpendicular to the coordinate plane. And since there is only 
one axis of rotation, there is only one inertia term and one angular acceleration term to 
consider. Thus, you can write: 


M ca = I a 

where M cg is the total moment and is calculated with the formulas discussed in the 
section “Force and Torque” on page 80 in Chapter 3, and I is calculated about the axis 
of rotation using the techniques discussed in the section “Mass, Center of Mass, and 
Moment of Inertia” on page 9 in Chapter 1. 

In their component forms, the set of equations of motion for two-dimensional kinetics 
problems are: 


XF x = m a x 
XF y = m a y 
XM cg = I a 

Since these equations indicate linear motion on the xy-plane, the angular acceleration 
will be about the z-axis perpendicular to the xy-plane. Likewise, the moment of inertia, 
I, will be taken about the z-axis. 

Recall from Chapter 3 that we calculate moment by taking the cross product of the 
position vector for the force under consideration and the force vector. This means that, 
unlike with particle kinetics, you now have to keep track of exactly where on the body 
each force is applied. This is best illustrated with an example. 

Consider the box of uniform density shown in Figure 4-6. Uniform density means that 
its center of gravity is at the box’s geometric center. Find the value of the minimum force, 
F , applied at the upper edge of the box, required to start tipping the box over. 


100 | Chapter 4: Kinetics 


www.it-ebooks.info 





In Figure 4-6, F„ is the applied force, R, and R 2 are the reaction forces at supports one 
and two, F fl and h' f2 are the forces due to friction at points one and two, and mg is the 
weight of the box. 

This is an example of the type of problem where you know something about the motion 
of the object and have to find the value of one or more forces acting on it. To find the 
value of the force that will be just enough to start tipping the box, you need to look at 
the instant when the reaction force at support two is 0. This implies that all of the weight 
of the box is now supported at point one and the box is starting to rotate over. At this 
instant, just before it starts to rotate, the angular acceleration of the box is 0. Note that 
the box’s linear acceleration isn’t necessarily 0—that is, you can push on the box and it 
may slide without actually tipping over. 

The equations of motion for this problem are: 


£F X = F p - F f i - Fq = m a x 
ZF y = Ri+R 2 -mg = ma y = 0 
ZM cg = F p (h/2) + R 2 (w/2) - Ri (w/2) + F f2 (h/2) + F fl (h/2) = 1 

a = 0 

Rewriting the second preceding equation when R 2 is 0 shows that R 1 is equal to the 
weight of the box. Further, when R 2 is 0, the R 2 (w/2) term drops out of the moment 
equation, which can be rewritten by solving for F in terms of R v Note that when R, 
goes to 0, so does F f2 . After some algebra, the equation looks as follows: 


Rigid-Body Kinetics | 101 


www.it-ebooks.info 






F p = mg (w/h) - Ffi 


Here you can see that the tipping force, applied to the upper edge, is proportional to the 
weight and size of the box (actually the ratio of its width to its height), which you can 
readily appreciate from a physical point of view. The friction term is important here 
because the existence of the friction force actually helps the box to tip. If the box were 
on a frictionless surface, it would tend to slide rather than tip. 

In the case of plane motion, or 2D motion, of rigid bodies as discussed here, you are 
able to readily set up the equations of motion and investigate both the linear as well as 
angular motion of the body. In generalized three-dimensional motion, the linear motion 
of rigid bodies is no different from that of particles; you simply track the motion of the 
rigid body’s center of gravity. In three dimensions, however, rotation gives us some grief, 
as it is no longer a simple matter of treating rotation about a single axis as in plane 
motion. In 3D you’ll have to consider rotation about any axis, which leads to some 
difficulties in representing arbitrary rotations (Euler angles won’t work for us) as well 
as to complications with determining moments of inertia for rotation about any axis. 
We’ll discuss these issues in Chapter 11 through Chapter 13. 


102 | Chapter 4: Kinetics 


www.it-ebooks.info 



CHAPTER 5 


Collisions 


Now that you understand the motion of particles and rigid bodies, you need to consider 
what happens when they run into each other. That’s what we’ll address in this chapter; 
specifically, we’ll show you how to handle particle and, more interestingly, rigid-body 
collision response. 

Before moving forward, we need to make a distinction between collision detection and 
collision response. Collision detection is a computational geometry problem involving 
the determination of whether and where two or more objects have collided. Collision 
response is a kinetics problem involving the motion of two or more objects after they 
have collided. While the two problems are intimately related, we’ll focus solely on the 
problem of collision response in this chapter. Later, in Chapter 7 through Chapter 13, 
we’ll show you how to implement collision detection and response in various real-time 
simulations, which draw upon concepts presented in this chapter. 

Our treatment of rigid-body collision response in this chapter is based on classical 
(Newtonian) impact principles. Here, colliding bodies are treated as rigid irrespective 
of their construction and material. As in earlier chapters, the rigid bodies discussed here 
do not change shape even upon impact. This, of course, is an idealization. You know 
from your everyday experience that when objects collide they dent, bend, compress, or 
crumple. For example, when a baseball strikes a bat, it may compress as much as three- 
quarters of an inch during the millisecond of impact. Notwithstanding this reality, we’ll 
rely on well-established analytical and empirical methods to approximate rigid-body 
collisions. 

This classical approach is widely used in engineering machine design, analysis, and 
simulations; however, for rigid-body simulations there is another class of methods, 


103 


www.it-ebooks.info 




known as penalty methods, at your disposal. 1 In penalty methods, the force at impact is 
represented by a temporary spring that gets compressed between the objects at the point 
of impact. This spring compresses over a very short time and applies equal and opposite 
forces to the colliding bodies to simulate collision response. Proponents of this method 
say it has the advantage of ease of implementation. However, one of the difficulties 
encountered in its implementation is numerical instability. There are other arguments 
for and against the use of penalty methods, but we won’t get into the debate here. Instead, 
we’ve included several references in the Bibliography for you to review if you are so 
inclined. Other methods of modeling collisions exist as well. For example, nonlinear 
finite element simulations are commonly used to model collisions during product de¬ 
sign, such as the impact of a cellphone with the ground. These methods can be quite 
accurate; however, they are too slow for real-time applications. Further, they are overkill 
for games. 

Impulse-Momentum Principle 

Impulse is defined as a force that acts over a very short period of time. For example, the 
force exerted on a bullet when fired from a gun is an impulse force. The collision forces 
between two colliding objects are impulse forces, as when you kick a football or hit a 
baseball with a bat. 

More specifically, impulse is a vector quantity equal to the change in momentum. The 
so-called impulse-momentum principle says that the change in moment is equal to the 
applied impulse. For problems involving constant mass and moment of inertia, you can 
write: 


Linear impulse = 6 ( t _ t01+ ) F dt = m (v. - v_) 

Angular impulse = 6 ( t _ t0 1 +) M dt = I (to+ - ©_) 

In these equations, F is the impulsive force, M is the impulsive torque (or moment), t 
is time, v is velocity, the subscript - refers to the instant just prior to impact, and the 
subscript + refers to the instant just after impact. You can calculate the average impulse 
force and torque using the following equations: 

F = m (v 4 - v_) / (t + - t_) 

M = I (® 4 - ©_) / (t+ - t_) 


1. We use the classical approach in this book and are mentioning penalty methods only to let you know that the 
method were going to show is not the only one. Roughly speaking, the penalty in penalty methods refers to 
the numerical spring constants, which are usually large, that are used to represent the stiffness of the springs 
and thus the hardness (or softness) of the colliding bodies. These constants are used in the system of equations 
of motion describing the motion of all the bodies under consideration before and after the collision. 


104 | Chapter 5: Collisions 


www.it-ebooks.info 



Consider this simple example: a 150 gram (0.15 kg) bullet is fired from a gun at a muzzle 
velocity of756 m/s. The bullet takes 0.0008 seconds to travel through the 610 mm (0.610 
m) rifle barrel. Calculate the impulse and the average impulsive force exerted on the 
bullet. In this example, the bullets mass is a constant 150 grams and its initial velocity 
is 0, thus its initial momentum is 0. Immediately after the gun is fired, the bullet’s mo¬ 
mentum is its mass times the muzzle velocity, which yields a momentum of 113.4 kg- 
m/s. The impulse is equal to the change in momentum, and is simply 113.4 kg-m/s. The 
average impulse force is equal to the impulse divided by the duration of application of 
the force, or in this case: 

Average impulse force = (113.4 kg-m/s) / (0.0008 s) 

Average impulse force = 141,750 N 

This is a simple but important illustration of the concept of impulse, and you’ll use the 
same principle when dealing with rigid-body impacts. During impacts, the forces of 
impact are usually very high and the duration of impact is usually very short. When two 
objects collide, each applies an impulse force to the other; these forces are equal in 
magnitude but opposite in direction. In the gun example, the impulse applied to the 
bullet to set it in motion is also applied in the opposite direction to the gun, giving you 
a nice kick in the shoulder. This is simply Newton’s third law in action. 

Impact 

In addition to the impulse momentum principle discussed in the previous section, our 
classical impact, or collision response, analysis relies on another fundamental principle: 
Newton’s principle of conservation of momentum, which states that when a system of 
rigid bodies collide, momentum is conserved. This means that for bodies of constant 
mass, the sum of their masses times their respective velocities before the impact is equal 
to the sum of their masses times their respective velocities after the impact: 

mivi_ + m 2 v 2 _ = mjvi + + m 2 v 2+ 

Here, m refers to mass, v refers to velocity, subscript 1 refers to body one, subscript 2 
refers to body two, subscript - refers to the instant just prior to impact, and subscript 
+ refers to the instant just after impact. 

A crucial assumption of this method is that during the instant of impact the only force 
that matters is the impact force; all other forces are assumed negligible over that very 
short duration. Remember this assumption, because in Chapter 10 we’ll rely on it when 
implementing collision response in an example 2D real-time simulation. 

We’ve already stated that rigid bodies don’t change shape during impacts, and you know 
from your own experience that real objects do change shape during impacts. What’s 
happening in real life is that kinetic energy is being converted to strain energy to cause 


Impact | 105 


www.it-ebooks.info 



the objects to deform. (See the sidebar “Kinetic Energy” on page 106 for further details on 
this topic.) When the deformation in the objects is permanent, energy is lost and thus 
kinetic energy is not conserved. 


Kinetic Energy 

Kinetic energy is a form of energy associated with moving bodies. It is equal to the energy 
required to accelerate the body from rest, which is also equal to the energy required to 
bring the moving body to a stop. As you might expect, kinetic energy is a function of 
the body’s speed, or velocity, in addition to its mass. The formula for linear kinetic energy 
is: 

KE linear = (1/2) m v 2 

Angular, or rotational, kinetic energy is a function of the body’s inertia and angular 
velocity: 

KE an g U i ar = (1/2) I (0“ 

Conservation of kinetic energy between two colliding bodies means that the sum of 
kinetic energy of both bodies prior to impact is equal to the sum of the kinetic energy 
of both bodies after impact: 

miv 2 i_ + m 2 v 2 2 _ = m!V 2 1+ + m 2 v 2 2+ 


Collisions that involve losses in kinetic energy are said to be inelastic, or plastic, colli¬ 
sions. For example, if you throw two clay balls against each other, their kinetic energy 
is converted to permanent strain energy in deforming the clay balls, and their collision 
response—that is, their motion after impact—is less than spectacular. If the collision is 
perfectly inelastic, then the two balls of clay will stick to each other and move together 
at the same velocity after impact. Collisions where kinetic energy is conserved are called 
perfectly elastic. In these collisions, the sum of kinetic energy of all objects before the 
impact is equal to the sum of kinetic energy of all objects after the impact. A good 
example of elastic impact (though not perfectly elastic) is the collision between two 
billiard balls where the ball deformation is negligible and certainly not permanent under 
normal circumstances. 

Of course, in reality, impacts are somewhere between perfectly elastic and perfectly 
inelastic. This means that for rigid bodies, which don’t change shape at all, we’ll have to 
rely on an empirical relation to quantify the degree of elasticity of the impact(s) that 
we’re trying to simulate. The relation that we’ll use is the ratio of the relative separation 
velocity to the relative approach velocity of the colliding objects: 


106 | Chapter 5: Collisions 


www.it-ebooks.info 




e = -(vi+ - v 2+ ) / (vi_ - v 2 _) 


Here e is known as the coefficient of restitution and is a function of the colliding objects’ 
material, construction, and geometry. This coefficient can be experimentally deter¬ 
mined for specific impact scenarios—for example, the collision between a baseball and 
bat, or a golf club and ball. For perfectly inelastic collisions, e is 0, and for perfectly elastic 
collisions, e is 1. For collisions that are neither perfectly inelastic nor perfectly elastic, e 
can be any value between 0 and 1. In this regard, the velocities considered are along the 
line of action of the collision. 

In frictionless collisions, the line of action of impact is a line perpendicular (or normal) 
to the colliding surfaces. When the velocity of the bodies is along the line of action, the 
impact is said to be direct. When the line of action passes through the center of mass of 
the bodies, the collision is said to be central. Particles and spheres of uniform mass 
distribution always experience central impact. Direct central impact occurs when the 
line of action passes through the centers of mass of the colliding bodies and their velocity 
is along the line of action. When the velocities of the bodies are not along the line of 
action, the impact is said to be oblique. You can analyze oblique impacts in terms of 
component coordinates where the component parallel to the line of action experiences 
the impact, but the component perpendicular to the line of action does not. Figure 5-1 
illustrates these impacts. 



As an example, consider the collision between two billiard balls illustrated in Figure 5-2. 


Impact | 107 


www.it-ebooks.info 






Figure 5-2. Example billiard ball collision 

Both balls are a standard 57 mm in diameter, and each weighs 156 grams. Assume that 
the collision is nearly perfectly elastic and the coefficient of restitution is 0.9. If the 
velocity of ball 1 when it strikes ball 2 is 6 m/s in the x-direction, as shown in 
Figure 5-2, calculate the velocities of both balls after the collision assuming that this is 
a frictionless collision. 

The first thing you need to do is recognize that the line of action of impact is along the 
line connecting the centers of gravity of both balls, which, since these are spheres, is also 
normal to both surfaces. You can then write the unit normal vector as follows: 

V((2r) 2 -r 2 )i-rj 

n = -2r- 

n = (0.866) i - (0.5)j 

where n is the unit normal vector, r is the ball radius, and i and j represent unit vectors 
in the x- and y-directions, respectively. 

Now that you have the line of action of the collision, or the unit normal vector, you can 
calculate the relative normal velocity between the balls at the instant of collision. 

v rn = [v i_ — v 2 _] • n 

v rn = [(6 m/s) i + (0 m/s) j ] . [ (0.864) i - (0.5) j] 
v rn = 5.18 m/s 

This will be used as v ln _ in the following equations. Notice here that since ball 2 is initially 
at rest, v 2 _ is 0. 

Now you can apply the principle of conservation of momentum in the normal direction 
as follows: 


108 | Chapter 5: Collisions 


www.it-ebooks.info 














m l Vin- + m 2 V 2n - = m v ln+ + m 2 V 2n+ 


Noting that m 1 equals m 2 since the balls are identical, and that v 2n _ is 0, and then solving 
for v ln+ yields: 


v ln+ = v ln-“ v 2n+ 

To actually solve for these velocities, you need to use the equation for coefficient of 
restitution and make the substitution for v ln+ . Then, you’ll be able to solve for v 2n+ . Here’s 
how to proceed: 


e = (—vin+ + v 2n+ ) / (v ln - v 2n _) 
e v !n _ = —(v ln _ - v 2n+ ) + v 2n+ 

V2n+ = Vln- (e + 1) / 2 
v 2n+ = (5.18 m/s)(1.9) / 2 = 4.92 m/s 

Using this result and the formula for v ln+ yields: 

vi n+ = 5.18 m/s -4.92 m/s = 0.26 m/s 

Since the collision is frictionless, there is no impulse acting in the tangential direction. 
This means that momentum is conserved in that direction too and that the final tan¬ 
gential speed of ball 1 is equal to its initial tangential speed, which in this case is equal 
to 3 m/s (this equals (6m/s) sin 30°). Since ball 2 had no initial tangential speed, its 
velocity after impact is solely in the normal direction. Converting these results back to 
x-y coordinates instead of normal and tangential coordinates yields the following ve¬ 
locities for each ball after impact: 

v 2+ = (4.92 m/s) sin 60° i - (4.92 m/s) cos 60 ° j 
vi + = [(0.26 m/s) cos 30° + (3 m/s) sin 30°] i + 

+ [(-0.26 m/s) sin 30° + (3 m/s) cos 30°)] j 
vi + = (1.72 m/s) i + (2.47 m/s) j 

To further illustrate the application of these collision response principles, consider an¬ 
other example, this time the collision between a baseball bat and baseball (as shown in 
Figure 5-3). We are looking at a side view, staring down the barrel of the bat. 


Impact | 109 


www.it-ebooks.info 




Figure 5-3. Example baseball and bat collision 

To a reasonable degree of accuracy, the motion of a baseball bat at the instant of collision 
can generally be described as independent of the batter—in other words, you can assume 
that the bat is moving freely and pivoting about a point located near the handle end of 
the bat. Assume that the ball strikes the bat on the sweet spot—that is, a point near 
the center of percussion. 2 Further assume that the bat is swung in the horizontal plane 
and that the baseball is traveling in the horizontal plane when it strikes the bat. The bat 
is of standard dimensions with a maximum diameter of 70 mm and a weight of 1.02 kg. 
The ball is also of standard dimensions with a radius of 37 mm and a weight of 0.15 kg. 
The ball reaches a speed of 40 m/s (90 mph) at the instant it strikes the bat, and the speed 
of the bat at the point of impact is 31 m/s (70 mph). For this collision, the coefficient of 
restitution is 0.46. In the millisecond of impact that occurs, the baseball compresses 
quite a bit; however, in this analysis assume that both the bat and the ball are rigid. 
Finally, assume that this impact is frictionless. 

As in the previous example, the line of action of impact is along the line connecting the 
centers of gravity of the bat and ball; thus, the unit normal vector is: 

_ -VVi + r 2 f - /y)i - rj 

H ^ 

n = (0.875) i + (0.484) j 

Here the subscripts 1 and 2 denote the bat and ball, respectively. 

The relative normal velocity between the bat and ball is: 


2. The center of percussion is a point located near one of the nodes of natural vibration, and is the point at 
which, when the bat strikes the ball, no force is transmitted to the handle of the bat. If you’ve ever hit a baseball 
incorrectly such that you get a painful vibrating sensation in your hands, then you know what it feels like to 
miss the center of percussion. 


110 | Chapter 5: Collisions 


www.it-ebooks.info 












v rn = [v 1 — - v 2 _] • n 

V rn = [(71 m/s) i + (0 m/s) j ] • [ (0.875) i - (0.484) j] 
v rn = 62.1 m/s 


The velocity components of the bat and ball in the normal direction are: 

vj n — = vi_ • n = 27.1 m/s 
v 2n _ = v 2 _ • n = -35.0 m/s 


Applying the principle of conservation of momentum in the normal direction and 
solving for v ln+ yields: 

mi v !n _ + m 2 v 2n _ = m! v !n+ + m 2 v 2n+ 

(1.02 kg) (27.1 m/s) + (0.15 kg) (-35.2 m/s) = 

=(1.02 kg) vi n _|_ + (0.15 kg) v 2n+ 
vi n+ = 21.92 m/s - (0.14 m/s) v 2n+ 

As in the previous example, applying the formula for coefficient of restitution with the 
preceding formula for v ln+ yields: 

e = (—vi n+ + v 2n+ ) / (v ln _ - v 2n _) 

0.46 = [-21.92 m/s + (0.14 m/s) v 2n+ + v 2n+ ] / [27.1 m/s + 35.2 

m/s] 

v 2n+ = 44.4 m/s and vi n+ = 15.7 m/s 

Here again, since this impact is frictionless, each object retains its original tangential 
velocity component. For the bat, this component is 15 m/s, while for the ball it’s -19.3 
m/s. Converting these normal and tangential components to x-y coordinates yields the 
following bat and ball velocities for the instant just after impact: 

V] + = 21.0 m/s i - 5.5 m/s j 
v 2+ = 30 m/s i + 38.7 m/s j 

Both of these examples illustrate fundamental impact analysis using the classical ap¬ 
proach. They also share an important assumption—that the impacts are frictionless. In 
reality, you know that billiard balls and baseballs and bats collide with friction; other¬ 
wise, you would not be able to apply English in billiards or create lift-generating spin 
on baseballs. Later in this chapter we’ll discuss how to include friction in your impact 
analysis. 


Impact | 111 


www.it-ebooks.info 



Linear and Angular Impulse 

In the previous section, you were able to work through the specific examples by hand 
using the principle of conservation of momentum and the coefficient of restitution. This 
approach will suffice if you’re writing games where the collision events are well defined 
and anticipated. However, if you’re writing a real-time simulation where objects, espe¬ 
cially arbitrarily shaped rigid bodies, may or may not collide, then you’ll want to use a 
more general approach. This approach involves the use of formulas to calculate the 
actual impulse between colliding objects so that you can apply this impulse to each 
object, instantly changing its velocity. In this section, we’ll derive the equations for 
impulse, both linear and angular, and we’ll show you how to implement these equations 
in code in Chapter 10. 

When you’re dealing with particles or spheres, the only impulse formula that you’ll need 
is that for linear impulse, which will allow you to calculate the new linear velocities of 
the objects after impact. So, the first formula that we’ll derive for you is that for linear 
impulse between two colliding objects, as shown in Figure 5-4. 


velocity after impact 



Body 1 


velocity before impact 


Figure 5-4. Two colliding particles (or spheres) 


For now, assume the collision is frictionless and the line of action of the impulse is along 
the line connecting the centers of mass of the two objects. This line is normal to the 
surfaces of both objects. 

To derive the formula for linear impulse, you have to consider the formula from the 
definition of impulse along with the formula for coefficient of restitution. Here let J 
represent the impulse: 


IJI = m (lv+1 - Iv J) 


112 | Chapter 5: Collisions 


www.it-ebooks.info 











e = —(lv 1+ l - lv 2 +l)/(lvi_l - lv 2 J) 


In these equations the velocities are those along the line of action of the impact, which 
in this case is a line connecting the centers of mass of the two objects. Since the same 
impulse applies to each object (just in opposite directions), you actually have three 
equations to deal with: 


IJI = mj (lvi+1 - lvi_l) 
l-JI = m 2 (lv 2+ l - Iv 2 —I) 
e = —(lv 1+ l— lv 2 +l)/(lvi_l - lv 2 J) 

Notice we’ve assumed that / acts positively on body 1 and its negation, -/, acts on body 
2. Also notice that there are three unknowns in these equations: the impulse and the 
velocities of both bodies after the impact. Since there are three equations and three 
unknowns, you can solve for each unknown by rearranging the two impulse equations 
and substituting them into the equation for e. After some algebra, you’ll end up with a 
formula for / that you can then use to determine the velocities of each body just after 
impact. Here’s how that’s done: 

For body 1: lvi+1 = IJI/mj + lvi_l 
For body 2: lv 2 +l = —IJI/m 2 + lv 2 J 

Substituting |v 1+ | and |v 2+ | into the equation for e yields: 

e (IviJ - Iv 2 _I) = -[(IJI/mi + IviJ) - (-IJI/m 2 + lv 2 _l)] 

e (Ivi-I - lv 2 _l) + lvi_l - lv 2 _I = -J (1/mj + l/m 2 ) 

Let |v r | = (|Vj_| - |v 2 _|); then: 

e lv r l + lv r l = -IJI (1/nq + l/m 2 ) 

IJI =-lv r l(e+ l)/(l/mj + l/m 2 ) 

Since the line of action is normal to the colliding surfaces, v r is the relative velocity along 
the line of action of impact, and J acts along the line of action of impact, which in this 
case is normal to the surfaces, as we’ve already stated. 

Now that you have a formula for the impulse, you can use the definition of impulse 
along with this formula to calculate the change in linear velocity of the objects involved 
in the impact. Here’s how that’s done in the case of two objects colliding: 

vi+ = vi_ + (IJI n)/mi 
v 2+ = v 2 _ + (-IJI n)/m 2 


Linear and Angular Impulse | 113 


www.it-ebooks.info 



Notice that for the second object, the negative of the impulse is applied since it acts on 
both objects equally but in opposite directions. 

When dealing with rigid bodies that rotate, you’ll have to derive a new equation for 
impulse that includes angular effects. You’ll use this impulse to calculate new linear and 
angular velocities of the objects just after impact. Consider the two objects colliding at 
point P, as shown in Figure 5-5. 



There’s a crucial distinction between this collision and that discussed earlier. In this case, 
the velocity at the point of contact on each body is a function of not only the objects’ 
linear velocity but also their angular velocities, and you’ll have to recall from Chap¬ 
ter 2 the following formula in order to calculate the velocities at the impact point on 
each body: 


v p = v g + (w X r) 

In this relation, r is the vector from the body’s center of gravity to the point P. 

Using this formula, you can rewrite the two formulas relating the linear velocity after 
impact to the impulse and initial velocity as follows: 

For body 1: vi g+ + (a>i+ X iq) = J/mi + vi g _ + (®i_ X iq) 

For body 2: v 2g + + (w 2+ X r 2 ) = -J/m 2 + v 2g _ + (<o 2 _ x r 2 ) 

There are two additional unknowns here, the angular velocities after impact, which 
means that you need two additional equations. You can get these equations from the 
definition of angular impulse: 

For body 1: (iq X J) = Ii (®i + - ®i_) 

For body 2: (r 2 X -J) = I 2 (to 2+ - w 2 _) 


114 | Chapter 5: Collisions 


www.it-ebooks.info 





Here we calculate the moment due to the impulse by taking the vector cross product of 
the impulse with the distance from the body’s center of gravity to the point of application 
of the impulse. 

By combining all of these equations with the equation for e and following the same 
procedure used when deriving the linear impulse formula, you’ll end up with a formula 
for | J| that takes into account both linear and angular effects, which you can then use 
to find the linear and angular velocities of each body immediately after impact. Here’s 
the result: 


IJI = -(v r « n)(e + l)/[l/mj + l/m 2 + n «((ri X n)/Ij) x rj + n • 

((r 2 X n)/I 2 ) X r 2 ] 

Here v r is the relative velocity along the line of action at the impact point P, and n is a 
unit vector along the line of action at the impact point pointing out from body 1. 

With this new formula for |J|, you can calculate the change in linear and angular ve¬ 
locities of the objects involved in the collision using these formulas: 

vi+ = Vi_ + (IJI n)/mi 
v 2+ = v 2 _ + (-IJI n)/m 2 
© 1 + = g>i_ + (ri X IJI n)/Ii 
©2+ = <*>2— + ( r 2 X -IJI n)/I 2 

As we said earlier, we’ll show you how to implement these formulas for impulse in code 
when you get to Chapter 10. 

Friction 

Friction acts between contacting surfaces to resist motion. When objects collide in any 
type of collision except direct impact, for that very brief moment of contact, they will 
experience a friction force that acts tangentially to the contacting surfaces. Not only will 
this tangential force change the linear velocities of the colliding objects in the tangential 
direction, but it will also create a moment (torque) on the obj ects, which tends to change 
their angular velocities. This tangential impulse combined with the normal impulse 
results in an effective line of action of the total collision impulse that is no longer per¬ 
pendicular to the contacting surfaces. 

In practice, it is very difficult to quantify this collision friction force due to the fact that 
the friction force is not necessarily constant if the collision is such that the friction force 
does not develop beyond the maximum static friction force. Further complications stem 
from the fact that objects do tend to deform when they collide, creating an additional 
source of resistance. That said, since the friction force is a function of the normal force 
between the contacting surfaces, you know that the ratio of the normal force to the 


Friction | 115 


www.it-ebooks.info 



friction force is equal to the coefficient of friction. If you assume that the collisions are 
such that the kinetic coefficient of friction is applicable, then this ratio is constant. 

hk = Ff/Fn 

Here, f' t is the tangential friction force and F n is the normal impact force. You can extend 
this to say that the ratio of the tangential impulse to normal impulse is equal to the 
coefficient of friction. 

Consider the collision between the golf club head and golf ball illustrated in Figure 5-6. 



Figure 5-6. Golf club-golf ball collision 


In the upper velocity diagram, v_ represents the relative velocity between the ball and 
club head at the instant of impact, v + represents the velocity of the ball just after impact, 
v t _ and v t+ represent the tangential components of the ball velocity at and just after the 
instant of impact, respectively. 

If this were a frictionless collision, v t _ and v t+ would be equal, as would the angles a and 
0. However, with friction the tangential velocity of the ball is reduced, making v t+ less 
than v t _, which also means that a will be less than 0. 

The lower force diagram in Figure 5-6 illustrates the forces involved in this collision 
with friction. Since the ratio of the tangential friction force to the normal collision force 
is equal to the coefficient of friction, you can develop an equation relating the angle cp 
to the coefficient of friction. 


tan cp = Ff / F n = p 

In addition to this friction force changing the linear velocity of the ball in the tangential 
direction, it will also change the angular velocity of the ball. Since the friction force is 


116 | Chapter 5: Collisions 


www.it-ebooks.info 








acting on the ball’s surface some distance from its center of gravity, it creates a moment 
(torque) about the ball’s center of gravity, which causes the ball to spin. You can develop 
an equation for the new angular velocity of the ball in terms of the normal impact force 
or impulse: 


£ M cg = Ff r = I C g dco/dt 
p F n r = I cg dco/dt 
p F n r dt = I cg dco 

6(t- to t+) Fn dt = I C g / (p r) to (o+) ® d (0 


Notice here that the integral on the left is the normal impulse; thus: 

Impulse = I eg / (p r) (co + - co_) 
co + = (Impulse) (p r) / I cg + co_ 

This relation looks very similar to the angular impulse equation that we showed you 
earlier in this chapter, and you can use it to approximate the friction-induced spin in 
specific collision problems. 

Turn back to the equation for impulse, /, in the last section that includes both linear and 
angular effects. Here it is again for convenience: 

IJI = -(v r * n)(e + 1) / [1/mj + l/m 2 + n *((rj x n)/Ij) x iq + n • 

((r 2 X n)/I 2 ) X r 2 ] 

This formula gives you the collision impulse in the normal direction. To see how friction 
fits in you must keep in mind that friction acts tangentially to the contacting surfaces, 
that combining the friction force with the normal impact force yields a new effective 
line of action for the collision, and that the friction force (and impulse) is a function of 
the normal force (impulse) and coefficient of friction. Considering all these factors, the 
new equations to calculate the change in linear and angular velocities of two colliding 
objects are as follows: 


Vi+ = vi_ + (J n + (p J) t) / mi 
v 2+ = v 2 _ + (-J n + (p J) t) / m 2 
w 1+ = «i- + (iq x (J n+ (p J) t)) / leg 
®2+ = < 0 2 _ + (r 2 X (-J n+ (p J) t)) / ^ 

In these equations, t is the unit tangent vector, which is tangent to the collision surfaces 
and at a right angle to the unit normal vector. You can calculate the tangent vector if 
you know the unit normal vector and the relative velocity vector in the same plane as 
the normal vector. 


Friction | 117 


www.it-ebooks.info 



t = (n x v r ) x n 
t = t / Itl 


For many problems that you’ll face, you may be able to reasonably neglect friction in 
your collision response routines since its effect may be small compared to the effect of 
the normal impulse itself. However, for some types of problems, friction is crucial. For 
example, the flight trajectory of a golf ball depends greatly on the spin imparted to it as 
a result of the club-ball collision. We’ll discuss how spin affects trajectory in the next 
chapter, which covers projectile motion. 


118 | Chapter 5: Collisions 


www.it-ebooks.info 



CHAPTER 6 


Projectiles 


This chapter is the first in a series of chapters that discuss specific real-world phenomena 
and systems, such as projectile motion and airplanes, with the goal of giving you a solid 
understanding of their real-life behavior. This understanding will help you to model 
these or similar systems accurately in your games. Instead of relying on purely idealized 
formulas, we’ll present a wide variety of practical formulas and data that you can use. 
We’ve chosen the examples in this and later chapters to illustrate common forces and 
phenomena that exists in many systems, not just the ones we’ll be discussing here. For 
example, while Chapter 16, “Ships and Boats,” discusses buoyancy in detail, buoyancy 
is not limited to ships; any object immersed in a fluid experiences buoyant forces. The 
same applies for the topics discussed in this chapter and Chapter 15, Chapter 17, Chap¬ 
ter 18, and Chapter 19. 

Once you understand what’s supposed to happen with these and similar systems, you’ll 
be in a better position to interpret your simulation results to determine if they make 
sense—that is, if they are realistic enough. You’ll also be better educated on what factors 
are most important for a given system such that you can make appropriate simplifying 
assumptions to help ease your effort. Basically, when designing and optimizing your 
code, you’ll know where to cut things out without sacrificing realism. This gets into the 
subject of parameter tuning. 

Over the next few chapters, we want to give you enough of an understanding of certain 
physical phenomenon such that you can tune your models for the desired behavior. If 
you are modeling several similar objects in your simulation but want each one to behave 
slightly differently, then you have to tune the forces that get applied to each object in 
order to achieve the varying behavior. Since forces govern the behavior of objects in 
your simulations, we’ll be focusing on force calculations with the intent of showing you 
how and why certain forces are what they are instead of simply using the idealized 
formulas discussed in Chapter 3. Parameter tuning isn’t just limited to tuning your 
model’s behavior—it also involves dealing with numerical issues, such as numerical 


119 


www.it-ebooks.info 




stability in your integration algorithms. We’ll discuss these issues more when we show 
you several simulation examples in Chapter 7 through Chapter 14. 

We’ve devoted this entire chapter to projectile motion because so many physical prob¬ 
lems that may find their way into your games fall in this category. Further, the forces 
governing projectile motion affect many other systems that aren’t necessarily projectiles 
—for example, the drag force experienced by projectiles is similar to that experienced 
by airplanes, cars, or any other object moving through a fluid such as air or water. 

A projectile is an object that is placed in motion by a force acting over a very short period 
of time, which, as you know from Chapter 5, is also called an impulse. After the proj ectile 
is set in motion by the initial impulse during the launching phase, the projectile enters 
into the projectile motion phase, where there is no longer a thrust or propulsive force 
acting on it. As you know already from the examples presented in Chapter 2 and Chap¬ 
ter 4, there are other forces that act on projectiles. (For the moment, we’re not talking 
about self-propelled “projectiles” such as rockets since, due to their propulsive force, 
they don’t follow “classical” projectile motion until after they’ve expended their fuel.) 

In the simplest case, neglecting aerodynamic effects, the only force acting on a proj ectile 
other than the initial impulsive force is gravitation. For situations where the projectile 
is near the earth’s surface, the problem reduces to a constant acceleration problem. 
Assuming that the earth’s surface is flat—that is, that its curvature is large compared to 
the range of the projectile—the following statements describe projectile motion: 

• The trajectory is parabolic. 

• The maximum range, for a given launch velocity, occurs when the launch angle is 
45°. 

• The velocity at impact is equal to the launch velocity when the launch point and 
impact point are at the same level. 

• The vertical component of velocity is 0 at the apex of the trajectory. 

• The time required to reach the apex is equal to the time required to descend from 
the apex to the point of impact assuming that the launch point and impact point 
are at the same level. 

• The time required to descend from the apex to the point of impact equals the time 
required for an object to fall the same vertical distance when dropped straight down 
from a height equal to the height of the apex. 

Simple Trajectories 

There are four simple classes of projectile motion problems that we’ll summarize: 

• When the target and launch point are at the same level 


120 | Chapter 6: Projectiles 


www.it-ebooks.info 



• When the target is at a level higher than the launch point 

• When the target is at a level lower than the launch point 

• When the projectile is dropped from a moving system (like an airplane) above the 
target 

In the first type of problem, the launch point and the target point are located on the 
same horizontal plane. In Figure 6-1, v 0 is the initial velocity of the projectile at the time 
of launch, cp is the launch angle, R is the range of the projectile, and h is the height of 
the apex of the trajectory. 



R 


Figure 6-1. Target and launch point at same level 

To solve this type of problem, use the formulas shown in Table 6-1. Note, in these 
formulas t represents any time instant after launch, and T represents the total time from 
launch to impact. 

Table 6-1. Formulas—target and launch point at same level 


1 To calculate: 

Use this formula: 1 

x(t) 

(v 0 COS cp) t 

y(t) 

(v 0 sin <p) t-(g t 2 ) / 2 

VxW 

v 0 cos cp 

Vy(t) 

v 0 sin cp — g t 

v(t) 

Jv 0 2 - 2gtv 0 sin ip + g 2 t 2 

h 

(v 0 2 sin 2 cp) / (2 g) 

R 

v 0 T cos cp 

T 

(2 v 0 sin cp) / g 


Remember to keep your units consistent when applying these formulas. If you are 
working in the SI (metric) system, length and distance values should be in meters (m); 


Simple Trajectories | 121 


www.it-ebooks.info 

















time should be in seconds (s); speed should be in meters per second (m/s); and accel¬ 
eration should be in meters per second squared (m/s 2 ). In the SI system, g is 9.8 m/s 2 . 

In the second type of problem, the launch point is located on a lower horizontal plane 
than the target. In Figure 6-2, the launch points y coordinate is lower than the targets 
y coordinate. 



Figure 6-2. Target higher than launch point 


For this type of problem, use the formulas shown in Table 6-2. Notice that most of these 
formulas are the same as those shown in Table 6-1. 

Table 6-2. Formulas—target higher than launch point 


1 To calculate: 

Use this formula: I 

<t) 

(v„ cos <p)t 

y(t) 

(v 0 sin <p) t-(g t 2 ) / 2 

v x (t) 

V 0 COS (p 

Vy(t) 

v 0 sin (p — g t 

v(t) 

^v 0 2 - 2 gtv 0 sin <p + g 2 t 2 

h 

(v 0 2 sin 2 cp) / (2 g) 

R 

v 0 T cos cp 

T 

(v 0 sin cp)/g + V , 


Actually, the only formula that has changed is that for T, where it has been revised to 
account for the difference in elevation between the target and the launch point. 

In the third type of problem, the target is located on a plane lower than the launch point; 
in Figure 6-3, the target’s y coordinate is lower than the launch point’s y coordinate. 


122 | Chapter 6: Projectiles 


www.it-ebooks.info 
























R 


Figure 6-3. Target lower than launch point 

Table 6-3 shows the formulas to use for this type of problem. Here again, almost all of 
the formulas are the same as those shown in Table 6-1. 

Table 6-3. Formulas—target lower than launch point 


1 To calculate: 

Use this formula: 1 

x(t) 

(v„ cos <p)t 

y(t) 

(v 0 sin <p) t-(g t 2 ) / 2 

v x (t) 

v„ cos cp 

Vy(t) 

v 0 sin <p — g t 

v(t) 

-y/r 0 2 - 2 gtv 0 sin tp + gh 2 

h 

b + (v 0 2 sin 2 cp) / (2 g) 

R 

v 0 T cos cp 

T 

(v 0 sin cp) / g + '/y- 


The only formulas that have changed are the formulas for h and T, which have been 
revised to account for the difference in elevation between the target and the launch point 
(except this time the target is lower than the launch point). 

Finally, the fourth type of problem involves dropping the projectile from a moving 
system, such as an airplane. In this case, the initial velocity of the projectile is horizontal 
and equal to the speed of the vehicle dropping it. Figure 6-4 illustrates this type of 
problem. 


Simple Trajectories | 123 


www.it-ebooks.info 





















Figure 6-4. Projectile dropped from a moving system 

Table 6-4 shows the formulas to use to solve this type of problem. Note here that when 
v D is 0, the problem reduces to a simple free-fall problem in which the projectile drops 
straight down. 

Table 6-4. Formulas—projectile dropped from a moving system 


1 To calculate: 

Use this formula: 1 

x(t) 

v 0 t 

y(t) 

h — (g t 2 ) / 2 

Vx(t) 

Vo 

Vy(t) 

-gt 

v(t) 

fvj + g 2 t 2 

h 

(g t 2 ) / 2 

R 

v„T 

T 



These formulas are useful if you’re writing a game that does not require a more accurate 
treatment of projectile motion—that is, if you don’t need or want to consider the other 
forces that can act on a projectile when in motion. If you are going for more accuracy, 
you’ll have to consider these other forces and treat the problem as we did in Chap¬ 
ter 4’s example. 

Drag 

In Chapter 3 and Chapter 4, we showed you the idealized formulas for viscous fluid 
dynamic drag as well as how to implement drag in the equations of motion for a pro- 


124 | Chapter 6: Projectiles 


www.it-ebooks.info 


















jectile. This was illustrated in the example program discussed in Chapter 4. Recall that 
the drag force is a vector just like any other force and that it acts on the line of action of 
the velocity vector but in a direction opposing velocity. While those formulas work in 
a game simulation, as we said before, they don’t tell the whole story. While we can’t treat 
the subject of fluid dynamics in its entirety in this book, we do want to give you a better 
understanding of drag than just the simple idealized equation presented earlier. 

Analytical methods can show that the drag on an object moving through a fluid is 
proportional to its speed, size, shape, and the density and viscosity of the fluid through 
which it is moving. You can also come to these conclusions by drawing on your own 
real-life experience. For example, when waving your hand through the air, you feel very 
little resistance; however, if you put your hand out of a car window traveling at 100 km/ 
h, then you feel much greater resistance (drag force) on your hand. This is because drag 
is speed dependent. When you wave your hand underwater—say, in a swimming pool 
—you’ll feel a greater drag force on your hand than you do when waving it in the air. 
This is because water is more dense and viscous than air. As you wave your hand un¬ 
derwater, you’ll notice a significant difference in drag depending on the orientation of 
your hand. If your palm is in line with the direction of motion—that is, you are leading 
with your palm—then you’ll feel a greater drag force than you would if your hand were 
turned 90 degrees as though you were executing a karate chop through the water. This 
tells you that drag is a function of the shape of the object. You get the idea. 

To facilitate our discussion of fluid dynamic drag, let’s look at the flow around a sphere 
moving through a fluid such as air or water. If the sphere is moving slowly through the 
fluid, the flow pattern around the sphere would look something like Figure 6-5. 



Figure 6-5. Flow pattern around slowly moving sphere 


Bernoulli’s equation, which relates pressure to velocity in fluid flow, says that as the fluid 
moves around the sphere and speeds up, the pressure in the fluid (locally) will go down. 
The equation, presented by Daniel Bernoulli in 1738, applies to frictionless incompres¬ 
sible fluid flow and looks like this: 1 

P/y + z + V 2 / (2g) = constant 


1. In a real fluid with friction, this equation will have extra terms that account for energy losses due to friction. 


Drag | 125 


www.it-ebooks.info 


















where P is the pressure at a point in the fluid volume under consideration, y is the specific 
weight of the fluid, z is the elevation of the point under consideration, V is the fluid 
velocity at that point, and g is the acceleration due to gravity. As you can see, if the 
expression on the left is to remain constant, and assuming that z is constant, then if 
velocity increases the pressure must decrease. Likewise, if pressure increases, then ve¬ 
locity must decrease. 

As you can see in Figure 6-5, the pressure will be greatest at the stagnation point, Sj, and 
will decrease around the leading side of the sphere and then start to increase again 
around the back of the sphere. In an ideal fluid with no friction, the pressure is fully 
recovered behind the sphere and there is a trailing stagnation point, S„ whose pressure 
is equal to the pressure at the leading stagnation point. Since the pressure fore and aft 
of the sphere is equal and opposite, there is no net drag force acting on the sphere. 

The pressure on the top and bottom of the sphere will be lower than at the stagnation 
points since the fluid velocity is greater over the top and bottom. Since this is a case of 
symmetric flow around the sphere, there will be no net pressure difference between the 
top and bottom of the sphere. 

In a real fluid there is friction, which affects the flow around the sphere such that the 
pressure is never fully recovered on the aft side of the sphere. As the fluid flows around 
the sphere, a thin layer sticks to the surface of the sphere due to friction. In this boundary 
layer , the speed of the fluid varies from 0 at the sphere surface to the ideal free stream 
velocity, as illustrated in Figure 6-6. 



Figure 6-6. Velocity gradient within boundary layer 


This velocity gradient represents a momentum transfer from the sphere to the fluid and 
gives rise to the frictional component of drag. Since a certain amount of fluid is stick¬ 
ing to the sphere, you can think of this as the energy required to accelerate the fluid and 
move it along with the sphere. (If the flow within this boundary layer is laminar, then 
the viscous shear stress between fluid “layers” gives rise to friction drag. When the flow 
is turbulent, the velocity gradient and thus the transfer of momentum gives rise to 
friction drag.) 


126 | Chapter 6: Projectiles 


www.it-ebooks.info 










Moving further aft along the sphere, the boundary layer grows in thickness and will not 
be able to maintain its adherence to the sphere surface, and it will separate at some point. 
Beyond this separation point, the flow will be turbulent, and this is called the turbulent 
wake. In this region, the fluid pressure is lower than that at the front of the sphere. This 
pressure differential gives rise to the pressure component of drag. Figure 6-7 shows how 
the flow might look. 



Figure 6-7. Flow pattern around sphere showing separation 


For a slowly moving sphere, the separation point will be approximately 80° from the 
leading edge. 

Now, if you were to roughen the surface of the sphere, you’ll affect the flow around it. 
As you would expect, this roughened sphere will have a higher friction drag component. 
However, more importantly, the flow will adhere to the sphere longer and the separation 
point will be pushed further back to approximately 115°, as shown in Figure 6-8. 



Figure 6-8. Flow around a roughened sphere 

This will reduce the size of the turbulent wake and the pressure differential, thus de¬ 
creasing the pressure drag. It’s paradoxical but true that, all other things being equal, a 
slightly roughened sphere will have less total drag than a smooth one. Ever wonder why 
golf balls have dimples? If so, there’s your answer. 

The total drag on the sphere depends very much on the nature of the flow around the 
sphere—that is, whether the flow is laminar or turbulent. This is best illustrated by 
looking at some experimental data. Figure 6-9 shows a typical curve of the total drag 
coefficient for a sphere plotted as a function of the Reynolds number. 


Drag | 127 


www.it-ebooks.info 







































Figure 6-9. Total drag coefficient for a smooth sphere versus Reynolds number 2 

The Reynolds number (commonly denoted N t or R n ) is a dimensionless number that 
represents the speed of fluid flow around an object. It’s a little more than just a speed 
measure, since it includes a characteristic length for the object and the viscosity and 
density of the fluid. The formula for the Reynolds number is: 

R n = (v L)/o 


or, 


R n = (v L p)/p 

where v is speed, L is a characteristic length of the object (diameter for a sphere), v is 
the kinematic viscosity of the fluid, p is the fluid mass density, and p is the absolute 
viscosity of the fluid. For the Reynolds number to work out as a dimensionless number 
velocity, length and kinematic viscosity must have units of m/s, m, and m 2 /s, respectively, 
within the SI system. 

This number is useful for non-dimensionalizing data measured from tests on an object 
of given size (like a model) such that you can scale the data to estimate the data for 
similar objects of different size. Here “similar” means that the objects are geometrically 
similar, just different scales, and that the flow pattern around the objects is similar. For 
a sphere the characteristic length is diameter, so you can use drag data obtained from a 
small model sphere of given diameter to estimate the drag for a larger sphere of different 


2. The curve shown here is intended to demonstrate the trend of Cj versus R n for a smooth sphere. For more 
accurate drag coefficient data for spheres and other shapes, refer to any college-level fluid mechanics text, such 
as Robert L. Daugherty, Joseph B. Franzini, and E. John Finnemore’s Fluid Mechanics with Engineering Ap¬ 
plications (McGraw-Hill). 


128 | Chapter 6: Projectiles 


www.it-ebooks.info 


















diameter. A more useful application of this scaling technique is estimating the viscous 
drag on ship or airplane appendages based on model test data obtained from wind tunnel 
or tow tank experiments. 

The Reynolds number is used as an indicator of the nature of fluid flow. A low Reynolds 
number generally indicates laminar flow, while a high Reynolds number generally in¬ 
dicates turbulent flow. Somewhere in between, there is a transition range where the flow 
makes the transition from laminar to turbulent flow. For carefully controlled experi¬ 
ments, this transition ( critical ) Reynolds number can consistently be determined. How¬ 
ever, in general the ambient flow field around an object—that is, whether it has low or 
high turbulence—will affect when this transition occurs. Further, the transition Rey¬ 
nolds number is specific to the type of problem being investigated (for example, whether 
you’re looking at flow within pipes, the flow around a ship, or the flow around an air¬ 
plane, etc.). 

We calculate the total drag coefficient, C d , by measuring the total resistance, R t , from 
tests and using the following formula: 


C d = R t / (0.5 p v 2 A) 

where A is a characteristic area that depends on the object being studied. For a sphere, 
A is typically the projected frontal area of the sphere, which is equal to the area of a 
circle of diameter equal to that of the sphere. By comparison, for ship hulls, A is typically 
taken as the underwater surface area of the hull. If you work out the units on the right- 
hand side of this equation, you’ll see that the drag coefficient is nondimensional (i.e., it 
has no units). 

Given the total drag coefficient, you can estimate the total resistance (drag) using the 
following formula: 


R t = (0.5 p v 2 A) C d 

This is a better equation to use than the ones given in Chapter 3, assuming you have 
sufficient information available—namely, the total drag coefficient, density, velocity, 
and area. Note the dependence of total resistance on velocity squared. To get R t in units 
of newtons (N), you must have velocity in m/s, area in m 2 , and density in kg/m 3 (re¬ 
member C d is dimensionless). 

Turning back now to Figure 6-9, you can make a couple of observations. First, you can 
see that the total drag coefficient decreases as the Reynolds number increases. This is 
due to the formation of the separation point and its subsequent move aft on the sphere 
as the Reynolds number increases and the relative reduction in pressure drag, as dis¬ 
cussed previously. At a Reynolds number of approximately 250,000, there is a dramatic 


Drag | 129 


www.it-ebooks.info 



reduction in drag. This is a result of the flow becoming fully turbulent with a corre¬ 
sponding reduction in pressure drag. 

In the Cannon2 example in Chapter 4, we implemented the ideal formula for air drag on 
the proj ectile. In that case we used a constant value of drag coefficient that was arbitrarily 
defined. As we said earlier, it would be better to use the formula presented in this chapter 
for total drag along with the total drag coefficient data shown in Figure 6-9 to estimate 
the drag on the projectile. While this is more “accurate,” it does complicate matters for 
you. Specifically, the drag coefficient is now a function of the Reynolds number, which 
is a function of velocity. You’ll have to set up a table of drag coefficients versus the 
Reynolds number and interpolate this table given the Reynolds number calculated at 
each time step. As an alternative, you can fit the drag coefficient data to a curve to derive 
a formula that you can use instead; however, the drag coefficient data may be such that 
you’ll have to use a piecewise approach and derive curve fits for each segment of the 
drag coefficient curve. The sphere data presented herein is one such case. The data does 
not lend itself nicely to a single polynomial curve fit over the full range of the Reynolds 
number. In such cases, you’ll end up with a handful of formulas for drag coefficient, 
with each formula valid over a limited range of Reynolds numbers. 

While the Cannon2 example does have its limitations, it is useful to see the effects of drag 
on the trajectory of the projectile. The obvious effect is that the trajectory is no longer 
parabolic. You can see in Figure 6-10 that the trajectory appears to drop off much more 
sharply when the projectile is making its descent after reaching its apex height. 



Another important effect of drag on trajectory (this applies to objects in free fall as well) 
is the fact that drag will limit the maximum vertical velocity attainable. This limit is the 
so-called terminal velocity. Consider an object in free fall for a moment. As the object 
accelerates toward the earth at the gravitation acceleration, its velocity increases. As 


130 | Chapter 6: Projectiles 


www.it-ebooks.info 






velocity increases, so does drag since drag is a function of velocity. At some speed the 
drag force retarding the object’s motion will increase to a point where it is equal to the 
gravitational force that’s pulling the object toward the earth. In the absence of any other 
forces that may affect motion, the net acceleration on the object is 0, and it continues 
its descent at the constant terminal velocity. 

Let us illustrate this further. Go back to the formula we derived for the y component 
(vertical component) of velocity for the projectile modeled in the Cannon2 example. 
Here it is again so you don’t have to flip back to Chapter 4: 

v y2 = (1 / C d ) e(- c d /m k (C d v y i + m g) - (m g) / C d 

It isn’t obvious from looking at this equation, but the velocity component, v y2 , asymptotes 
to some constant value as time increases. To help you visualize this, we’ve plotted this 
equation, as shown in Figure 6-11. 



As you can see, over time the velocity reaches a maximum absolute value of about 
-107.25 speed units. The negative velocities indicate that the velocity is in the negative 
y-direction—that is, the object is falling toward the earth in this case. (For this calcu¬ 
lation we arbitrarily assumed a mass of 100, a drag coefficient of 30, and an initial velocity 
of 0.) 

Assuming an initial velocity of 0 and equating the formula for total resistance shown 
earlier to the weight of an object, you can derive the following formula for terminal 
velocity for an object in free fall: 


v t 


I -mg 
y C d pA 


Drag | 131 


www.it-ebooks.info 
















The trick in applying this formula is in determining the right value for the drag coeffi¬ 
cient. Just for fun, let’s assume a drag coefficient of 0.5 and calculate the terminal velocity 
for several different objects. This exercise will allow you to see the influence of the 
object’s size on terminal velocity. Table 6-5 gives the terminal velocities for various 
objects in free fall using an air density of 1.225 kg/m 3 (air at standard atmospheric 
pressure at 15°C). Using this equation with density in kg/m 3 means that m must be in 
kg, g in m/s 2 , and A in m 2 in order to get the terminal speed in m/s. We went ahead and 
converted from m/s to kilometers per hour (km/h) to present the results in Table 6-5. 
The weight of each object shown in this table is simply its mass, m, times g. 


Table 6-5. Terminal velocities for various objects 


1 Object 

Weight (N) 

Area (m 2 ) 

Terminal velocity (km/h) 1 

Skydiver in free fall 

801 

0.84 

201 

Skydiverwith open parachute 

801 

21.02 

40 

Baseball (2.88 in diameter) 

1.42 

4.19x10 -3 

121 

Golf ball (1.65 in diameter) 

0.5 

1.40x10 -3 

116 

Raindrop (0.16 in diameter) 

3.34X10 -4 

1.29x10 -5 

32 


Although we’ve talked mostly about spheres in this section, the discussions on fluid flow 
generally apply to any object moving through a fluid. Of course, the more complex the 
object’s geometry, the harder it is to analyze the drag forces on it. Other factors such as 
surface condition, and whether or not the object is at the interface between two fluids 
(such as a ship in the ocean) further complicate the analysis. In practice, scale model 
tests are particularly useful. In the Bibliography, we give several sources where you can 
find more practical drag data for objects other than spheres. 

Magnus Effect 

The Magnus effect (also known as the Robbins effect) is quite an interesting phenom¬ 
enon. You know from the previous section that an object moving through a fluid en¬ 
counters drag. What would happen if that object were now spinning as it moved through 
the fluid? For example, consider the sphere that we talked about earlier and assume that 
while moving through a fluid such as air or water, it spins about an axis passing through 
its center of mass. What happens when the sphere spins is the interesting part—it ac¬ 
tually generates lift! That’s right, lift. From everyday experience, most people usually 
associate lift with a wing-like shape such as an airplane wing or a hydrofoil. It is far less 
well known that cylinders and spheres can produce lift as well—that is, as long as they 
are spinning. We’ll use the moving sphere to explain what’s happening here. 

From the previous section on drag, you know that for a fast-moving sphere there will 
be some point on the sphere where the flow separates, creating a turbulent wake behind 
the sphere. Recall that the pressure acting on the sphere within this turbulent wake is 


132 | Chapter 6: Projectiles 


www.it-ebooks.info 






lower than the pressure acting on the leading surface of the sphere, and this pressure 
differential gives rise to the pressure drag component. When the sphere is spinning— 
say, clockwise—about a horizontal axis passing through its center, as shown in 
Figure 6-12, the fluid passing over the top of the sphere will be sped up while the fluid 
passing under the sphere will be retarded. 



Remember, because of friction, there is a thin boundary layer of fluid that attaches to 
the sphere’s surface. At the sphere’s surface, the velocity of the fluid in the boundary 
layer is 0 relative to the sphere. The velocity increases within the boundary layer as you 
move further away from the sphere’s surface. In the case of the spinning sphere, there 
is now a difference in fluid pressure above and below the sphere due to the increase in 
velocity above the sphere and the decrease in velocity below the sphere. Further, the 
separation point on the top side of the sphere will be pushed further back along the 
sphere. The end result is an asymmetric flow pattern around the sphere with a net lift 
force (due to the pressure differential) perpendicular to the direction of flow. If the 
surface of the sphere is roughened a little, not only will frictional drag increase, but this 
lift effect will increase as well. 

Don’t let the term lift confuse you into thinking that this force always acts to lift, or 
elevate, the sphere. The effect of this lift force on the sphere’s trajectory is very much 
tied to the axis of rotation about which the sphere is spinning as related to the direction 
in which the sphere is traveling (that is, its angular velocity). 

The magnitude of the Magnus force is proportional to the speed of travel, rate of spin, 
density of fluid, size of the object, and nature of the fluid flow. This force is not easy to 
calculate analytically, and as with many problems in fluid dynamics, you must rely on 
experimental data to accurately estimate it for a specific object under specific conditions. 
There are, however, some analytical techniques that will allow you to approximate the 
Magnus force. Without going into the theoretical details, you can apply the Kutta- 


Magnus Effect | 133 


www.it-ebooks.info 























Joukouski theroem to estimate the lift force on rotating objects such as cylinders and 
spheres. The Kutta-Joukouski theorem is based on a frictionless idealization of fluid 
flow involving the concept of circulation around the object (like a vortex around the 
object). You can find the details of this theory in any fluid dynamics text (we give some 
references in the Bibliography), so we won’t go into the details here. However, we will 
give you some results. 

For a spinning circular cylinder moving through a fluid, you can use this formula to 
estimate the Magnus lift force: 


Fl = 2 k p L v r 2 a) 

where v is the speed of travel, L is the length of the cylinder, r is its radius, and to is its 
angular velocity in radians per second (rad/s). If you have spin, n, in revolutions per 
second (rps), then to = 2 tt n. If you have spin, n, in revolutions per minute (rpm), then 
to = (2 tt n) / 60. 

For a spinning sphere moving through a fluid, you can use this formula: 

F L = (2 ;t p v r 4 w) / (2 r) 

where r is the radius of the sphere. Consistent units for these equations would yield lift 
force in pounds in the English system or newtons in the SI system. In the SI system, the 
appropriate units for these quantities are kg/m 3 , m/s, and m, respectively. 

Keep in mind that these formulas only approximate the Magnus force; they’ll get you 
in the ballpark, but they are not exact and actually could be off by up to 50% depending 
on the situation. These formulas assume that 1) there is no slip between the fluid and 
the rotating surface of the object, 2) there is no friction, 3) surface roughness is not taken 
into account, and 4) there is no boundary layer. 

At any rate, these equations will allow you to approximate the Magnus effect for flying 
objects in your games, where you’ll be able to model the relative differences between 
objects of different size that may be traveling at different speeds with different spin rates. 
You’ll get the look right. If numerical accuracy is what you’re looking for, then you’ll 
have to turn to experimental data for your specific problem. 

Similar to the drag data shown in the previous section, experimental lift data is generally 
presented in terms of lift coefficient. Using an equation similar to the drag equation, 
you can calculate the lift force with the following equation: 

F l = (0.5 p v 2 A) C L 

As usual, it’s not as simple as this equation makes it appear. The trick is in determining 
the lift coefficient, C L , which is a function of surface conditions, the Reynolds number, 


134 | Chapter 6: Projectiles 


www.it-ebooks.info 



velocity, and spin rate. Further, experiments show that the drag coefficient is also affected 
by spin. 

For example, consider a golf ball struck perfectly (right!) such that the ball spins about 
a horizontal axis perpendicular to its direction of travel while in flight. In this case the 
Magnus force will tend to lift the ball higher in the air, increasing its flight time and 
range. For a golf ball struck such that its initial velocity is 58 m/s with a take-off angle 
of 10 degrees, the increase in range due to Magnus lift is on the order of 59 meters; thus, 
it’s clear that this effect is significant. In fact, over the long history of the game of golf, 
people have attempted to maximize this effect. In the late 1800s, when golf balls were 
still made with smooth surfaces, players observed that used balls with roughened sur¬ 
faces flew even better than smooth balls. This observation prompted manufacturers to 
start making balls with rough surfaces so as to maximize the Magnus lift effect. The 
dimples that you see on modern golf balls are the result of many decades of experience 
and research and are thought to be optimum. 

Typically a golf ball takes off from the club with an initial velocity on the order of 76 m/ 
s, with a backspin on the order of 60 revolutions per second (rps). For these initial 
conditions, the corresponding Magnus lift coefficient is within the range of 0.1 to 0.35. 
Depending on the spin rate, this lift coefficient can be as high as 0.45, and the lift force 
acting on the ball can be as much as 50% of the ball’s weight. 

If the golf ball is struck with a less-than-perfect stroke (that’s more like it), the Magnus 
lift force may work against you. For example, if your swing is such that the ball leaves 
the club head spinning about an axis that is not horizontal, then the ball’s trajectory will 
curve, resulting in a slice or a draw. If you top the ball such that the upper surface of the 
ball is spinning away from you, then the ball will tend to curve downward much more 
rapidly, significantly reducing the range of your shot. 

As another example, consider a baseball pitched such that it’s spinning with topspin 
about a horizontal axis perpendicular to its direction of travel. Here the Magnus force 
will tend to cause the ball to curve in a downward direction, making it drop more rapidly 
than it otherwise would without spin. If the pitcher spins the ball such that the axis of 
rotation is not horizontal, then the ball will curve out of the vertical plane. Another trick 
that pitchers use is to give the ball backspin, making it appear (to the batter) to actually 
rise. This rising fastball does not actually rise, but because of the Magnus lift force it 
falls much less rapidly than it would without spin. 

For a typical pitched speed and spin rate of 45 m/s and 30 rps, respectively, the lift force 
can be up to 33% of the ball’s weight. For a typical curveball, the lift coefficient is within 
the range of 0.1 to 0.2, and for flyballs it can be up to 0.4. 

These are only two examples; however, you need not look far to find other examples of 
the Magnus force in action. Think about the behavior of cricket balls, soccer balls, tennis 
balls, or ping-pong balls when they spin in flight. Bullets fired from a gun with a rifling 


Magnus Effect | 135 


www.it-ebooks.info 



barrel also spin and are affected by this Magnus force. There have even been sailboats 
built with tall, vertical, rotating cylindrical “sails” that use the Magnus force for pro¬ 
pulsion. We’ve also seen technical articles describing a propeller with spinning cylin¬ 
drical blades instead of airfoil-type blades. 

To further illustrate the Magnus effect, we’ve prepared a simple example program that 
simulates a ball being thrown with varying amounts of backspin (or topspin). This 
example is based on the cannon example, so here again, the code should look familiar 
to you. In this example we’ve neglected drag, so the only forces that the ball will see are 
due to gravity and the Magnus effect. We did this to isolate the lift-generating effect of 
spin and to keep the equations of motion clearer. 

Since most of the code for this example is identical, or very similar, to the previous 
cannon examples, we won’t repeat it here. We will, however, show you the global vari¬ 
ables used in this simulation along with a revised DoSi.mutation function that takes care 
of the equations of motion: 


//.// 

// Global variables required for this simulation 

//.// 

TVector VI; // Initial velocity (given), m/s 

TVector V2; // Velocity vector at time t, m/s 

double m; // Projectile mass (given), kg 

TVector si; // Initial position (given), m 

TVector s2; // The projectile's position (displacement) vector, m 

double time; // The time from the instant the projectile 

// is launched, s 

double tine; // The time increment to use when stepping 

// through the simulation, s 

double g; // acceleration due to gravity (given), m/s A 2 

double spin; // spin in rpm (given) 

double omega; // spin in radians per second 

double radius; // radius of projectile (given), m 

#define PI 3.14159f 

#define RHO 1.225f // kg/m A 3 

//.// 

int DoSimulation(void) 

//.....// 

{ 

double C = PI * PI * RHO * radius * radius * radius * omega; 
double t; 


// step to the next time in the simulation 
time+=tlnc; 
t = time; 

// Calc. V2: 

V2.i = 1.0f/(1.0f-(t/m)*(t/m)*C*C) * (VI.i + C * VI.j * (t/m) - 


136 | Chapter 6: Projectiles 


www.it-ebooks.info 







C * g * (t*t)/m); 

V2.j = VI.j + (t/m)*C*V2.i - g*t; 

// Calc. S2: 

s2.1 = sl.i + VI.i * t + (1.0f/2.0f) * (C/n * V2.j) * (t*t); 

s2.j = sl.j + VI.j * t + (1.0f/2.0f) * ( ((C*V2. i) - m*g)/m ) * (t*t); 


// Check for collision with ground (x-z plane) 
if(s2. j <= 0) 
return 2; 

// Cut off the simulation if it's taking too long 

// This is so the program does not get stuck in the while loop 

if(time>60) 

return 3; 

return 0; 

} 

The heart of this simulation is the lines that calculate V2 and s2, the instantaneous 
velocity and position of the projectile, respectively. The equations of motion here come 
from the 2D kinetic equations of motion including gravity, as discussed in Chapter 4, 
combined with the following formula (shown earlier) for estimating the Magnus lift on 
a spinning sphere: 


F l = (2 n 2 p v r 4 a) / (2 r) 

You can see the effect of spin on the projectile’s trajectory by providing the sample 
program with different values for spin in revolutions per minute. The program converts 
this to radians per second and stores this value in the variable omega. A positive spin 
value indicates bottom spin such that the bottom of the sphere is spinning away from 
you, while a negative spin indicates topspin, where the top of the ball spins away from 
you. Bottom spin generates a positive lift force that will tend to extend the range of the 
projectile, while topspin generates negative lift that will force the projectile toward the 
ground, shortening its range. (Note that this example assumes that the spin axis is hor¬ 
izontal and perpendicular to the plane of the screen.) Figure 6-13 illustrates this be¬ 
havior. 


Magnus Effect | 137 


www.it-ebooks.info 




Figure 6-13. Magnus effect sample program 

Variable Mass 

In Chapter 1 we mentioned that some problems in dynamics involve variable mass. 
We’ll look at variable mass here since it applies to self-propelled projectiles such as 
rockets. When a rocket is producing thrust to accelerate, it loses mass (fuel) at some 
rate. When all of the fuel is consumed (burnout), the rocket no longer produces thrust 
and has reached its maximum speed. After burnout you can treat the trajectory of the 
rocket just as you would a non-self-propelled projectile, as discussed earlier. However, 
while the rocket is producing thrust, you need to consider its mass change since this 
will affect its motion. 

In cases where the mass change of the object under consideration is such that the mass 
being expelled or taken in has 0 absolute velocity—like a ship consuming fuel, for ex¬ 
ample—you can set up the equations of motion as you normally would, where the sum 
of the forces equals the rate of change in momentum. However, in this case mass will 
be a function of time, and your equations of motion will look like this: 

EF = m a = d/dt (m v) =m (dv/dt) + (dm/dt) v 

You can proceed to solve them just as you would normally, but keep in mind the time 
dependence of mass. 

A rocket, on the other hand, expels mass at some nonzero velocity, and you can’t use 
the preceding approach to properly account for its mass change. In this case, you need 
to consider the relative velocity between the expelled mass and the rocket itself. The 
linear equation of motion now looks like this: 

ZF = m dv/dt + dm/dt u 


138 | Chapter 6: Projectiles 


www.it-ebooks.info 

























where u is the relative velocity between the expelled mass and the object (the rocket in 
this case). 

For a rocket traveling straight up, neglecting air resistance and the pressure at the ex¬ 
haust nozzle, the only force acting on the rocket is due to gravity. But the rocket is 
expelling mass (burning fuel). How it expels this mass is not important here, since the 
forces involved are internal to the rocket; we need to consider only the external forces. 
Let the fuel burn rate be -m’. The equation of motion (in the vertical direction) for the 
rocket is as follows: 


XF = m dv/dt + dm/dt u 
-mg = m dv/dt - m’ u 

If you rearrange this so that it looks like there’s only an ma term on the right of this 
equation, you get: 


m’ u - mg = m dv/dt = ma 

Here you can see that the thrust that propels the rocket into the air is equal to m ’u. Since 
the fuel burn rate is constant, the mass of the rocket at any instant in time is equal to: 

m = m 0 - m’t 

where m D is the initial mass, and the burn rate, m\ is in the form mass per unit time. 


Variable Mass | 139 


www.it-ebooks.info 



www.it-ebooks.info 


PART II 


Rigid-Body Dynamics 


Part II focuses on rigid-body dynamics and development of both single- and multibody 
simulations. This part covers numerical integration, real-time simulation of particles 
and rigid bodies, and connected rigid bodies. Generally, this part covers what most game 
programmers consider elements of a physics engine. 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 7 


Real-Time Simulations 


This chapter is the first in a series of chapters designed to give you a thorough intro¬ 
duction to the subject of real-time simulation. We say introduction because the subject 
is too vast and complex to adequately treat in a few chapters; however, we say thor¬ 
ough because we’ll do more than touch on real-time simulations. In fact, we’ll walk you 
through the development of two simple simulations, one in two dimensions and the 
other in three dimensions. 

What we hope to do is give you enough of an understanding of this subject so that you 
can pursue it further with confidence. In other words, we want you to have a solid 
understanding of the fundamentals before jumping in to use someone else’s physics 
engine, or venturing out to write your own. 

In the context of this book, a real-time simulation is a process whereby you calculate 
the state of the object (or objects) you’re trying to represent on the fly. You don’t rely on 
prescripted motion sequences to animate your object, but instead you rely on your 
physics model, the equations of motion, and your differential equation solver to take 
care of the motion of your object as the simulation progresses. This sort of simulation 
can be used to model rigid bodies like the airplane in our FlightSim example, or flexible 
bodies such as cloth and human figures. Perhaps one of the most fundamental aspects 
of implementing a real-time rigid-body simulator is solving the equations of motion 
using numerical integration techniques. For this reason, we’ll spend this entire chapter 
explaining the numerical integration techniques that you’ll use later in the 2D and 3D 
simulators that we’ll develop. 

If you refer back for a moment to Chapter 4, where we outlined a generic procedure for 
solving kinetics problems, you’ll see that we’ve covered a lot of ground so far. The pre¬ 
ceding chapters have shown you how to estimate mass properties and develop the gov¬ 
erning equations of motion. This chapter will show you how to solve the equations of 
motion in order to determine acceleration, velocity, and displacement. We’ll follow this 


143 


www.it-ebooks.info 





chapter up with several showing you how to implement both 2D and 3D rigid-body 
simulations. 

Integrating the Equations of Motion 

By now you should have a thorough understanding of the dynamic equations of motion 
for particles and rigid bodies. If not, you may want to go back and review Chapter 1 
through Chapter 4 before reading this one. The next aspect of dealing with the equations 
of motion is actually solving them in your simulation. The equations of motion that 
we’ve been discussing can be classified as ordinary differential equations. In Chap¬ 
ter 2 and Chapter 4, you were able to solve these differential equations explicitly since 
you were dealing with simple functions for acceleration, velocity, and displacement. 
This won’t be the case for your simulations. As you’ll see in later chapters, force and 
moment calculations for your system can get pretty complicated and may even rely on 
tabulated empirical data, which will prevent you from writing simple mathematical 
functions that can be easily integrated. This means that you have to use numerical in¬ 
tegration techniques to approximately integrate the equations of motion. We say ap¬ 
proximately because solutions based on numerical integration won’t be exact and will 
have a certain amount of error depending on the chosen method. 

We’re going to start with a rather informal explanation of how we’ll apply numerical 
integration because it will be easier to grasp. Later we’ll get into some of the formal 
mathematics. Take a look at the differential equation of linear motion for a particle (or 
rigid body’s center of mass): 


F = m dv/dt 

Recall that this equation is a statement of force equals mass times acceleration, where F 
is force, m is mass, and dv/dt is the time derivative of velocity, which is acceleration. In 
the simple examples of the earlier chapters of this book, we rewrote this equation in the 
following form so it could be integrated explicitly: 

dv/dt = F/m 
dv = (F/m) dt 

One way to interpret this equation is that an infinitesimally small change in velocity, 
dv, is equal to (F/m) times an infinitesimally small change in time. In earlier examples, 
we integrated explicitly by taking the definite integral of the left side of this equation 
with respect to velocity and the right side with respect to time. In numerical integration 
you have to take finite steps in time, thus dt goes from being infinitely small to some 
discrete time increment, At, and you end up with a discrete change in velocity, Av: 

Av = (F/m) At 


144 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 



It is important to notice here that this does not give a formula for instantaneous velocity; 
instead, it gives you only an approximation of the change in velocity. Thus, to approx¬ 
imate the actual velocity of your particle (or rigid body), you have to know what its 
velocity was before the time change At. At the start of your simulation, at time 0, you 
have to know the starting velocity of your particle. This is an initial condition and is 
required in order to uniquely define your particle’s velocity as you step through time 
using this equation: 1 


Vt+At = v t + (F/m) At 


where the initial condition is: 


v t =o = v 0 

Here v t is velocity at some time t, v t+At is velocity at some time plus the time step, At is 
the time step, and v 0 is the initial velocity at time 0. 

You can integrate the linear equation of motion one more time in order to approximate 
your particles displacement (or position). Once you’ve determined the new velocity 
value, at time t+ At, you can approximate displacement using: 


S t+At — s t + At (v t+ At) 


where the initial condition on displacement is: 


S t =0 = So 

The integration technique discussed here is known as Euler’s method, and it is the most 
basic integration method. While Euler’s method is easy to grasp and fairly straightfor¬ 
ward to implement, it isn’t necessarily the most accurate method. 

You can reason that the smaller you make your time step—that is, as At approaches dt 
—the closer you’ll get to the exact solution. There are, however, computational problems 
associated with using very small time steps. Specifically, you’ll need a huge number of 
calculations at very small Af’s, and since your calculations won’t be exact (depending 
on numerical precision you’ll be rounding off and truncating numbers), you’ll end up 
with a buildup of round-off error. This means that there is a practical limit as to how 
small a time step you can take. Fortunately, there are several numerical integration 
techniques at your disposal that are designed to increase accuracy for reasonable step 
sizes. 


1. In mathematics, this sort of problem is termed an initial value problem. 


Integrating the Equations of Motion | 145 


www.it-ebooks.info 



Even though we used the linear equation of motion for a particle, this integration tech¬ 
nique (and the ones we’ll show you later) applies equally well to the angular equations 
of motion. 

Euler's Method 

The preceding explanation of Euler’s method was, as we said, informal. To treat Euler’s 
method in a more mathematically rigorous way, we’ll look at the Taylor series expansion 
of a general function, y{x ). Taylor’s theorem lets you approximate the value of a function 
at some point by knowing something about that function and its derivatives at some 
other point. This approximation is expressed as an infinite polynomial series of the 
form: 


y(x + Ax) = y(x) + (Ax) y'(x) + ((Ax) 2 / 2!) y"(x) + ((Ax) 3 / 3!) 

y'"(x) + ■ ■ ■ 

where y is some function of x, (x + Ax) is the new value of x at which you want to 
approximate y, y is the first derivative of y, y" is the second derivative of y, and so on. 

In the case of the equation of motion discussed in the preceding section, the function 
that you are trying to approximate is the velocity as a function of time. Thus, you can 
write v(f) instead ofy(x), which yields the Taylor expansion: 

v(t + At) = v(t) + (At) v'(t) + ((At) 2 / 2!) v"(t) + ((At) 3 / 3!) v"'(t) 

+ • • • 

Note here that v'(t) is equal to dv/dt, which equals F/m in the example equation of motion 
discussed in the preceding section. Note also that you know the value of v at time t. 
What you want to find is the value of v at time t + At knowing v at time t and its derivative 
at time t. As a first approximation, and since you don’t know anything about v’s second, 
third, or higher derivatives, you can truncate the polynomial series after the term (At) 
v'(t), which yields: 


v(t + At) = v(t) + (At) v'(t) 

This is the Euler integration formula that you saw in the last section. Since Euler’s for¬ 
mula goes out only to the term that includes the first derivative, the rest of the series 
that was left off is the truncation error. These terms that were left off are called higher- 
order terms, and getting rid of them results in a first-order approximation. The rationale 
behind this approximation is that the further you go in the series, the smaller the terms 
and the less influence they have on the approximation. Since At is presumed to be a 
small number, At 2 is even smaller, At 3 even smaller, and so on, and since these At terms 
appear in the numerators, each successively higher-order term gets smaller and smaller. 


146 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 



In this case, the first truncated term, ((At) 2 / 2!) v"(f), dominates the truncation error, 
and this method is said to have an error of order (At) 2 . 

Geometrically, Euler’s method approximates a new value, at the current step, for the 
function under consideration by extrapolating in the direction of the derivative of the 
function at the previous step. This is illustrated in Figure 7-1. 



Figure 7-1. Euler integration step 

Figure 7-1 illustrates the truncation error and shows that Eulers method will result in 
a polygonal approximation of the smooth function under consideration. Clearly, if you 
decrease the step size, you increase the number of polygonal segments and better ap¬ 
proximate the function. As we said before, though, this isn’t always efficient to do since 
the number of computations in your simulation will increase and round-off error will 
accumulate more rapidly. 

To illustrate Euler’s method in practice, let’s examine the linear equation of motion for 
the ship example of Chapter 4: 


T - (C v) = ma 

where T is the propeller’s thrust, C is a drag coefficient, v is the ship’s velocity, m its mass, 
and a its acceleration. 

Figure 7-2 shows the Euler integration solution, using a 0.5s time step, superimposed 
over the exact solution derived in Chapter 4 for the ship’s speed over time. 


Euler's Method | 147 


www.it-ebooks.info 











Zooming in on this graph allows you to see the error in the Euler approximation. This 
is shown in Figure 7-3. 



6.5 7 7.5 8 8.5 


Time 


Figure 7-3. Euler error 

Table 7-1 shows the numerical values of speed versus time for the range shown in 
Figure 7-3. Also shown in Table 7-1 is the percent difference, the error, between the 
exact solution and the Euler solution at each time step. 


148 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 























Table 7-1. Exact solution versus Euler solution 


1 Time(s) 

Velocity, exact (m/s) 

Velocity, Euler (m/s) 

Error 1 

6.5 

9.559084 

9.733158 

1.82% 

7 

10.06829 

10.2465 

1.77% 

7.5 

10.55267 

10.73418 

1.72% 

8 

11.01342 

11.19747 

1.67% 

8.5 

11.4517 

11.63759 

1.62% 


As you can see, the truncation error in this example isn’t too bad. It could be better, 
though, and we’ll show you some more accurate methods in a moment. Before that, 
however, you should notice that in this example Euler’s method is also stable—that is, 
it converges well with the exact solution as shown in Figure 7-4, where we’ve carried 
the time range out further. 



Here’s a code snippet that implements Euler’s method for this example: 


// Global Variables 


float 

float 

float 

float 

float 


// thrust 

// drag coefficient 
// velocity 
// mass 

// displacement 


// This function progresses the simulation by dt seconds using 


Euler's Method | 149 


www.it-ebooks.info 





















// Euler's basic method 
void StepSimuiation(float dt) 

{ 

float F; // total force 

float A; // acceleration 

float Vnew; // new velocity at time t + dt 

float Snew; // new position at time t + dt 

// Calculate the total force 
F = (T - (C * V)); 

// Calculate the acceleration 
A = F / M; 

// Caiculate the new velocity at time t + dt 
// where V is the velocity at time t 
Vnew = V + A * dt; 

// Calculate the new displacement at time t + dt 
// where S is the displacement at time t 
Snew = S + Vnew * dt; 

// Update old velocity and displacement with the new ones 
V = Vnew; 

S = Snew; 

} 

Although Euler’s method is stable in this example, that isn’t always so, depending on the 
problem you’re trying to solve. This is something that you must keep in mind when 
implementing any numerical integration scheme. What we mean by stable here is that, 
in this case, the Euler solution converges with the exact solution. An unstable solution 
could manifest errors in two ways. First, successive values could oscillate above and 
below the exact solution, never quite converging on it. Second, successive values could 
diverge from the exact solution, creating a greater and greater error over time. 

Take a look at Figure 7-5. This figure shows how Euler’s method can become very un¬ 
stable. What you see in the graph represents the vibratory motion of a spring-mass 
system. This is a simple dynamical system that should exhibit regular sinusoidal motion. 


150 | Chapter 7; Real-Time Simulations 


www.it-ebooks.info 




It’s clear from the figure that using Euler’s method yields terribly unstable results. You 
can see how the motion amplitude continues to grow. If this were a game, say, where 
you have a few objects connected by springs interacting with one another, then this sort 
of instability would manifest itself by wildly unrealistic motion of those objects. Worse 
yet, the simulation could blow up, numerically speaking. 

Often, your choice of step size affects stability where smaller step sizes tend to eliminate 
or minimize instability and larger steps aggravate the problem. If you’re working with 
a particularly unwieldy function, you might find that you have to decrease your step 
size substantially in order to achieve stability. This, however, increases the number of 
computations you need to make. One way around this difficulty is to employ what’s 
called an adaptive step size method, in which you change your step size on the fly de¬ 
pending on the magnitude of a predicted amount of truncation error from one step to 
the next. If the truncation error is too large, then you back up a step, decrease your step 
size, and try again. 

One way to implement this for Euler’s method is to first take a step of size At to obtain 
an estimate at time t + At, and then take two steps (starting from time t again) of size 
At/2 to obtain another estimate at time t + At. Since we’ve been talking velocity in the 


Euler's Method | 151 


www.it-ebooks.info 










































examples so far, let’s call the first estimate v 1 and the second estimate v 2 . 2 A measure of 
the truncation error is then: 


e t = Ivi - v 2 l 


If you wish to keep the truncation error within a specified limit, e to , then you can use 
the following formula to find out what your step size should be in order to maintain the 
desired accuracy: 


Atnew — Atold ( e to I e t) 

Here, Af old is the old time step and Af new is the new one that you should use to maintain 
the desired accuracy. You’ll have to make this check for each time step, and if you find 
that the error warrants a smaller time step, then you’ll have to back up a step and repeat 
it with the new time step. 

Here’s a revised StepSimulation function that implements this adaptive step size tech¬ 
nique, checking the truncation error on the velocity integration: 

// New global variable 

float eto; // truncation error tolerance 

// This function progresses the simulation by dt seconds using 
// Euler's basic method with an adaptive step size 
void StepSimulation(float dt) 

{ 


float 

F; 

// total force 


float 

A; 

// acceleration 


float 

Vnew; 

// new velocity at time 

t + dt 

float 

Snew; 

// new position at time 

t + dt 

float 

VI, M2: 

; // temporary velocity ' 

variables 

float 

dtnew; 

// new time step 


float 

et; 

// truncation error 



// Take one step of size dt to estimate the new velocity 
F = (T - (C * V)); 

A = F / M; 

VI = V + A * dt; 

// Take two steps of size dt/2 to estimate the new velocity 
F = (T - (C * V)); 

A = F / M; 

V2 = V + A * (dt/2); 

F = (T - (C * M2))-, 


2. Even though we’re talking about velocity and time here, these techniques apply to any function—for example, 
displacement versus time, etc. 


152 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 



A = F / M; 

V2 = V2 + A * (dt/2); 

// Estimate the truncation error 
et = absf(Vl - V2); 

// Estimate a new step size 
dtnew = dt * SQRT(eto/et); 


if (dtnew < dt) 

{ // take at step at the new smaller step size 
F = (T - (C * V)); 

A = F / M; 

Vnew = V + A * dtnew; 

Snew = S + Vnew * dtnew; 

} else 

{ // original step size is okay 
Vnew = VI; 

Snew = S + Vnew * dt; 

} 

// Update old velocity and displacement with the new ones 
V = Vnew; 

S = Snew; 

} 

Better Methods 

At this point, you might be wondering why you can’t simply use more terms in the Taylor 
series to reduce the truncation error of Euler’s method. In fact, this is the basis for several 
integration methods that offer greater accuracy than Euler’s basic method for a given 
step size. Part of the difficulty associated with picking up more terms in the Taylor’s 
series expansion is in being able to determine the second, third, fourth, and higher 
derivatives of the function you’re trying to integrate. The way around this problem is 
to perform additional Taylor series expansions to approximate the derivatives of the 
function under consideration and then substitute those values back into your original 
expansion. 

Taking this approach to include one more Taylor term beyond the basic Euler method 
yields a so-called improved Euler method that has a reduced truncation error on the 
order of (At ) 3 instead of (At) 2 . The formulas for this method are: 

kt = (At) y'(t, y) 
k 2 = (At) y'(t + At, y + k;) 
y(t + At) = y(t) + Yi (k! + k 2 ) 


Better Methods | 153 


www.it-ebooks.info 



Here y is a function of t, and y is the derivative as a function of t and possibly of y 
depending on the equations you’re trying to solve, and At the step size. 

To make this clearer for you, we’ll show these formulas in terms of the ship example 
equation of motion of Chapter 4, the same example that we discussed in the previous 
section. In this case, velocity is approximated by the following formulas: 

k! = At [1/m (T - C v t )] 

k 2 = AUl/mCT-CCvt + k!))] 
v t +At = V t + V4(ki + k 2 ) 

where v t is the velocity at time t, and v t+At is the new velocity at time t+At. 

Here is the revised StepSimulation function showing how to implement this method 
in code: 

// This function progresses the simulation by dt seconds using 
// the "improved" Euler method 
void StepSimulation(float dt) 

{ 

float F; // total force 

float A; // acceleration 

float Vnew; // new velocity at time t + dt 

float Snew; // new position at time t + dt 

float kl, k2; 


F = (T - (C * V)); 

A = F/M; 
kl = dt * A; 

F = (T - (C * (V + kl))); 

A = F/M; 
k2 = dt * A; 

// Calculate the new velocity at time t + dt 
// where V is the velocity at time t 
Vnew = V + (kl + k2) / 2; 

// Calculate the new displacement at time t + dt 
// where S is the displacement at time t 
Snew = S + Vnew * dt; 

// Update old velocity and displacement with the new ones 
V = Vnew; 

S = Snew; 

} 


154 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 



We can carry out this procedure of taking on more Taylor terms even further. The 
popular Runge-Kutta method takes such an approach to reduce the truncation error to 
the order of (At) 5 . The integration formulas for this method are as follows: 


kt = (At) y'(t, y) 
k 2 = (At) y'(t + At/2, y + k x /2) 
k 3 = (At) y'(t + At/2, y + k 2 /2) 
k 4 = (At) y'(t + At, y + k 3 ) 
y(t + At) = y(t) + 1/6 (k 3 + 2 (k 2 ) + 2 (k 3 ) + k 4 ) 

Applying these formulas to our ship example yields: 

k, = At [1/m (T - C v t )] 
k 2 = At [1/m (T - C (v t + k 3 /2))] 
k 3 = At [1/m (T - C (v t + k 2 /2))] 
k 4 = At[l/m(T-C(v t + k 3 ))] 

V t+At — v t + 1/6 (kj + 2 (k 2 ) + 2 (k 3 ) + IC 4 ) 

For our example, the Runge-Kutta method is implemented as follows: 

// This function progresses the simulation by dt seconds using 
// the Runge-Kutta method 
void StepSimulation(float dt) 

{ 

float F; // total force 

float A; // acceleration 

float Vnew; // new velocity at time t + dt 

float Snew; // new position at time t + dt 

float kl, k2, k3, k4; 


F = (T - (C * V)); 

A = F/M; 
kl = dt * A; 

F = (T - (C * (V + kl/2))); 
A = F/M; 
k2 = dt * A; 

F = (T - (C * (V + k2/2))); 
A = F/M; 
k3 = dt * A; 

F = (T - (C * (V + k3))); 

A = F/M; 
k4 = dt * A; 


Better Methods | 


155 


www.it-ebooks.info 



// Calculate the new velocity at tine t + dt 
// where V is the velocity at tine t 
Vnew = V + (kl + 2*k2 + 2*k3 + k4) / 6; 

// Calculate the new displacenent at tine t + dt 
// where S is the displacenent at tine t 
Snew = S + Vnew * dt; 

// Update old velocity and displacenent with the new ones 
V = Vnew; 

S = Snew; 

} 

To show you how accuracy is improved over the basic Euler method, we’ve superim¬ 
posed integration results for the ship example using these two methods over those 
shown in Figure 7-2 and Figure 7-3. Figure 7-6 and Figure 7-7 show the results, where 
Figure 7-7 is a zoomed view of 7-6. 



156 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 




















11.5 

11 

I 10.5 

£ 

10 

9.5 

6.5 7 7.5 8 8.5 

Time 


Figure 7-7. A closer look 

As you can see from these figures, it’s impossible to discern the curves for the improved 
Euler and Runge-Kutta methods from the exact solution because they fall almost right 
on top of each other. These results clearly show the improvement in accuracy over the 
basic Euler method, whose curve is distinct from the other three. Over the interval from 
6.5 to 8.5 seconds, the average truncation error is 1.72%, 0.03%, and 3.6xl0 _6 % for 
Euler’s method, the improved Euler method, the Runge-Kutta method, respectively. It 
is obvious, based on these results, that for this problem, the Runge-Kutta method yields 
substantially better results for a given step size than the other two methods. Of course, 
you pay for this accuracy, since you have several more computations per step in the 
Runge-Kutta method. 

Both of these methods are generally more stable than Euler’s method, which is a huge 
benefit in real-time applications. Recall our discussion earlier about the stability of Eu¬ 
ler’s method. Figure 7-5 showed the results of applying Euler’s method to an oscillating 
dynamical system. There, the motion results that should be sinusoidal were wildly er¬ 
ratic (i.e., unstable). Applying the improved Euler method, or the Runge-Kutta method, 
to the same problem yields stable results, as shown in Figure 7-8. 



Exact 

Euler 

Improved 

R-K 


Better Methods | 157 


www.it-ebooks.info 















Figure 7-8. Stable results using the improved Euler or the Runge-Kutta methods 


Here the oscillatory motion is clearly sinusoidal, as it should be. The results for this 
particular problem are almost identical whether you use the improved Euler method or 
the Runge-Kutta method. Since for this problem the results of both methods are virtually 
the same, you can save computational time and memory using the improved Euler 
method versus the Runge-Kutta method. This can be a significant advantage for real¬ 
time games. Remember the Runge-Kutta method requires four derivative computations 
per time step. 

These methods aren’t the only ones at your disposal, but they are the most common. 
The Runge-Kutta method is particularly popular as a general-purpose numerical inte¬ 
gration scheme. Other methods attempt to improve computational efficiency even fur¬ 
ther—that is, they are designed to minimize truncation error while still allowing you to 
take relatively large step sizes so as to reduce the number of steps you have to take in 
your integration. Still other methods are especially tailored for specific problem types. 
We cite some pretty good references for further reading on this subject in the Bibliog¬ 
raphy. 


158 | Chapter 7: Real-Time Simulations 


www.it-ebooks.info 










































































Summary 

At this point you should be comfortable with the terms that appear in the equations of 
motion and be able to calculate terms like the sum of forces and moments, mass, and 
inertia. You should also have a solid understanding of basic numerical integration tech¬ 
niques. Implementing these techniques in code is really straightforward since they are 
composed of simple polynomial functions. The hard part is developing the derivative 
function for your problem. In the case of the equations of motion, the derivative function 
will include all your force and moment calculations for the particle or rigid body that 
you are modeling. You’ll see some more numerical integration code when you get to 
Chapter 8, Chapter 9, and Chapter 11. 


Summary | 159 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 8 


Particles 


In this chapter we’ll show you how to apply what you’ve learned in Chapter 7 in a simple 
particle simulator. Before getting to the specifics of the example we’ll present, let’s con¬ 
sider particles in general. Particles are simple idealizations that can be used to simulate 
all sorts of phenomena or special effects within a game. For example, particle simulations 
are often used to simulate smoke, fire, and explosions. They can also be used to simulate 
water, dust clouds, and swarms of insects, among many other things. Really, your imag¬ 
ination is the only limit. Particles lend themselves to simulating both discrete objects 
like bouncing balls and continua like water. Plus, you can easily ascribe an array of 
attributes to particles depending on what you’re modeling. 

For example, say, you’re modeling fire using particles. Each particle will rise in the air, 
and as it cools its color will change until it fades away. You can tie the particle’s color to 
its temperature, which is modeled using thermodynamics. The attribute you’d want to 
track is the particle’s temperature. In a previous work, AI for Game Programmers 
(O’Reilly), this book’s coauthor David M. Bourg used particles to represent swarms of 
insects that would swarm, flock, chase, and evade depending on the artificial intelligence 
(AI). The AI controlled their behavior, which was then implemented as a system of 
particles using principles very similar to what you’ll see in this chapter. 

Particles are not limited to collections of independent objects either. Later in this book, 
you’ll learn how to connect particles together using springs to create deformable objects 
such as cloth. Particles are extremely versatile, and you’ll do well to learn how to leverage 
their simplicity. 

You can use particles to model sand in a simple phone application that simulates an 
hourglass. Couple this sand model with the accelerometer techniques you’ll learn about 
in Chapter 21, and you’ll be able to make the sand flow by turning the phone over. 

You can easily use particles to simulate bullets flying out of a gun. Imagine a Gatling 
gun spewing forth a hail of lead, all simulated using simple particles. Speaking of spew- 


161 


www.it-ebooks.info 




ing, how about using particles to simulate debris flung from an erupting volcano as a 
special effect in your adventure game set in prehistoric times? Remember the Wooly 
Willy toy? To make particles a direct part of game play, consider a diversionary appli¬ 
cation where you drag piles of virtual magnetic particles around a portrait photograph, 
giving someone a lovely beard or mustache much like Wooly Willy. 

Hopefully, you’re now thinking of creative ways to use particles in your games. So, let’s 
address implementation. There are two basic ingredients to implementing a particle 
simulator: the particle model and the integrator. (Well, you could argue that a third basic 
ingredient is the renderer, where you actually draw the particles, but that’s more graphics 
than physics, and we’re focusing on modeling and integrating in this book.) 

The model very simply describes the attributes of the particles in the simulation along 
with their rules of behavior. We mean this in the physics sense and not the AI sense in 
this book, although in general the model you implement may very well include suitable 
AI rules. Now, the integrator is responsible for updating the state of the particles 
throughout the simulation. In this chapter, the particles’ states will be described by their 
position and velocity at any given time. The integrator will update each particle’s state 
under the influence of several external stimuli—forces such as gravity, aerodynamic 
drag, and collisions. 

The rest of this chapter will walk you through the details of a simple particle simulation 
in an incremental manner. The first task willbe to simulate a set of particles falling under 
the influence of gravity alone. Even though this sounds elementary, such an example 
encompasses all of the basic ingredients mentioned earlier. Once gravity is under con¬ 
trol, we’ll show you how to implement still air drag and wind forces to influence the 
particles’ motion. Then, we’ll make things more interesting by showing you how to 
implement collision response between the particles and a ground plane plus random 
obstacles. This collision stuff will draw on material presented in Chapter 5, so be sure 
to read that chapter first if you have not already done so. 

Figure 8-1 through Figure 8-4 show a few frames of this example simulation complete 
with obstacles and collisions. Use your imagination here to visualize the particles falling 
under the influence of gravity until they impact the circular objects, at which time they 
bounce around and ultimately settle on the ground. 


162 | Chapter 8: Particles 


www.it-ebooks.info 




Figure 8-1. Particles falling under the influence of gravity 


Particles | 163 


www.it-ebooks.info 







164 | Chapter 8: Particles 


www.it-ebooks.info 







Figure 8-3. More collisions 


Particles | 165 


www.it-ebooks.info 







Figure 8-4. Particles coming to rest on the ground plane 


While working through this chapter, keep in mind that everything you’re learning here 
will be directly applicable to 2D and 3D simulations. Chapters following this one will 
build on the material covered here. We’ll focus on two dimensions in this chapter and 
later in the book we’ll show you how to extend the simulation to 3D. Actually, for particle 
simulations it’s almost trivial to make the leap from 2D to 3D. Trust us on this for now. 

Simple Particle Model 

The particle model we’ll begin with is very simple. All we want to achieve at first is to 
have the particles fall under the influence of gravity. The particles will be initialized with 
an altitude above a ground plane. Upon the start of the simulation, gravity will act on 
each particle, continuously causing each to accelerate toward the ground plane, gaining 
speed as it goes. Imagine holding a handful of small rocks up high and then releasing 
them. Simple, huh? 


166 | Chapter 8: Particles 


www.it-ebooks.info 












There are several particle attributes we must consider even for this simple example. Our 
model assumes that each particle has mass, and a set diameter (we’re assuming our 
particles are circles in 2D or spheres in 3D), occupies some position in space, and is 
traveling at some velocity. Additionally, each particle is acted upon by some net external 
force, which is the aggregate of all forces acting on the particle. These forces will be 
gravity alone to start with, but will eventually include drag and impact forces. We set 
up a Particle class to encapsulate these attributes as follows: 

class Particle { 


public: 

float 

fMass; 

// Total mass 

Vector 

vPosltlon; 

// Position 

Vector 

vVeloclty; 

// Velocity 

float 

fSpeed; 

// Speed (magnitude of the velocity) 

Vector 

vForces; 

// Total force acting on the particle 

float 

fRadlus; 

// Particle radius used for collision detection 

Vector 

vGravlty; 

// Gravity force vector 

Particle(void); 

// Constructor 

void 

CalcLoads(vold); // Aggregates forces acting on the particle 

void 

UpdateBodyEuler(double dt); // Integrates one time step 

void 

Draw(vold); 

// Draws the particle 


}; 

Most of these attributes are self-explanatory given the comments we’ve included. Notice 
that several of these attributes are Vecto r types. These vectors are defined in the custom 
math library we’ve included in Appendix A. This type makes managing vectors and 
performing arithmetic operations with them a breeze. Take a look at Appendix A to see 
what this custom type does. We’ll just remind you of the data structure Vector uses: 
three scalars called x, y, and z representing the three dimensions of a location or of a 
movement in some direction. The z component will always be set to 0 in this chapter’s 
examples. 

You should have noticed the f Speed property in the Particle class. This property stores 
the magnitude of the velocity vector, the particle’s speed. We’ll use this later when com¬ 
puting aerodynamic drag forces. We’ve also included a Vector type property called 
vG r a vi ty, which stores the gravity force vector defining the magnitude and the direction 
in which the gravity force acts. This is not really necessary, as you could hardcode the 
gravity force vector or use a global variable; however, we’ve included it here to illustrate 
some creative flexibility. For example, you could redefine the gravity vector in a game 
that uses accelerometer input to determine gravity’s direction with respect to a particular 
device’s orientation (see Chapter 21). And you may have a game where some particles 
react to different gravities depending on their type, which can be of your own concoc¬ 
tion. 


Simple Particle Model | 167 


www.it-ebooks.info 



Aside from properties, you’ll notice several methods in the Particle class. The con¬ 
structor is trivial. It sets everything to 0 except the particles mass, radius, and the gravity 
force vector. The following code illustrates how everything is initialized: 

Particle::Partlcle(vold) 

{ 

fMass = 1.0; 
vPosltion.x = 0.0; 
vPosltion.y = 0.0; 
vPositlon.z = 0.0; 
vVelocity.x = 0.0; 
vVelocity.y = 0.0; 
vVelocity.z = 0.0; 
fSpeed = 0.0; 
vForces.x = 0.0; 
vForces.y = 0.0; 
vForces.z = 0.0; 
fRadius = 0.1; 
vGravlty.x = 0; 

vGravtty.y = fMass * _GRAVITYACCELERATION; 

} 

Now is probably a good time to explain the coordinate system we’ve assumed. Our world 
origin is located at the lower-left corner of the example program’s window with positive 
x pointing to the right and positive y pointing up. The acceleration due to gravity acts 
downward (i.e., in the negative y-direction). We’re using the SI system of units and have 
defined the acceleration due to gravity as follows: 

#deflne _GRAVITYACCELERATION -9.8f 

That’s 9.8 m/s 2 in the negative y-direction. We’ve set the mass of each particle to 1 kg by 
default, which means the force due to gravity is 1 kg times 9.8 m/s 2 , or 9.8 newtons of 
force. We’ve set the radius of each particle to one-tenth of a meter. These masses and 
radii are really arbitrary; you can set them to anything suitable for what you’re modeling. 

The CalcLoads method is responsible for computing all the loads—forces—acting on 
the particle, with the exception of impact forces (we’ll handle those later). For now, the 
only force acting on the particles is that due to gravity, or simply, the weight of each 
particle. CalcLoads is very simple at this point: 

void Particle::CalcLoads(void) 

{ 

// Reset forces: 
vForces.x = 0.0f; 
vForces.y = 0.0f; 

// Aggregate forces: 
vForces += vGravlty; 

} 


168 | Chapter 8: Partides 


www.it-ebooks.info 




The first order of business is to reset the vForces vector. vForces is the vector containing 
the net force acting on the particle. All of these forces are aggregated in CalcLoads, as 
shown by the line vForces += vGravity. Again, so far, the only force to aggregate is 
that due to gravity. 

Integrator 

The UpdateBodyEuler method integrates the equations of motion for each particle. 
Since we’re dealing with particles, the only equation of motion we need concern our¬ 
selves with is that for translation; rotation does not matter for particles (at least not for 
us here). The following code sample shows UpdateBodyEuler. 

void Particle::UpdateBodyEuler(double dt) 

{ 

Vector a; 

Vector dv; 

Vector ds; 

// Integrate equation of motion: 
a = vForces / fMass; 

dv = a * dt; 
vVeloctty += dv; 

ds = vVeloctty * dt; 
vPosltlon += ds; 

// Mtsc. calculations: 
fSpeed = vVeloctty .MagnttudeQ; 

} 

As the name of this method implies, we’ve implemented Euler’s method of integration 
as described in Chapter 7. Using this method, we simply need to divide the aggregate 
forces acting on a particle by the mass of the particle to get the particle’s acceleration. 
The line of code a = vForces / fMass does just this. Notice here that a is a Vector, as 
is vForces. fMass is a scalar, and the / operator defined in the Vector class takes care 
of dividing each component of the vForces vector by fMass and setting the corre¬ 
sponding components in a. The change in velocity, dv, is equal to acceleration times the 
change in time, dt. The particle’s new velocity is then computed by the line vVeloctty 
+= dv. Here again, vVeloctty and dv are Vectors and the += operator takes care of the 
vector arithmetic. This is the first actual integration. 

The second integration takes place in the next few lines, where we determine the par¬ 
ticle’s displacement and new position by integrating its velocity. The line ds = vVeloc 
ity * dt determines the displacement, or change in the particle’s position, and the line 
vPosltlon += ds computes the new position by adding the displacement to the parti¬ 
cle’s old position. 


Simple Partide Model | 169 


www.it-ebooks.info 



The last line in UpdateBody Euler computes the particle’s speed by taking the magnitude 
of its velocity vector. 

For demonstration purposes, using Euler’s method is just fine. In an actual game, the 
more robust method described in Chapter 7 is advised. 

Rendering 

In this example, rendering the particles is rather trivial. All we do is draw little circles 
using Windows API calls wrapped in our own functions to hide some of the Windows- 
specific code. The following code snippet is all we need to render the particles. 

void Particle::Draw(void) 

{ 

RECT r; 

float drawRadius = max(2, fRadius); 

SetRect(&r, vPosition.x - drawRadius, 

_WINHEIGHT - (vPosition.y - drawRadius), 
vPosition.x + drawRadius, 

_WINHEIGHT - (vPosition.y + drawRadius)); 

DrawEllipse(&r, 2, RGB(0,0,0)); 

} 

You can use your own rendering code here, of course, and all you really need to pay 
close attention to is converting from world coordinates to window coordinates. Re¬ 
member, we’ve assumed our world coordinate system origin is in the lower-left corner 
of the window, whereas the window drawing coordinate system has its origin in the 
upper-left corner of the window. To transform coordinates in this example, all you need 
to do is subtract the particle’s y-position from the height of the window. 

The Basic Simulator 

The heart of this simulation is handled by the Particle class described earlier. However, 
we need to show you how that class is used in the context of the main program. 

First, we define a few global variables as follows: 

// Global Variables: 
int FrameCounter = 0; 

Particle Units[_MAX_NUM_UNITS]; 

FrameCounter counts the number of time steps integrated before the graphics display 
is updated. How many time steps you allow the simulation to integrate before updating 
the display is a matter of tuning. You’ll see how this is used momentarily when we discuss 
the UpdateSimulation function. Units is an array of Particle types. These will rep¬ 
resent moving particles in the simulation—the ones that fall from above and bounce off 
the circular objects we’ll add later. 


170 | Chapter 8: Particles 


www.it-ebooks.info 



For the most part, each unit is initialized in accordance with the Particle constructor 
shown earlier. However, their positions are all at the origin, so we make a call to the 
following Initialize function to randomly distribute the particles in the upper-middle 
portion of the screen within a rectangle of width _SPAWN_AREA_R*4 and a height of 
_SPAWN_AREA_R, where _SPAWN_AREA_R is just a global define we made up. 

boot Initialize(void) 

{ 

int i; 

GetRandomNumber(0, _WINWIDTH, true); 

for(i=0; i<_MAX_N UM_U NIT S; 1++) 

{ 

Unitsfi].vPosition.x = GetRandomNumber(_WINWIDTH/2-_SPAWN_AREA_R*2, 
_WINWIDTH/2+_SPAWN_AREA_R*2, false); 

Unitsfi].vPosition.y = _WINHEIGHT - 

GetRandomNumber(_WINHEIGHT/2-_SPAWN_AREA_R, 
_WINHEIGHT/2, false); 

} 

return true; 

} 

OK, now let’s consider UpdateSimulation as shown in the code snippet that follows. 
This function gets called every cycle through the programs main message loop and is 
responsible for cycling through all the Units, making appropriate function calls to up¬ 
date their positions, and rendering the scene. 

void UpdateSimulation(void) 

{ 

double dt = _TIMESTEP; 
int i; 

// initialize the back buffer 
if(FrameCounter >= _RENDER_FRAME_COUNT) 

{ 

ClearBackBuffer(); 

} 

// update the particles (Units) 
for(i=0; i<_MAX_NUM_UNITS; U+) 

{ 

Unitsfi] .CalcLoadsQ; 

Unitsfi].UpdateBodyEuler(dt); 

if(FrameCounter >= _RENDER_FRAME_COUNT) 

{ 

Units[i].Draw(); 

} 


The Basic Simulator | 171 


www.it-ebooks.info 



lf(Units[i].vPosition.x > _WINWIDTH) Unitsft].vPosition.x = 0; 
lf(Units[i].vPosition.x < 0) Unlts[l].vPosition.x = _WINWIDTH; 
if(Units[i].vPosition.y > _WINHEIGHT) Units[i].vPosition.y = 0; 
if(Units[i].vPosition.y < 0) Units[i].vPosition.y = _WINHEIGHT; 

} 

// Render the scene if required 
if(FrameCounter >= _RENDER_FRAME_COUNT) { 

CopyBackBufferToWindow(); 

FraneCounter = 0; 

} eise 

FrameCounter++; 

} 

The two local variables in UpdateSimulation are dt and i. i is trivial and serves as a 
counter variable, dt represents the small yet finite amount of time, in seconds, over 
which each integration step is taken. The global def ine_TIMESTEP stores the time step, 
which we have set to 0.1 seconds. This value is subject to tuning, which we’ll discuss 
toward the end of this chapter in the section “Tuning” on page 186. 

The next segment of code checks the value of the frame counter, and if the frame counter 
has reached the defined number of frames, stored in _RENDER_FRAME_COUNT, then the 
back buffer is cleared to prepare it for drawing upon and ultimately copying to the 
screen. 

The next section of code under the comment update the particles does just that by 
calling the CalcLoads and UpdateBodyEuler methods of each Unit. These two lines are 
responsible for updating all the forces acting on each particle and then integrating the 
equation of motion for each particle. 

The next few lines within the for loop draw each particle if required and wrap each 
particles position around the window extents should they progress beyond the edges 
of the window. Note that we’re using window coordinates in this example. 

Implementing External Forces 

We’ll add a couple of simple external forces to start with—still air drag, and wind force. 
We’ll use the formulas presented in Chapter 3 to approximate these forces, treating them 
in a similar manner. Recall that still air drag is the aerodynamic drag force acting against 
an object moving at some speed through still air. Drag always acts to resist motion. 
While we’ll use the same formulas to compute a wind force, recall that wind force may 
not necessarily act to impede motion. You could have a tailwind pushing an object along, 
or the wind could come from any direction with components that push the object side¬ 
ways. In this example we’ll assume a side wind from left to right, acting to push the 
particles sideways, with the still air drag resisting their falling motion. When we add 
collisions later, this same drag formulation will act to resist particle motion in any di¬ 
rection in which they travel as they bounce around. 


172 | Chapter 8: Particles 


www.it-ebooks.info 



The formula we’ll use to model still air drag is: 

F d = >/ 2 pV 2 AC d 

Here F d is the magnitude of the drag force. Its direction is directly opposite the velocity 
of the moving particle, p is the density of air through which the particle moves, V is the 
magnitude of the particles velocity (its speed), A is the projected area of the particle as 
though it’s a sphere, and C d is a drag coefficient. 

We can use this same formula to estimate the wind force pushing the particle sideways. 
The only difference this time is that V is the wind speed, and the direction of the resulting 
wind force is from our assumed left-to-right direction. 

To add these two forces to our simulation, we need to make a few additions to the 
Particle class’s CalcLoads method. The following code shows how CalcLoads looks 
now. Remember, all we had in here originally were the first three lines of executable 
code shown next—the code that initializes the aggregate force vector and then the line 
of code that adds the force due to gravity to the aggregate force. All the rest of the code 
in this method is new. 

void Particle::CalcLoads(void) 

{ 

// Reset forces: 
vForces.x = 0.0f; 
vForces.y = 0.0f; 

// Aggregate forces: 

// Gravity 
vForces += vGravity; 

// Still air drag 
Vector vDrag; 

Float fDrag; 

vDrag-=vVelocity; 
vDrag. NorpializeQ; 

fDrag = 0.5 * _AIRDENSITY * fSpeed * fSpeed * 

(3.14159 * fRadius * fRadius) * _DRAGCOEFFICIENT; 

vDrag*=fDrag; 

vForces += vDrag; 

// Wind 

Vector vWind; 

vWind.x = 0.5 * _AIRDENSITY * _WINDSPEED * 

_WINDSPEED * (3.14159 * fRadius * fRadius) * 

_DRAGCOEFFICIENT; 


Implementing External Forces | 173 


www.it-ebooks.info 



vForces += vklind; 


} 

So after the force due to gravity is added to the aggregate, two new local variables are 
declared. vDrag is a vector that will represent the still air drag force. fDrag is the mag¬ 
nitude of that drag force. Since we know the drag force vector is exactly opposite to the 
particle’s velocity vector, we can equate vDrag to negative vVelocity and then normalize 
vDrag to obtain a unit vector pointing in a direction opposite of the particles velocity. 
Next we compute the magnitude of the drag force using the formula shown earlier. This 
line handles that: 

fDrag = 0.5 * _AIRDENSITY * fSpeed * fSpeed * 

(3.14159 * fRadius * fRadius) * _DRAGCOEFFICIENT; 

Here, _AIRDENSITY is a global define representing the density of air, which we have set 
to 1.23 kg/m 3 (standard air at 15°C). fSpeed is the particle’s speed: the magnitude of its 
velocity. The 3.14159 * fRadius * fRadius line represents the projected area of the 
particle assuming the particle is a sphere. And finally, _DRAGCOEFFICIENT is a drag co¬ 
efficient that we have set to 0.6. We picked this value from the chart of drag coefficient 
for a smooth sphere versus the Reynolds number shown in Chapter 6. We simply eye- 
balled a value in the Reynolds number range from le4 to le5. You have a choice here 
of tuning the drag coefficient value to achieve some desired effect, or you can create a 
curve fit or lookup table to select a drag coefficient corresponding to the Reynolds 
number of the moving particle. 

Now that we have the magnitude of the drag force, we simply multiply that force by the 
unit drag vector to obtain the final drag force vector. This vector then gets aggregated 
in vForces. 

We handle the wind force in a similar manner with a few differences in the details. First, 
since we know the unit wind force vector is in the positive x-direction (i.e., it acts from 
left to right), we can simply set the x component of the wind force vector, vWind, to the 
magnitude of the wind force. We compute that wind force using the same formula we 
used for still air drag with the exception of using the wind speed instead of the particle’s 
speed. We used _WINDSPEED, a global define, to represent the wind speed, which we 
have set to 10 m/s (about 20 knots). 

Finally, the wind force is aggregated in vForces. 

At this stage the particles will fall under the influence of gravity, but not as fast as they 
would have without the drag force. And now they’ll also drift to the right due to the 
wind force. 


174 | Chapter 8: Partides 


www.it-ebooks.info 



Implementing Collisions 

Adding external forces made the simulation a little more interesting. However, to really 
make it pop, we’re going to add collisions. Specifically, we’ll handle particle-to-ground 
collisions and particle-to-object collisions. If you have not yet read Chapter 5, which 
covers collisions, you should because we’ll implement principles covered in that chapter 
here in the example. We’ll implement enough collision handling in this example to allow 
particles to bounce off the ground and circular objects, and we’ll come back to collision 
handling in more detail in Chapter 10. The material in this chapter should whet your 
appetite. We’ll start with the easier case of particle-to-ground collisions. 

Partide-to-Ground Collisions 

Essentially what we’re aiming to achieve with particle-to-ground collision detection is 
to prevent the particles from passing through a ground plane specified at some y coor¬ 
dinate. Imagine a horizontal impenetrable surface that the particles cannot pass 
through. There are several things we must do in order to detect whether a particle is 
indeed colliding with the ground plane. If so, then we need to handle the collision, 
making the particles respond in a suitable manner. 

The left side of Figure 8-5 illustrates a collision scenario. It’s easy to determine whether 
or not a collision has taken place. Over a given simulation time step, a particle may have 
moved from some previous position (its position at the previous time step) to its current 
position. If this current position puts the centroid coordinate of the particle within one 
particle radius of the ground plane, then a collision might be occurring. We say might 
because the other criteria we need to check in order to determine whether or not a 
collision is happening is whether or not the particle is moving toward the ground plane. 
If the particle is moving toward the ground plane and it’s within one radius of the ground 
plane, then a collision is occurring. It may also be the case that the particle has passed 
completely through the ground plane, in which case we assume a collision has occurred. 


Implementing Collisions | 175 


www.it-ebooks.info 



Previous Position 



Collision Detected Penetration Prevented 


Figure 8-5. Particle-to-ground collision 

To prevent such penetration of the ground plane, we need to do two things. First, we 
must reposition the particle so that it is just touching the ground plane, as shown on 
the right side of Figure 8-5. Second, we must apply some impact force resulting from 
the collision in order to force the particle to either stop moving down into the ground 
plane or to move away from the ground plane. All these steps make up collision detection 
and response. 

There are several changes and additions that we must make to the example code in order 
to implement particle-to-ground collision detection and response. Let’s begin with the 
Particle class. 

We’ve added three new properties to Particle, as follows: 
class Particle { 


Vector vPreviousPosition; 
Vector vlmpactForces; 
bool bCollision; 


}; 

vPreviousPosition is used to store the particle’s position at the previous time step— 
that is, at time t-dt. vlmpactForces is used to aggregate all of the impact forces acting 


176 | Chapter 8: Particles 


www.it-ebooks.info 














on a particle. You’ll see later that it is possible for a particle to collide with more than 
one object at the same time. bCollision is simply a flag that is used to indicate whether 
or not a collision has been detected with the particle at the current time step. This is 
important because when a collision occurs, at that instant in time, we assume that the 
only forces acting on the particle are the impact forces; all of the other forces—gravity, 
drag, and wind—are ignored for that time instant. We use bCollision in the updated 
CalcLoads method: 

void Particle::CalcLoads(void) 

{ 

// Reset forces: 
vForces.x = 0.0f; 
vForces.y = 0.0f; 

// Aggregate forces: 
if(bCollision) { 

// Add Impact forces (if any) 
vForces += vlmpactForces; 

} else { 

// Gravity 
vForces += vGravity; 

// Still air drag 
Vector vDrag; 
float fDrag; 

vDrag -= vVelocity; 
vDrag.Normalize(); 

fDrag = 0.5 * _AIRDENSITY * fSpeed * fSpeed * 

(3.14159 * fRadius * fRadius) * _DRAGCOEFFICIENT; 
vDrag *= fDrag; 
vForces += vDrag; 

// Wind 

Vector vWind; 

vWind.x = 0.5 * _AIRDENSITY * _WINDSPEED * _WINDSPEED * 

(3.14159 * fRadius * fRadius) * _DRAGCOEFFICIENT; 
vForces += vWind; 

} 

} 

The only difference between this version of CalcLoads and the previous one is that we 
added the conditional if (bCollision) { ... } else { ... }. If bCollision is true, 
then we have a collision to deal with and the only forces that get aggregated are the 
impact forces. If there is no collision, if bCollision is false, then the non-impact forces 
are aggregated in the usual manner. 

You may have caught that we are aggregating impact forces in this example. This is an 
alternate approach to the one shown in Chapter 5 . There we showed you how to calculate 
an impulse and change an object s velocity in response to a collision, using conservation 


Implementing Collisions | 177 


www.it-ebooks.info 



of momentum. Well, we’re still calculating impulses just like in Chapter 5; however, in 
this example, we’re going to compute the impact force based on that impulse and apply 
that force to the colliding objects. We’ll let the numerical integrator integrate that force 
to derive the colliding particle’s new velocities. Either method works, and we’ll show 
you an example of the former method later. We’re showing the latter method here just 
to illustrate some alternatives. The advantage of this latter method is that it is easy to 
compute impact forces due to multiple impacts and let the integrator take care of them 
all at once. 

Now, with these changes made to Particle, we need to add a line of code to Up 
dateSimulation, as shown here: 

void UpdateSimulation(vold) 

1 


// update computer controtled units: 
for(i=0; i<_MAX_NUM_UNITS; i++) 

{ 

Unitsfi].bColtision = CheckForCollisions(&(Units[i])); 
Unitsfi] .CalcLoadsQ; 

Unitsfi].UpdateBodyEuter(dt); 


} // end i-loop 


1 

The newline is Units[i].bCollision = CheckForCollisions(&(Units[i]));.Check 
ForCollisions is a new function that takes the given unit, whose pointer is passed as 
an argument, and checks to see if it’s colliding with anything—in this case, the ground. 
If a collision is detected, CheckForCollisions also computes the impact force and re¬ 
turns true to let us know a collision has occurred. CheckForCollisions is as follows: 

boot CheckForColltsions(Particle* p) 

1 


Vector 

n; 

Vector 

vr; 

ftoat 

vrn; 

ftoat 

3; 

Vector 

Ft; 

bool 

hasColltston = false; 


178 | Chapter 8: Particles 


www.it-ebooks.info 



// Reset aggregate impact force 
p->vImpactForces.x = 0; 
p->vImpactForces.y = 0; 

// check for collisions with ground plane 
if(p->vPosition.y <= (_GROUND_PLANE+p->fRadius)) { 
n.x = 0; 
n.y = 1; 

vr = p->vVelocity; 
vrn = vr * n; 

// check to see if the particle is moving toward the ground 
if(vrn < 0.0) { 

3 = -(vr*n) * (-RESTITUTION + 1) * p->fMass; 

Fi = n; 

Fi *= J/_TIMESTEP; 
p->vImpactForces += Fi; 

p->vPosition.y = _GROUND_PLANE + p->fRadius; 
p->vPosition.x = ((_GROUND_PLANE + p->fRadius - 
p->vPreviousPosition.y) / 

(p->vPosition.y - p->vPreviousPosition.y) * 
(p->vPosition.x - p->vPreviousPosition.x)) + 
p->vPreviousPosition.x; 

hasCollision = true; 

} 

} 

return hasCollision; 

} 

CheckForCollisions makes two checks: 1) it checks to see whether or not the particle 
is making contact or passing through the ground plane; and 2) it checks to make sure 
the particle is actually moving toward the ground plane. Keep in mind a particle could 
be in contact with the ground plane right after a collision has been handled with the 
particle moving away from the ground. In this case, we don’t want to register another 
collision. 

Let’s consider the details of this function, starting with the local variables, n is a vector 
that represents the unit normal vector pointing from the ground plane to the particle 
colliding with it. For ground collisions, in this example, the unit normal vector is always 
straight up since the ground plane is flat. This means the unit normal vector will always 
have an x component of 0 and its y component will be 1. 

The Vector vr is the relative velocity vector between the particle and the ground. Since 
the ground isn’t moving, the relative velocity is simply the velocity of the particle, vrn 
is a scalar that’s used to store the component of the relative velocity in the direction of 
the collision unit normal vector. We compute vrn by taking the dot product of the 
relative velocity with the unit normal vector. 3 is a scalar that stores the impulse resulting 
from the collision. Fi is a vector that stores the impact force as derived from the impulse 


Implementing Collisions | 179 


www.it-ebooks.info 



3. Finally, hasCollision is a flag that’s set based on whether or not a collision has been 
detected. 

Now we’ll look at the details within CheckForCollisions. The first task is to initialize 
the impact force vector, vlmpactForces, to 0. Next, we make the first collision check by 
determining if the y-position of the particle is less than the ground plane height plus 
the particles radius. If it is, then we know a collision may have occurred. (_GR0UND_P LAN E 
represents they coordinate of the ground plane, which we have set to 100.) If a collision 
may have occurred, then we make the next check—to determine if the particle is moving 
toward the ground plane. 

To perform this second check, we compute the unit normal vector, relative velocity, and 
relative velocity component in the collision normal direct as described earlier. If the 
relative velocity in the normal direction is negative (i.e., if vrn < 0), then a collision has 
occurred. If either of these checks is false, then a collision has not occurred and the 
function exits, returning false. 

The interesting stuff happens if the second check passes. This is where we have to de¬ 
termine the impact force that will cause the particle to bounce off the ground plane. 
Here’s the specific code that computes the impact force: 

J = -(vr*n) * (-RESTITUTION + 1) * p->fMass; 

Fi = n; 

Fi *= J/_TIMESTEP; 
p->vImpactForces += Ft; 

p->vPosltion.y = _GROUND_PLANE + p->fRadtus; 
p->vPosition.x = (_GROUND_PLANE + p->fRadius - 
p->vPreviousPosition.y) / 

(p->vPosition.y - p->vPreviousPosition.y) * 
(p->vPositton.x - p->vPreviousPosition.x) + 
p->vPreviousPosition.x; 

hasCollision = true; 

We compute the impulse using the formulas presented in Chapter 5. 3 is a scalar equal 
to the negative of the relative velocity in the normal direction times the coefficient of 
restitution plus 1 times the particle mass. Recall that the coefficient of restitution, _RES 
TITUTION, governs how elastic or inelastic the collision is, or in other words, how much 
energy is transferred back to the particle during the impact. We have this value set to 
0.6, but it is tunable depending on what effect you’re trying to achieve. A value of 1 
makes the particles very bouncy, while a value of, say, 0.1 makes them sort of stick to 
the ground upon impact. 


180 | Chapter 8: Particles 


www.it-ebooks.info 



Now, to compute the impact force, Fi, that will act on the particle during the next time 
step, making it bounce off the ground, we set Fi equal to the collision normal vector. 
The magnitude of the impact force is equal to the impulse, J, divided by the time step 
in seconds. The line Fi *= J/_TIMESTEP; takes care of calculating the final impact force. 

To keep the particle from penetrating the ground, we reposition it so that it’s just resting 
on the ground. The y-position is easy to compute as the ground plane elevation plus the 
radius of the particle. We compute the x-position by linearly interpolating between the 
particles previous position and its current position using the newly computed y- 
position. This effectively backs up the particle along the line of action of its velocity to 
the point where it is just touching the ground plane. 

When you run the simulation now, you’ll see the particles fall, drifting a bit from left to 
right until they hit the ground plane. Once they hit, they’ll bounce on the ground, 
eventually coming to rest. Their specific behavior in this regard depends on what drag 
coefficient you use and what coefficient of restitution you use. If you have wind applied, 
when the particles do come to rest, vertically, they should still drift to the right as though 
they are sliding on the ground plane. 

Partide-to-Obstade Collisions 

To make things really interesting, we’ll now add those circular obstacles you saw in 
Figure 8-1 through Figure 8-4. The particles will be able to hit them and bounce off or 
even settle down into crevasses made by overlapping obstacles. The obstacles are simply 
static particles. We’ll define them as particles and initialize them but then skip them 
when integrating the equations of motion of the dynamic particles. Here’s the declara¬ 
tion for the Obstacles array: 

Particle Obstacles[_NUM_OBSTACLES]; 

Initializing the obstacles is a matter of assigning them positions and a common radius 
and a mass. The few lines of code shown next were added to the main program’s Initi 
alize function to randomly position obstacles in the lower, middle portion of the win¬ 
dow above the ground plane. Figure 8-1 through Figure 8-4 illustrate how they are 
distributed. 

bool Initialize(void) 

1 


for(i=0; 1<_NUM_0BSTACLES; t++) 
{ 


Obstaclesfi].vPosition.x = GetRandomNumber(_WINWIDTH/2 - 

_OBSTACLE_RADIUS*10, 

_WINWIDTH/2 + 

_OBSTACLE_RADIUS*10, false); 


Implementing Collisions | 181 


www.it-ebooks.info 



Obstaclesfi].vPosition.y = GetRandomNurnber(_GROUND_PLANE + 

_OBSTACLE_RADIUS, JJINHEIGHT/2 - 
_0BSTACLE_RADIUS*4, false); 
Obstacles[l].fRadius = _OBSTACLE_RADIUS; 

Obstaclesfi].fMass = 100; 

} 


} 

Drawing the obstacles is easy since they are Particle types with a Draw method that 
already draws circular shapes. We created DrawObstacles to iterate through the Obsta 
cles array, calling the Draw method of each obstacle. 

void DrawObstacles(void) 

{ 

int i; 

for(i=0; i<_NUM_OBSTACLES; U+) 

{ 

Obstacles[i].Draw(); 

} 

} 

DrawObstacles is then called from UpdateSimulatlon: 

void UpdateSimulation(void) 

{ 


// initialize the back buffer 
if(FrameCounter >= _RENDER_FRAME_COUNT) 

{ 

ClearBackBuffer(); 

// Draw ground plane 

DrawLine(0, _WINHEIGHT - _GROUND_PLANE, 

_WINWIDTH, _WINHEIGHT - _GROUND_PLANE, 
3, RGB(0,0,0)); 

DrawObstacles(); 

} 


} 


182 | Chapter 8: Particles 


www.it-ebooks.info 



The last bit of code we need to add to have fully functioning collisions with obstacles 
involves adding more collision detection and handling code to the CheckForColli 
sions function. Before we look at CheckForCollisions, let’s consider colliding circles 
in general to gain a better understanding of what the new code will do. 

Figure 8-6 illustrates two circles colliding. We aim to detect whether or not these circles 
are colliding by checking the distance between their centers. If the distance between the 
two centers is greater than the sum of the radii of the circles, then the particles are not 
colliding. The topmost illustration in Figure 8-6 shows the distance, d, between centers 
and the distance, s, between the edges of the circles; s is the gap between the two. Another 
way to think about this is that if s is positive, then there’s no collision. Referring to the 
middle illustration in Figure 8-6, if s is equal to 0, then the circles are in contact. If s is 
a negative number, as shown in the bottommost illustration, then the circles are pene¬ 
trating. 



We’ll apply these principles for detecting colliding circles to detecting collisions between 
our particles and obstacles since they are both circles. Figure 8-7 illustrates how our 
particle-to-obstacle collisions might look. 


Implementing Collisions | 183 


www.it-ebooks.info 





We’ll calculate s for each particle against each obstacle to determine contact or pene¬ 
tration. If we find either, then we’ll perform the relative velocity check in the same 
manner we did for particle-to-ground collisions to see if the particle is moving toward 
the obstacle. If it is, then we have a collision and we’ll back up the particle along the 
collision normal vector line of action, which is simply the line connecting the centers 
of the particle and the obstacle. We’ll also compute the impact force like we did earlier 
and let the integrator take care of the rest. 

OK, now let’s look at the new code in CheckForCollisions: 

bool CheckForColllstons(Particle* p) 

{ 


// Check for collisions with obstacles 
float r; 

Vector d; 
float s; 


for(i=0; i<_NUM_OBSTACLES; i++) 

{ 

r = p->fRadius + Obstacles[i].fRadius; 
d = p->vPosition - Obstaclesfi].vPosition; 
s = d.Magnitude() - r; 


184 | Chapter 8: Particles 


www.it-ebooks.info 












if(s <= 0.0) 

{ 

d.Normalize(); 
n = d; 

vr = p->vVeloctty - Obstaclesfi].vVelocity; 
vrn = vr*n; 


lf(vrn < 0.0) 

{ 

3 = -(vr*n) * (_RESTITUTION + 1) / 

(l/p->fMass + l/Obstacles[i].fMass); 
Ft = n; 

Ft *= J/JTIMESTEP; 
p->vImpactForces += Fi; 

p->vPosition -= n*s; 
hasCollision = true; 

} 

} 

} 


} 

The new code is nearly the same as the code that checks for and handles particle-to- 
ground collisions. The only major differences are in how we compute the distance be¬ 
tween the particle and the obstacle and how we adjust the colliding particle’s position 
to prevent it from penetrating an obstacle, since the unit normal vector may not be 
straight up as it was before. The rest of the code is the same, so let’s focus on the differ¬ 
ences. 

As explained earlier and illustrated in Figure 8-6, we need to compute the separation, 
s, between the particle and the obstacle. So to get s, we declare a variable r and equate 
it to the sum of radii of the particle and the obstacle against which we’re checking for a 
collision. We define d, a Vector, as the difference between the positions of the particle 
and obstacle. The magnitude of d minus r yields s. 

If s is less than 0, then we make the relative velocity check. Now, in this case the collision 
normal vector is along the line connecting the centers of the two circles representing 
the particle and the obstacle. Well, that’s just the vector d we already calculated. To get 
the unit normal vector, we simply normalize d. The relative velocity vector is simply the 
difference in velocities of the particle and the obstacle. Since the obstacles are static, the 
relative velocity is just the particle’s velocity. But we calculated the relative velocity by 
taking the vector difference vr = p->vVelocity - Obstacles [i] .vVelocity, because 
in a more advanced scenario, you might have moving obstacles. 


Implementing Collisions | 185 


www.it-ebooks.info 



Taking the dot product of the relative velocity vector, vr, with the unit normal vector 
yields the relative velocity in the collision normal direction. If that relative velocity is 
less than 0, then the particle and the object are colliding and the code goes on to calculate 
the impact force in a manner similar to that described earlier for the particle-to-ground 
collisions. The only difference here is that both the particle’s and object’s masses appear 
in the impulse formula. Earlier we assumed the ground was infinitely massive relative 
to the particle’s mass, so the 1/m term for the ground went to 0, essentially dropping out 
of the equation. Refer back to Chapter 5 to recall the impulse formulas. 

Once the impact force is calculated, the code backs up the particle by a distance equal 
to s, the penetration, along the line of action of the collision normal vector, giving us 
what we desire (as shown in Figure 8-7). 

Now, when you run this simulation you’ll see the particles falling down, bouncing off 
the obstacles or flowing around them depending on the value you’re using for coefficient 
of restitution, ultimately bouncing and coming to rest on the ground plane. If you have 
a wind speed greater than 0, then the particles will still drift along the ground plane 
from left to right. 

Tuning 

Tuning is an important part of developing any simulator. Tuning means different things 
to different people. For some, tuning is adjusting formulas and coefficients to make your 
simulation match some specific “right answer,” while to others tuning is adjusting pa¬ 
rameters to make the simulation look and behave how you want it to, whether or not 
it’s technically the right answer. After all, the right answer for a game is that it’s fun and 
robust. Speaking of robustness, other folks view tuning in the sense of adjusting pa¬ 
rameters to make the simulation stable. In reality, this is all tuning and you should think 
of it as a necessary part of developing your simulation. It’s the process by which you 
tweak, nudge, and adjust things to make the simulation do what you want it to do. 

For example, you can use this same example simulation to model very springy rubber 
balls. To achieve this, you’ll probably adjust the coefficient of restitution toward a value 
approaching 1 and perhaps lower the drag coefficient. The particles will bounce all over 
the place with a lot of energy. If, on the other hand, you want to model something along 
the lines of mud, then you’ll lower the coefficient of restitution and increase the drag 
coefficient. There is no right or wrong combination of coefficient of restitution or drag 
coefficient to use, so long as you are pleased with the results. 

Another aspect you might tune is the number of simulation frames per rendering frame. 
You may find the simulation calculations take so long that your resulting animations 
are too jerky because you aren’t updating the display enough. The converse may be true 
in other cases. An important parameter that plays into this is the time step size you take 
at each simulation iteration. If the step size is too small, you’ll perform a lot of simulation 


186 | Chapter 8: Particles 


www.it-ebooks.info 



steps, slowing the animation down. On the other hand, a small time step can keep the 
simulation numerically stable. Your chosen integrator plays a huge role here. 

If you make your time step too large, the simulation may just blow up and not work. It 
will be numerically unstable. Even if it doesn’t blow up, you might see weird results. For 
example, if the time step in the example simulation discussed in this chapter is too large, 
then particles may completely step over obstacles in a single time step, missing the 
collision that would otherwise have happened. (We’ll show you in Chapter 10 how to 
deal with that situation.) 

In general, tuning is a necessary part of developing physics-based simulations, and we 
encourage you to experiment—trying different combinations of parameters to see what 
results you can achieve. You should even try combinations that may break the example 
in this chapter to see what happens and what you should try to avoid in a deployed 
game. 


Tuning | 187 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 9 


2D Rigid-Body Simulator 


After reading Chapter 8, you’ve learned the main ingredients that go into a simulator, 
specifically a particle simulator. In this chapter we’ll look beyond particles at 2D rigid 
bodies. The main difference here is that rigid bodies rotate, and you must deal with an 
additional equation of motion—namely, the angular equation of motion relating a rigid 
body’s angular acceleration and inertia to the sum of all moments (torques) acting on 
the rigid body. The fundamental elements of the simulator—the model, integrator, Ten¬ 
derer, etc.—are the same as before; you just have to deal with rotation. In two dimen¬ 
sions, handling rotation is simple. Things get a bit more involved when handling rota¬ 
tion in three dimensions, and we’ll treat that problem in Chapter 11. 

The example we’ll take a close look at in this chapter is simple by design. We want to 
focus on the differences between the particle simulator and a 2D rigid-body simulator. 
In Chapter 10, we’ll extend this simple example to deal with multiple rigid bodies and 
collisions. That’s where things really get interesting. For now, we’ll consider a single rigid 
body, a virtual hovercraft, that moves around the screen under the influences of thrust 
forces that you can control with the keyboard. While simple, this example covers the 
most fundamental aspects of simulating 2D rigid bodies. 

Figure 9-1 shows our virtual hovercraft. The pointy end is the front, and the hovercraft 
will start off moving from the left side of the screen to the right. Using the arrow keys, 
you can increase or decrease its speed and make it turn left or right (port or starboard). 


189 


www.it-ebooks.info 




2 


-> x (0°) 


+ Rotations 


t 

y (90°) 



Figure 9-1. 2D rigid-body example 


In this simulation, the world coordinate system has its x-axis pointing to the right, its 
y-axis pointing down toward the bottom of the screen, and the z-axis pointing into the 
screen. Even though this is a 2D example where all motion is confined to the x-y plane, 
you still need a z-axis about which the hovercraft will rotate. Also, the local, or body- 
fixed, coordinate system has its x-axis pointing toward the front of the hovercraft, its 
y-axis pointing to the starboard side, and its z-axis into the screen. The local coordinate 
system is fixed to the rigid body at its center of gravity location. 

Model 

The hovercraft modeled in this simulation is a simplified version of the hovercraft we’ll 
model in Chapter 17. You can refer to Chapter 17 for more details on that model. For 
convenience we repeat some of the basic properties of the model here. Figure 9-2 illus¬ 
trates the main features of the model. 


190 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 















Figure 9-2. Simple hovercraft model 

We’re assuming this hovercraft operates over smooth land and is fitted with a single 
airscrew propeller, located toward the aft end of the craft, that provides forward thrust. 
For controllability, the craft is fitted with two bow thrusters, one to port and the other 
to starboard. These bow thrusters are used to steer the hovercraft. 

We use a simplified drag model where the only drag component is due to aerodynamic 
drag on the entire craft with a constant projected area. This model is similar to the one 
used in Chapter 8 for particle drag. A more rigorous model would consider the actual 
projected area of the craft as a function of the direction of relative velocity, as in the 
flight simulator example discussed in Chapter 15, as well as the frictional drag between 
the bottom of the crafts skirt and the ground. We also assume that the center of drag— 
the point through which we can assume the drag force vector is applied—is located some 
distance aft of the center of gravity so as to give a little directional stability (that is, to 
counteract rotation). This serves the same function as the vertical tail fins on aircraft. 
Again, a more rigorous model would include the effects of rotation on aerodynamic 
drag, but we ignore that here. 

In code, the first thing you need to do to represent this vehicle is define a rigid-body 
class that contains all of the information you’ll need to track it and calculate the forces 


Model | 191 


www.it-ebooks.info 



































and moments acting on it. This RigidBody2D class is very similar to the Particle class 
from Chapter 8, but with some additions mostly dealing with rotation. Here’s how we 
did it: 


class RigidBody2D { 
public: 

float fMass; 

float flnertia; 

float 
Vector 
Vector 
Vector 
Vector 


// total mass (constant) 
// mass moment of inertia 


flnertialnverse; 

vPosition; 

vVelocity; 

vVelocityBody; 

vAngularVelocity; 


// inverse of mass moment of inertia 
// position in earth coordinates 
// velocity in earth coordinates 
// velocity in body coordinates 
// angular velocity in body coordinates 


float 

float 


fSpeed; 
fOrientation; 


// speed 
// orientation 


Vector 

Vector 


vForces; 

vMoment; 


// total force on body 
// total moment on body 


float ThrustForce; // Magnitude of the thrust force 

Vector PThrust, SThrust; // bow thruster forces 


float 

float 

float 


fWidth; 

fLength; 

fHeight; 


// bounding dimensions 


Vector CD; // location of center of drag in body coordinates 

Vector CT; // location of center of propeller thrust in body coords. 

Vector CPT; // location of port bow thruster thrust in body coords. 

Vector CST; // location of starboard bow thruster thrust in body 

// coords. 


float ProjectedArea; 


// projected area of the body 


RigidBody2D(void); 

void CalcLoads(void); 

void UpdateBodyEuler(double dt); 

void SetThrusters(bool p, bool s); 

void ModulateThrust(bool up); 

}; 

The code comments briefly explain each property, and so far you’ve seen all these prop¬ 
erties somewhere in this book, so we won’t explain them again here. That said, notice 
that several of these properties are the same as those shown in the Particle class from 
Chapter 8. These properties include fMass, vPosition, vVelocity, fSpeed, vForces, 
and fRadius. All of the other properties are new and required to handle the rotational 
motion aspects of rigid bodies. 


192 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



The RigidBody2D constructor is straightforward, as shown next, and simply initializes 
all the properties to some arbitrarily tuned values we decided worked well. In Chap¬ 
ter 17, you’ll see how we model a more realistic hovercraft. 

RlgtdBody2D::RtgidBody2D(void) 

{ 

fMass = 100; 

flnertta = 500; 

flnerttalnverse = l/flnertia; 

vPositton.x = 0; 

vPosltton.y = 0; 

fWidth = 10; 

fLength = 20; 

fHeight = 5; 

fOrtentation = 0; 

CD.x = -0.25*fLength; 

CD.y = 0.0f; 

CD.z = 0.0f; 

CT.x = -0.5*fLength; 

CT.y = 0.0f; 

CT.z = 0.0f; 

CPT.x = 0.5*fLength; 

CPT.y = -0.5*fWidth; 

CPT.z = 0.0f; 

CST.x = 0.5*fLength; 

CST.y = 0.5*fklidth; 

CST.z = 0.0f; 

ProjectedArea = (fLength + fWidth)/2 * fHeight; // an approximation 
ThrustForce = _THRUSTFORCE; 

} 

As in the particle simulator of Chapter 8, you’ll notice here that the Vector class is 
actually a triple (that is, it has three components—x, y, and z). Since this is a 2D example, 
the z components will always be 0, except in the case of the angular velocity vector where 
only the z component will be used (since rotation occurs only about the z-axis). The 
class that we use in this example is discussed in Appendix A. The reason we didn’t write 
a separate 2D vector class, one with only x and y components, is because we’ll extend 
this code to 3D later and wanted to get you accustomed to using the 3D vector class. 
Besides, it’s pretty easy to create a 2D vector class from the 3D class by simply stripping 
out the z component. 

As with the particle example of Chapter 8, we need a CalcLoads method for the rigid 
body. As before, this method will compute all the loads acting on the rigid body, but 
now these loads include both forces and moments that will cause rotation. CalcLoads 
looks like this: 


Model | 193 


www.it-ebooks.info 




void RigidBody2D::CalcLoads(void) 

{ 

Vector Fb; // stores the sum of forces 

Vector Mb; // stores the sum of moments 

Vector Thrust; // thrust vector 

// reset forces and moments: 
vForces.x = 0.0f; 
vForces.y = 0.0f; 


vForces.z = 0.0f; 

// 

always 

zero 

in 

2D 

vMoment.x = 0.0f; 

// 

always 

zero 

in 

2D 

vMoment.y = 0.0f; 

// 

always 

zero 

in 

2D 


vMoment.z = 0.0f; 

Fb.x = 0.0f; 

Fb.y = 0.0f; 

Fb.z = 0.0f; 

Mb.x = 0.0f; 

Mb.y = 0.0f; 

Mb.z = 0.0f; 

// Define the thrust vector, which acts through the craft's CG 
Thrust.x = 1.0f; 

Thrust.y = 0.0f; 

Thrust.z = 0.0f; // zero in 2D 

Thrust *= ThrustForce; 

// Calculate forces and moments in body space: 

Vector vLocalVelocity; 
float fLocalSpeed; 

Vector vDragVector; 
float tmp; 

Vector vResultant; 

Vector vtmp; 

// Calculate the aerodynamic drag force: 

// Calculate local velocity: 

// The local velocity includes the velocity due to 
// linear motion of the craft, 

// plus the velocity at each element 
// due to the rotation of the craft. 

vtmp = vAngularVelocity A CD; // rotational part 
vLocalVelocity = vVelocityBody + vtmp; 

// Calculate local air speed 
fLocalSpeed = vLocalVelocity .MagnitudeQ; 

// Find the direction in which drag will act. 

// Drag always acts in line with the relative 


194 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



// velocity but in the opposing direction 
if(fLocalSpeed > tol) 

{ 

vLocalVelocity.Normalize(); 
vDragVector = -vLocalVelocity; 

// Determine the resultant force on the element, 
tmp = 0.5f * rho * fLocalSpeed*fLocalSpeed 
* ProjectedArea; 

vResultant = vDragVector * _LINEARDRAGCOEFFICIENT * tmp; 

// Keep a running total of these resultant forces 
Fb += vResultant; 

// Calculate the moment about the CG 

// and keep a running total of these moments 

vtmp = CD A vResultant; 

Mb += vtmp; 

} 

// Calculate the Port & Starboard bow thruster forces: 

// Keep a running total of these resultant forces 

Fb += PThrust; 


// Calculate the moment about the CG of this element's force 
// and keep a running total of these moments (total moment) 
vtmp = CPT A PThrust; 

Mb += vtmp; 

// Keep a running total of these resultant forces (total force) 

Fb += SThrust; 

// Calculate the moment about the CG of this element's force 
// and keep a running total of these moments (total moment) 
vtmp = CST A SThrust; 

Mb += vtmp; 

// Now add the propulsion thrust 

Fb += Thrust; // no moment since line of action is through CG 

// Convert forces from model space to earth space 
vForces = VRotate2D(f0rientation, Fb); 

vMoment += Mb; 

} 

The first thing that CalcLoads does is initialize the force and moment variables that will 
contain the total of all forces and moments acting on the craft at any instant in time. 
Just as we must aggregate forces, we must also aggregate moments. The forces will be 


Model | 195 


www.it-ebooks.info 



used along with the linear equation of motion to compute the linear displacement of 
the rigid body, while the moments will be used with the angular equation of motion to 
compute the orientation of the body. 

The function then goes on to define a vector representing the propeller thrust, Thrust. 
The propeller thrust vector acts in the positive (local) x-direction and has a magnitude 
defined by ThrustForce, which the user sets via the keyboard interface (we’ll get to that 
later). Note that if ThrustForce is negative, then the thrust will actually be a reversing 
thrust instead of a forward thrust. 

After defining the thrust vector, this function goes on to calculate the aerodynamic drag 
acting on the hovercraft. These calculations are very similar to those discussed in 
Chapter 17. The first thing to do is determine the relative velocity at the center of drag, 
considering both linear and angular motion. You’ll need the magnitude of the relative 
velocity vector when calculating the magnitude of the drag force, and you’ll need the 
direction of the relative velocity vector to determine the direction of the drag force since 
it always opposes the velocity vector. The line vtmp = vAngularVelocity A CD computes 
the linear velocity at the drag center by taking the vector cross product of the angular 
velocity vector with the position vector of the drag center, CD. The result is stored in a 
temporary vector, vtnp, and then added vectorially to the body velocity vector, vVelo 
city Body. The result of this vector addition is a velocity vector representing the velocity 
of the point defined by CD, including contributions from the body’s linear and angular 
motion. We compute the actual drag force, which acts in line with but in a direction 
opposing the velocity vector, in a manner similar to that for particles, using a simple 
formula relating the drag force to the speed squared, density of air, projected area, and 
a drag coefficient. The following code performs this calculation: 

vLocalVelocity.Normalize(); 
vDragVector = -vLocalVelocity; 

// Determine the resultant force on the element, 
tmp = 0.5f * rho * fLocalSpeed*fLocalSpeed 
* ProjectedArea; 

vResultant = vDragVector * _LINEARDRAGCOEFFICIENT * tmp; 

Note that the drag coefficient, LINEARDRAGCOEFFICIENT, is defined as follows: 

#define LINEARDRAGCOEFFICIENT 1.25f 

Once the drag force is determined, it gets aggregated in the total force vector as follows: 
Fb += vResultant; 

In addition to aggregating this force, we must aggregate the moment due to that force 
in the total moment vector as follows: 

vtmp = CD A vResultant; 

Mb += vtmp; 


196 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



The first line computes the moment due to the drag force by taking the vector cross 
product of the position vector, to the center of drag, with the drag force vector. The 
second line adds this force to the variable, accumulating these moments. 

With the drag calculation complete, CalcLoads proceeds to calculate the forces and 
moments due to the bow thrusters, which may be active or inactive at any given time. 

Fb += PThrust; 

vtmp = CPT A PThrust; 

Mb += vtmp; 

The first line aggregates the port bow thruster force into Fb. PThrust is a force vector 
computed in the SetThrusters method in response to your keyboard input. The next 
two lines compute and aggregate the moment due to the thruster force. A similar set of 
code lines follows, computing the force and moment due to the starboard bow thruster. 

Next, the propeller thrust force is added to the running total of forces. Remember, since 
the propeller thrust force acts through the center of gravity, there is no moment to worry 
about. Thus, all we need is: 

Fb += Thrust; // no moment since line of action is through CG 

Finally, the total force is transformed from local coordinates to world coordinates via a 
vector rotation given the orientation of the hovercraft, and the total forces and moments 
are stored so they are available when it comes time to integrate the equations of motion 
at each time step. 

As you can see, computing loads on a rigid body is a bit more complex than what you 
saw earlier when dealing with particles. This, of course, is due to the nature of rigid 
bodies being able to rotate. What’s nice, though, is that all this new complexity is en¬ 
capsulated in CalcLoads, and the rest of the simulator is pretty much the same as when 
we’re dealing with particles. 

Transforming Coordinates 

Let’s talk about transformation from local to world coordinates a bit more since you’ll 
see this sort of transform again in a few places. When computing forces acting on the 
rigid body, we want those forces in a vector form relative to the coordinates that are 
fixed with respect to the hovercraft (e.g., relative to the body’s center of gravity with the 
x-axis pointing toward the front ofthe body and the y-axis pointing toward the starboard 
side). This simplifies our calculations of forces and moments. However, when integrat¬ 
ing the equation of motion to see how the body translates in world coordinates, we use 
the equations of motion in world coordinates, requiring us to represent the aggregate 
force in world coordinates. That’s why we rotated the aggregate force at the end of the 
CalcLoads method. 


Model | 197 


www.it-ebooks.info 



In two dimensions, the coordinate transformation involves a little trigonometry as 
shown in the following VRotate2D function: 

Vector VRotate2D( float angle. Vector u) 

{ 

float x,y; 

x = u.x * cos(DegreesToRadians(-angle)) + 
u.y * sin(DegreesToRadians(-angle)); 
y = -u.x * sin(DegreesToRadlans(-angle)) + 
u.y * cos(DegreesToRadians(-angle)); 

return Vector( x, y, 0); 

} 

The angle here represents the orientation of the local, body fixed coordinate system with 
respect to the world coordinate system. When converting from local coordinates to 
world coordinates, use a positive angle; use a negative angle when going the other way. 
This is just the convention we’ve adopted so transformations from local coordinates to 
world coordinates are positive. You can see we actually take the negative of the angle 
parameter, so in reality you could do away with that negative, and then transformations 
from local coordinates to world coordinates would actually be negative. It’s your pref¬ 
erence. You’ll see this function used a few more times in different situations before the 
end of this chapter. 

Integrator 

The UpdateBodyEuler method actually integrates the equations of motion for the rigid 
body. Since we’re dealing with a rigid body, unlike a particle, we have two equations of 
motion: one for translation, and the other for rotation. The following code sample shows 
UpdateBodyEuler. 

void RigldBody2D: :LlpdateBodyEuler(double dt) 

I 

Vector a; 

Vector dv; 

Vector ds; 
float aa; 
float dav; 
float dr; 

// Calculate forces and moments: 

CalcLoads(); 

// Integrate linear equation of motion: 
a = vForces / fMass; 

dv = a * dt; 
vVelocity += dv; 


198 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



ds = vVelocity * dt; 
vPosition += ds; 

// Integrate angular equation of motion: 
aa = vMoment.z / flnertia; 

dav = aa * dt; 

vAngularVeloclty.z += dav; 

dr = RadiansToDegrees(vAngularVeloclty.z * dt); 
fOrientation += dr; 

// Misc. calculations: 
fSpeed = vVelocity.MagnitudeQ; 

vVelocttyBody = VRotate2D(-fOrientation, vVelocity); 

} 

As the name of this method implies, we’ve implemented Euler’s method of integration 
as described in Chapter 7. Integrating the linear equation of motion for a rigid body 
follows exactly the same steps we used for integrating the linear equation of motion for 
particles. All that’s required is to divide the aggregate forces acting on a body by the 
mass of the body to get the body’s acceleration. The line of code a = vForces / 
fMass does just this. Notice here that a is a Vector, as is vForces. fMass is a scalar, and 
the / operator defined in the Vector class takes care of dividing each component of the 
vForces vector by fMass and setting the corresponding components in a. The change 
in velocity, dv, is equal to acceleration times the change in time, dt. The body’s new 
velocity is then computed by the line vVelocity += dv. Here again, vVelocity and dv 
are Vectors and the += operator takes care of the vector arithmetic. This is the first actual 
integration for translation. 

The second integration takes place in the next few lines, where we determine the body’s 
displacement and new position by integrating its velocity. The line ds = vVelocity * 
d t determines the displacement, or change in the body’s position, and the line vPosition 
+= ds computes the new position by adding the displacement to the body’s old position. 
That’s it for translation. 

The next order of business is to integrate the angular equation of motion to find the 
body’s new orientation. The line a a = vMoment.z / flnertia; computes the body’s 
angular acceleration by dividing the aggregate moment acting on the body by its mass 
moment of inertia, aa is a scalar, as is flnertia since this is a 2D problem. In 3D, things 
are a bit more complicated, and we’ll get to that in Chapter 11. 

We compute the change in angular velocity, dav, a scalar, by multiplying aa by the time 
step size, dt. The new angular velocity is simply the old velocity plus the change: vAn 
gula rVelocity. z += dav. The change in orientationis equal to the new angular velocity 
multiplied by the time step: vAngularVelocity .z * dt. Notice that we convert the 


Model | 199 


www.it-ebooks.info 



change in orientation from radians to degrees here since we’re keeping track of orien¬ 
tation in degrees. You don’t really have to, so long as you’re consistent. 

The last line in UpdateBody Euler computes the body’s linear speed by transforming the 
magnitude of its velocity vector to local, body coordinates. Recall in CalcLoads that we 
require the body’s velocity in body-fixed coordinates in order to compute the drag force 
on the body. 


Rendering 

In this simple example, rendering the virtual hovercraft is just a little more involved 
than rendering the particles in the example from Chapter 8. All we do is draw a few 
connected lines using Windows API calls wrapped in our own functions to hide some 
of the Windows-specific code. The following code snippet is all we need to render the 
hovercraft: 


void DrawCraft(RigldBody2D craft, COLORREF clr) 

{ 

Vector vList[5]; 

doubte wd, Ig; 

int t; 

Vector vl; 

wd = craft.fWtdth; 

Ig = craft.fLength; 

vList[0].x = tg/2; vLtst[0].y = wd/2; 

vList[l].x = -tg/2; vList[l].y = wd/2; 

vList[2].x = -lg/2; vList[2].y = -wd/2; 

vList[3].x = tg/2; vLtst[3].y = -wd/2; 

vList[4].x = tg/2*1.5; vLtst[4].y = 0; 

for(i=0; i<5; i++) 

1 

vl = VRotate2D(craft.f0rlentatfon, vList[i]); 
vLtstfi] = vl + craft.vPosttion; 

} 


DrawLine(vLtst[0].x, vList[0].y, vList[l].x, vLtst[l].y, 2, clr); 
DrawLine(vLtst[l].x, vList[l].y, vList[2].x, vLtst[2].y, 2, clr); 
DrawLine(vLtst[2].x, vLtst[2].y, vList[3].x, vLlst[3].y, 2, clr); 
DrawLine(vList[3].x, vLtst[3].y, vList[4].x, vLlst[4].y, 2, clr); 
DrawLine(vLtst[4].x, vList[4].y, vList[0].x, vLtst[0].y, 2, clr); 

} 

You can use your own rendering code here, of course, and all you really need to pay 
close attention to is transforming the coordinates for the outline of the hovercraft from 
body to world coordinates. This involves rotating the vertex coordinates from body- 
fixed space using the VRotate2D function and then adding the position of the center of 
gravity of the hovercraft to each transformed vertex. These lines take care of this coor¬ 
dinate transformation: 


200 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



for(l=0; i<5; i++) 

{ 

vl = VRotate2D(craft.fOrientation, vLlst[i]); 
vLtstfi] = vl + craft.vPosttion; 

} 

The Basic Simulator 

The heart of this simulation is handled by the RigidBody2D class described earlier. 
However, we need to show you how that class is used in the context of the main program. 
This simulator is very similar to that shown in Chapter 8 for particles, so if you’ve read 
that chapter already you can breeze through this section. 

First, we define a few global variables as follows: 

// Global Variables: 

int FraneCounter = 0; 

RlgidBody2D Craft; 

FraneCounter counts the number of time steps integrated before the graphics display 
is updated. How many time steps you allow the simulation to integrate before updating 
the display is a matter of tuning. You’ll see how this is used momentarily when we discuss 
the UpdateSimulation function. Craft is a RigidBody2D type that will represent our 
virtual hovercraft. 

For the most part, Craft is initialized in accordance with the RigidBody2D constructor 
shown earlier. However, its position is at the origin, so we make a call to the following 
Initialize function to locate the Craft in the middle of the screen vertically and on 
the left side. We set its orientation to 0 degrees so it points toward the right side of the 
screen: 

bool Initialize(void) 

{ 

Craft.vPosition.x = JJINWIDTH/10; 

Craft.vPosition.y = JJINHEIGHT/2; 

Craft, fomentation = 0; 

return true; 

} 

OK, now let’s consider UpdateSimulation as shown in the code snippet below. This 
function gets called every cycle through the program’s main message loop and is re¬ 
sponsible for making appropriate function calls to update the hovercraft’s position and 
orientation, as well as rendering the scene. It also checks the states of the keyboard arrow 
keys and makes appropriate function calls: 

void UpdateSinulatlon(void) 

{ 

double dt = _TIMESTEP; 

RECT r; 


The Basic Simulator | 201 


www.it-ebooks.info 



Craft.SetThrusters(false, false); 


if (IsKeyDown(VKJJP)) 

Craft.ModulateThrust(true); 

if (IsKeyDown(VK_DOWN)) 

Craft.ModulateThrust(false); 

if (IsKeyDown(VK_RIGHT)) 

Craft.SetThrusters(true, false); 

if (IsKeyDown(VK_LEFT)) 

Craft.SetThrusters(false, true); 

// update the simulation 
Craft.UpdateBodyEuler(dt); 

if(FrameCounter >= _RENDER_FRAME_COUNT) 

{ 

// update the display 
ClearBackBuffer(); 

DrawCraft(Craft, RGB(0,0,255)); 

CopyBackBufferToWindow(); 

FrameCounter = 0; 

} else 

FrameCounter++; 

if(Craft.vPosition.x > _WINWIDTH) Craft.vPosition.x = 0; 
if(Craft.vPosition.x < 0) Craft.vPosition.x = _WINWIDTH; 
if(Craft.vPosition.y > _WINHEIGHT) Craft.vPosition.y = 0; 
if(Craft.vPosition.y < 0) Craft.vPosition.y = _WINHEIGHT; 

} 

The local variable dt represents the small yet finite amount of time, in seconds, over 
which each integration step is taken. The global define _TIMESTEP stores the time step, 
which we have set to 0.001 seconds. This value is subject to tuning. 

The first action UpdateSimulatton takes is to reset the states of the bow thrusters to 
inactive by calling the SetThrusters method as follows: 

Craft.SetThrusters(false, false); 

Next, the keyboard is polled using the function IsKeyDown. This is a wrapper function 
we created to encapsulate the necessary Windows API calls used to check key states. If 
the up arrow key is pressed, then the RigidBody2D method ModulateTh rust is called, 
as shown here: 

Craft.ModulateThrust(true); 


202 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



If the down arrow key is pressed, then ModulateThrust is called, passing false instead 
of true. 

ModulateThrust looks like this: 

void RigidBody2D::ModulateThrust(bool up) 

{ 

double dT = up ? _DTHRUST:-_DTHRUST; 

ThrustForce += dT; 

if(ThrustForce > _MAXTHRUST) ThrustForce = _MAXTHRUST; 
if(ThrustForce < _MINTHRUST) ThrustForce = _MINTHRUST; 

} 

All it does is increment the propeller thrust force by a small amount, either increasing 
it or decreasing it, depending on the value of the up parameter. 

Getting back to UpdateSimulation, we make a couple more calls to I sKeyDown, checking 
the states of the left and right arrow keys. If the left arrow key is down, then the Rigid 
Body2D method SetThrusters is called, passing false as the first parameter and true 
as the second parameter. If the right arrow key is down, these parameter values are 
reversed. SetThrusters looks like this: 

void RigidBody2D::SetThrusters(bool p, bool s) 

1 

PThrust.x = 0; 

PThrust.y = 0; 

SThrust.x = 0; 

SThrust.y = 0; 

if (p) 

PThrust.y = _STEERINGFORCE; 
if(s) 

SThrust.y = -_STEERINGFORCE; 

} 

It resets the port and starboard bow thruster thrust vectors and then sets them according 
to the parameters passed in SetThrusters. If p is true, then a right turn is desired and 
a port thrust force, PThrust, is created, pointing toward the starboard side. This seems 
opposite of what you’d expect, but it is the port bow thruster that is fired, pushing the 
bow of the hovercraft toward the right (starboard) side. Similarly, if s is true, a thrust 
force is created that will push the bow of the hovercraft to the left (port) side. 

Now with the thrust forces managed, UpdateSimulation makes the call: 

Craft.UpdateBodyEuler(dt) 

UpdateBodyEuler integrates the equations of motion as discussed earlier. 

The next segment of code checks the value of the frame counter. If the frame counter 
has reached the defined number of frames (stored in _RENDER_FRAME_COUNT), then the 


The Basic Simulator | 203 


www.it-ebooks.info 




back buffer is cleared to prepare it for drawing upon and ultimately copying to the 
screen. 

Finally, the last four lines of code wrap the hovercraft’s position around the edges of the 
screen. 

Tuning 

You’ll probably want to tune this example to run well on your computer since we didn’t 
implement any profiling for processor speed. Moreover, you should tune the various 
parameters governing the behavior of the hovercraft to see how it responds. The way 
we have it set up now makes the hovercraft exhibit a soft sort of response to turning— 
that is, upon application of turning forces, the craft will tend to keep tracking in its 
original heading for a bit even while yawed. It will not respond like a car would turn. 
You can change this behavior, of course. 

Some things we suggest you play with include the time step size and the various con¬ 
stants we’ve defined as follows: 


#define 

_THRUSTFORCE 

5.0f 

#define 

_MAXTHRUST 

10.0f 

#define 

_MINTHRUST 

0.0f 

#define 

_DTHRUST 

0.001f 

#define 

_STEERINGFORCE 

3.0f 

#define 

LINEARDRAGCOEFFICIENT 


_THRUSTFORCE is the initial magnitude of the propeller thrust force. _MAXTHRUST and 
_MINTHRUST set upper and lower bounds to this force, which is modulated by the user 
pressing the up and down arrow keys. _DTHRUST is the incremental change in thrust in 
response to the user pressing the up and down arrow keys. _STEERINGFORCE is the mag¬ 
nitude of the bow thruster forces. You should definitely play with this value to see how 
the behavior of the hovercraft changes. Finally, _LINEARDRAGCOEFFICIENT is the drag 
coefficient used to compute aerodynamic drag. This is another good value to play with 
to see how behavior is affected. Speaking of drag, the location of the center of drag that’s 
initialized in the RigidBody2D constructor is a good parameter to change in order to 
understand how it affects the behavior of the hovercraft. It influences the craft’s direc¬ 
tional stability, which affects its turning radius—particularly at higher speeds. 


204 | Chapter 9:2D Rigid-Body Simulator 


www.it-ebooks.info 



CHAPTER 10 


Implementing Collision Response 


In this chapter, we’ll show you how to add a little excitement to the hovercraft example 
discussed in the preceding chapter. Specifically, we’ll add another hovercraft and show 
you how to add collision response so that the hovercraft can crash into each other and 
bounce off like a couple of bumper cars. This is an important element for many types 
of games, so it’s crucial that you understand the code that we’ll present here. Now would 
be a good time to go back and review Chapter 5 to refresh your memory on the funda¬ 
mentals of rigid-body collision response since we’ll use the principles and formulas 
discussed there to develop the collision response algorithms for the hovercraft simula¬ 
tion. In Chapter 8 you saw how to implement linear collision response for particles, and 
now we’ll show you how to handle angular effects. 

To start simply, we’ll first show you how to implement collision response as if the hov¬ 
ercraft were a couple of particles just like those in Chapter 8. This approach uses only 
linear impulse and does not include angular effects, so the results will be somewhat 
unrealistic for these hovercraft; however, this approach is applicable to other types of 
problems that you may be interested in (for example, billiard ball collisions). Plus, taking 
this approach allows us to show you very clearly the distinction between linear and 
angular effects. Including angular effects will make the simulation much more realistic; 
when the hovercraft crash into each other, not only will they bounce off each other, but 
they will also spin. 

Before diving into collisions, let’s add another hovercraft to the example we started in 
Chapter 9. Recall in that example, we had a single craft that you could control using the 
keyboard. Now, we’ll add another hovercraft that simply moves under constant forward 
thrust. Later, when we add collision detection and response you’ll be able to run into 
this new hovercraft to alter its course. 

Referring back to the example from Chapter 9, we need to add another craft as follows: 

RigtdBody2D Craft2; 


205 


www.it-ebooks.info 




We’re calling the new hovercraft, very creatively, Craft2. In the Initialize function, 
we must now add the following code: 

boot Initialtze(vold) 

{ 


Craft2.vPosttion.x = _WINWIDTH/2; 
Craft2.vPosition.y = _WINHEIGHT/2; 
Craft2.f0rientation = 90; 


} 

This new code sample positions the second hovercraft in the middle of the screen and 
pointing toward the bottom. 

There are a few required changes to UpdateSimulation as well. First, add Craft2.Up 
dateBodyEuler(dt); right after the line Craft.UpdateBodyEuler(dt);. Then, add 
DrawCraft(Craft2, RGB(200, 200, 0)); after the similar line that draws the first 
Craft. Craft2 will be drawn yellow to distinguish it from the first Craft. Finally, add 
the following lies at the end of UpdateSimulation: 

lf(Craft2.vPosttion.x > J/JINWIDTH) Craft2.vPosition.x = 0; 
lf(Craft2.vPosition.x < 0) Craft2.vPosition.x = _WINWIDTH; 
if(Craft2.vPosition.y > _WINHEIGHT) Craft2.vPosition.y = 0; 
if(Craft2.vPosition.y < 0) Craft2.vPosition.y = _WINHEIGHT; 

Now, we can add the code to handle collision detection and response, allowing you to 
ram your hovercraft into the new one we just added. 

Linear Collision Response 

In this section, we’ll show you how to implement simple collision response, assuming 
that the two hovercraft are particles. We’re going to implement only bare-minimum 
collision detection in this simulation; however, regardless of the level of sophistication 
of your collision detection routines, there are very specific pieces of information that 
you must collect from your collision detection routine(s) in order for your physics- 
based collision response routines to work. 

To revise the hovercraft example of the previous chapter to include simple collision 
response, you’ll have to modify the UpdateSimulation function and add a couple more 
functions: CheckForCollision and Applylmpulse. 

Before showing you CheckForCollision, we want to explain what your collision de¬ 
tection function must do. First, it must let you know whether or not there is a collision 
occurring between the hovercraft. Secondly, it must let you know if the hovercraft are 


206 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



penetrating each other. Thirdly, if the hovercraft are colliding, it must tell you what the 
collision normal vector is and what the relative velocity is between the colliding hov¬ 
ercraft. 

To determine whether or not there is a collision, you need to consider two factors: 

• Whether or not the objects are close enough, within numerical tolerances, to be 
considered in colliding contact 

• What the relative normal velocity is between the objects 

If the objects aren’t close to each other, they obviously have not collided. If they are 
within your tolerance for contact, then they may be colliding; and if they are touching 
and overlapping such that they are moving inside each other, they are penetrating, as 
illustrated in Figure 10-1. If your collision detection routine finds that the two objects 
are indeed close enough to be in colliding contact, then you have to do another check 
on the relative normal velocity to see if they are moving away from each other or toward 
each other. A collision occurs when the objects are in contact and the contact points are 
moving toward each other. 



Penetration is important because if your objects overlap during the simulation, the re¬ 
sults won’t look realistic—you’ll have one hovercraft moving inside the other. What you 
have to do is detect this penetration condition and then back up your simulation, reduce 
the time step, and try again. You keep doing this until they are no longer penetrating or 
they are within tolerance to be considered colliding. 

You need to determine the normal velocity vector of the collision in order to calculate 
the collision impulse that will be used to simulate their response to the collision. For 
simple cases, determining this normal vector is fairly straightforward. In the case of 
particles or spheres, the collision normal is simply along the line that connects the 


Linear Collision Response | 207 


www.it-ebooks.info 




centers of gravity of each colliding object; this is central impact, as discussed in Chap¬ 
ter 5, and is the same as that used for the particle example in Chapter 8. 

Now take a look at the function we’ve prepared for this simulation to check for collisions: 

tnt CheckForCollision (pRigidBody2D bodyl, pRigtdBody2D body2) 

{ 

Vector d; 

float r; 

int retval = 0; 

float s; 

Vector vl, v2; 
float Vrn; 

r = bodyl->ColRadius + body2->ColRadlus; 
d = bodyl->vPositlon - body2->vPositlon; 
s = d.MagnitudeQ - r; 

d.Normalize(); 
vCollisionNormal = d; 

vl = bodyl->vVelocity; 
v2 = body2->vVelocity; 
vRelatlveVelocity = vl - v2; 

Vrn = vRelatlveVelocity * vColllsionNornal; 
if((fabs(s) <= ctol) && (Vrn < 0.0)) 

{ 

retval = 1; // collision; 

CollisionBodyl = bodyl; 

CollisionBody2 = body2; 

} else if(s < -ctol) 

{ 

retval = -1; // interpenetrating 
} else 

retval = 0; // no collision 
return retval; 

} 

This function uses a simple bounding circle check to determine whether or not the 
hovercraft are colliding. The first thing it does is calculate the distance, r, that represents 
the absolute minimum separation between these hovercraft when they are in contact. 
ColRadius is the radius of the bounding circle of the hovercraft. We must compute it 
for each hovercraft upon initialization as follows: 

->ColRadius = SQRT(fLength*fLength + fWidth*fWidth); 

Next, the distance separating the hovercraft at the time this function is called is deter¬ 
mined and stored in the variable d. Since we’re assuming that these hovercraft are par¬ 
ticles, determining d is simply a matter of calculating the distance between the coordi- 


208 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



nates of each craft’s center of gravity. In terms of vectors, this is simply the position 
vector of one craft minus the position vector of the other. 

Once the function has d and r, it needs to determine the actual amount of space, s, 
separating the hovercraft’s bounding circles. After this separation is determined, the 
function normalizes the vector d. Since the vector d is along the line that separates the 
hovercraft’s centers of gravity, normalizing it yields the collision normal vector that we 
need for our collision response calculations. The collision normal vector is saved in the 
global variable vCollisionNormal. 

After calculating the collision normal, this function goes on to determine the relative 
velocity between the hovercraft. In vector form, this is simply the difference between 
the velocity vectors of each craft. Note that the velocity vectors used here must be in 
global coordinates, not body-fixed (local) coordinates. Since what’s really needed to 
determine if a collision is made is the relative normal velocity, the function proceeds to 
take the vector dot product of the relative velocity and the collision normal vectors, 
saving the result in the variable Vrn. 

At this point, all of the calculations are complete, and the only thing left to do is make 
the appropriate checks to determine if there is a collision, penetration, or no collision 
at all. 

The first check is to see if the hovercraft are colliding. We determine this by comparing 
the absolute value of the separation between the hovercraft, s, with a distance tolerance, 
ctol. If the absolute value of s is less than ctol, a collision might be occurring. The 
second requirement is that the relative normal velocity be negative, which implies that 
the points of impact on the hovercraft are moving toward each other. If there is a col¬ 
lision, the function returns a 1 to indicate that collision response is necessary. 

If the hovercraft are found not to be colliding, then we perform a second check to see 
if they’ve moved so close together that they are penetrating each other. In this case, if s 
is less than -ctol, the hovercraft are penetrating and the function returns a -1. If the 
hovercraft are not colliding and not penetrating, then the function simply returns a 0, 
indicating that no further action is required. 

Before moving on, let’s say a word or two about ctol—the collision tolerance distance. 
This value is subject to tuning. There’s no single value that works well in all cases. You 
must consider the overall sizes of the objects potentially colliding, the step size you’re 
using, and how far the colliding objects are from the viewer while being rendered (i.e., 
their scale). Basically, you should choose a value that makes collisions look correct, so 
that on the one hand objects do not appear to be penetrating each other, and on the 
other hand you do not report a collision when objects do not appear to be touching at 
all. 


Linear Collision Response | 209 


www.it-ebooks.info 



Take a look now at the other new function. Apply Impulse: 

void ApplyImpulse(pRigidBody2D bodyl, pRigidBody2D body2) 

{ 

float j; 


j = (-(1+fCr) * (vRelativeVelocity*vCollisionNormal)) / 

( (vCollisionNormal*vCollisionNomal) * 

(l/bodyl->fMass + l/body2->fMass) ); 

bodyl->vVeloclty += (j * vColllsionNomal) / bodyl->fMass; 
body2->vVeloclty -= (j * vColllsionNomal) / body2->fMass; 

} 

This is a simple but crucial function for collision response. What it does is calculate the 
linear collision impulse as a function of the colliding hovercraft’s relative normal ve¬ 
locity, masses, and coefficient of restitution, using the formula that we showed you in 
Chapter 5. Further, it applies this impulse to each hovercraft, effectively changing their 
velocities in response to the collision. Note that the impulse is applied to one hovercraft 
and then the negative impulse applied to the other. 

With those two new functions complete, it’s now time to revise UpdateSimulation to 
handle collision detection and response as the simulation steps through time. Here’s 
what the new UpdateSimulation function looks like: 

void UpdateSimulation(float dt) 

{ 

float dtime = dt; 

bool tryAgain = true; 

int check=0; 

RigldBody2D craftlCopy, craft2Copy; 
bool didPen = false; 

int count = 0; 


Craft.SetThrusters(false, false); 

if (IsKeyDown(VK_UP)) 

Craft,ModulateThrust(true); 

if (IsKeyDown(VK_DOWN)) 

Craft,ModulateThrust(false); 

if (IsKeyDown(VK_RIGHT)) 

Craft.SetThrusters(true, false); 

if (IsKeyDown(VK_lEFT)) 

Craft.SetThrusters(false, true); 


while(tryAgain && dtime > tol) 


210 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



{ 

tryAgain = false; 

memcpy(&craftlCopy, &Craft, sizeof(RtgidBody2D)); 
memcpy(&craft2Copy, &Craft2, sizeof(RigidBody2D)); 

Craft.UpdateBodyEuler(dtlne); 

Craft2.UpdateBodyEuler(dtime); 

CollisionBodyl = 0; 

ColllsionBody2 = 0; 

check = CheckForCollision(&craftlCopy, &craft2Copy); 

If(check == PENETRATING) 

{ 

dtime = dtime/2; 
tryAgain = true; 
didPen = true; 

} else tf(check == COLLISION) 

{ 

if(CollisionBodyl != 0 && CollisionBody2 != 0) 

ApplyImpulse(CollisionBodyl, CollisionBody2); 

} 

} 

if(IdidPen) 

{ 

memcpy(&Craft, &craftlCopy, sizeof(RigidBody2D)); 
memcpy(&Craft2, &craft2Copy, sizeof(RigidBody2D)); 

} 

} 

Obviously, this version is more complicated than the original version. There’s one main 
reason for this: penetration could occur because the hovercraft can move far enough 
within a single time step to become overlapped. Visually, this situation is unappealing 
and unrealistic, so you should to try to prevent it. 

The first thing this function does is enter a while loop: 

while(tryAgain && dtime > tol) 

{ 


} 

This loop is used to back up the simulation if penetration has occurred on the initial 
time step. What happens is this: the function first tries to update the hovercraft and then 
checks to see if there is a collision. If there is a collision, then it gets handled by applying 
the impulse. If there is penetration, however, then you know the time step was too big 
and you have to try again. When this occurs, tryAgain is set to true, the time step is 
cut in half, and another attempt is made. The function stays in this loop as long as there 


Linear Collision Response | 211 


www.it-ebooks.info 



is penetration or until the time step has been reduced to a size small enough to force an 
exit to the loop. The purpose of this looping is to find the largest step size, less than or 
equal to dt, that can be taken and still avoid penetration. You either want a collision or 
no collision. 

You might ask yourself when does small become too small in terms of time step? Too 
small is obviously when the time step approaches 0 and your entire simulation grinds 
to a halt. Therefore, you may want to put in some criteria to exit this loop before things 
slow down too much. This is all subject to tuning, by the way, and it also depends on 
the value you set for ctol. We can’t stress enough the importance of tuning these pa¬ 
rameters. Basically, you must strive for visual realism while keeping your frame rates 
up to required levels. 

Looking inside this while loop reveals what’s going on. First, tryAgain is set to false, 
optimistically assuming that there will be no penetration, and we make copies of the 
hovercraft’s states, reflecting the last successful call to UpdateSimulation. 

Next, we make the usual call to UpdateBody for each copy of the hovercraft. Then a call 
to the collision detection function, CheckForCollision, is made to see if Craft is col¬ 
liding with or penetrating Craft2. If there is penetration, then tryAgain is set to true, 
dtime is cut in half, didPen is set to true, and the function takes another lap through 
the while loop. didPen is a flag that lets us know that a penetration condition did occur. 

If there was a collision, the function handles it by applying the appropriate impulse: 

if(ColtistonBodyl != 0 && CollisionBody2 != 0) 

ApplyInputse(CollistonBodyl, CollisionBody2); 

After getting through the while loop, the updated hovercraft states are saved and Upda 
teSimulation is complete. 

The last bit of code you need to add includes a few new global variables and defines: 

#define LINEARDRAGCOEFFICIENT 0.25f 

#define COEFFICIENTOFRESTITUTION 0.5f 

#define COLLISIONTOLERANCE 2.0f 

Vector vColllsionNormal; 

Vector vRelatlveVelocity; 

float fCr = COEFFICIENTOFRESTITUTION; 

float const ctol = COLLISIONTOLERANCE; 

The only one we haven’t mentioned so far, although you’ve seen it in Applylmpulse, is 
fCr, the coefficient of restitution. Here we have it set to 0.5, which means that the 
collisions are halfway between perfectly elastic and perfectly inelastic (refer back to our 
earlier discussions on coefficients of restitution in Chapter 5 if you’ve forgotten these 
terms). This is one of those parameters that you’ll have to tune to get the desired be¬ 
havior. 


212 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



While we’re on the subject of tuning, we should mention that you’ll also have to play 
with the linear drag coefficient used to calculate the drag force on the hovercraft. While 
this coefficient is used to simulate fluid dynamic drag, it also plays an important role in 
terms of numerical stability. You need some damping in your simulation so that your 
integrator does not blow up—that is, damping helps keep your simulation stable. 

That’s pretty much it as far as implementing basic collision response. If you run this 
example, you’ll be able to drive the hovercraft into each other and bounce off accord¬ 
ingly. You can play around with the mass of each hovercraft and the coefficient of res¬ 
titution to see how the craft behave when one is more massive than the other, or when 
the collision is somewhere between perfectly elastic and perfectly inelastic. 

You may notice that the collision response in this example sometimes looks a little 
strange. Keep in mind that’s because this collision response algorithm, so far, assumes 
that the hovercraft are round when in fact they are rectangular. This approach will work 
just fine for round objects like billiard balls, but to get the level of realism required for 
non-round rigid bodies you need to include angular effects. We’ll show you how to do 
that in the next section. 

Angular Effects 

Including angular effects will yield more realistic collision responses for these rigid 
bodies, the hovercraft. To get this to work, you’ll have to make several changes to 
Applylmpulse and CheckForCollision;. UpdateSimulation will remain unchanged. 
The more extensive changes are in CheckForCollision, so we’ll discuss it first. 

The new version of CheckForCollision will do more than a simple bounding circle 
check. Here, each hovercraft will be represented by a polygon with four edges and four 
vertices, and the types of contact that will be checked for are vertex-vertex and vertex- 
edge contact (see Figure 10-2). 1 


1. Note that this function does not handle multiple contact points. 


Angular Effects | 213 


www.it-ebooks.info 




In addition to the tasks discussed in the last section, this new version of CheckForCol 
lision must also determine the exact point of contact between the hovercraft. This is 
a very important distinction between this new version and the last. You need to know 
the point of contact because in order to affect the angular velocity, you must apply the 
impulse at the point of contact. In the last section, the normal to the contact point always 
passed through the center of gravity of the hovercraft because we assumed they were 
spheres; that’s not the case here. 

This now brings up the challenge of finding the collision normal. There are two cases 
to consider here. In edge-vertex collisions, the normal is always perpendicular to the 
edge that’s involved in the collision. In vertex-vertex collisions, however, the normal is 
ambiguous, so we’ve resorted to taking the normal parallel to the line connecting the 
hovercraft’s centers of gravity. 

All of these considerations make CheckForCollisions a little more involved than in 
the previous section. The following code listing shows what we mean: 


214 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 






int CheckForCollision(pRigidBody2D bodyl, pRigidBody2D body2) 
{ 


Vector 

d; 

float 

r; 

int 

retval = 0; 

float 

s; 

Vector 

vListl[4], vList2[4]; 

float 

wd, Ig; 

int 

t, j; 

bool 

haveNodeNode = false; 

bool 

interpenetrating = false; 

bool 

haveNodeEdge = false; 

Vector 

vl, v2, u; 

Vector 

edge, p, proj; 

float 

dist, dot; 

float 

Vrn; 


// First check to see if the bounding circles are colliding 
r = bodyl->fLength/2 + body2->fLength/2; 
d = bodyl->vPosition - body2->vPosition; 
s = d.MagnitudeQ - r; 


if(s 

{ 


<= ctol) 

// We have a possible collision, check further 
// build vertex lists for each hovercraft 
wd = bodyl->fWidth; 

Ig = bodyl->fLength; 

vListl[0].y = wd/2; vListl[0].x = lg/2; 

vListl[l].y = -wd/2; vListl[l].x = lg/2; 

vListl[2].y = -wd/2; vListl[2].x = -lg/2; 

vListl[3].y = wd/2; vListl[3].x = -lg/2; 


for(l=0; i<4; i++) 

{ 

VRotate2D(bodyl->f0rientation, vListl[i]); 
vListlfi] = vListlfi] + bodyl->vPosition; 

} 


wd = body2->fWidth; 
Ig = body2->fLength; 
vList2[0].y = wd/2; 
vList2[l].y = -wd/2; 
vList2[2].y = -wd/2; 
vList2[3].y = wd/2; 


vList2[0].x = lg/2; 
vList2[l].x = lg/2; 
vList2[2].x = -lg/2; 
vLlst2[3].x = -lg/2; 


for(t=0; i<4; i++) 

{ 

VRotate2D(body2->fOrientation, vList2[i]); 
vList2[i] = vList2[i] + body2->vPosition; 

} 

// Check for vertex-vertex collision 


Angular Effects | 215 


www.it-ebooks.info 



for(i=0; i<4 && !haveNodeNode; i++) 

{ 

for(j=0; j<4 && !haveNodeNode; j++) 

{ 


vColllsionPoint = vListl[l]; 
bodyl->vCollisionPoint = vColllsionPoint - 
bodyl->vPosition; 

body2->vCollisionPoint = vColllsionPoint - 
body2->vPosition; 

vCollisionNornal = bodyl->vPosition - 
body2->vPosition; 

vCollisionNornal.Nornalize(); 

vl = bodyl->vVelocityBody + 

(body 1 - >vAngula rVelocity A body 1 - >vCollisionPoint); 

v2 = body2->vVelocityBody + 

(body 2 - >vAngula rVelocity A body 2 - >vCollisionPoin t); 

vl = VRotate2D(bodyl->f0rientation, vl); 
v2 = VRotate2D(body2->fOrientation, v2); 

vRelativeVelocity = vl - v2; 

Vrn = vRelativeVelocity * vCollisionNornal; 

if( ArePointsEqual(vListl[i], 

vList2[j]) && 

(Vrn < 0.0) ) 
haveNodeNode = true; 


} 

} 

// Check for vertex-edge collision 
if(!haveNodeNode) 

{ 

for(i=0; i<4 && !haveNodeEdge; i++) 

{ 

for(j=0; j<3 && !haveNodeEdge; j++) 

{ 

if(j--2) 

edge = vList2[0] - vList2[j]; 

else 

edge = vList2[j+l] - vList2[j]; 
u = edge; 
u.Nornalize(); 

p = vListl[i] - vList2[j]; 


216 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



proj = (p * u) * u; 


d = p A u; 

dist = d.Magnltude(); 

vCollislonPoint = vl_istl[i]; 
bodyl->vColllstonPotnt = vColllstonPolnt - 
body1->vPosition; 

body2->vColllstonPolnt = vCollisionPoint - 
body2->vPosltlon; 

vCollislonNornal = ((u A p) A u); 
vCollislonNornal.Normallze(); 

vl = bodyl->vVelocityBody + 
(bodyl->vAngularVelocity A 
bodyl->vColllsionPolnt); 

v2 = body2->vVelocltyBody + 
(body2->vAngularVelocity A 
body2->vColllslonPolnt); 

vl = VRotate2D(bodyl->f0rlentatlon, vl); 
v2 = VRotate2D(body2->f0rlentatlon, v2); 

vRelati.veVeloci.ty = (vl - v2); 

Vrn = vRelativeVelocity * vColltstonNornal; 

if( (proj.Magnitude() > 0.0f) && 

(proj.Magnitude() <= edge.Magnitude()) && 
(dtst <= ctol) && 

(Vrn < 0.0) ) 
haveNodeEdge = true; 

} 

} 

} 

// Check for penetration 

If(!haveNodeNode && ! haveNodeEdge) 

{ 

for(l=0; t<4 && Unterpenetratlng; 1++) 

{ 

for(j=0; j<4 && Unterpenetratlng; j++) 

{ 

tf(j==3) 

edge = vLlst2[0] - vLlst2[j]; 

else 

edge = vLlst2[j+l] - vLlst2[j]; 

p = vLlstl[l] - vLlst2[j]; 
dot = p * edge; 


Angular Effects | 217 


www.it-ebooks.info 



lf(dot < 0) 

{ 


If(Interpenetrating) 

{ 


interpenetrating = true; 


retval = -1; 

} eise If(haveNodeNode || haveNodeEdge) 

{ 

retval = 1; 


} else 

retval = 0; 


} else 

{ 

retval = 0; 

} 

return retval; 

} 

The first thing that CheckForCollision does is perform a quick bounding-circle check 
to see if there is a possible collision. If no collision is detected, the function simply exits, 
returning 0. This is the same bounding-circle check performed in the earlier version: 

r = bodyl->fLength/2 + body2->fLength/2; 
d = bodyl->vPosition - body2->vPosition; 
s = d.MagnitudeQ - r; 

if(s <= ctol) 

{ 


} else 

retval = 0; 

} 

If the bounding-circle check indicates the possibility of a collision, then CheckForCol 
lision proceeds by setting up a couple of polygons, represented by vertex lists, for each 
hovercraft: 


wd = bodyl->fWidth; 
lg = bodyl->fLength; 
vLtstl[0].y = wd/2; 
vListlfl].y = -wd/2; 
vListl[2].y = -wd/2; 
vListl[3].y = wd/2; 


vLlstl[0].x = lg/2; 
vLlstl[l].x = lg/2; 
vListl[2].x = -lg/2; 
vListl[3].x = -lg/2; 


218 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 




for(i=0; i<4; i++) 

{ 

VRotate2D(bodyl->fOrientation, vListl[i]); 
vListl[i] = vListlfi] + bodyl->vPosition; 

} 


wd = body2->fWidth; 
Ig = body2->fLength; 
vList2[0].y = wd/2; 
vList2[l].y = -wd/2; 
vList2[2].y = -wd/2; 
vList2[3].y = wd/2; 
for(i=0; i<4; i++) 

{ 


vList2[0].x = lg/2; 
vList2[l].x = lg/2; 
vList2[2] .x = -lg/2; 
vLlst2[3].x = -lg/2; 


VRotate2D(body2->fOrientation, vList2[i]); 
vList2[i] = vList2[i] + body2->vPosition; 


} 


The vertex lists are initialized in unrotated body-fixed (local) coordinates based on the 
length and width of the hovercraft. The vertices are then rotated to reflect the orientation 
of each hovercraft. After that, the position of each hovercraft is added to each vertex to 
convert from local coordinates to global coordinates 


Checking first for vertex-vertex collisions, the function iterates through each vertex in 
one list, comparing it with each vertex in the other list to see if the points are coincident. 


// Check for vertex-vertex collision 
for(i=0; i<4 && !haveNodeNode; i++) 

{ 

for(j=0; j<4 && !haveNodeNode; j++) 

{ 


vCollisionPoint = vListlfi]; 
bodyl->vCollisionPoint = vCollisionPoint - 
bodyl->vPosition; 

body2->vCollisionPoint = vCollisionPoint - 
body2->vPosition; 

vCollisionNornal = bodyl->vPosition - 
body2->vPosition; 

vCollisionNornal.Nornalize(); 

vl = bodyl->vVelocityBody + 

(bodyl->vAngularVelocity A bodyl->vCollisionPoint); 

v2 = body2->vVelocityBody + 

(body 2 - >vAngula rVelocity A body 2 - >vCollisionPoin t); 

vl = VRotate2D(bodyl->f0rientation, vl); 
v2 = VRotate2D(body2->fOrientation, v2); 


Angular Effects | 219 


www.it-ebooks.info 



vRelativeVelocity = vl - v2; 

Vrn = vRelativeVelocity * vCollisionNormal; 

if( ArePointsEqual(vListl[i], 

vList2[j]) && 

(Vrn < 0.0) ) 
haveNodeNode = true; 


} 

} 

This comparison makes a call to another new function, ArePointsEqual: 

tf( ArePointsEqual(vListl[i], 

vList2[j]) && 

(Vrn < 0.0) ) 
haveNodeNode = true; 

ArePointsEqual simply checks to see if the points are within a specified distance from 
each other, as shown here: 

bool ArePointsEqual(Vector pi, Vector p2) 

{ 

// Points are equal if each component is within ctol of each other 
if( (fabs(pl.x - p2.x) <= ctol) && 

(fabs(pl.y - p2.y) <= ctol) && 

(fabs(pl.z - p2.z) <= ctol) ) 
return true; 

else 

return false; 

} 

Within the nested for loops of the vertex-vertex check, we perform a number of im¬ 
portant calculations to determine the collision normal vector and relative velocity that 
are required for collision response. 

First, we calculate the collision point, which is simply the coordinates of a vertex that is 
involved in the collision. Note that this point will be in global coordinates, so it will have 
to be converted to local coordinates for each hovercraft in order to be useful for collision 
response. Here’s how that’s done: 

vCollislonPoint = vListlfi]; 
bodyl->vCollislonPoint = vCollisionPoint - 
bodyl->vPosition; 

body2->vCollislonPoint = vCollisionPoint - 
body2->vPosition; 

The second calculation is aimed at determining the collision normal vector, which for 
vertex-vertex collisions we’ve assumed is along the line connecting the centers of gravity 


220 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



of each hovercraft. The calculation is the same as that shown in the earlier version of 
CheckForCollision: 


vCollisionNormal = bodyl->vPosition - 
body2->vPosition; 

vCollistonNormal.Normalize(); 

The third and final calculation is aimed at determining the relative velocity between the 
points of impact. This is an important distinction from the earlier version, since the 
velocities of the points of impact on each body are functions of the linear and angular 
velocities of the hovercraft: 

vl = bodyl->vVelocityBody + 

(bodyl->vAngularVelocity A bodyl->vCotlisionPotnt); 

v2 = body2->vVelocityBody + 

(body2->vAngularVelocity A body2->vCollisionPoint); 

vl = VRotate2D(bodyl->f0rientatlon, vl); 
v2 = VRotate2D(body2->fOrientatlon, v2); 

vRelativeVetocity = vl - v2; 

Vrn = vRelativeVetocity * vCollisionNomal; 

Here, vl and v2 represent the velocities of the points of collision relative to each hov¬ 
ercraft in local coordinates, which are then converted to global coordinates. Once we’ve 
obtained the relative velocity, vRelativeVelocity, we obtain the relative normal ve¬ 
locity, Vrn, by taking the dot product of the relative velocity with the collision normal 
vector. 

If there is no vertex-vertex collision, CheckForCollision proceeds to check for vertex- 
edge collisions: 

// Check for vertex-edge collision 
if(!haveNodeNode) 

{ 

for(i=0; i<4 && !haveNodeEdge; i++) 

{ 

for(j=0; j<3 && !haveNodeEdge; j++) 

{ 

if(j==3) 

edge = vList2[0] - vList2[j]; 

else 

edge = vList2[j+l] - vList2[j]; 
u = edge; 
u.NormalizeO; 

p = vListl[i] - vList2[j]; 
proj = (p * u) * u; 

d = p A u; 


Angular Effects | 221 


www.it-ebooks.info 



dlst = d.Magnitude(); 


vCollisionPoint = vLlstl[i]; 
bodyl->vCollisionPoint = vCollisionPoint - 
bodyl->vPosition; 

body2->vCollisionPoint = vCollisionPoint - 
body2->vPosition; 

vCollisionNornal = ((u A p) A u); 
vCollisionNornal. Nornalize(); 

vl = bodyl->vVelocityBody + 

(bodyl->vAngularVelocity A 
bodyl->vCollisionPoint); 

v2 = body2->vVelocityBody + 

(body2->vAngularVelocity A 
body2->vCollisionPoint); 

vl = VRotate2D(bodyl->f0rientation, vl); 
v2 = VRotate2D(body2->f0rientation, v2); 

vRelativeVelocity = (vl - v2); 

Vrn = vRelativeVelocity * vCollisionNornal; 

if( (proj.Magnitude() > 0.0f) && 

(proj.Magnitude() <= edge.MagnitudeQ) && 

(dist <= ctol) && 

(Vrn < 0.0) ) 
haveNodeEdge = true; 

} 

} 

} 

Here, the nested f o r loops check each vertex in one list to see if it is in contact with each 
edge built from the vertices in the other list. After building the edge under consideration, 
we save and normalize a copy of it to represent a unit vector pointing along the edge: 

if(j==3) 

edge = vList2[0] - vList2[j]; 

else 

edge = vList2[j+l] - vList2[j]; 
u = edge; 
u.Nornalize(); 

Variable u represents that unit vector, and it will be used in subsequent calculations. The 
next set of calculations determines the location of the projection of the vertex under 
consideration onto the edge under consideration, as well as the minimum distance from 
the vertex to edge: 


222 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



p = vListl[i] - vList2[j]; 
proj = (p * u) * u; 

d = p A u; 

dist = d.Magni.tude(); 

Variable p is a vector from the first vertex on the edge to the vertex under consideration, 
and proj is the distance from the first edge vertex, along the edge, to the point upon 
which the vertex projects, dist is the minimum distance from the vertex to the edge. 
Figure 10-3 illustrates this geometry. 



If there is a collision, the global location of the point of impact is equal to the vertex 
under consideration, which we must convert to local coordinates for each hovercraft, 
as shown here: 


vCollistonPoint = vListl[i]; 
bodyl->vCollisionPotnt = vColltsionPolnt - 
bodyl->vPosition; 

body2->vCollisionPotnt = vCollistonPoint - 
body2->vPosition; 

Since, in this type of collision, the collision normal vector is perpendicular to the edge, 
you can determine it by taking the result of the cross product of u and p and crossing it 
with u as follows: 


vCollisionNormal = ((u A p) A u); 
vCollisionNormal. Nomaltze(); 

These calculations give you a unit length vector in the plane of vectors u and p and 
perpendicular to the edge. 

Next, the relative velocity between the points of impact on each hovercraft is determined, 
just as in the vertex-vertex collision check: 

vl = bodyl->vVelocityBody + 

(bodyl->vAngularVelocity A 
bodyl->vColtisionPoint); 


Angular Effects | 223 


www.it-ebooks.info 




v2 = body2->vVelocttyBody + 
(body2->vAngularVelocity 
body2->vCollisionPoint); 


vl = VRotate2D(bodyl->f0rientatlon, vl); 
v2 = VRotate2D(body2->f0rientatlon, v2); 

vRelatlveVelocity = (vl - v2); 

Vrn = vRelatlveVelocity * vCollistonNormal; 

In determining whether or not the vertex under consideration is in fact colliding with 
an edge, you have to check to see if the distance from the vertex is within your collision 
tolerance, and you also have to make sure the vertex actually projects onto the edge (that 
is, it does not project beyond the endpoints of the edge). Additionally, you need to make 
sure the relative normal velocity indicates that the points of contact are moving toward 
each other. Here’s how this check looks: 

if( (proj.Magnitude() > 0.0f) && 

(proj.Magnltude() <= edge.MagnitudeO) && 

(dlst <= ctol) && 

(Vrn < 0.0) ) 
haveNodeEdge = true; 

After CheckForCollision checks for vertex-vertex and vertex-edge collisions, it goes 
on to check for penetration: 

if(!haveNodeNode && !haveNodeEdge) 

1 

for(l=0; !<4 && Unterpenetrating; 1++) 

{ 

for(j=0; j<4 && linterpenetrating; j++) 

{ 

tf(j==3) 

edge = vList2[0] - vList2[j]; 

else 

edge = vList2[j+l] - vList2[j]; 

p = vListlfi] - vList2[j]; 
dot = p * edge; 
if(dot < 0) 

{ 

interpenetrating = true; 

} 

} 

} 

1 

This check is a standard point-in-polygon check using the vector dot product to deter¬ 
mine if any vertex of one polygon lies within the bounds of the other polygon. After 
this check, the function simply returns the appropriate result. Here again, 0 indicates 
no collision or penetration, 1 indicates a collision, and -1 indicates penetration. 


224 | Chapter 10: Implementing Collision Response 


www.it-ebooks.info 



With CheckForCollision out of the way, turn your attention to Applylmpulse, which 
also has to be revised to include angular effects. Specifically, you need to use the impulse 
formula that includes angular as well as linear effects (see Chapter 5), and you also have 
to apply the impulse to the hovercraft’s angular velocities in addition to their linear 
velocities. Here’s how the new Applylmpulse function looks: 

void ApplyImpulse(pRlgidBody2D bodyl, pRigidBody2D body2) 

{ 

float j; 

j = (-(1+fCr) * (vRelatlveVeloci.ty*vColllsionNormal)) / 

( (l/bodyl->fMass + l/body2->fMass) + 

(vCollisionNormal * (((bodyl->vCollisionPoint A 
vCollisionNormal)/bodyl->fInertia) A bodyl->vCollisionPoint)) + 
(vCollisionNormal * (((body2->vCollisionPoint A 
vCollisionNormal)/body2->fInertia) A body2->vCollisionPoint)) 

); 


bodyl->vVelocity += (j * vCollisionNormal) / bodyl->fMass; 
bodyl->vAngularVelocity += (bodyl->vCollisionPoint A 

(j * vCollisionNormal)) / 
bodyl->fInertia; 

body2->vVelocity -= (j * vCollisionNormal) / body2->fMass; 
body2->vAngularVelocity -= (body2->vCollisionPoint A 

(j * vCollisionNormal)) / 
body2->fInertia; 

} 

Remember, the impulse is applied to one hovercraft while its negative is applied to the 
other. 

That does it for this new version of the hovercraft simulation. If you run the program 
now, you’ll see that you can crash the hovercraft into each other and they bounce and 
rotate accordingly. This makes for a much more realistic simulation than the simple, 
linear collision response approach of the last section. Here again, you can play with the 
mass of each hovercraft and the coefficient of restitution to see how these parameters 
affect the collision response between the hovercraft. 


Angular Effects | 225 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 11 


Rotation in 3D Rigid-Body Simulators 


A fundamental difference between particles and rigid bodies is that we cannot ignore 
rotation of rigid bodies. This applies to both 2D and 3D rigid bodies. In two dimensions, 
it’s quite easy to express the orientation of a rigid body; you need only a single scalar to 
represent the body’s rotation about a single axis. In three dimensions, however, there 
are three primary coordinate axes about each of which a rigid body may rotate. More¬ 
over, a rigid body in three dimensions may rotate about any arbitrary axis, not neces¬ 
sarily one of the coordinate axes. 

In two dimensions, we say that a rigid body has only one rotational degree of freedom, 
whereas in three dimensions we say that a rigid body has three rotational degrees of 
freedom. This may lead you to infer that in three dimensions, you must have three scalar 
quantities to represent a body’s rotation. Indeed, this is a minimum requirement, and 
you’re probably already familiar with a set of angles that represent the orientation of a 
rigid body in 3D—namely, the three Euler angles (roll, pitch, and yaw) that we’ll talk 
about in Chapter 15. 

These three angles—roll, pitch, and yaw—are very intuitive and easy for us to visualize. 
For example, in an airplane the nose pitches up or down, the plane rolls (or banks) left 
or right, and the yaw (or heading) changes to the left or right. Unfortunately, there’s a 
problem with using these three Euler angles in rigid-body simulations. The problem is 
a numerical one that occurs when the pitch angle reaches plus or minus 90 degrees (tt/ 
2). When this happens, roll and yaw become ambiguous. Worse yet, the angular equa¬ 
tions of motion written in terms of Euler angles contain terms involving the cosine of 
the pitch angle in the denominator, which means that when the pitch angle is plus or 
minus 90 degrees the equations become singular (i.e., there’s division by 0). If this hap¬ 
pens in your simulation, the results would be unpredictable to say the least. Given this 
problem with Euler angles, you must use some other means of keeping track of orien¬ 
tation in your simulation. We’ll discuss two such means in this chapter—specifically, 
rotation matrices and quaternions. 


227 


www.it-ebooks.info 




Virtually every computer graphics book that we’ve read contains a chapter or section 
on using rotation matrices. Far fewer discuss quaternions, but if you’re familiar with 
quaternions, it’s probably in the same context as rotation matrices—that is, how they 
are used to rotate 3D points, objects, scenes, and points of view. In a simulation, however, 
you need to get a little more out of rotation matrices or quaternions and will use them 
in a different context than what you might be accustomed to. Specifically, you need to 
keep track of a body’s orientation in space and, moreover, the change in orientation over 
time. So it’s in this light that we’ll discuss rotation matrices and quaternions. We’ll try 
to be as concise as possible so as not to cloud the water with the proofs and derivations 
that you can find in the texts referred to in the Bibliography. 

Rotation Matrices 

A rotation matrix is a 3x3 matrix that, when multiplied with a point or vector, results 
in the rotation of that point about some axis, yielding a new set of coordinates. You can 
rotate points about axes in one coordinate system or you can use rotation matrices to 
convert points from one coordinate system to another, where one is rotated relative to 
the other. 

Rotating a vector by a rotation matrix is typically written as follows: if v is a vector, and 
R is a rotation matrix, then v’ is v rotated by R according to the formula: 

v’=Rv 

You can combine multiple rotation matrices reflecting multiple sequential rotations into 
a single rotation matrix using usual matrix multiplication. If the rotation matrices are 
expressed in terms of fixed, global coordinates, then they are combined as follows: 

R c = Ri R2 

Here R c is the combined rotation matrix reflecting a rotation first by R, and then by R 2 . 
If the rotation matrices are expressed in terms of rotating, body-fixed coordinates, then 
they are combined in the reverse order as follows: 

R c = R2 Ri 

We won’t go into the proof of this relation, but the reason it’s different depending on 
how you’ve defined your rotation matrices is that rotation matrices defined in fixed 
coordinates are unaffected by the rotation itself since the coordinate axes stay fixed. On 
the other hand, if the rotation matrices are defined relative to a coordinate system that 
is rotating due to sequential application of rotation matrices, then all rotation matrices 
after the first will be affected since they were first defined relative to the original state 
of the coordinate system—that is, before the first rotation matrix was applied. This 
means that the subsequent rotation matrices must be corrected to reflect the new system 


228 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 



as affected by the previous rotation before they can be correctly applied. In other words, 
you have to rotate R, by R, to get a new R 2 before applying it. All this happens to work 
out in such a way that you reverse the order of multiplication of rotation matrices when 
they are defined in a rotating coordinate system. 

Figure 11-1 shows a right-handed coordinate system that illustrates the directions of 
positive rotation about each coordinate axis. 



Let’s consider rotation around the z-axis where the point shown in Figure 11 -2 is rotated 
through an angle 0. 



The coordinates of the point before the rotation are (x,y,z) and after the rotation the 
coordinates are (x r ,y r , z r ). The rotated coordinates are related to the original coordinates 
and the rotation angle by the following: 


x r = x cos 0 — y sin 0 
y r = x sin 0 -)- y cos 0 
z r = z 


Rotation Matrices | 229 


www.it-ebooks.info 














Notice that since the point is rotating about the z-axis, its z coordinate remains un¬ 
changed. To write this in the vector-matrix notation, v’ = R v, let v = [x y z] and let R 
be the matrix: 


cos(0 z ) —sin(0 z ) 0 

sin(0 z ) cos(# z ) 0 

0 0 1 

Here v’ will be the new, rotated vector, v’ = [x r y r zj. 

Rotation about the x- and y-axes is similar to the z-axis; however, in those cases the x 
andy coordinates remain constant during rotations about each axis, respectively. Look¬ 
ing at rotation about each axis separately will yield three rotation matrices similar to the 
one we just showed you for rotation about the z-axis. 

For rotation about the x-axis, the matrix is: 

1 0 0 
0 cos (# x ) —sin(0 x ) 

0 sin(d x ) cos (0 X ) 

And for rotation about the y-axis, the matrix is: 

cos(d y ) 0 sin(0 y ) 

0 1 0 
—sin(0y) 0 cos(0 y ) 

These are the rotation matrices you typically see in computer graphics texts in the con¬ 
text of matrix transforms, such as translation, scaling, and rotation. You can combine 
all three of these matrices into a single rotation matrix to represent combinations of 
rotations about each coordinate axis, using matrix multiplication as mentioned earlier. 

In rigid-body simulations, you can use a rotation matrix to represent the orientation of 
a rigid body. Another way to think of it is the rotation matrix, when applied to the 
unrotated rigid body aligned with the fixed global coordinate system, will rotate the 
rigid body’s coordinates so as to resemble the body’s current orientation at any given 
time. This leads to another important consideration when using rotation matrices to 
keep track of orientation in rigid-body simulations: the fact that the rotation matrix will 
be a function of time. 

Once you set up your initial rotation matrix for the rigid body, you’ll never directly 
calculate it again from orientation angles; instead, the forces and moments applied to 
the rigid body will change the body’s angular velocity, likewise causing small changes 


230 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 









in orientation at each time step throughout the simulation. Thus, you can see that you 
must have a means of relating the rotation matrix to angular velocity so that you can 
update the orientation accordingly. The formula you need is as follows: 

d R / dt = Q R 

Here, fl is a skew symmetric matrix built from the angular velocity vector components 
as follows: 


fl = 


0 

<x > 7 


—a> z 0)y 

0 — (D x 

w x 0 


Notwithstanding a rigorous proof of this relation, it’s easy to see its beauty, which is that 
you can differentiate the rotation matrix by simply matrix multiplying by the angular 
velocity (in the form of fl). In a simulation you’ll know your initial rotation matrix, and 
you’ll calculate the angular velocity at each time step; thus, you can easily progress, or 
integrate, the rotation matrix. 

You should be able to see here that since you’ll only explicitly calculate the rotation 
matrix once and will update it with a matrix multiply, you won’t have to use computa¬ 
tionally expensive trigonometric functions during each time step. Further, you avoid 
the singularity problem mentioned in the introduction to this chapter. 

It should also be obvious that you gain these benefits at some price. First, you have to 
deal with nine parameters in the rotation matrix (each element in the 3x3 rotation 
matrix) to represent three angular degrees of freedom. Secondly, in order to do that, 
you need to impose constraints on the rotation matrix; specifically, you need to enforce 
the constraint that the matrix be orthogonal with a determinant of 1 so that it satisfies 
the following (each column in the matrix represents a unit vector, and they are all at 
right angles to each other): 1 


r t r = i 

Here R T is the transpose of R, and I is the identity matrix. Due to numerical errors such 
as roundoff and truncation, you’ll have to enforce this constraint very often in your 
simulation. Otherwise, your rotation matrix will do more than rotate your objects, it 
may scale or translate them too. 

Instead of dealing with nine parameters and trying to constrain six degrees of freedom 
so that only the three you want can be represented, you could take an alternative ap- 


1. Two vectors are orthogonal if their dot product is 0. 


Rotation Matrices | 231 


www.it-ebooks.info 





proach that lets you keep the advantages rotation matrices have to offer, but at a cheaper 
price. That alternative, quaternions, is the subject of the next section. 

Quaternions 

Quaternions are somewhat of a mathematical oddity. They were developed over 100 
years ago by William Hamilton through his work in complex (imaginary) math but have 
found very little practical use. A quaternion is a quantity, kind of like a vector, but made 
up of four components. It is typically written in the form: 

q = qo + q x * + q y j + q z k 

A quaternion is really a four-dimensional quantity in complex space and, unfortunately, 
does not lend itself to visualization. Don’t worry, though: our use of quaternions to 
represent orientation in three dimensions does allow us to attach a physical meaning to 
them, as you’ll see in a moment. 

Of particular interest to us is what’s known as a unit quaternion that satisfies the fol¬ 
lowing: 


qo 2 + q x 2 + q y 2 + q z 2 = i 

This is analogous to a normalized, or unit, vector. 

You can also write a quaternion in the form q = [q 0 , v], where v is the vector, q y i + q y ) 
+ q z k, and q„ is a scalar. In the context of rotation, v represents the direction in which 
the axis of rotation points. For a given rotation, 0, about an arbitrary axis represented 
by the unit vector u, the representative quaternion can be written as follows: 

q = [cos(0/2), sin(0/2) u] 

This is illustrated in Figure 11 -3 for an arbitrary rigid body rotating about an axis passing 
through its center of gravity. The rigid body rotates through an angle 0 from the position 
shown in light gray to the position shown in dark gray. Here, the unit vector u is the 
vector v normalized to unit length. 


232 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 




You can readily see that quaternions, when used to represent rotation or orientation, 
require you to deal with only four parameters instead of nine, subject to the easily 
satisfied constraint that the quaternion be a unit quaternion. 

The use of quaternions to represent orientation is similar to how you would use rotation 
matrices. First, you set up a quaternion that represents the initial orientation of the rigid 
body at time 0 (this is the only time you’ll calculate the quaternion explicitly). Then you 
update the orientation to reflect the new orientation at a given instant in time using the 
angular velocities that are calculated for that instant. As you can see here, the differential 
equation relating an orientation quaternion to angular velocity is very similar to that 
for rotation matrices: 


dq/dt = (1/2) © q 

Here, the angular velocity is written in quaternion form as [0, to] and is expressed in 
fixed, global coordinates, (to is still angular velocity, but you have to put it in quaternion 
form instead of vector form when multiplying it by a quaternion q.) If to is expressed in 
rotating, body-fixed coordinates, then you need to use this equation: 

dq/dt = (1/2) q © 

As with rotation matrices, you can use quaternions to rotate points or vectors. If v is a 
vector, then v’ is the rotated vector subject to the quaternion q: 

v’= qvq* 

Here q* is the conjugate of the quaternion q defined as: 

q* = qo - q x i - q y j - q z k 

You can also use the preceding formula to convert vectors from one coordinate system 
to another, where one is rotated relative to the other. You have to do this, for example, 
in your simulations where you are converting forces defined in fixed, global coordinates 


Quaternions | 233 


www.it-ebooks.info 





to rotating, body-fixed coordinates so that you can apply the forces to the body; or you 
might have to convert a body’s velocity defined in global coordinates to body coordinates 
so that you can use the velocity in force calculations. 


Quaternion Operations 


As with vectors and matrices, quaternions have their own rules for the various opera¬ 
tions that you’ll need, such as multiplication, addition, subtraction, and so on. To make 
it easy on you, we’ve included sample code in Appendix C that implements all of the 
quaternion operations you’ll need; however, we want to highlight a few of the more 
important ones here. 

The Quaternion class is defined with a scalar component, n, and vector component, v, 
where v is the vector, xi + yj + zk. The class has two constructors, one of which initializes 
the quaternion to 0, and the other of which initializes the elements to those passed to 
the constructor: 

class Quaternion { 

public: 


float n; // number (scalar) part 

Vector v; // vector part: v.x, v.y, v.z 


Quaternion(void); 

Quaternion(float e0, float el, float e2, float e3); 


}; 


Magnitude 

The Magnitude method returns the magnitude of the quaternion according to the fol¬ 
lowing formula: 



This is similar to calculating the magnitude of a vector, except that for quaternions you 
have to take the fourth term, the scalar n, into account. 

Here’s the code that calculates the magnitude for our Quaternion class: 


inline float Quaternion::Magnitude(void) 
{ 


return (float) sqrt(n*n + v.x*v.x + v.y*v.y + v.z*v.z); 

} 


234 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 




Conjugate: The ~ operator 

The conjugate of the product of quaternions is equal to the product of the quaternion 
conjugates, but in reverse order: 


~(qp) = (~p)(~q) 


Here’s the code that computes the conjugate for our Quaternion class: 


Quaternion operator-(void) const { return Quaternion( n. 


-v.x, 

-v.y. 


-v.z);} 


QVRotate 

This function rotates the vector v by the unit quaternion q according to this formula: 

p’ = (q)(v)(~q) 

Here, ~q is the conjugate of the unit quaternion, q: 

inline Vector QVRotate(Quaternion q, Vector v) 

{ 

Quaternion t; 
t = q*v*(~q); 
return t.GetVectorQ; 

} 

This operator takes the conjugate of the quaternion, ~q, which is simply the negative of 
the vector part. If q = [n, x i + y j + zk], then ~q = [n, (-x) i + (-y)) + (-z) k]. 

Quaternion multiplication: The * operator 

This operator performs quaternion multiplication according to the following formula: 

q p = n q n p - v q • v p + n q v p + n p v q + (v q X v p ) 

Here, n q n p - v q • v p is the scalar part of the result while n q v p + n p v q + (v q x v p ) is the 
vector part. Also note that v q and v p are the vector parts of q and p, respectively, • is the 
vector dot product operator, and x is the vector cross product operator. 

Quaternion multiplication is associative but not commutative, thus: 

q(ph) = (qp)h 

qp^pq 

Here’s the code that multiplies two Quaternions, ql and q2: 


Quaternions | 235 


www.it-ebooks.info 



Inline Quaternion operator*(Quaternlon ql, Quaternion q2) 

{ 

return Quaternlon(ql.n*q2.n - ql.v.x*q2.v.x 

- ql.v.y*q2.v.y - ql.v.z*q2.v.z, 
ql.n*q2.v.x + ql.v.x*q2.n 

+ ql.v.y*q2.v.z - ql.v.z*q2.v.y, 
ql.n*q2.v.y + ql.v.y*q2.n 

+ ql.v.z*q2.v.x - ql.v.x*q2.v.z, 
ql.n*q2.v.z + ql.v.z*q2.n 

+ ql.v.x*q2.v.y - ql.v.y*q2.v.x); 

} 

Vector multiplication: The * operator 

This operator multiplies the quaternion, q, by the vector v as though the vector v were 
a quaternion with its scalar component equal to 0. There are two forms of this operator 
depending on the order in which the quaternion and vector are encountered. Since v is 
assumed to be a quaternion with its scalar part equal to 0, the rules of multiplication 
follow those outlined earlier for quaternion multiplication: 

Inline Quaternion operator*(Quaternlon q, Vector v) 

{ 

return Quaternlon( -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z), 

q.n*v.x + q.v.y*v.z - q.v.z*v.y, 
q.n*v.y + q.v.z*v.x - q.v.x*v.z, 
q.n*v.z + q.v.x*v.y - q.v.y*v.x); 

} 

Inline Quaternion operator*(Vector v, Quaternion q) 

{ 

return Quaternlon( -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z), 

q.n*v.x + q.v.z*v.y - q.v.y*v.z, 
q.n*v.y + q.v.x*v.z - q.v.z*v.x, 
q.n*v.z + q.v.y*v.x - q.v.x*v.y); 

} 

MakeQFromEulerAngles 

This function constructs a quaternion from a set of Euler angles. 

For a given set of Euler angles, yaw (t|/), pitch (x), and roll (<p), defining rotation about 
the z-axis, then the y-axis, and then the x-axis, you can construct the representative 
rotation quaternion. You do this by first constructing a quaternion for each Euler angle 
and then multiplying the three quaternions following the rules of quaternion multipli¬ 
cation. Here are the three quaternions representing each Euler rotation angle: 

qroii = [cos(cp/2), (sin(cp/2)) i + 0 j + 0 k] 
qpitch = [cos(t 12), 0 i + (sin(x 12)) j + 0 k] 
q yaw = [cos(\|/ 12), 0 i + 0 j + (sin(\|/ 12)) k] 


236 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 




Each one of these quaternions is of unit length. 2 

Now you can multiply these quaternions to obtain a single one that represents the ro¬ 
tation, or orientation, defined by the three Euler angles: 

Q = by aw Q pi tell Qroll 

Performing this multiplication yields: 

q = [{cos(cp/2) cos(t 12) cos(q/ 12) + sin(cp/2) sin(x /2) sin(\p 12)}, 

{sin(cp/2) cos(t 12) cos(\|/ 12) - cos(cp/2) sin(x 12) sin(\|/ /2)} i + 

{cos(cp/2) sin(x 12) cos(\|/ 12) + sin(cp/2) cos(x 12) sin(\|/ /2)} j + 

{cos(cp/2) cos(x 12) sin(\|/ 12) - sin(cp/2) sin(x 12) cos(\|/ 12)} k] 

Here’s the code that takes three Euler angles and returns a quaternion: 

Inline Quaternion MakeQFromEulerAngles(float x, float y, float z) 

{ 

Quaternion q; 

double roll = DegreesToRadians(x); 

double pitch = DegreesToRadians(y); 

double yaw = DegreesToRadians(z); 

double cyaw, cpitch, croll, syaw, spitch, sroll; 

double cyawcpitch, syawspitch, cyawspitch, syawcpitch; 

cyaw = cos(0.5f * yaw); 
cpitch = cos(0.5f * pitch); 
croll = cos(0.5f * roll); 
syaw = sin(0.5f * yaw); 
spitch = sin(0.5f * pitch); 
sroll = sin(0.5f * roll); 

cyawcpitch = cyaw*cpitch; 
syawspitch = syaw*spitch; 
cyawspitch = cyaw*spitch; 
syawcpitch = syaw*cpitch; 

q.n = (float) (cyawcpitch * croll + syawspitch * sroll); 

q.v.x = (float) (cyawcpitch * sroll - syawspitch * croll); 

q.v.y = (float) (cyawspitch * croll + syawcpitch * sroll); 

q.v.z = (float) (syawcpitch * croll - cyawspitch * sroll); 

return q; 

} 


2. You can verify this by recalling the trigonometric relation cos 2 0 + sin 2 0=1. 


Quaternions | 237 


www.it-ebooks.info 



MakeEulerAnglesFromQ 

This function extracts the three Euler angles from a given quaternion. 

You can extract the three Euler angles from a quaternion by first converting the qua¬ 
ternion to a rotation matrix and then extracting the Euler angles from the rotation 
matrix. Let R be a nine-element rotation matrix: 


r n 

r 12 


t*21 

?22 

r 23 

Til 

1*32 

r 33 


and let q be a quaternion: 

q = [n, x i + y j + z k] 


Then each element in R is calculated from q as follows: 

9999 

r u = n- + x z - y z - z z 
i 2 i = 2xy+2zn 
r 3 i = 2zx — 2yn 
r \2 = 2xy — 2zn 
r 22 = n 2 - x 2 + y 2 - z 2 
r 3 2 = 2zy + 2xn 
rj 3 = 2xz + 2yn 
r 23 = 2yz — 2xn 
r 33 = n- - x- - y z + z z 


To extract the Euler angles, yaw (\|/), pitch (t), and roll (cp), from R, you can use these 
relations: 


tan i|/ = r 2 i / ru 
sin t = -r 3 i 
tan cp = r 32 / r 33 


Here’s the code that extracts the three Euler angles, returned in the form of a Vector, 
from a given quaternion: 

inline Vector MakeEulerAnglesFromQ(Quaternion q) 

{ 

double rll, r21, r31, r32, r33, rl2, rl3; 

double q00, qll, q22, q33; 

double tnp; 

Vector u; 


238 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 





q00 = q.n * q.n; 
qll = q.v.x * q.v.x; 
q22 = q.v.y * q.v.y; 
q33 = q.v.z * q.v.z; 

rll = q00 + qll - q22 - q33; 
r21 = 2 * (q.v.x*q.v.y + q.n*q.v.z); 
r31 = 2 * (q.v.x*q.v.z - q.n*q.v.y); 
r32 = 2 * (q.v.y*q.v.z + q.n*q.v.x); 
r33 = q00 - qll - q22 + q33; 

tnp = fabs(r31); 
if (trip > 0.999999) 

{ 

rl2 = 2 * (q.v.x*q.v.y - q.n*q.v.z); 
rl3 = 2 * (q.v.x*q.v.z + q.n*q.v.y); 

u.x = RadlansToDegrees(0.0f); //roll 

u.y = RadiansToDegrees((float) (-(pl/2) * r31/tnp)); // pitch 

u.z = RadiansToDegrees((float) atan2(-rl2, -r31*rl3)); // yaw 
return u; 

} 

u.x = RadiansToDegrees((float) atan2(r32, r33)); // roll 
u.y = RadiansToDegrees((float) asin(-r31)); // pitch 

u.z = RadiansToDegrees((float) atan2(r21, rll)); // yaw 
return u; 


} 

Quaternions in 3D Simulators 

The quaternion operations just presented are required when you are using quaternions 
to represent orientation in 3D simulations. All the 3D simulations discussed in this book 
use these quaternion operations, and in this section we’ll highlight where they are used 
in the context of the airplane example presented in Chapter 15. 

When initializing the orientation of the airplane, you have to set its orientation qua¬ 
ternion to something corresponding to the Euler angles you desire. You do so as follows: 

Airplane.qOrientatlon = MakeQFromEulerAngles(iRoll, IPitch, iYaw); 

In this code sample, Airplane is a rigid-body class with the property qOrientation, 
which represents the orientation quaternion, which is a Quaternion class. iRoll, 
iPitch, and iYaw are the three Euler angles describing the orientation of the airplane. 

If at any time you want to report the Euler angles—for example, in a heads-up display¬ 
like interface for the game player—you can use MakeEulerAnglesFrornQ, as follows: 


Quaternions in 3D Simulators | 239 


www.it-ebooks.info 



// get the Euler angles for our information 
Vector u; 

u = MakeEulerAnglesFromQ(Airplane.qOrientation); 

Airplane.vEulerAngles.x = u.x; // roll 

Airplane.vEulerAngles.y = u.y; // pitch 

Airplane.vEulerAngles.z = u.z; // yaw 

Very often, it’s more convenient to calculate loads on an object like the airplane using 
body-fixed coordinates. For example, when computing aerodynamic drag on the air¬ 
plane, you’ll want to know the relative air velocity over the aircraft in body-fixed coor¬ 
dinates. The resulting drag force will also be in body-fixed coordinates. However, when 
resolving all the loads on the aircraft to determine its motion in earth-fixed coordinates, 
you’ll want to convert those forces from body-fixed coordinates to earth-fixed coordi¬ 
nates. You can use QVRotate to rotate any vector, such as a force vector, from one co¬ 
ordinate system to another. The following code sample shows how QVRotate is used to 
convert a force vector in body-fixed coordinates to the equivalent force in earth-fixed 
coordinates. 

void CalcAirplaneLoads(vold) 

{ 


// Convert forces from model space to earth space 
Airplane.vForces = QVRotate(Airplane.qOrlentation, Fb); 


} 

Throughout the simulation, you’ll have to update the airplane’s orientation by integrat¬ 
ing the angular equations of motion. The first step in handling angular motion is to 
calculate the new angular velocity at a given time step based on the previously calculated 
moments acting on the airplane and its mass properties. We do this in body coordinates 
using the angular equation of motion: 

£ M cg = dH cg /dt = I (dco/dt) + (to X (I to)) 

The next step is to integrate again to update the airplane’s orientation, which is expressed 
as a quaternion. Here, you need to use the differential equation relating an orientation 
quaternion to angular velocity that we discussed earlier: 

dq/dt = (1/2) to q 


240 | Chapter 11: Rotation in 3D Rigid-Body Simulators 


www.it-ebooks.info 



Next, to enforce the constraint that this orientation quaternion be a unit quaternion, 
you must normalize the orientation quaternion. The following code sample illustrates 
these steps: 


// calculate the angular velocity of the airplane in body space: 
Airplane.vAngularVelocity += Airplane.nlnertialnverse * 

(Airplane.vMoments - 
(Airplane. vAngularVelocity'' 
(Airplane.mlnertia * 

Airplane.vAngularVelocity))) 

* dt; 

// calculate the new rotation quaternion: 

Airplane.qOrientation += (Airplane.qOrientation * 

Airplane.vAngularVelocity) * 

(0.5f * dt); 

// now normalize the orientation quaternion: 
mag = Airplane. qOrientation. MagnitudeQ; 
if (mag != 0) 

Airplane.qOrientation /= mag; 

// calculate the velocity in body space: 

// (we'll need this to calculate lift and drag forces) 

Airplane.vVelocityBody = QVRotate(~Airplane.qOrientation, 

Airplane.vVelocity); 


Notice the last line of code in the preceding sample. That line converts the airplanes 
velocity vector from earth-fixed coordinates to body-fixed coordinates using QVRo 
tate. Recall that it’s more convenient to compute body forces in body-fixed coordinates. 
QVRot a t e allows you to work with vectors back and forth from body-fixed to earth-fixed 
coordinates. 


Quaternions in 3D Simulators | 241 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 12 


3D Rigid-Body Simulator 


In this chapter we’ll show you how to make the leap from 2D to 3D by implementing a 
rigid-body simulation of an airplane. Specifically, this is a simulation of the hypothetical 
airplane model that we’ll discuss extensively in Chapter 15. This airplane is of typical 
configuration with its large wings forward, its elevators aft, a single vertical tail, and 
plain flaps fitted on the wings. 

As with the 2D simulator in previous chapters, we’ll concentrate on the code that im¬ 
plements the physics part of the simulator and not the platform-specific GUI aspects of 
the simulations. 

As in 2D, there are four main elements to this 3D simulation—the model, integrator, 
user input, and rendering. Remember, the model refers to your idealization of the thing 
—an airplane, in this case—that you are trying to simulate, while the integrator refers 
to the method by which you integrate the differential equations of motion. These two 
elements take care of most of the physics of the simulation. The user input and rendering 
elements refer to how you’ll allow the user to interact with and view your simulation. 

In this simulation, the world coordinate system has its positive x-axis pointing into the 
screen, its positive y-axis pointing to the left of your screen, and the positive z-axis 
pointing up. Also, the local, or body-fixed, coordinate system has its positive x-axis 
pointing toward the front of the airplane, its positive y-axis pointing to the port side 
(left side), and its positive z-axis pointing up. Since this is a 3D simulation of an airplane, 
once you get it running, you’ll be able to fly in any direction, looping, banking, diving, 
and climbing, or performing any other aerobatic maneuver you desire. 

Model 

One of the most important aspects of this simulation is the flight model. We’ll spend all 
of Chapter 15 discussing the physics behind this flight model, so we won’t include that 
discussion here except to introduce a few key bits of code. 


243 


www.it-ebooks.info 




To implement the flight model, you first need to prepare a rigid-body structure to en¬ 
capsulate all of the data required to completely define the state of the rigid body at any 
instant during the simulation. We’ve defined a structure called RigidBody for this pur¬ 
pose: 

typedef struct _RtgidBody { 


float 

fMass; 

// 

total mass 

Matrix3x3 

mlnertia; 

// 

mass moment of inertia 



// 

in body coordinates 

Matrix3x3 

mlnertialnverse; 

// 

inverse of mass moment of inertia 

Vector 

vPosition; 

// 

position in earth coordinates 

Vector 

vVelocity; 

// 

velocity in earth coordinates 

Vector 

vVelocityBody; 

// 

velocity in body coordinates 

Vector 

vAngularVelocity;// 

angular velocity in body coordinates 

Vector 

vEulerAngles; 

// 

Euler angles in body coordinates 

float 

fSpeed; 

// 

speed (magnitude of the velocity) 

Quaternion 

qOrientation; 

// 

orientation in earth coordinates 

Vector 

vForces; 

// 

total force on body 

Vector 

vMoments; 

// 

total moment (torque) on body 

} RigidBody, *pRigidBody; 




You’ll notice that it is very similar to the RigidBody2D structure that we used in the 2D 
hovercraft simulation. One significant difference, however, is that in the 2D case, ori¬ 
entation was a single float value, and now in 3D it’s a quaternion of type Quaternion. 
We discussed the use of quaternions for tracking rigid-body orientation in the previous 
chapter, and Appendix C contains a complete definition of the Quaternion class. 

The next step in defining the flight model is to prepare an initialization function to 
initialize the airplane at the start of the simulation. For this purpose, we’ve prepared a 
function called InltlallzeAlrplane: 

RigidBody Airplane; // global variable representing the airplane 


void InitializeAirplane(void) 

{ 

float iRoll, iPitch, iYaw; 

// Set initial position 
Airplane.vPosition.x = -5000.0f; 
Airplane.vPosition.y = 0.0f; 
Airplane.vPosition.z = 2000.0f; 

// Set initial velocity 
Airplane.vVelocity.x = 60.0f; 
Airplane.vVelocity.y = 0.0f; 
Airplane.vVelocity.z = 0.0f; 


244 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 



Airplane.fSpeed = 60.0f; 


// Set initial angular velocity 
Airplane.vAngularVelocity.x = 0.0f; 

Airplane.vAngularVelocity.y = 0.0f; 

Airplane.vAngularVelocity.z = 0.0f; 

// Set the initial thrust, forces, and moments 
Airplane.vForces.x = 500.0f; 

Airplane.vForces.y = 0.0f; 

Airplane.vForces.z = 0.0f; 

ThrustForce = 500.0; 

Airplane.vMoments.x = 0.0f; 

Airplane.vMoments.y = 0.0f; 

Airplane.vMoments.z = 0.0f; 

// Zero the velocity in body space coordinates 
Airplane.vVelocityBody.x = 0.0f; 

Airplane.vVelocityBody.y = 0.0f; 

Airplane.vVelocityBody.z = 0.0f; 

// Set these to false at first, 

// you can control later using the keyboard 
Stalling = false; 

Flaps = false; 

// Set the initial orientation 
iRoll = 0.0f; 
iPitch = 0.0f; 
iYaw = 0.0f; 

Airplane.qOrientation = MakeQFromEulerAngles(iRoll, iPitch, iYaw); 

// Now go ahead and calculate the plane's mass properties 
CalcAirplaneMassProperties(); 

} 

This function sets the initial location, speed, attitude, and thrust for the airplane and 
goes on to calculate its mass properties by making a call to CalcAirplaneMassProper 
ties. You’ll see much more of this function in Chapter 15, so we won’t show the whole 
thing here. We do want to point out a portion of the code that is distinctly different from 
what you do in a 2D simulation, and that’s the calculation of the moment of inertia 
tensor: 

void CalcAirplaneMassProperties(void) 

{ 


// Now calculate the moments and products of inertia for the 
// combined elements. 


Model | 245 


www.it-ebooks.info 



// (This 
Ixx = 0; 
Ixy = 0; 
for (i = 
{ 

Ixx 


Iyy 


Izz 


Ixy 

Ixz 

lyz 

} 


inertia matrix (tensor) is in body coordinates) 

Iyy = 0; Izz = 0; 

Ixz = 0; lyz = 0; 

0; i< 8; i++) 

+= Element[i].vLocallnertia.x + Elementfi].fMass * 
(Element[i].vCGCoords.y*Element[i].vCGCoords.y + 
Element[i].vCGCoords.z*Element[i].vCGCoords.z); 

+= Element[i].vLocallnertia.y + Element[i].fMass * 
(Element[i].vCGCoords.z*Element[l].vCGCoords.z + 
Element[i].vCGCoords.x*Element[i].vCGCoords.x); 

+= Element[i].vLocallnertia.z + Elementfi].fMass * 
(Element[i].vCGCoords.x*Element[i].vCGCoords.x + 
Element[i].vCGCoords.y*Element[i].vCGCoords.y); 

+= Element[i].fMass * (Elementfi].vCGCoords.x * 
Element[i].vCGCoords.y); 

+= Element[i].fMass * (Element[i].vCGCoords.x * 
Element[i].vCGCoords.z); 

+= Element[i].fMass * (Element[i].vCGCoords.y * 
Element[i].vCGCoords.z); 


// Finally set up the airplane's mass 
// inverse of the inertia matrix 
Airplane.fMass = mass; 

Airplane.mlnertia.ell = Ixx; 

Airplane.mlnertia.el2 = -Ixy; 
Airplane.mlnertia.el3 = -Ixz; 
Airplane.mlnertia.e21 = -Ixy; 
Airplane.mlnertia.e22 = Iyy; 

Airplane.mlnertia.e23 = -lyz; 
Airplane.mlnertia.e31 = -Ixz; 
Airplane.mlnertia.e32 = -lyz; 
Airplane.mlnertia.e33 = Izz; 


and its inertia matrix and take the 


Airplane.mlnertialnverse = Airplane.mlnertia.Inverse(); 

} 

The airplane is modeled by a number of elements, each representing a different part of 
the airplane’s structure—for example, the tail rudder, elevators, wings, and fuselage (see 
Chapter 15 for more details). The code specified here takes the mass properties of each 
element and combines them, using the techniques discussed in Chapter 7 to come up 
with the combined inertia tensor for the entire aircraft. The important distinction be¬ 
tween these calculations in a 3D simulation and the 2D simulation is that here the inertia 
is a tensor and in 2D it is a single scalar. 

InitializeAirplane is called at the very start of the program. We found it convenient 
to make the call right after the applications main window is created. 

The final part of the flight model has to do with calculating the forces and moments 
that act on the airplane at any given instant in time during the simulation. As in the 2D 


246 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 



hovercraft simulation, without this sort of function, the airplane will do nothing. For 
this purpose we’ve defined a function called CalcAirpla neLoad s, which is called at every 
step through the simulation. This function relies on a couple of other functions— 
namely, LiftCoefficient, DragCoefficient, RudderLiftCoefficient, and Rudder 
DragCoef f icient. All of these functions are shown and discussed in detail in the section 
“Modeling” on page 305 in Chapter 15. 

For the most part, the code contained in CalcAirplaneLoads is similar to the code you’ve 
seen in the CalcLoads function of the hovercraft simulation. CalcAirplanLoads is a 
little more involved since the airplane is modeled by a number of elements that con¬ 
tribute to the total lift and drag on the airplane. There’s also another difference that 
we’ve noted here: 

void CalcAtrptaneLoads(vold) 

{ 


// Convert forces from node! space to earth space 
Airplane.vForces = QVRotate(Airplane.qOrientation, Fb); 

// Apply gravity (g is defined as -32.174 ft/s A 2) 
Airplane.vForces.z += g * Airplane.fMass; 


} 

Just about all of the forces acting on the airplane are first calculated in body-fixed co¬ 
ordinates and then converted to earth-fixed coordinates before the gravity force is ap¬ 
plied. The coordinate conversion is effected through the use of the function QVRotate, 
which rotates the force vector based on the airplane’s current orientation, represented 
by a quaternion. 1 

Integration 

Now that the code to define, initialize, and calculate loads on the airplane is complete, 
you need to develop the code to actually integrate the equations of motion so that the 
simulation can progress through time. The first thing you need to do is decide on the 
integration scheme that you want to use. In this example, we decided to go with the 
basic Euler’s method. We’ve already discussed some better methods in Chapter 7. We’re 
going with Euler’s method here because it’s simple and we didn’t want to make the code 


1. QVRotate is defined in Appendix C. 


Integration | 247 


www.it-ebooks.info 



here overly complex, burying some key code that we need to point out to you. In practice, 
you’re better off using one of the other methods we discuss in Chapter 7 instead of Euler’s 
method. With that said, we’ve prepared a function called StepSimulation that handles 
all of the integration necessary to actually propagate the simulation: 

void StepSimulation(float dt) 

{ 

// Take care of translation first: 

// (If this body were a particle, this is all you would need to do.) 

Vector Ae; 

// calculate all of the forces and moments on the airplane: 

CalcAirplaneLoads(); 

// calculate the acceleration of the airplane in earth space: 

Ae = Airplane.vForces / Airplane.fMass; 

// calculate the velocity of the airplane in earth space: 

Airplane.vVelocity += Ae * dt; 

// calculate the position of the airplane in earth space: 

Airplane.vPosition += Airplane.vVelocity * dt; 


// Now handle the rotations: 
float mag; 

// calculate the angular velocity of the airplane in body space: 
Airplane.vAngularVelocity += Airplane.mlnertialnverse * 

(Airplane.vMoments - 
(Airplane.vAngularVelocity A 
(Airplane.mlnertia * 

Airplane.vAngularVelocity))) 

* dt; 

// calculate the new rotation quaternion: 

Airplane.qOrientation += (Airplane.qOrientation * 

Airplane.vAngularVelocity) * 

(0.5f * dt); 

// now normalize the orientation quaternion: 
mag = Airplane. qOrientation. MagnitudeQ; 
if (mag != 0) 

Airplane.qOrientation /= mag; 

// calculate the velocity in body space: 

// (we'll need this to calculate lift and drag forces) 

Airplane.vVelocityBody = QVRotate(~Airplane.qOrientation, 

Airplane.vVelocity); 


// calculate the air speed: 


248 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 




Airplane.fSpeed = Airplane.vVelocity.Magnitude(); 


// get the Euler angles for our information 
Vector u; 

u = MakeEulerAnglesFromQ(Airplane.qOrientation); 
Airplane.vEulerAngles.x = u.x; // roll 

Airplane.vEulerAngles.y = u.y; // pitch 

Airplane.vEulerAngles.z = u.z; // yaw 


} 

The very first thing that StepSimulation does is call CalcAirplaneLoads to calculate 
the loads acting on the airplane at the current instant in time. StepSimulation then 
goes on to calculate the linear acceleration of the airplane based on current loads. Next, 
the function goes on to integrate, using Eulers method, once to calculate the airplane’s 
linear velocity and then a second time to calculate the airplanes position. As we’ve 
commented in the code, if you were simulating a particle this is all you would have to 
do; however, since this is not a particle, you need to handle angular motion. 

The first step in handling angular motion is to calculate the new angular velocity at this 
time step, using Euler integration, based on the previously calculated moments acting 
on the airplane and its mass properties. We do this in body coordinates using the fol¬ 
lowing equation of angular motion but rewritten to solve for do: 

£ M cg = dH cg /dt = I (dw/dt) + (to x (I to)) 

The next step is to integrate again to update the airplane’s orientation, which is expressed 
as a quaternion. Here, you need to use the differential equation relating an orientation 
quaternion to angular velocity that we showed you in Chapter 11: 

dq/dt = (1/2) to q 

Next, to enforce the constraint that this orientation quaternion be a unit quaternion, 
the function goes ahead and normalizes the orientation quaternion. 

Since the linear velocity was previously calculated in global coordinates (the fixed co¬ 
ordinate system), and since CalcAirplaneLoads needs the velocity in the body-fixed 
(rotating) coordinates system, the function goes ahead and rotates the velocity vector, 
storing the body-fixed vector in the vVelocityBody member of the RigidBody structure. 
This is done here as a matter of convenience and uses the quaternion rotation function 
QVRotate to rotate the vector based on the airplane’s current orientation. Notice here 
that we use the conjugate of the orientation quaternion since we’re now rotating from 
global coordinates to body coordinates. 


Integration | 249 


www.it-ebooks.info 




As another convenience, we calculate the air speed, which is simply the magnitude of 
the linear velocity vector. This is used to report the air speed in the main window title 
bar. 

Lastly, the three Euler angles—roll, pitch, and yaw—are extracted from the orientation 
quaternion so that they can also be reported in the main window title bar. The function 
to use here is MakeEulerAnglesFropiQ, which is defined in Appendix C. 

Don’t forget, StepSimulation must be called once per simulation cycle. 

Flight Controls 

At this point, the simulation still won’t work very well because you have not implemented 
the flight controls. The flight controls allow you to interact with the airplane’s various 
controls surfaces in order to actually fly the plane. We’ll use the keyboard as the main 
input device for the flight controls. Remember, in a physics-based simulation such as 
this one, you don’t directly control the motion of the airplane; you control only how 
various forces are applied to the airplane, which then, by integration over time, affect 
the airplane’s motion. 

For this simulation, the flight stick is simulated by the arrow keys. The down arrow pulls 
back on the stick, raising the nose; the up arrow pushes the stick forward, causing the 
nose to dive; the left arrow rolls the plane to the left (port side); and the right arrow 
rolls the plane to the right (starboard side). The X key applies left rudder action to cause 
the nose of the plane to yaw toward the left, while the C key applies right rudder action 
to cause the nose to yaw toward the right. Thrust is controlled by the A and Z keys. The 
A key increments the propeller thrust by 100 pounds, and the Z key decrements the 
thrust by 100 pounds. The minimum thrust is 0, while the maximum available thrust is 
3,000 pounds. The F key activates the landing flaps to increase lift at low speed, while 
the D key deactivates the landing flaps. 

We control pitch by deflecting the flaps on the aft elevators; for example, to pitch the 
nose up, we deflect the aft elevator flaps upward (that is, the trailing edge of the elevator 
is raised with respect to the leading edge). We control roll in this simulation by applying 
the flaps differentially; for example, to roll right, we deflect the right flap upward and 
the left flap downward. Finally, we control yaw by deflecting the vertical tail rudder; for 
example, to yaw left, we deflect the trailing edge of the tail rudder toward the left. 

We’ve prepared several functions to handle the flight controls that should be called 
whenever the user is pressing one of the flight control keys. There are two functions for 
the propeller thrust: 

void IncThrust(vold) 

{ 

ThrustForce += _DTHRUST; 
if(ThrustForce > _MAXTHRUST) 


250 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 



ThrustForce = _MAXTHRUST; 

} 

void DecThrust(void) 

{ 

ThrustForce -= _DTHRUST; 
if(ThrustForce < 0) 

ThrustForce = 0; 

} 

IncThrust simply increases the thrust by _DTHRUST checking to make sure it does not 
exceed _MAXTHRUST. We’ve defined _DTHRUST and _MAXTHRUST as follows: 

#define _DTHRUST 100.0f 

#define _MAXTHRUST 3000.0f 

DecTh rust, on the other hand, decreases the thrust by _DTHRUST checking to make sure 
it does not fall below 0. 

To control yaw, we’ve prepared three functions that manipulate the rudder: 

void LeftRudder(void) 

{ 

Element[6].flncidence = 16; 

} 

void RightRudder(void) 

{ 

Element[6].flncidence = -16; 

} 

void ZeroRudder(void) 

{ 

Element[6].flncidence = 0; 

} 

LeftRudder changes the incidence angle of Element[6], the vertical tail rudder, to 16 
degrees, while RightRudder changes the incidence angle to -16 degrees. ZeroRudder 
centers the rudder at 0 degrees. 

The ailerons, or flaps, are manipulated by these functions to control roll: 

void RollLeft(void) 

{ 

Element[0].iFlap = 1; 

Element[3].iFlap = -1; 

} 

void RollRight(void) 

{ 

Element[0].iFlap = -1; 

Element[3].iFlap = 1; 

} 


Flight Controls | 251 


www.it-ebooks.info 



void ZeroAilerons(void) 

{ 

Etement[0].iFtap = 0; 

Element[3].iFlap = 0; 

} 

RollLeft deflects the port aileron, located on the port wing section (Element[0]), up¬ 
ward, and the starboard aileron, located on the starboard wing section (Element[3]), 
downward. RollRight does just the opposite, and ZeroAilerons resets the flaps back 
to their undeflected positions. 

We’ve defined yet another set of functions to control the aft elevators so as to control 
pitch: 

void PitchUp(void) 

{ 

Element[4].iFtap = 1; 

Etement[5].iFtap = 1; 

} 

void PitchDown(void) 

{ 

Element[4].iFtap = -1; 

ElementfS].iFtap = -1; 

} 


void ZeroEtevators(void) 

{ 

Etement[4].iFtap = 0; 

Etement[5].iFtap = 0; 

1 

Element[4] and Element[5] are the elevators. Pitchllp deflects their flaps upward, and 
PitchDown deflects their flaps downward. ZeroElevators resets their flaps back to their 
undeflected positions. 

Finally, there are two more functions to control the landing flaps: 
void FtapsDown(void) 

f 

Etementfl].iFtap = - 1 ; 

Etement[2].iFtap = -1; 

Ftaps = true; 

1 

void ZeroFtaps(void) 

{ 

Etementfl].iFtap = 0; 

Etement[2].iFtap = 0; 


252 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 



Flaps = false; 

} 

The landing flaps are fitted on the inboard wings sections, port and starboard, which 
are Element[l] and Element[2]. FlapsDown deflects the flaps downward, while Zero 
Flaps resets them back to their undeflected position. 

As we said, these functions should be called when the user is pressing the flight control 
keys. Further, they need to be called before StepSimulation is called so that they can 
be included in the current time step’s force and moment calculations. The sequence of 
calls should look something like this: 


ZeroRudderQ; 
ZeroAilerons(); 
ZeroElevators(); 

// pitch down 
if (IsKeyDown(VKJJP)) 
PitchDown(); 

// pitch up 

if (IsKeyDown(VK_DOWN)) 
PitchLlp(); 

// roll left 
if (IsKeyDown(VK_LEFT)) 
RollLeft(); 

// roll right 
if (IsKeyDown(VK_RIGHT)) 
RollRight(); 

// Increase thrust 
if (IsKeyDown(0x41)) // A 
IncThrust(); 

// Decrease thrust 
if (IsKeyDown(0x5A)) // Z 
DecThrust(); 

// yaw left 

if (IsKeyDown(0x58)) // x 
LeftRudder(); 

// yaw right 

if (IsKeyDown(0x43)) // c 
RightRudder(); 


Flight Controls | 253 


www.it-ebooks.info 



// landing flaps down 
if (IsKeyDown(0x46)) //f 
FlapsDownQ; 

// landing flaps up 
if (IsKeyDown(0x44)) // d 
ZeroFlapsQ; 

StepSinulation(dt); 


Before StepSimulation is called, we check each of the flight control keys to see if it is 
being pressed. If so, then the appropriate function is called. 

The function IsKeyDown, which checks whether a certain key is pressed, looks like this 
in a Windows implementation: 

BOOL IsKeyDown(short KeyCode) 

{ 


SHORT retval; 

retval = GetAsyncKeyState(KeyCode); 

if (HIBYTE(retval)) 
return TRUE; 

return FALSE; 

} 

The important thing to note here is that the keys are being checked asynchronously 
because it is possible that more than one key will be pressed at any given time, and they 
must be handled simultaneously instead of one at a time (as would be the case in the 
standard Windows message processing function). 

The addition of flight control code pretty much completes the physics part of the sim¬ 
ulation. So far, you have the model, the integrator, and the user input or flight control 
elements completed. All that remains is setting up the application’s main window and 
actually drawing something that represents what you’re simulating. We’ll leave that part 
up to you, or you can look at the example we’ve included on the book’s website to see 
what we did on a Windows machine. 


254 | Chapter 12:3D Rigid-Body Simulator 


www.it-ebooks.info 



CHAPTER 13 


Connecting Objects 


Simulating particles and rigid bodies is great fun, and with these simple entities you can 
achieve a wide variety of effects or simulate a wide variety of objects. In this chapter 
we’ll take things a step further, showing you how to simulate connected particles and 
rigid bodies. Doing so opens a whole new realm of possibilities. In this book’s first 
edition, David showed you how to use springs and particles to simulate cloth. Chap¬ 
ter 17 in the first edition covers that, and the corresponding “Cloth Simulation” example 
on the book’s website implements the model. As shown in Figure 13-1, the flag model 
is simply a collection of particles initially laid out in a grid pattern connected by linear 
springs that are then rendered to look like cloth. The springs give structure to the par¬ 
ticles, keeping them organized in a mesh that can be rendered while allowing them to 
move, emulating the movement of a flowing fabric. 


255 


www.it-ebooks.info 





Figure 13-1. Network of particles and springs 


Each line in the wireframe flag shown in Figure 13-1 represents a spring-damper ele¬ 
ment, while the nodes where these springs intersect represent the particles. We modeled 
the springs using the spring-damper formulas that we showed you back in Chapter 3. 
The (initially) horizontal and vertical springs provide the basic structure for the flag, 
while the diagonal springs are there to resist shear forces and lend further strength to 
the cloth. Without these shear springs, the cloth would be quite stretchy. Note that there 
are no particles located at the intersection of the diagonal springs. 

In this chapter, we’ll show you how to use those same techniques to simulate something 
like a hanging rope or vine. You can use these techniques to simulate all sorts of things 
besides cloth and rope or vines. For example, you can model the swing of a golf club if 
you can imagine one rigid body representing the arm and another representing the golf 
club. We’ll get to that example in Chapter 19, but for now let’s see how to model a hanging 
rope or vine and some other springy objects. 


256 | Chapter 13: Connecting Objects 


www.it-ebooks.info 
























Application of linear springs is not the only method available to connect objects, but it 
has the advantages of being conceptually simple, easy to implement, and effective. One 
of the potential disadvantages is that you can run into numerical stability problems if 
the springs are too stiff. We’ll talkmore about these issues throughout this chapter. Also, 
the examples we’ll cover are in 2D for simplicity, but the techniques apply in 3D, too. 

Springs and Dampers 

You learned in Chapter 3 that springs are structural elements that, when connected 
between two objects, apply equal and opposite forces to each object. This spring force 
follows Hooke’s law and is a function of the stretched or compressed length of the spring 
relative to the rest length of the spring and the spring constant. The spring constant is 
a quantity that relates the force exerted by the spring to its deflection: 

F s = -k s (L-r) 

Here, F s is the spring force, k s is the spring constant, L is the stretched or compressed 
length of the spring, and r is the rest length of the spring. The negative sign in the 
preceding equation just means that the force is in the opposite direction of the dis¬ 
placement. 

Dampers are usually used in conjunction with springs in numerical simulations. They 
act like viscous drag in that dampers act against velocity. The force developed by a 
damper is proportional to the relative velocity of the connected objects and a damping 
constant, k d , that relates relative velocity to damping force. 

Fd = -kd (vi - V 2 ) 

This equation shows the damping force, F d , as a function of the damping constant and 
the relative velocity of the connected points on the two connected bodies. 

Typically, springs and dampers are combined into a single spring-damper element 
where a single formula is used to represent the combined force. In vector notation, the 
formula for a spring-damper element connecting two bodies is: 

F] = -{k s (L - r) + k d (( Vl - v 2 ) • L)/L} L/L 

Here, is the force exerted on body 1, while the force, F 2 , exerted on body 2 is: 


F 2 = -Ft 


L is the length of the spring-damper (L, not in bold print, is the magnitude of the vector 
L), which is equal to the vector difference in position between the connected points on 
bodies 1 and 2. If the connected objects are particles, then L is equal to the position of 


Springs and Dampers | 257 


www.it-ebooks.info 



body 1 minus the position of body 2. Similarly, and v 2 are the velocities of the con¬ 
nected points on bodies 1 and 2. The quantity (v t - v 2 ) represents the relative velocity 
between the connected bodies. 

It’s fairly straightforward to connect particles with springs (and dampers); you need 
only specify the particles to which the spring is connected and compute the stretched 
or compressed length of the spring as the particles move relative to each other. The force 
generated by the spring is then applied equally (but in opposite directions) to the con¬ 
nected particles. This is a linear force. 

For rigid bodies, things are a bit more complicated. First, not only do you have to specify 
to which body the spring is attached, but you must also specify the precise points on 
each object where the spring attaches. Then, in addition to the linear force applied by 
the spring to each body, you must also compute the resulting moment on each body 
causing each to rotate. 

Connecting Particles 

From swinging vines in Activision’s Pitfall to barnacle tongues in Valve Corporation’s 
Half-Life, dangling rope-like objects have appeared in video games in various incarna¬ 
tions since the very early days of video gaming. Some implementations, such as those 
in the 1982 versions of Pitfall, are implemented rather simply and unrealistically, while 
others, such as barnacle tongues, are implemented more realistically in how they dangle 
and swing. Whether it’s a vine, rope, chain, or tongue, you can use particles and springs 
to simulate realistic rope-like behavior. We’ll show you how in the following simple 
example. 

Rope 

You know from your real-life experience that ropes are flexible, although some are more 
flexible than others. Ropes are elastic and stretch to varying extents. They drape when 
suspended by their two ends. They bend when swinging or when collapsing on the 
ground. We can capture all these behaviors using simple particles connected with 
springs. Figure 13-2 illustrates the rope example we’ll cover here. 


258 | Chapter 13: Connecting Objects 


www.it-ebooks.info 




Figure 13-2. Swinging rope 

The example consists of a rope comprising 10 particles and 9 springs. At the start of the 
simulation, the rope, originally extended straight out to the right, falls under the influ¬ 
ence of gravity, swinging left and right until it comes to rest (hanging straight down). 
The dots represent particles and the lines represent springs. The topmost particle is 
fixed, and the illustration on the left in Figure 13-2 shows the rope swinging down from 
right to left while the illustration on the right shows the rope swinging back from left 
to right. 

This example uses all the same code and techniques presented in Chapter 7 through 
Chapter 9 for simulating particles and rigid bodies. Really, the only difference is that we 
have to compute a new force—the spring force on each object. But before we do that, 
we have to define and initialize the springs. 

Spring structure and variables 

The following code sample shows the spring data structure we set up to store each 
spring’s information: 

typedef struct _Sprtng { 
tnt Endl; 

tnt End2; 

float k; 

float d; 


Connecting Particles | 259 


www.it-ebooks.info 









float InitialLength; 

} Spring, *pSpring; 

Specifically, this information includes: 

Endl 

A reference to the first particle to which the spring is connected 
End2 

A reference to the second particle to which the spring is connected 
k 

The spring constant 

d 

The damping constant 
InitialLength 

The unstretched length of the spring 

This structure is appropriate for connecting particles. We’ll make a slight modification 
to this structure later, when we get to the example where we’re connecting rigid bodies. 

There are defines and variables unique to this example that must be set up as follows: 


#define 

_NUM_OBJECTS 

10 

#define 

_NUM_SPRINGS 

9 

#define 

_SPRING_K 

1000 

#define 

_SPRING_D 

100 

Particle 

Objects[_NUM_0B3ECTS]; 

Spring 

Springs[_NUM_SPRINGS]; 


As stated earlier, there are 10 particles (objects) and 9 springs in this simulation. The 
arrays Objects and Springs are used to keep track of them. We also set up a few 
defines representing the spring and damping constants. The values shown here are 
arbitrary, and you can change them to suit whatever behavior you desire. The higher 
the spring constant, the stiffer the springs; whereas the lower the spring constant, the 
stretchier the springs. Stretchy springs make your rope more elastic. Keep in mind while 
tuning these values that if you make the spring constant too high, you’ll probably have 
to make the simulation time step smaller and/or use a robust integration scheme to 
avoid numerical instabilities. 

The damping constant controls how quickly the springiness of the springs dampens 
out. You’ll end up tuning this value to get the behavior you desire. A small value can 
make the rope seem jittery, while a large value will make the stretchiness appear 
smoother. Higher damping also helps alleviate numerical instabilities to some extent, 
although it’s no substitute for a robust integration scheme. 


260 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



Initialize the particles and springs 

Initially, our particle rope is set up horizontally, as shown in Figure 13-3, with the left¬ 
most particle, pO, fixed—that is, the particle pO will not move, and the remainder of the 
rope will pivot about pO. For convenience, all remaining particles are incrementally 
indexed from left to right. 



pO pi p2 p3 p4 p5 p6 p7 p8 p9 

sO si s2 s3 s4 s5 s6 s7 s8 




Figure 13-3. Particle rope setup 


There are nine springs, which are indexed from left to right as illustrated in 
Figure 13-3. Spring 0 connects particle 0 to particle 1, spring 1 connects particle 1 to 
particle 2, and so on. The following code sample shows how all this is initialized: 

boot Inttiallze(void) 

1 

Vector r; 

int 1; 

Objects[0].bLocked = true; 

// Initialize particle locations from left to right. 
for(i=0; i<_NUM_OBJECTS; U+) 

{ 

Objectsfi].vPosition.x = _WINWIDTH/2 + Objects[0].fLength * i; 

Objectsfi].vPosition.y = _WINHEIGHT/8; 

} 

// Initialize springs connecting particles from left to right. 
for(i=0; i<_NUM_SPRINGS; i++) 

{ 

Springsfi].Endl = i; 

Springsfi].End2 = i+1; 

r = Objects[i+l].vPosition - Objectsfi].vPosition; 

Springsfi].InitialLength = r.MagnitudeQ; 

Springs[i].k = _SPRING_K; 

Springs[i].d = _SPRING_D; 

} 


Connecting Particles | 261 


www.it-ebooks.info 









return true; 

} 

First, the local variables r and i are declared, r will be used to compute the initial, 
unstretched length of the springs, and i will be used to index the Objects and Springs 
arrays. Second, Objects [0], the one that is fixed, has its bLocked property set to true, 
indicating that it does not move (that is, it’s locked). 

Next, the particle positions are initialized starting from the first particle—the fixed one 
positioned at the middle of the screen—and proceeding to the rest of the particles, 
offsetting each to the right by an amount equal to property fLength. fLength is an 
arbitrary length that you can define, that represents the spacing of the particles and, 
subsequently, the initial length of the springs connecting the particles. 

Finally, we set up the springs, connecting each particle to its neighbor on the right. 
Starting at the first spring, we set its end references to the index of the particle to its left 
and right in the properties Endl and End2, respectively. These indices are simply i and 
i+l, as shown in the preceding code sample within the last for loop. The initial length 
vector of the spring is computed and stored in the vector r, where r = Objects [i 
+1]. vPosition - Objectsfi]. vPosition. The magnitude of this vector is the initial 
spring length, which is stored in the spring’s property, InitialLength. This step isn’t 
strictly necessary in this example since you already know that the property fLength 
discussed earlier is the initial length of each spring. However, we’ve done it this general 
way since you may not necessarily initialize the particle positions as we have simply 
done. 

Update the simulation 

Updating the particle positions at each simulation time step, under the influence of 
gravity and spring forces proceeds just like in the earlier examples of Chapter 8 and 
Chapter 9. Essentially, you must compute the forces on the particles, integrate the equa¬ 
tions of motion, and redraw the scene. As usual in our examples, the function Update 
Simulation is called on to perform these tasks. For the current example, UpdateSimu 
lation looks like this: 

void UpdateSimuLation(void) 

{ 


double 

dt = _TIMESTEP; 

int 

i; 

double 

f, dl; 

Vector 

ptl, pt2; 

int 

j; 

Vector 

r; 

Vector 

F; 

Vector 

vl, v2, vr; 


// Initialize the spring forces on each object to zero. 
for(i=0; i<_NUM_OBJECTS; i++) 


262 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



{ 

Objects[i].vSprings.x = 0; 

Objects[i].vSprings.y = 0; 

Objectsfi].vSprings.z = 0; 

} 

// Calculate all spring forces based on positions of connected objects. 
for(i=0; i<_NUM_SPRINGS; i++) 

{ 

j = Springs[i].Endl; 

ptl = Objectsfj].vPosition; 

vl = Objects[j].vVelocity; 

j = Springs[i].End2; 

pt2 = Objects[j].vPosition; 

v2 = Objectsfj].vVelocity; 

vr = v2 - vl; 
r = pt2 - ptl; 

dl = r.Magnitude() - Springs[i].InitialLength; 

f = Springs[i].k * dl; // - means compression, + means tension 

r.Normalize(); 

F = (r*f) + (Springsfi].d*(vr*r))*r; 

j = Springs[i].Endl; 

Objects[j].vSprings += F; 

j = Springs[i].End2; 

Objects[j].vSprings -= F; 


// Integrate equations of motion as usual. 


// Render the scene as usual. 


} 

As you can see, there are several local variables here. We’ll explain each one as we get 
to the code where it’s used. After the local variable declarations, this function’s first task 
is to reset the aggregate spring forces on each particle to 0. Each particle stores the 
aggregate spring force in the property vSprings, which is a vector. In this example, each 
particle will have up to two springs acting on it at any given time. 


Connecting Particles | 263 


www.it-ebooks.info 




The next block of code in the for loop computes the springs forces acting on each 
particle. There are several steps to this, so we’ll go through each one. First the loop is 
set up to step through the list of springs. Recall that each spring is connected to two 
particles, so each step through the loop will compute a spring force and apply it to two 
separate particles. 

Within the loop, the variable j is used as a convenience to temporarily store the index 
that refers to the Object to which the spring is attached. For each spring j is first set to 
the spring’s Endl property. A temporary variable, ptl, is then set equal to the position 
of the Object to which j refers. Another temporary variable, vl, is set to the velocity of 
the Object to which j refers. Next, j is set to the index of End2, the other Object to 
which the current spring is attached, and that object’s position and velocity are stored 
in pt2 and v2, respectively. This sort of temporary variable use isn’t necessary, of course, 
but it makes the following lines of code that compute the spring force more readable in 
our opinion. 

vr is a vector that stores the relative velocity between the two ends of the spring. We 
compute vr by subtracting vl from v2. Similarly, r is a vector that stores the relative 
distance between the two ends of the spring. We compute r by subtracting ptl from 
pt2. The magnitude of r represents the stretched or compressed length of the spring. 
The change in spring length is computed and stored in d l as follows: 

dl = r.Magnitude!) - Springs[i].InittalLength; 

dl will be negative if the computed length is shorter than the initial length of the spring. 
This implies that the spring is in compression and should act to push the particles away 
from each other. A positive dl means the spring is in tension and should act to pull the 
particles toward each other. The line: 

f = Springs[t].k * dl; 

computes the corresponding spring force as a function of dl and the spring constant. 
Note that f is a scalar and we have not yet computed its line of action, although we know 
it acts along the line connecting the particles at Endl and End2. That line is represented 
by r, which we computed earlier. And the spring force is just f times the unit vector 
along r. Since we’re including damping, we have to use the spring-damper equation for 
the total force acting on each particle, which we call the vector F. F is computed as 
follows: 

F = (r*f) + (Springs[i].d*(vr*r))*r; 

The first term on the right side of the equals sign is the Hooke’s law-based spring force, 
and the second term is the damping force. Note here that r is a unit vector previously 
computed using the line: 

r.Normalize!); 


264 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



Finally, the spring force is applied to each particle connected by the spring. Remember, 
the force is equal in magnitude but opposite in direction for each particle. The lines: 

j = Springs[t].Endl; 

Objects!j].vSprings += F; 

apply the spring force to the particle at the first end of the spring, whereas the lines: 

j = Springs[i].End2; 

Objects[j].vSprings -= F; 

apply the opposite spring force to the particle at the second end of the spring. 

That’s it for computing and applying the spring forces. The remainder of the code is 
business as usual, where we compute the force due to gravity and add it to the aggregate 
spring force for each particle and then integrate the equations of motion. Finally, we 
render the scene at each time step. 

Connecting Rigid Bodies 

As with particles, you can connect rigid bodies with springs to simulate some interesting 
things. For example, you may want to simulate something as simple as a linked chain, 
where each link is connected to the other in series. Or perhaps you want to simulate 
connected body parts to simulate rag doll physics or maybe a golfer’s swing. All these 
require some means of connecting rigid bodies. In this section we’ll show you how to 
use linear spring-dampers, the same we’ve discussed already, to connect rigid bodies. 
We’ll start with a simple analog to the rope example discussed earlier. Instead of con¬ 
necting particles with springs to simulate a dangling rope, we’ll connect rigid links to 
simulate a dangling rope or chain. Later, we’ll show you how linear springs can be used 
to restrain angular motion. 

Links 

In this example, each link is rigid in that it does not deform; however, the links are 
connected by springs in a way that allows the ensemble to swing, stretch, and bend in 
a manner similar to a hanging chain. Figure 13-4 illustrates our swinging linked chain 
as it swings from right to left and then back toward the right. 


Connecting Rigid Bodies | 265 


www.it-ebooks.info 




Figure 13-4. Swinging links 


As in the rope example, the topmost link is connected to a fixed point by a spring, such 
that the linked chain pivots around and hangs from the fixed point. The rectangles 
represent each rigid link, with the lines connecting the rectangles representing springs. 

To model this linked chain, we need only make a few changes to the rope example to 
address the fact that we’re now dealing with rigid bodies that can rotate versus particles. 
This requires us to specify the point on each body to which the springs are attached, 
and in addition to computing the spring forces acting on each body, we must also com¬ 
pute the moments due to those forces. Aside from these spring force and moment 
computations, the remainder of the simulation is the same as those discussed in Chap¬ 
ter 7 through Chapter 12. 

Basic structures and variables 

We can use the Spring structure shown earlier in the rope example again here with one 
small modification. Basically, we need to change the type of the endpoint references, 
Endl and End2, from integers to a new structure we’ll call EndPoint. The new Spring 
structure looks like this: 

typedef struct _Spring { 

EndPoint Endl; 

EndPoint End2; 

float k; 


266 | Chapter 13: Connecting Objects 


www.it-ebooks.info 











float d; 

float InitlalLength; 

} Spring, *pSpring; 

The new EndPolnt structure is as follows: 

typedef struct _EndPolntRef { 
int ref; 

Vector pt; 

} EndPoint; 

Here, ref is the index referring to the Object to which the spring is attached, and pt is 
the point in the attached Objects local coordinate system to which the spring is attached. 
Notice from Figure 13-4 that the first spring, the topmost one, is connected to a single 
object; the other end of it is connected to a fixed point in space. We’ll use a ref of-1 to 
indicate that a spring’s endpoint is connected to a fixed point in space instead of an 
object. 

As in the rope example, we have a few important defines and variables to set up: 


#define _NUM_OBJECTS 10 

#define _NUM_SPRINGS 10 

#deflne _SPRING_K 1000 

#define _SPRING_D 100 


RlgidBody2D Objects[_NUM_OBJECTS]; 

Spring Springs[_NUM_SPRINGS]; 

These are the same as before except now we have 10 springs instead of 9, and Objects 
is of type RigidBody2D instead of Particle. 

The damping and spring constants play the same role here as they did in the rope 
example. 

Initialize 

Initially our linked chain is set up horizontally, just like the rope example, but with the 
link and spring indices shown in Figure 13-5. Each rectangle represents a rigid link, and 
a spring attached to the left end of each link connects the link to its neighbor to the left. 
In the case of the first link, L0, the spring connects the left end of the link to a fixed point 
in space. 


Connecting Rigid Bodies | 267 


www.it-ebooks.info 




■This end attached to fixed point in space 

i LO LI L2 L3 L4 L5 L6 L7 L8 L9 

.. 1 1 1 1 1 

sO si s2 s3 s4 s5 s6 s7 s8 s9 




Figure 13-5. Linked-chain setup 


The code for this setup is only a little more involved than that for the rope example; the 
additional complexity is due to having to deal with specific points on the rigid bodies 
to which each spring is attached. The following code sample contains the modified 
Initialize function: 

boot Initialize(void) 

{ 

Vector r; 

Vector pt; 

int i; 

// Initialize objects for linked chain. 
for(i=0; i<_NUM_LINKS; i++) 

{ 

Objectsfi].vPosition.x = _WINWIDTH/2 + Objects[0].fLength * i; 

Objectsfi].vPosition.y = _WINHEIGHT/8; 

Objectsfi].fOrientation = 0; 

} 

// Connect end of the first object to a fixed point in space. 

Springs[0].Endl.ref = -1; 

Springs[0].Endl.pt.x = _WINklIDTH/2-Objects[0]. fLength/2; 

Springs[0].Endl.pt.y = JJINHEIGHT/8; 

Springs[0].End2.ref = 0; 

Springs[0].End2.pt.x = -Objects[0].fLength/2; 

Springs[0].End2.pt.y = 0; 

pt = VRotate2D(Objects[0].fOrientation, Springs[0].End2.pt) 

+ Objects[0].vPosition; 
r = pt - Springs[0].Endl.pt; 

Springs[0]. InftialLength = r.MagnitudeQ; 


268 | Chapter 13: Connecting Objects 


www.it-ebooks.info 










Sprlngs[0].k = _SPRING_K; 

Springs[0].d = _SPRING_D; 

// Connect end of all remaining springs. 
for(i=l; 1<_NUM_LINKS; i++) 

{ 

Sprlngsfl].Endl.ref = i-1; 

Sprlngsfl].Endl.pt.x = Objects[i-l].fLength/2; 

Sprlngsfl].Endl.pt.y = 0; 

Springsfi].End2.ref = i; 

Springsfi].End2.pt.x = -Objects[i].fLength/2; 

Springsfi].End2.pt.y = 0; 

pt = VRotate2D(Objects[i].fOrientation, Springs[i].End2.pt) 

+ Objectsfl].vPosition; 

r = pt - (VRotate2D(Objects[i-l].fOrlentatlon, Springs[i].Endl.pt) 

+ Objects[i-l].vPosition); 

Springsfi].InitialLength = r.MagnltudeQ; 

Springs[i].k = _SPRING_K; 

Springs[i].d = _SPRING_D; 

} 

return true; 

} 

The local variables r and I are the same as before; however, there’s a new variable, pt, 
that we use to temporarily store the coordinates of specific points when converting from 
one coordinate system to another. We’ll see how this is done shortly. 

After the local variables are declared, the Object positions are initialized, starting from 
the first Object positioned at the middle of the screen and proceeding to the rest of the 
Objects, offsetting each to the right by an amount equal to property fLength. Here, 
f Length is an arbitrary length representing the length of each rigid body, not the length 
of the springs connecting each rigid body. As you’ll see momentarily, the initial length 
of all the springs in this example is 0. 

You should be aware that the coordinates for each object computed here are the coor¬ 
dinates of the object’s center of gravity, which in this example we defined as the middle 
of the rectangle representing each object. Since these are rigid bodies, not only must 
you specify their initial positions, but you must also specify their initial orientations as 
shown in the preceding code sample. The way we have this example set up, each object 
is initialized with an orientation of 0 degrees. 

The next task is to set up the spring connecting the first link, the one on the left, to a 
fixed point in space. The following code handles this task: 

// Connect end of the first object to a fixed point In space. 

Sprlngs[0].Endl.ref = -1; 


Connecting Rigid Bodies | 269 


www.it-ebooks.info 



Sprlngs[0].Endl.pt.x = _WINWIDTH/2-Objects[0].fLength/2; 

Springs[0].Endl.pt.y = JJINHEIGHT/8; 

Sprlngs[0].End2.ref = 0; 

Springs[0].End2.pt.x = -Objects[0].fLength/2; 

Sprtngs[0].End2.pt.y = 0; 

pt = VRotate2D(Objects[0].fOrientation, Springs[0].End2.pt) 

+ Objects[0].vPositlon; 
r = pt - Springs[0].Endl.pt; 

Springs[0]. InttialLength = r.MagnitudeQ; 

Springs[0].k = _SPRING_K; 

Sprtngs[0].d = _SPRING_D; 

The first spring, Spring[0], has its first endpoint, Endl, set to refer to -1, which, as 
explained earlier, means that this end of the spring is connected to some fixed point in 
space. The location of the point, stored in the Endl. pt property, must be specified in 
global coordinates as shown previously. 

Now the second end of the first spring is connected to the left end of the first link; 
therefore, End2. ref of the first spring is set to 0, which is the index to the first Object. 
The point on Object[0] to which the spring is attached is the leftmost end on the 
centerline of the object; thus, its coordinates—relative to the object’s center of gravity 
location and specified in local, body-fixed coordinates—are: 

Springs[0].End2.pt.x = -Objects[0].fLength/2; 

Sprtngs[0].End2.pt.y = 0; 

Now remember, the points on Objects to which springs are attached are specified in 
body-fixed, local coordinates of each referenced object, whereas any point fixed in space 
to which a spring is attached and not on an Object must be specified in global, earth- 
fixed coordinates. You have to keep these coordinates straight and make the appropriate 
rotations when computing spring lengths throughout the simulation. The code; 

pt = VRotate2D(Objects[0].fOrientation, Springs[0].End2.pt) 

+ Objects[0].vPositlon; 
r = pt - Springs[0].Endl.pt; 

illustrates how to do this. To compute the initial spring length, we need to compute the 
relative distance between the endpoints of the spring. In case of the first spring, Endl 
was specified in global coordinates, but End 2 was specified in the local coordinate system 
of Object [0]. Therefore, we have to convert the coordinates of End2 from local coor¬ 
dinates to global coordinates before calculating the relative distance between the ends. 
The preceding line, which calls the VRotate2D function you saw in earlier chapters, 
rotates the locally specified point, End2.pt, from local to global coordinates; it then adds 
the Objects position to the result, arriving at a point, pt, in global coordinates coinci¬ 
dent with the second endpoint of the spring. The relative distance, r, is the second 
endpoint, pt, minus the first endpoint, Endl. pt. 


270 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



Finally, we compute the initial length of the spring by taking the magnitude of r and 
storing the result in the springs InitialLength property. 

With the first spring out of the way, the Initialize function enters a loop to set up the 
remaining springs. Proceeding from left to right in Figure 13-5, the first endpoint, 
Endl, is connected to the right side of Object [i-1], and the second endpoint, End2, is 
connected to the left side of Object [i]. Be aware that each endpoint of each spring is 
specified in different coordinate systems. The left end is in the coordinate system of 
Object[i-l], while the right end is in the coordinate system ofObject[i].It may seem 
trivial during this setup, but when things start moving and rotating it is critically im¬ 
portant to keep these coordinate systems straight. Doing so involves transforming each 
endpoint coordinate from the local system of the body to which it’s attached to the global 
coordinate system. This is illustrated as follows: 

pt = VRotate2D(0bjects[i].fOrientation, Springsfi].End2.pt) 

+ Objectsfi].vPosition; 

r = pt - (VRotate2D(0bjects[i-l].fOrientation, Springs[l].Endl.pt) 

+ Objects[l-l].vPosition); 

The first line converts the spring attachment point End2 from the local coordinate system 
of Object[i] to global coordinates by performing a rotation and translation using 
functions you’ve already seen numerous times now. The result is temporarily stored in 
the local variable, pt. The second line converts the spring attachment point Endl from 
the local coordinate system of Object [i-1] to global coordinates and then subtracts 
the result from pt, yielding a vector, r, representing the relative distance between the 
spring’s endpoints. The magnitude of r is the spring’s initial length. Performing these 
same calculations during the simulation will result in the spring’s stretched or com¬ 
pressed length. That calculation is performed in UpdateSinulation. 

Update 

The function UpdateSimulation is substantially the same as that discussed in the rope 
example. There are a few differences that we’ll highlight here. Again, these differences 
are due to the fact that we’re now dealing with rigid bodies that rotate rather than simple 
particles. The following code sample shows the additions to UpdateSimulation. You 
can see there are a couple of new variables, M and Fo. M is used to temporarily store 
moments due to spring forces Fo in the local coordinates of each Object. 

Just as the property vSprings was initialized to 0 at the start of UpdateSimulation, so 
too must we initialize vMSprings to 0. Recall, vSprings aggregates the spring forces 
acting on each Object. For rigid bodies that rotate, we’ll use vMSprings to aggregate the 
moments on each Object resulting from those spring forces: 

void UpdateSinulatlon(void) 

{ 


Connecting Rigid Bodies | 271 


www.it-ebooks.info 




Vector 

Vector 


M; 

Fo; 


// Initialize the spring forces and moments on each object to zero. 
for(i=0; i<_NUM_OBJECTS; i++) 

{ 


Objectsfi].vMSprings.x = 0; 
Objectsfi].vMSprings.y = 0; 
Objectsfi].vMSprings.z = 0; 


// Calculate all spring forces based on positions of connected objects 
for(i=0; i<_NUM_SPRINGS; i++) 

{ 

if(Springs[i].Endl.ref == -1) 

{ 

ptl = Springsfij.Endl.pt; 

vl.x = vl.y = vl.z = 0; // point is not moving 
} else { 

j = Springs[i].Endl.ref; 

ptl = Objects[j].vPosition + VRotate2D(0bjects[j].fOrientation, 

Springs[i].Endl.pt); 

vl = Objects[j].vVelocity + VRotate2D(0bjects[j].fOrientation, 
Objects[j].vAngularVelocity A Springs[i].Endl.pt); 

} 

if(Springs[i].End2.ref == -1) 

{ 

pt2 = Springsfi].End2.pt; 
v2.x = v2.y = v2.z = 0; 

} else { 

j = Springs[i].End2.ref; 

pt2 = Objects[j].vPosition + VRotate2D(0bjects[j].fOrientation, 

Springs[i].End2.pt); 

v2 = Objects[j].vVelocity + VRotate2D(0bjects[j].fOrientation, 
Objects[j].vAngularVelocity A Springs[i].End2.pt); 

} 

// Compute spring-damper force, 
vr = v2 - vl; 
r = pt2 - ptl; 

dl = r.Magnitude() - Springs[i].InitialLength; 

f = Springs[i].k * dl; 

r.Normalize(); 

F = (r*f) + (Springs[i].d*(vr*r))*r; 

// Aggregate the spring force on each connected object 


272 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



j = Springs[i].Endl.ref; 

if(j != -1) 

Objects[j].vSprings += F; 
j = Springs[i].End2.ref; 

if(j != -1) 

Objects[j].vSprings -= F; 


// convert force to first ref local coords 
// Get local lever 
// calc moment 

// Compute and aggregate moments due to spring force 
// on each connected object, 
j = Springs[i].Endl.ref; 
lf(j != -1) 

{ 

Fo = VRotate2D(-0bjects[j]. fomentation, F); 
r = Springs[i].Endl.pt; 

M = r A Fo; 

Objects!j].vMSprlngs += M; 

} 

j = Springs[i].End2.ref; 

if(j!= -1) 

{ 

Fo = VRotate2D(-0bjects[j]. fomentation, F); 
r = Springs[i].End2.pt; 

M = r A Fo; 

Objects[j].vMSprlngs -= M; 

} 


// Integrate equations of motion as usual. 


// Render the scene as usual. 


} 

As in the rope example, UpdateSimulation steps through all the Springs, computing 
their stretched or compressed length, the relative velocity of each spring’s endpoints, 
and the resulting spring forces. These calculations are a bit different in this current 
example because we have to handle rotation, as explained earlier. 


Connecting Rigid Bodies | 273 


www.it-ebooks.info 




Upon entering the for loop in the preceding code sample, Endl of the current spring is 
checked to see if it’s connected to a fixed point in space. If so, the temporary variable 
ptl stores the global coordinates of the endpoint, and the variable vl stores the velocity 
of the endpoint, which is 0. If the endpoint reference is a valid Object, then we compute 
the position of the endpoint, stored in ptl, just like we did in the Initialize function, 
using a coordinate transform as follows: 

ptl = Objects!j].vPosition + VRotate2D(0bjects[j].fOrlentation, 

Springs[i].Endl.pt); 

We compute the velocity of that point as shown in Chapter 9 by first computing the 
velocity of the point due to rotation in body-fixed coordinates, converting that to global 
coordinates, and then adding the result to the Objects linear velocity. This is accom¬ 
plished in the following code: 

vl = Objects!j].vVelocity + VRotate2D(0bjects[j].fOrlentation, 

Objects!j].vAngularVelocity A Springs[i].Endl. pt); 

We then repeat these calculations for the second endpoint of the spring. 

Once we’ve obtained the positions and velocities of the spring endpoints, we compute 
the spring-damper force in the same manner as in the rope example. The resulting spring 
forces are aggregated in the vSprings property of each object. Note that if the spring 
endpoint reference is a fixed point in space, we do not aggregate the force on that fixed 
point. 

Since the Objects are rigid bodies here, we now have to compute the moment due to 
the spring force acting on each object. You must do this so that when we integrate the 
equations of motion, the objects rotate properly. 

For the Object connected to Endl of the current spring, the following lines compute 
the moment: 

Fo = VRotate2D(-0bjects[j].fOrlentation, F); 
r = Springs[i].Endl.pt; 

M = r A Fo; 

Objects!j].vMSprings += M; 

Fo is a vector representing the spring force computed earlier on the current Object in 
the current Object’s local, body-fixed coordinate system. The line: 

Fo = VRotate2D(-Objects!j].fOrlentation, F); 

transforms F from global to local coordinates of the current Object, Object! j ]. 

r is set to the local, body-fixed coordinates of the spring attachment point for the current 
Object, and we compute the resulting moment by taking the vector cross product of r 
with Fo. The result is stored in the vector variable M, which gets aggregated in the Object 
property vMSprings. We then perform these same sorts of calculations for the Object 
connected to the other end of the spring. 


274 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



After these calculations, the rest of UpdateSimulation is the same as that shown earlier; 
the function integrates the equations of motion and renders the scene. 

Upon running this simulation, you’ll see the linked chain swing down and to the left 
and then back and forth until the motion dampens out. You’ll also notice there’s some 
stretch to the springs between the objects that appears to increase as you look from the 
lower link to the upper link. This is indeed a non-uniform stretch in the springs, which 
makes sense when you consider that the upper spring has more weight, thus more force, 
pulling down on it than does the lower spring. 

As in this rope example, you can tune the spring and damping constants to minimize 
the spring stretch if that gap created by the stretched spring bothers you. You must keep 
in mind numerical stability if your springs are too stiff, and here again, you must im¬ 
plement a robust integrator. 

Rotational Restraint 

So far we’ve used springs only to attach objects in a way that keeps the attachment points 
together but allows the objects to rotate about the attachment point. This is a so-called 
pinned joint. If you want a fixed joint that minimizes the amount of rotation between 
the connected objects, you can add another spring to restrain the connected objects’ 
rotation. 

Figure 13-6 illustrates an example comprising two rigid objects connected at their ends, 
forming a ninety-degree angle. The uppermost end of the first object is connected to a 
fixed point in space as in our rope and linked-chain examples. Under gravity, the as¬ 
sembly would rotate and swing around this fixed point. However, unlike the linked- 
chain example, the extra spring prevents the lower link from pivoting around the other 
end of the first link, as illustrated in Figure 13-7. 



Figure 13-6. Rotation restraint setup 


Connecting Rigid Bodies | 275 


www.it-ebooks.info 













Figure 13-7. Rotation restraint in action 

The setup for this example is relatively straightforward and consists of setting the initial 
positions and orientations of two rigid bodies and connecting three springs. 

This example’s Initialize function is as follows: 

boot Inttiallze(vold) 

{ 

Vector r; 

Vector pt; 

int t; 

// Position objects 

Objects[0].vPosition.x = _WINWIDTH/2; 

Objects[0].vPosition.y = _WINHEIGHT/8+Objects[0].fLength/2; 

Objects[0].fOrlentation = 90; 

Objects[l].vPosition.x = _WINWIDTH/2+0bjects[l].fLength/2; 

Objects[l].vPosition.y = _WINHEIGHT/8+Objects[0].fLength; 

Objects[l].fOrlentation = 0; 

// Connect end of the first object to the earth: 

Springs[0].Endl.ref = -1; 

Springs[0].Endl.pt.x = _WINWIDTH/2; 

Springs[0].Endl.pt.y = JJINHEIGHT/8; 

Springs[0].End2.ref = 0; 

Springs[0].End2.pt.x = -Objects[0].fLength/2; 

Springs[0].End2.pt.y = 0; 

pt = VRotate2D(Objects[0].fOrlentation, Springs[0].End2.pt) + 


276 | Chapter 13: Connecting Objects 


www.it-ebooks.info 








Objects[0].vPosttion; 
r = pt - Springs[0].Endl.pt; 

Springs[0].InttialLength = r.MagnitudeQ; 

Springs[0].k = _SPRING_K; 

Springs[0].d = _SPRING_D; 

// Connect other end of first object to end of second object 
1 = 1; 

Springs[i].Endl.ref = 1-1; 

Springs[i].Endl.pt.x = Objects[i-l].fLength/2; 

Springs[i].Endl.pt.y = 0; 

Springs[i].End2.ref = i; 

Springs[i].End2.pt.x = -Objects[i].fLength/2; 

Springsfi].End2.pt .y = 0; 

pt = VRotate2D(Objects[i].fOrientation, Springs[i].End2.pt) + 
Objectsfi].vPosttion; 

r = pt - (VRotate2D(0bjects[i-l].fOrientation, Springs[i].Endl.pt) + 
Objects[i-l].vPosttion); 

Springsfi].InttialLength = r.MagnitudeQ; 

Springs[i].k = _SPRING_K; 

Springs[i].d = _SPRING_D; 

// Connect CG of objects to each other 
Springs[2].Endl.ref = 0; 

Springs[2].Endl.pt.x = 0; 

Springs[2].Endl.pt.y = 0; 

Springs[2].End2.ref = 1; 

Springs[2].End2.pt.x = 0; 

Springs[2].End2.pt.y = 0; 

r = Objects[l].vPosition - Objects[0].vPosttion; 

Springs[2]. InitialLength = r.MagnitudeQ; 

Springs[2].k = _SPRING_K; 

Springs[2].d = _SPRING_D; 

} 

The two Objects are positioned with the lines: 

Objects[0].vPosttion.x = _WINWIDTH/2; 

Objects[0].vPosttion.y = _WINHEIGHT/8+Objects[0].fLength/2; 
Objects[0].fOrientation = 90; 

Objects[l].vPosttion.x = _WINWIDTH/2+0bjects[l].fLength/2; 

Objects[l].vPosttion.y = _WINHEIGHT/8+Objects[0].fLength; 

Objects[l].fOrientation = 0; 


Connecting Rigid Bodies | 277 


www.it-ebooks.info 



Basically, the first Object, Object[0], is located somewhere toward the top middle of 
the screen with an initial rotation of ninety degrees so that it stands vertically. The second 
Object, Object [1], is positioned so that it lies horizontally with its left end coincident 
with the lower end of the first object. We’ll put a spring there momentarily, but first, 
we’ll connect a spring to the upper end of the first object to connect it to a fixed point. 
The following code takes care of that spring using the same techniques discussed earlier: 

// Connect end of the first object to the earth: 

Sprlngs[0].Endl.ref = -1; 

Springs[0].Endl.pt.x = JJINWIDTH/2; 

Sprlngs[0].Endl.pt.y = JJINHEIGHT/8; 

Springs[0].End2.ref = 0; 

Springs[0].End2.pt.x = -Objects[0].fLength/2; 

Springs[0].End2.pt.y = 0; 

pt = VRotate2D(Objects[0].fOrientation, Sprlngs[0].End2.pt) + 

Objects[0].vPosttion; 
r = pt - Sprlngs[0].Endl.pt; 

Springs[0]. InltialLength = r.MagnitudeQ; 

Springs[0].k = _SPRING_K; 

Springs[0].d = _SPRING_D; 

Now, we connect a spring at the corner formed by the two objects using the following 
code: 


// Connect other end of first object to end of second object 

1 = 1 ; 

Springs[i].Endl.ref = 1-1; 

Springsfi].Endl.pt.x = Objects[l-l].fLength/2; 

Springs[i].Endl.pt.y = 0; 

Springs[i].End2.ref = i; 

Springs[i].End2.pt.x = -Objectsfi].fLength/2; 

Springs[i].End2.pt.y = 0; 

pt = VRotate2D(0bjects[i].fOrientation, Springsfi].End2.pt) + 

Objectsfi].vPosition; 

r = pt - (VRotate2D(0bjects[i-l].fOrientation, Springsfi].Endl.pt) + 
Objects[i-l].vPosition); 

Springs[i]. InitialLength = r.MagnitudeQ; 

Springs[i].k = _SPRING_K; 

Springs[i].d = _SPRING_D; 

If we stop here, the simulation will behave just like the linked-chain example, albeit we’ll 
have a very short chain. So, to prevent rotation at the corner, we’ll add another spring 
connecting the centers of gravity of the objects. You can use other points if you desire; 
we chose the centers of gravity for convenience. The following code adds this rotational 
restraint spring: 


278 | Chapter 13: Connecting Objects 


www.it-ebooks.info 



// Connect CG of objects to each other 
Springs[2].Endl.ref = 0; 

Springs[2].Endl.pt.x = 0; 

Sprlngs[2].Endl.pt.y = 0; 

Sprtngs[2].End2.ref = 1; 

Sprlngs[2].End2.pt.x = 0; 

Springs[2].End2.pt.y = 0; 

r = Objects[l].vPosition - Objects[0].vPosition; 

Springs[2]. InttialLength = r.MagnitudeQ; 

Springs[2].k = _SPRING_K; 

Sprtngs[2].d = _SPRING_D; 

The rest of this simulation is the same as in the linked-chain example. There are no 
other code modifications required. It’s all in the setup. 

Now, if you want to allow some amount of rotation or flexibility in the joint, you can 
do so by tuning the spring constant for the rotation restraint spring. Using linear springs 
creatively, you can model all sorts of joints very simply. 


Connecting Rigid Bodies | 279 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 14 


Physics Engines 


A physics engine is the part of your game that contains all the code required for whatever 
you’re trying to simulate using physics-based techniques. For many game programmers, 
a physics engine is a real-time, rigid-body simulator such as the sort we’ve discussed 
earlier in this book. The open source and licensable physics engines available to you are 
typically of the rigid-body-simulator variety. Some physics engines are rather generic 
and are useful for general rigid bodies and particles; others include various connectors 
and constraints, enabling ragdoll simulation. Still others focus on soft bodies and fluids. 
Fewer actually focus on the physics of some specific thing, like a car or a boat. A simple 
Internet search on the phrase “game physics engine” will generate many links to potential 
options for your use. That said, you could always write your own physics engine. 

Building Your Own Physics Engine 

We’re advocates of using physics where you need it. Sure, you can write a general- 
purpose physics engine for a game, but if you’re creating a game that doesn’t require a 
general-purpose physics engine, then don’t write one. That may sound obvious, but 
sometimes we are compelled to do more than what we need just so we can say we did 
it. Aside from the effort involved, a general-purpose physics engine will probably be 
less efficient than a purpose-built physics engine. By purpose-built, we mean designing 
the physics engine specifically to suit what you’re trying to simulate. For example, a 
general-purpose physics engine would surely include particles, rigid bodies, connectors, 
other force effectors, and who knows what else—fluids, perhaps—and be fully 3D. But 
if you’re writing a 2D side-scrolling game for a smartphone, you certainly won’t need 
3D with the associated complexities involved in dealing with rotation and collisions in 
3D; and if your game simply involves throwing a ball of fuzz at some arbitrary junk, 
then you may not even need to deal with rigid bodies at all. We’re being somewhat 
facetious here, but the point is, unless you must write a general-purpose physics engine 
—say, if you plan to license it as a middleware product or use it in a variety of game 


281 


www.it-ebooks.info 




types—then don’t write one. Instead, write one specifically optimized for the game 
you’re working on. 

Let’s consider a few examples. Let’s say you’re writing a 3D first-person shooter and you 
want to use physics to simulate how wooden barrels and crates blow apart when shot. 
Typically, such an effect would show pieces of wood flying off in different directions 
while falling under the influence of gravity. You could simulate such an effect in 3D 
using rigid bodies and you wouldn’t even need to consider collisions, unless you wanted 
the pieces to bounce off each other or other objects. Ignoring these aspects greatly sim¬ 
plifies the underlying physics engine. Consider another example. Let’s say you’re work¬ 
ing on a game involving flying an airplane. You can use physics to simulate the flight 
dynamics, as we explain in this book, without the need for particles, connectors, or even 
collision response. 

The point of all this discussion is that you should consider which aspects of your game 
will really benefit from physics and write your physics engine to deal specifically with 
those aspects. 

Another thing to consider is whether or not you need real-time physics. You might 
expect, after reading the available game physics literature, that your game must include 
real-time simulations if it is to incorporate physics. However, there are many ways to 
include physics in a game without having to solve the physics via real-time simulations. 
We show you an example in Chapter 19 whereby a golf swing is simulated in order to 
determine club head velocity at the time of club-ball impact. In this case, given specific 
initial parameters, we can solve the swing quickly, almost instantaneously, to determine 
the club speed, which can then be used as an initial condition for the ball flight. The 
ball’s flight can be solved quickly as well and not necessarily in real time. It really depends 
on how you want to present the result to the player. If your game involves following the 
flight of the ball as it soars through the air, then you might want to simulate its flight in 
real time so you can realistically move the ball and camera. If, however, you simply want 
to show where the ball ends up, then you need not perform the simulation in real time. 
For such a simple problem, you can solve for the final ball location quicker than real 
time. Sometimes, the action you’re simulating may happen so fast in real life that you’ll 
want to slow it down for your game. Following a golf ball’s flight in real time might have 
the camera moving so fast that your player won’t be able to enj oy the beautifully rendered 
bird’s-eye view of the course. In this case, you rapidly solve the flight path, save the data, 
and then animate the scene at a more enjoyable pace of your choosing. 

We don’t want to come across as trying to talk you out of writing a physics engine if you 
so choose. The point of our discussion so far is that you simply don’t have to write a 
generic, real-time physics engine in order to use physics in your games. You have other 
options as we’ve just explained. 

Assuming that, after all these considerations, you need to write a physics engine, then 
we have the following to offer. 


282 | Chapter 14: Physics Engines 


www.it-ebooks.info 



A physics engine is just one component of a game engine. The other components include 
the graphics engine, audio engine, AI engine, and whatever other engines you may 
require or whatever other components of a game you may elevate to the status of engine. 
Whatever the case, the physics engine handles the physics. Depending on whom you 
talk to, you’ll get different ideas on what composes a physics engine. Some will say that 
the heart of the physics engine is the collision detection module. Well, what if your game 
doesn’t require collision detection, yet it still uses physics to simulate certain behaviors 
or features? Then collision detection certainly cannot be the heart of your physics en¬ 
gine. Some programmers will certainly take issue with these statements. To them, a 
physics engine simulates rigid-body motion using Newtonian dynamics while taking 
care of collision detection and response. To us, a significant component of a physics 
engine is the model—that is, the idealization of the thing you’re trying to simulate in a 
realistic manner. You cannot realistically simulate the flight characteristics of a specific 
aircraft by treating it as a generic rigid body. You have to develop a representative model 
of that aircraft including very specific features; otherwise, it’s a hack (which, by the way, 
we recognize as a valid and long-established approach). 

Earlier, in Chapter 7 and Chapter 13, we showed you several example simulations. While 
simple, these examples include many of the required components of a generic physics 
engine. There are the particle and rigid-body classes that encapsulate generic object 
properties and behaviors, physics models that govern object behaviors, collision detec¬ 
tion and response systems, and a numerical integrator. Additionally, those examples 
include interfacing the physics code with user input and visual feedback. These examples 
also show the basic flow from user input to physics solver to visual feedback. 

In summary, the major components of a generic physics engine include: 

• Physics models 

• Simulated objects manager 

• Collision detection engine or interface thereto 

• Collision response module 

• Force effectors 

• Numerical integrator 

• Game engine interface 


Physics Models 

Physics models are the idealizations of the things you’re simulating. If your physics 
engine is a generic rigid-body simulator used to simulate an assortment of solid objects 
your players can knock around, throw, shoot, and generally interact with in a basic 
manner, then the physics model will probably be very generic. It’s probably safe to as- 


Building Your Own Physics Engine | 283 


www.it-ebooks.info 



sume that each object will be subject to gravity’s pull, thus mass will be an important 
attribute. Size will also be important, not only because you’ll need to know how big 
things are when checking for collisions and handling other interactions, but also because 
size is related to the distribution of the object’s mass. More precisely, each object will 
have mass moment of inertia attributes. The objects will most likely also have some 
ascribed coefficient of restitution that will be used during collision response handling. 
Additionally, you might ascribe some friction coefficients that may be used during col¬ 
lision response or in situations where the objects may slide along a floor. As the objects 
will likely find themselves airborne at some point, you’ll probably also include a drag 
coefficient for each object. All of these parameters will help you differentiate massive 
objects from lighter ones or compact objects from voluminous ones. 

If your simulation involves more than generic rigid bodies, then your physics will be 
more specific and perhaps far more elaborate. A great example of a more complicated 
model is flight simulation. No matter how good your generic rigid-body model, it won’t 
fly like any specific aircraft if it flies at all. You must develop a model that captures flight 
aerodynamics specific to the aircraft you’re simulating. Chapter 15 shows how to put 
together a model for an aircraft that can be used in a real-time flight simulation. 

The other chapters in Part IV of this book are meant to give you a taste of modeling 
aspects for a variety of things you might simulate in a game. Just as you cannot simulate 
an aircraft with a generic rigid-body model, you cannot simulate a ship with an aircraft 
model, nor can you simulate a golf ball with a ship model. The point is that you must 
spend some time designing your physics model specific to what you’re going to simulate 
in your game. Time spent here is just as important to creating a realistic physics engine 
as time spent on designing a robust integration scheme or collision detection system. 
We can’t overstate the importance of the physical model. The model is what defines the 
behavior of the thing you’re simulating. 

Simulated Objects Manager 

Your simulated objects manager will be responsible for instantiating, initializing, and 
disposing of objects. It will also be responsible for maintaining links between object 
physics and other attributes such as geometry, for example, if in a 3D simulation you 
use the same polyhedron to render an object and for collision detection and response. 

You must have some means of managing the objects in your simulation. One can imag¬ 
ine many different approaches to managing these objects, and unless your simulation 
uses just a handful of objects or fewer, essentially what you need is a list of objects of 
whatever class you’ve defined. You’ve seen in previous chapters’ examples where we use 
simple arrays of RigidBody type objects or Particle type objects. If all the objects in 
your simulation are the same, then you need only a single class capturing all their be¬ 
havior. However, for more diversity, you should use a list of various classes with each 
class encapsulating the code required to implement its own physical model. This is 


284 | Chapter 14: Physics Engines 


www.it-ebooks.info 



particularly important with respect to the forces acting on the model. For example, you 
could have some objects representing projectiles with others representing aircraft. These 
different classes will share some common code (for example, collision detection); how¬ 
ever, the way forces are computed on each will vary due to the differences in how they 
are modeled. With such an approach, each class must have code that implements its 
particular model. During integration, the entire list will be traversed, calling the force 
aggregation method for each object, and the particular class will handle the details suit¬ 
able for the type of object. 

In some simple cases, you need not use different object classes if the types of objects 
you plan to use are not too different. For example, it would be fairly straightforward to 
implement a single class capable of handling both particles and rigid bodies. The object 
class could include an obj ect type property used to denote whether the object is a particle 
or a rigid body, and then the class methods would call the appropriate code. Again, this 
will work satisfactorily for simple objects with few differences. If you want to simulate 
more than two types of objects or if they are very different, you’re probably better off 
using different classes specific to each object being simulated. 

However you structure your classes or lists, the flow of processing your objects will 
generally be the same. Every physics tick —that is, every time step in the physics simu¬ 
lation—you must check for object collisions, resolve those collisions, aggregate the usual 
forces on each object, integrate the equations of motion for each object, and then update 
each object’s state. 

As we said, this is the general flow at every physics tick, or time step, which may not be 
the same as your rendering steps. For example, for accuracy in your simulation you may 
have to take small steps around a millisecond or so. You wouldn’t want to update the 
graphics every millisecond when you need only about a third as many graphics updates 
per second. Thus, your objects manager will have to be integrated with your overall 
game engine, and your game engine must be responsible for making sure the physics 
and graphics are updated appropriately. 

Collision Detection 

If collisions are an important part of your game, then a robust collision detection system 
is required. 

Your collision detection system is distinct from the collision response system or module, 
though the two go hand in hand. Collision detection is the computational geometry 
problem of determining if objects collide and, if so, what points are making contact. 
These points are sometimes called the contact manifold. They’re just the points that are 
touching, which could be a line or surface, though for simplicity usually the point, end 
points, or points defining the contact surface boundary are all that are included in the 
contact manifold. 


Building Your Own Physics Engine | 285 


www.it-ebooks.info 



The collision detection system’s role is very specific: determine which objects are col¬ 
liding, what points on each object are involved in the collision, and the velocities of 
those points. It sounds straightforward, but actual implementation can get quite com¬ 
plex. There are situations where fast-moving objects may go right though other objects, 
especially thin ones, over a single time step, making the collision detection system miss 
the collision if it relies solely on checking the separation distance between objects and 
their relative velocity (i.e., it detects a collision if the objects are within some collision 
tolerance and are also moving toward each other). A robust collision detection system 
will capture this situation and respond accordingly. In Chapter 8 we simply check if 
particles moved past the ground over the course of a single time step, for example, and 
then reset their position to that of the ground plane level. We can handle many situations 
using such simple techniques, especially when dealing with objects passing through 
floors or walls; however, other situations may require more complex algorithms to pre¬ 
dict if a collision will occur sometime in the near future depending on how fast objects 
are moving relative to each other. This latter case is called continuous collision detection, 
and it is covered in many Internet, book, and technical paper sources. Many commercial 
and open source physics engines advertise their capability to handle continuous colli¬ 
sion detection. 

Another challenge associated with collision detection is the fact that it can be very time- 
consuming if you have a large or even moderate number of objects in your simulation. 
There are various techniques to deal with this. First, the game space is partitioned in 
some coarse grid-like manner, and this grid is used to organize objects depending on 
which cell they occupy. Then, in the second phase of collision detection, only those 
objects occupying adjacent cells are checked against each other to see if they are col¬ 
liding. Without this grid partitioning, pairwise checks of every object against every other 
object would be very computationally expensive. The second phase of collision detec¬ 
tion is often a broad approach using bounding spheres or bounding boxes, which may 
be axis- or body-aligned. If the bounding spheres or boxes of each object are found to 
collide, then the objects likewise may be colliding and further checks will be required; 
otherwise, we can infer that the objects are not colliding. In the case of a potential 
collision, these further checks become more complex depending on the geometry of the 
objects. This phase generally involves polygon- and vertex-level checks; there are well- 
established techniques for performing such checks that we won’t get into here. Again, 
there’s a wealth of literature on collision detection available online. 

Collision Response 

Once the collision detection system does its job, it’s time for the collision response system 
to deal with the colliding objects. Earlier in this book, we showed you how to implement 
an impulse-moment collision response method. Recall that this method assumes that 
at the instant of collision, the most significant forces acting on the objects are the col¬ 
lision forces, so all other forces can be ignored for that instant. The method then com- 


286 | Chapter 14: Physics Engines 


www.it-ebooks.info 



putes the resulting velocities of the objects after colliding and instantly changes their 
velocities accordingly. To perform the required calculations, the collision response sys¬ 
tem requires the objects colliding, of course, the collision points, and the velocities of 
those points. Also, each object must have some associated mass and coefficient of res¬ 
titution, which are likewise used to compute the resulting velocities of the objects after 
the collision. 

In practice, the collision response system works hand in hand with the collision detec¬ 
tion system, particularly when dealing with objects that may be penetrating each other. 
As we mentioned earlier, in many cases an object penetrating another, such as an object 
penetrating a wall or floor, can simply be moved so that it is just touching the wall or 
floor. Other cases maybe more complicated, and iterative algorithms are used to resolve 
the penetration. For example, if penetration is detected, then the simulation may back 
up to the previous time step and take a short time step to see if penetration still occurs. 
If it does not, the simulation proceeds; otherwise, the simulation takes an even smaller 
time step. This process repeats until penetration does not occur. This works fine in many 
cases; however, sometimes the penetration is never resolved and the simulation could 
get stuck taking smaller and smaller time steps. This failure to resolve could be attributed 
to objects that are just outside the collision distance tolerance at one instant, and due 
to numerical errors, exceedingly small time steps are required to stay outside of the 
distance tolerance. Some programmers simply put an iteration limit in the code to 
prevent the simulation from getting stuck, but the consequences in every situation may 
be unpredictable. The continuous collision detection approach we mentioned earlier 
avoids this sort of problem by predicting the future collision or penetration and dealing 
with it ahead of time. Whatever the approach, there will be some back and forth and 
data exchange between your collision detection and response systems to avoid excessive 
penetration situations. 

Additionally, there are situations when an object may come to rest in contact with an¬ 
other—for example, a box resting on the floor. There are many ways to deal with such 
contact situations, one of which is to just allow the impulse-momentum approach to 
deal with it. This works just fine in many cases; however, sometimes the objects in resting 
contact will jitter with the impulse-momentum approach. One resolution to this jitter¬ 
ing problem is to put those objects to sleep—that is, if they are found to be colliding, 
but their relative velocities are smaller than some tolerance, they are put to sleep. A 
related but somewhat more complicated approach is to compute the contact normal 
between the object and the floor and set that velocity to 0. This serves as a constraint, 
preventing the object from penetrating the floor while still allowing it to slide along the 
floor. 

Force Effectors 

Force effectors apply direct or indirect force on the objects in your simulations. Your 
physics engine may include several. For example, if your engine allows users to move 


Building Your Own Physics Engine | 287 


www.it-ebooks.info 



objects around with the mouse, then you’ll need some virtualization of the force applied 
by the user via the mouse or a finger on a touch screen. This is an example of a direct 
force. Another direct force effector could be a virtual jet engine. If you associate that 
virtual engine, which produces some thrust force, with some object, then the associated 
object will behave as though it were pushed around by the jet. 

Some examples of indirect force effectors include gravity and wind. Gravity applies force 
on objects by virtue of their mass, but it is typically modeled as body acceleration and 
not an explicit force. Wind can be viewed as exerting a pressure force on an object, and 
that force will be a function of the object’s size and drag coefficients. 

You can imagine all sorts of force effectors, from ones similar to those just described to 
perhaps some otherworldly ones. Whatever you imagine, you must remember that a 
force has magnitude, direction, and some central point of application. If you put a jet 
engine on the side of a box, the box will not only translate but will spin as well. Wind 
creates a force that has a center of pressure, which is the point through which you can 
assume the total wind force acts. The direction of the force and point of application are 
important for capturing both translation and rotation. As an example, consider the 
hovercraft we modeled in Chapter 9 that included two bow thrusters for steering and a 
propeller for forward motion. Each of these direct force effectors—the bow thrusters 
and the propeller—is applied at specific locations on the hovercraft. The bow thrusters 
are located toward the bow and point sideways in order to create spin, thus allowing 
some steering. The propeller is located on the center line of the hovercraft, which passes 
through the hovercraft’s center of gravity so that it does not create spin and instead 
simply pushes the craft forward. There’s another force effector in that model—aerody¬ 
namic drag, which is an indirect force effector. The drag force is applied at a point aft 
of the center of gravity so that it creates some torque, or moment, which in this model 
helps keep the hovercraft pointed straight; it provides some directional stability. 

Whatever force effectors you contrive, they all must be aggregated for each object and 
dealt with in your numerical integrator. Thus, your integrator must have some means 
of accessing all the force effector information required to accurately simulate their effect 
on each associated object. 

Numerical Integrator 

The integrator is responsible for solving the equations of motion for each object. We 
showed you how to do this earlier, in Chapter 7 through Chapter 13. In your generic 
physics engine you’ll iterate through all the objects in the simulation to compute their 
new velocities, positions, and orientations at every time step. To make these calculations, 
your integrator must have access to the force effectors associated with each object. The 
forces will be used to compute accelerations, which will then be integrated to compute 
velocities, and those in turn will be used to compute positions and orientations. 


288 | Chapter 14: Physics Engines 


www.it-ebooks.info 



You can handle aggregating the forces in a few ways. You could aggregate all the forces 
on all objects prior to looping through the objects integrating the equations of motion, 
but this would require looping through all the objects twice. Alternatively, since you’re 
looping through the object list in order to integrate each object’s equations of motion, 
you can simply aggregate each object’s forces during the integration step. A complication 
arises when object pairs apply forces to each other. A linear spring and damper, for 
example, connected between two objects, apply equal and opposite forces to each object. 
The force is a function of the relative distance between the objects (the spring compo¬ 
nent) and their relative velocity (the damping component). So, if during a given time 
step you aggregate the forces on one of the objects in the pair, the resulting force will 
be a function of the current relative position and velocities of the objects. Integrating 
that object will give it a new position and velocity. Then, when you get to the other object 
in the pair, if you recomputed the spring force, it will be a function of the new relative 
position and velocity between the objects that includes the new displacement and ve¬ 
locity of the previously updated object but the old displacement and velocity of the 
current object. This is inconsistent with Newton’s law of equal and opposite forces. You 
can resolve this problem by storing the force computed for the first object and applying 
it to the second one without recomputing the spring force for the second object. 


Building Your Own Physics Engine | 289 


www.it-ebooks.info 



www.it-ebooks.info 


PART III 


Physical Modeling 


Part III focuses on physical modeling. The aim of this part is to provide you with valuable 
physical insight so you can make better judgments on what to include in your models 
and what you can safely leave out without sacrificing physical realism. We cannot and 
do not attempt to cover all the possible things you might want to simulate. Instead, we 
cover several typical things you may try to simulate in a game—such as aircraft, boats, 
and sports balls, among others—in order to give you some insight into their physical 
nature and into some of the choices you must make when developing suitable models. 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 15 


Aircraft 


If you are going to write a flight simulation game, one of the most important aspects of 
your game engine will be your flight model. Yes, your 3D graphics, user interface, story, 
avionics system simulation, and coding are all important, but what really defines the 
behavior of the aircraft that you are simulating is your flight model. Basically, this is 
your simplified version of the physics of aircraft flight—that is, your assumptions, ap¬ 
proximations, and all the formulas you’ll use to calculate mass, inertia, and lift and drag 
forces and moments. 

There are four major forces that act on an airplane in flight: gravity, lift, thrust, and drag. 
Gravity, of course, is the force that tends to pull the aircraft to the ground, while lift is 
the force generated by the wings (or lifting surfaces) of the aircraft to counteract gravity 
and enable the plane to stay aloft. The thrust force generated by the aircraft’s propulsor 
(jet engine or propeller) increases the aircraft’s velocity and enables the lifting surfaces 
to generate lift. Finally, drag counteracts the thrust force, tending to impede the aircraft’s 
motion. Figure 15-1 illustrates these forces. 



Lift 

* 



Gravity 


Figure 15-1. Forces on aircraft inflight 


293 


www.it-ebooks.info 





We’ve already discussed the force due to gravity in earlier chapters, so we won’t address 
it again in this chapter except to say that the total of all lift forces must be greater than 
or equal to the gravitational force if an aircraft is to maintain flight. 

To address the other three forces acting on an aircraft, we’ll refer to a simplified, generic 
model of an airplane and use it as an illustrative example. There are far too many aircraft 
types and configurations to treat them all in this short chapter. Moreover, the subject 
of aerodynamics is too broad and complex. Therefore, the model that we’ll look at will 
be of a typical subsonic configuration, as shown in Figure 15-2. 


Aileron 

Straight, rectangular wing 

Flap 

Elevator 

Propulsor Cockpit Fuselage 


Span 


Tail/Rudder 


Figure 15-2. Model configuration 

In this configuration the main lifting surfaces (the large wings) are located forward on 
the aircraft, with relatively smaller lifting surfaces located toward the tail. This is the 
basic arrangement of most aircraft in existence today. 

We’ll have to make some assumptions in order to make even this simplified model 
manageable. Further, we’ll rely on empirical data and formulas for the calculation of lift 
and drag forces. 

Geometry 

Before getting into lift, drag, and thrust, we need to go over some basic geometry and 
terms to make sure we are speaking the same language. Familiarity with these terms 


294 | Chapter 15: Aircraft 


www.it-ebooks.info 







will also help you quickly find what you are looking for when searching through the 
references that we’ll provide later. 

First, take another look at the arrangement of our model aircraft in Figure 15-2. The 
main body of the aircraft, the part usually occupied by cargo and people, is called the 
fuselage. The wings are the large rectangular lifting surfaces protruding from the fuselage 
near the forward end. The longer dimension of the wing is called its span, while its 
shorter dimension is called its chord length, or simply chord. The ratio of span squared 
to wing area is called the aspect ratio, and for rectangular wings this reduces to the ratio 
of span-to-chord. 

In our model, the ailerons are located on the outboard ends of the wings. The flaps are 
also located on the wings inboard of the ailerons. The small wing-like surfaces located 
near the tail are called elevators. And the vertical flap located on the aft end of the tail 
is the rudder. We’ll talk more about what these control surfaces do later. 

Taking a close look at a cross section of the wing helps to define a few more terms, as 
shown in Figure 15-3. 



The airfoil shown in Figure 15-3 is a typical cambered airfoil. Camber represents the 
curvature of the airfoil. If you draw a straight line from the trailing edge to the leading 
edge, you end up with what’s called the chord line. Now if you divide the airfoil into a 
number of cross sections, like slices in a loaf of bread, going from the trailing edge to 
the leading edge, and then draw a curved line passing through the midpoint of each 
section’s thickness, you end up with the mean camber line. The maximum difference 
between the mean camber line and the chord line is a measure of the camber of the 
airfoil. The angle measured between the direction of travel of the airfoil (the relative 
velocity vector of the airfoil as it passes through the air) and the chord line is called the 
absolute angle of attack. 


Geometry | 295 


www.it-ebooks.info 





When an aircraft is in flight, it may rotate about any axis. It is standard practice to always 
refer to an aircraft’s rotations about three axes relative to the pilot. Thus, these axes— 
the pitch axis, the roll axis, and the yaw axis—are fixed to the aircraft, so to speak, 
irrespective of its actual orientation in three-dimensional space. 

The pitch axis runs transversely across the aircraft—that is, in the port-starboard di¬ 
rection. 1 Pitch rotation is when the nose of the aircraft is raised or lowered from the 
pilot’s perspective. The roll axis runs longitudinally through the center of the aircraft. 
Roll motions (rotations) about this axis result in the wing tips being raised or lowered 
on either side of the pilot. Finally, the yaw axis is a vertical axis about which the nose of 
the aircraft rotates in the left-to-right (or right-to-left) direction with respect to the pilot. 
These rotations are illustrated in Figure 15-4. 



1. Port is to the pilots left and starboard is to the pilots right when he or she is sitting in the cockpit facing 
forward. 


296 | Chapter 15: Aircraft 


www.it-ebooks.info 














Lift and Drag 

When an airfoil moves through a fluid such as air, lift is produced. The mechanisms by 
which this occurs are similar to those in the case of the Magnus lift force, discussed 
earlier in Chapter 6, in that Bernoulli’s law is still in effect. However, this time, instead 
of rotation it’s the airfoil’s shape and angle of attack that affect the flow of air so as to 
create lift. 

Figure 15-5 shows an airfoil section moving through air at a speed V. V is the relative 
velocity between the foil and the undisturbed air ahead of the foil. As the air hits and 
moves around the foil, it splits at the forward stagnation point located near the foil 
leading edge such that air flows both over and under the foil. The air that flows under 
the foil gets deflected downward, while the air that flows over the foil speeds up as it 
goes around the leading edge and over the surface of the foil. The air then flows smoothly 
off the trailing edge; this is the so-called Kutta condition. Ideally, the boundary layer 
remains “attached” to the foil without separating as in the case of the sphere discussed 
in Chapter 6. 


Relative air velocity 


» 


Velocity vector 

M - 


Low pressure. 


High pressure . "'•CvC 



Figure 15-5. Airfoil moving through air 


The relatively fast-moving air above the foil results in a region of low pressure above 
the foil (remember Bernoulli’s equation that shows pressure is inversely proportional 
to velocity in fluid flow). The air hitting and moving along the underside of the foil 
creates a region of relatively high pressure. The combined effect of this flow pattern is 
to create regions of relatively low and high pressure above and below the airfoil. It’s this 
pressure differential that gives rise to the lift force. By definition, the lift force is per¬ 
pendicular to the line of flight—that is, the velocity vector. 


Lift and Drag | 297 


www.it-ebooks.info 
















Note that the airfoil does not have to be cambered in order to generate lift; a flat plate 
oriented at an angle of attack relative to the airflow will also generate lift. Likewise, an 
airfoil does not have to have an angle of attack either. Cambered airfoils can generate 
lift at 0, or even negative, angles of attack. Thus, in general, the total lift force on an 
airfoil is composed of two components: the lift due to camber and the lift due to attack 
angle. 

Theoretically, the thickness of an airfoil does not contribute to lift. You can, after all, 
have a thin curved wing as in the case of wings made from fabric (such as those used 
for hang gliders). In practice, thickness is utilized for structural reasons. Further, thick¬ 
ness at the leading edge can help delay stall (more on this in a moment). 

The pressure differential between the upper and lower surfaces of the airfoil also gives 
rise to a drag force that acts in line with, but opposing, the velocity vector. The lift and 
drag forces are perpendicular to each other and lie in the plane defined by the velocity 
vector and the vector normal (perpendicular) to the airfoil chord line. When combined, 
these two force components, lift and drag, yield the resultant force acting on the airfoil 
in flight. This is illustrated in Figure 15-5. 

Both lift and drag are functions of air density, speed, viscosity, surface area, aspect ratio, 
and angle of attack. Traditionally, the lift and drag properties of a given foil design are 
expressed in terms of nondimensional coefficients C L and C D , respectively: 

C L = L / [(1/2) p V 2 S] 

C D = D / [(1/2) p V 2 S] 

where S is the wing planform area (span times chord for rectangular wings), L is the lift 
force, D is the drag force, V is the speed through the air, and p (rho) is air density. These 
coefficients are experimentally determined from wind tunnel tests of model airfoil de¬ 
signs at various angles of attack. The results of these tests are usually presented as graphs 
of lift and drag coefficient versus attack angle. Figure 15-6 through Figure 15-8 illustrate 
some typical lift and drag charts for a wing section. 


298 | Chapter 15: Aircraft 


www.it-ebooks.info 





Lift and Drag | 299 


www.it-ebooks.info 



























































0.18 

0.16 

0.14 

■S 0.12 
.03 

,§S 

fj 0.1 

o 

CO 

1 0.08 

| 

S 0.06 

0.04 

0.02 

0 


*■» 













































10 -5 0 5 10 15 

Attack Angle (degrees) 

C M 

- - - - Cy with flap lowered 15 degrees 


Figure 15-8. Typical C M versus attack angle 


The most widely known family of foil section designs and test data is the NACA foil 
sections. Theory of Wing Sections by Ira H. Abbott and Albert E. Von Doenhoff (Dover) 
contains a wealth of lift and drag data for practical airfoil designs (see the Bibliogra¬ 
phy for a complete reference to this work). 2 

In practice, the flow of air around a wing is not strictly two-dimensional—that is, flowing 
uniformly over each parallel cross section of the wing—and there exists a span-wise 
flow of air along the wing. The flow is said to be three-dimensional. The more three- 
dimensional the flow, the less efficient the wing. 3 This effect is reduced on longer, high- 
aspect-ratio wings (and wings with end plates where the effective aspect ratio is in¬ 
creased); thus, high-aspect-ratio wings are comparatively more efficient. 

To account for the effect of aspect ratio, wing sections of various aspect ratios for a given 
foil design are usually tested so as to produce a family of lift and drag curves versus 
attack angle. There are other geometrical factors that affect the flow around wings; for 


2. Theory of Wing Sections includes standard foil section geometry and performance data, including the well- 
known NACA family of foil sections. The appendixes to Theory of Wing Sections have all the data you need 
to collect lift and drag coefficient data for various airfoil designs, including those with flaps. 

3. Lifting efficiency can be expressed in terms of lift-to-drag ratio. The higher the lift-to-drag ratio, the more 
efficient the wing or foil section. 


300 | Chapter 15: Aircraft 


www.it-ebooks.info 





























a rigorous treatment of these, we refer you to the Theory of Wing Sections and Fluid- 
Dynamic Lift. 4 

Turning back to Figure 15-6, you’ll notice that the drag coefficient increases sharply 
with attack angle. This is reasonable, as you would expect the wing to produce the most 
drag when oriented flat against or perpendicular to the flow of air. 

A look at the lift coefficient curve, which initially increases linearly with attack angle, 
shows that at some attack angle the lift coefficient reaches a maximum value. This angle 
is called the critical attack angle. For angles beyond the critical, the lift coefficient drops 
off rapidly and the airfoil (or wing) will stall and cease to produce lift. This is bad. When 
an aircraft stalls in the air, it will begin to drop rapidly until the pilot corrects the stall 
situation by, for example, reducing pitch and increasing thrust. When stall occurs, the 
air no longer flows smoothly over the trailing edge, and the corresponding high angle 
of attack results in flow separation (as illustrated in Figure 15-9). This loss in lift is also 
accompanied by an increase in drag. 



Figure 15-9. Stalled airfoil 


Theoretically, the resultant force acting on an airfoil acts through a point located at one- 
quarter the chord length aft of the leading edge. This is called the quarter-chord point. 
In reality, the resultant force line of action will vary depending on attack angle, pressure 
distribution, and speed, among other factors. However, in practice it is reasonable to 
assume that the line of action passes through the quarter-chord point for typical op¬ 
erational conditions. To account for the difference between the actual line of action of 
the resultant and the quarter-chord point, we must consider the pitching moment about 
the quarter-chord point. This pitching moment tends to tilt the leading edge of the foil 
down. In some cases this moment is relatively small compared to the other moments 


4. Fluid-Dynamic Lift, by Sighard F. Hoerner and Henry V. Borst, and Fluid-Dynamic Drag, by Sighard F. 
Hoerner (both self-published by Hoerner), contain tons of practical charts, tables, and formulas for virtually 
every aspect of aircraft aerodynamics. They even include material appropriate for high-speed boats and 
automobiles. 


Lift and Drag | 301 


www.it-ebooks.info 


















acting on the aircraft, and it may be neglected. 5 An exception may be when the foil has 
deflected flaps. 

Flaps are control devices used to alter the shape of the foil so as to change its lift char¬ 
acteristics. Figure 15-6 also shows typical lift, drag, and moment coefficients for an 
airfoil fitted with a plain flap deflected downward at 15°. 6 Notice the significant increase 
in lift, drag, and pitch moment when the flap is deflected. Theory of Wing Sections also 
provides data for flapped airfoils for flap angles between -15° and 60°. 

Other Forces 

The most notable force that we’ve yet to discuss is thrust—the propulsion force. Thrust 
provides forward motion; without it, the aircraft’s wings can’t generate lift and the air¬ 
craft won’t fly. Thrust, whether generated by a propeller or a jet engine, is usually ex¬ 
pressed in pounds, and a common ratio used to compare the relative merits of aircraft 
powering is the thrust-to-weight ratio. This ratio is the maximum thrust deliverable by 
the propulsion plant divided by the aircraft’s total weight. When the thrust-to-weight 
ratio is greater than one, the aircraft is capable of overcoming gravity in a vertical climb. 
This is more like a rocket than a traditional airplane. Most normal planes are not capable 
of this, but many military planes do have thrust-to-weight ratios of greater than one. 
However, airplane engines rely on oxygen in the atmosphere to combust their fuel with 
and to produce the force that propels them forward. As the plane climbs higher, the 
engines will have less oxygen and produce less thrust. The thrust-to-weight ratio will 
fall, and eventually the plane will again need lift from the wings to maintain its altitude. 
Even when the plane is climbing vertically like a rocket, the wings still generate lift, and 
in this case try to pull the airplane away from a vertical trajectory. 

Besides gravity, thrust, wing lift, and wing drag, there are other forces that act on an 
aircraft in flight. These are drag forces (and lift in some cases) on the various components 
of the aircraft besides the wings. For example, the fuselage contributes to the overall 
drag acting on the aircraft. Additionally, anything sticking out of the fuselage will con¬ 
tribute to the overall drag. If it’s not a wing, anything sticking out of the fuselage is 
typically called an appendage. Some examples of appendages are the aircraft landing 
gear, canopy, bombs, missiles, fuel pods, and air intakes. 

Typically, drag data for fuselages and appendages is expressed in terms of a drag coef¬ 
ficient similar to that discussed in Chapter 6, where experimentally determined drag 
forces are nondimensionalized by projected frontal area (S), density (p), and velocity 

5. Aircraft designers must always consider this pitching moment when designing the aircrafts structure, as this 
moment tends to want to twist the wings off the fuselage. 

6. There’s a large variety of flap designs besides the plain trailing-edge flap discussed here. Flaps are typically 
referred to in the literature as high lift devices , and the references we’ll provide in this chapter give rough 
descriptions of the most common designs. 


302 | Chapter 15: Aircraft 


www.it-ebooks.info 



squared (V 2 ). This means that the experimentally measured drag force is divided by the 
quantity (1/2) p V 2 S to get the dimensionless drag coefficient. Depending on the object 
under consideration, the drag coefficient data will be presented as a function of some 
important geometric parameter, such as attack angle in the case of airfoils, or length- 
to-height ratio in the case of canopies. Here again, Hoerner’s Fluid-Dynamic Drag is an 
excellent source of practical data for all sorts of fuselage shapes and appendages. 

For example, when an aircraft’s landing gear is down, the wheels (as well as associated 
mechanical gear) contribute to the overall drag force on the aircraft. Hoerner reports 
drag coefficients based on the frontal area of some small-plane landing-gear designs to 
be in the range of 0.25 to 0.55. By comparison, drag coefficients for typical external 
storage pods (such as for fuel), which are usually streamlined, can range from 0.06 to 
0.26. 

Another component of the total drag force acting on aircraft in flight is due to skin 
friction. Aircraft wings, fuselages, and appendages are not completely smooth. Weld 
seams, rivets, and even paint cause surface imperfections that increase frictional drag. 
As in the case of the sphere data presented in Chapter 6. This frictional drag is dependent 
on the nature of the flow around the part of the aircraft under consideration—that is, 
whether the flow is laminar or turbulent. This implies that frictional drag coefficients 
for specific surfaces will generally be a function of the Reynolds number. 

In a rigorous analysis of a specific aircraft’s flight, you’d of course want to consider all 
these additional drag components. If you’re interested in seeing the nitty-gritty details 
of such calculations, we suggest you take a look at Chapter 14 of Fluid-Dynamic Drag, 
where Hoerner gives a detailed example calculation of the total drag force on a fighter 
aircraft. 

Control 

The flaps located on the inboard trailing edge of the wing in our model are used to alter 
the chord and camber of the wing section to increase lift at a given speed. Flaps are used 
primarily to increase lift during slow speed flight, such as when taking off or landing. 
When landing, flaps are typically deployed at a high downward angle (downward flap 
deflections are considered positive) on the order to 30° to 60°. This increases both the 
lift and drag of the wings. During landing, this increase in drag also assists in slowing 
the aircraft to a suitable landing speed. During takeoff, this increase in drag works 
against you in that it necessitates higher thrust to get up to speed; thus, flaps may not 
be deployed to as great an angle as when you are landing. 

Ailerons control or induce roll motion by producing differential lift between the port 
and starboard wing sections. The basic aileron is nothing more than a pair of trading- 
edge flaps fitted to the tips of the wings. These flaps move opposite each other, one 
deflecting upward and the other downward, to create a lift differential between the port 


Control | 303 


www.it-ebooks.info 



and starboard wings. This lift differential, separated by the distance between the ailer¬ 
ons, creates a torque that rolls the aircraft. To roll the aircraft to the port side (the pilot’s 
left), the starboard aileron would be deflected in a downward direction while the port 
aileron would be deflected in an upward direction relative to the pilot. Likewise, the 
opposite deflections of the ailerons would induce a roll to the starboard side. In a real 
aircraft, the pilot controls the ailerons by moving the flight stick to either the left or 
right. 

Elevators, the tail “wings,” are used to control the pitch of the aircraft. (Elevators can be 
flaps, as shown in Figure 15-2, or the entire tail wing can rotate as on the Lockheed 
Martin F-16.) When the elevators are deflected such that their trailing edge goes down 
with respect to the pilot, a nose-down pitch rotation will be induced; that is, the tail of 
the aircraft will tend to rise relative to its nose, and the aircraft will dive. In an actual 
aircraft, the pilot achieves this by pushing the flight stick forward. When elevators are 
deflected such that their tailing edge goes up, a nose-up pitch rotation will be induced. 

Elevators are very important for trimming (adjusting the pitch of) the aircraft. Generally, 
the aircraft’s center of gravity is located above the mean quarter-chord line of the aircraft 
wings such that the center of gravity is in line with the main lift force. However, as we 
explained earlier, the lift force does not always pass through the quarter-chord point. 
Further, the aircraft’s center of gravity may very well change during flight—for example, 
as fuel is burned off and when ordnance is released. By controlling the elevators, the 
pilot is able to adjust the attitude of the aircraft such that all of the forces balance and 
the aircraft flies at the desired orientation (pitch angle). 

Finally, the rudder is used to control yaw. The pilot uses foot pedals to control the rudder; 
pushing the left (port) pedal yaws left and pushing the right pedals yaws right (star¬ 
board). The rudder is useful for fine-tuning the alignment of the aircraft for approach 
on landing or when sighting up a target. Typically, large rudder action tends to also 
induce roll motion that must be compensated for by proper use of the ailerons. 

In some cases the rudder consists of a flap on the trailing edge of the vertical tail, while 
in other cases there is no rudder flap and the entire vertical tail rotates. In both cases, 
the vertical tail, which also provides directional stability, will usually have a symmetric 
airfoil shape; that is, its mean camber line will be coincident with its chord line. When 
the aircraft is flying straight and level, the tail will not generate lift since it is symmetric 
and its attack angle will be 0. However, if the plane sideslips (yaws relative to its flight 
direction), then the tail will be at an angle of attack and will generate lift, tending to 
push the plane back to its original orientation. 


304 | Chapter 15: Aircraft 


www.it-ebooks.info 



Modeling 

Although we’ve yet to cover a lot of the material required to implement a real-time flight 
simulator, we’d like to go ahead and outline some of the steps necessary to calculate the 
lift and drag forces on your model aircraft: 

1. Discretize the lifting surfaces into a number of smaller wing sections. 

2. Collect geometric and foil performance data. 

3. Calculate the relative air velocity over each wing section. 

4. Calculate the attack angle for each wing section. 

5. Determine the appropriate lift and drag coefficients and calculate lift and drag 
forces. 

The first step is relatively straightforward in that you need to divide the aircraft into 
smaller sections where each section is approximately uniform in characteristics. Per¬ 
forming this step for the model shown in Figure 15-2, you might divide the wing into 
four sections—one for each wing section that’s fitted with an aileron and one for each 
section that’s fitted with a flap. You could also use two sections to model the elevators, 
one port and one starboard, and another section to model the tail/rudder. Finally, you 
could lump the entire fuselage together as one additional section or further subdivide 
it into smaller sections depending on how detailed you want to get. 

If you’re going to model your aircraft as a rigid body, you’ll have to account for all of 
the forces and moments acting on the aircraft while it is in flight. Since the aircraft is 
composed of a number of different components, each contributing to the total lift and 
drag, you’ll have to break up your calculations into a number of smaller chunks and 
then sum all contributions to get the resultant lift and drag forces. You can then use 
these resultant forces along with thrust and gravity in the equations of motion for your 
aircraft. You can, of course, refine your model further by adding more components for 
such items as the cockpit canopy, landing gear, external fuel pods, bombs, etc. The level 
of detail to which you go depends on the degree of accuracy you’re going for. If you are 
trying to mimic the flight performance of a specific aircraft, then you need to sharpen 
your pencil. 

Once you’ve defined each section, you must now prepare the appropriate geometric and 
performance data. For example, for the wings and other lifting surfaces you’ll need to 
determine each section’s initial incidence angle (its fixed pitch or attack angle relative 
to the aircraft reference system), span, chord length, aspect ratio, planform area, and 
quarter-chord location relative to the aircraft’s center of gravity. You’ll also have to pre¬ 
pare a table of lift and drag coefficients versus attack angle appropriate for the section 
under consideration. Since this data is usually presented in graphical form, you’ll have 
to pull data from the charts to build your lookup table for use in your game. Finally, 


Modeling | 305 


www.it-ebooks.info 



you’ll need to calculate the unit normal vector perpendicular to the plane of each wing 
section. (You’ll need this later when calculating angle of attack.) 

These first two steps need only be performed once at the beginning of your game or 
simulation since the data will remain constant (unless your plane changes shape or its 
center of gravity shifts during your simulation). 

The third step involves calculating the relative velocity between the air and each com¬ 
ponent so you can calculate lift and drag forces. At first glance, this might seem trivial 
since the aircraft will be traveling at an air speed that will be known to you during your 
simulation. However, you must also remember that the aircraft is a rigid body and in 
addition to the linear velocity of its center of gravity, you must account for its rotational 
velocity. 

Back in Chapter 2, we gave you a formula to calculate the relative velocity of any point 
on a rigid body that was undergoing both linear and rotational motion: 

v R = v cg + (o) X r) 

This is the formula you’ll need to calculate the relative velocity at each component in 
your model. In this case, v cg is the vector representing the air speed and flight direction 
of the aircraft, o> (omega) is the angular velocity vector of the aircraft, and ris the distance 
vector from the aircraft’s center of gravity to the component under consideration. 

When dealing with wings, once you have the relative velocity vector, you can proceed 
to calculate the attack angle for each wing section. The drag force vector will be parallel 
to the relative velocity vector, while the lift force vector will be perpendicular to the 
velocity vector. Angle of attack is then the angle between the lift force vector and the 
normal vector perpendicular to the plane of the wing section. This involves taking the 
dot product of these two vectors. 

Once you have the attack angle, you can go to your coefficient of lift and drag versus 
attack angle tables to determine the lift and drag coefficients to use at this instant in 
your simulation. With these coefficients, you can use the following formulas to estimate 
the magnitudes of lift and drag forces on the wing section under consideration: 

Lift = C L (1/2) p V 2 S 
Drag = C D (1/2) p V 2 S 

This is a very simplified approach that only approximates the lift and drag character¬ 
istics. This approach does not account for span-wise flow effects, or the flow effects 
between adjacent wing sections. Nor does this approach account for air disturbances, 
such as downwash, that may affect the relative angle of attack for a wing section. Further, 
the airflow over each wing section is assumed to be steady and uniform. 


306 | Chapter 15: Aircraft 


www.it-ebooks.info 



As a simple example, consider wing panel 1, which is the starboard aileron wing section. 
Assume that the wing is set at an initial incidence angle of 3.5° and that the plane is 
traveling at a speed of 38.58 m/s in level flight at low altitude with a pitch angle of 4.5°. 
This wing section has a chord length of 1.585 m and the span of this section is 1.829 m. 
Using the lift and drag data presented in Figure 15-6, calculate the lift and drag on this 
wing section, assuming the ailerons are not deflected and that the density of air is 1.221 
kg/m 3 . 

The first step is to calculate the angle of attack, which is 8°, based on the information 
provided. Now, looking at Figure 15-6, you can find the airfoil lift and drag coefficients 
to be 0.92 and 0.013, respectively. 

Next, you’ll need to calculate the planform area of this section, which is simply its chord 
times its span. This yields 2.899 m 2 . Now you have enough information to calculate lift 
and drag as follows: 


Lift = C L (1/2) p V 2 S 

Lift = 0.92 (1/2) (1.221 kg/m 3 ) (38.58 m/s) 2 (2.899 m 2 ) 

Lift = 2,412.8 N 

Drag = C D (1/2) p V 2 S 

Drag = 0.013 (1/2) (1.221 kg/m 3 ) (38.58 m/s) 2 (2.899 m 2 ) 

Drag = 35.6 N 

In your simulation, you’ll have to perform a similar set of calculations for every com¬ 
ponent that you’ve defined. As you can see, using this sort of empirical data and for¬ 
mulas, although only approximate, lends itself to fairly easy calculations. The hard part 
is deciding what to model and finding the right data, and after that the lift and drag 
calculations are pretty simple. 

We’ve prepared an example program to show you how to model a simple airplane using 
the method shown here. The program is named FlightSim.exe and is a real-time, 3D 
flight simulator. The small aircraft simulated resembles that shown in Figure 15-2. 

This program includes the following source files along with a text file ( Instructions.txt) 
that explains the flight controls: 

• Physics, cpp and Physics, h 

• D3dstuff.cpp and D3dstuff.h 

• Mymath.h 

• Winmain.cpp 

As we said, this program is a real-time simulation, and it treats the aircraft as a rigid 
body. We’ve covered real-time simulations earlier in this book, and Chapter 12 in par- 


Modeling | 307 


www.it-ebooks.info 



ticular covered some aspects of this flight simulation; therefore, some of the code to 
follow will be familiar to you. In this present chapter, though, we’re going to focus on a 
few specific functions that implement the flight model. These functions are contained 
in the source file Physics.cpp. 


The first function we want you to look at is CalcAirplaneMassProperties: 


//-.// 

// This model uses a set of eight discrete elements to represent the 
// airplane. The elements are described below: 

// 

// Element 0 

// Element 1 

// Element 2 

// Element 3 

// Element 4 

// Element 5 

// Element 6 

// Element 7 

// 

// 

// 

It 
tt 

//-- 
void 


Outboard; port (left) wing section fitted with ailerons 
Inboard; port wing section fitted with landing flaps 
Inboard; starboard (right) wing section fitted with 
landing flaps 

Outboard; starboard wing section fitted with ailerons 
Port elevator fitted with flap 
Starboard elevator fitted with flap 

Vertical tail/rudder (no flap; the whole thing rotates) 
The fuselage 


This function first sets up each element and then goes on to calculate 
the combined weight, center of gravity, and inertia tensor for the plane. 
Some other properties of each element are also calculated, which you'll 
need when calculating the lift and drag forces on the plane. 

.// 

CalcAirplaneMassProperties(void) 


float 

mass; 

Vector 

vMoment; 

Vector 

CG; 

int 

t; 

float 

Ixx, Iyy, Izz, Ixy, Ixz, Iyz 

float 

in, di; 


// Initialize the elements here 

// Initially the coordinates of each element are referenced from 

// a design coordinates system located at the very tail end of the plane, 

// its baseline and center line. Later, these coordinates will be adjusted 
// so that each element is referenced to the combined center of gravity of 
// the airplane. 

Element[0].fMass = 6.56f; 

Element[0].vDCoords = Vector(14.5f,12.0f,2.5f); 

Element[0].vLocallnertia = Vector(13.92f,10.50f,24.00f); 

Element[0].flncidence = -3.5f; 

Element[0].fDihedral = 0.0f; 

Element[0].fArea = 31.2f; 

Element[0].iFlap = 0; 

Element[l].fMass = 7.31f; 

Element[l].vDCoords = Vector(14.5f,5.5f,2.5f); 

Element[l].vLocallnertia = Vector(21.95f,12.22f,33.67f); 


308 | Chapter 15: Aircraft 


www.it-ebooks.info 








Elementfl].flncidence = -3.5f; 

Element[l].fDihedral = 0.0f; 

Elenentfl].fArea = 36.4f; 

Elenentfl].iFlap = 0; 

Element[2].fMass = 7.31f; 

Elenent[2].vDCoords = Vector(14.5f,-5.5f,2.5f); 
Elenent[2].vLocallnertia = Vector(21.95f,12.22f,33.67f); 
Element[2].flncidence = -3.5f; 

Element[2].fDihedral = 0.0f; 

Elenent[2].fArea = 36.4f; 

Element[2].iFlap = 0; 

Element[3].fMass = 6.56f; 

Elenent[3].vDCoords = Vector(14.5f,-12.0f,2.5f); 
Elenent[3].vLocallnertia = Vector(13.92f,10.50f,24.00f); 
Element[3].flncidence = -3.5f; 

Element[3].fDihedral = 0.0f; 

Elenent[3].fArea = 31.2f; 

Elenent[3].iFlap = 0; 

Element[4].fMass = 2.62f; 

Elenent[4].vDCoords = Vector(3.03f,2.5f,3.0f); 

Elenent[4].vLocallnertia = Vector(0.837f,0.385f,1.206f); 
Element[4].flncidence = 0.0f; 

Element[4].fDihedral = 0.0f; 

Element[4].fArea = 10.8f; 

Elenent[4].iFlap = 0; 

Element[5].fMass = 2.62f; 

Element[5].vDCoords = Vector(3.03f,-2.5f,3.0f); 
Element[5].vLocallnertia = Vector(0.837f,0.385f,1.206f); 
Element[5].flncidence = 0.0f; 

Element[5].fDihedral = 0.0f; 

Elenent[5].fArea = 10.8f; 

Elenent[5].iFlap = 0; 

Element[6].fMass = 2.93f; 

Element[6].vDCoords = Vector(2.25f,0.0f,5.0f); 

Element[6].vLocallnertia = Vector(1.262f,1.942f,0.718f); 
Element[6].flncidence = 0.0f; 

Elenent[6].fDihedral = 90.0f; 

Elenent[6].fArea = 12.Of; 

Element[6].iFlap = 0; 

Element[7].fMass = 31.8f; 

Element[7].vDCoords = Vector(15.25f,0.0f,1. 5f); 
Element[7].vLocallnertia = Vector(66.30f,861.9f,861.9f); 
Element[7].flncidence = 0.0f; 

Element[7].fDihedral = 0.0f; 

Elenent[7].fArea = 84.0f; 

Elenent[7].iFlap = 0; 


Modeling 


| 309 


www.it-ebooks.info 



// Calculate the vector normal (perpendicular) to each lifting surface. 

// This is required when you are calculating the relative air velocity for 
// lift and drag calculations, 
for (i = 0; i< 8; i++) 

{ 

in = DegreesToRadians(Element[i].flncidence); 
di = DegreesToRadians(Element[i].fDihedral); 

Element[i].vNormal = Vector((float)sin(in), (float)(cos(in)*sin(di)), 

(float)(cos(in)*cos(di))); 

Element[i].vNormal.Normalize(); 

} 

// Calculate total mass 
mass = 0; 

for (i = 0; i< 8; i++) 

mass += Elementfi].fMass; 

// Calculate combined center of gravity location 
vMoment = Vector(0.0f, 0.0f, 0.0f); 
for (i = 0; i< 8; i++) 

{ 

vMoment += Element[i].fMass*Element[i].vDCoords; 

} 

CG = vMoment/mass; 

// Calculate coordinates of each element with respect to the combined CG 
for (i = 0; i< 8; i++) 

{ 

Element[i].vCGCoords = Element[i].vDCoords - CG; 

} 


// Now calculate the moments and products of inertia for the 
// combined elements. 

// (This inertia matrix (tensor) is in body coordinates) 

Ixx = 0; Iyy = 0; Izz = 0; 

Ixy = 0; Ixz = 0; Iyz = 0; 

for (i = 0; i< 8; i++) 

{ 


Ixx += Element[i].vLocallnertia.x + Element[i].fMass * 
(Element[i].vCGCoords.y*Element[i].vCGCoords.y + 
Element[i].vCGCoords.z*Element[i].vCGCoords.z); 

Iyy += Element[i].vLocallnertia.y + Element[i].fMass * 
(Element[i].vCGCoords.z*Element[i].vCGCoords.z + 
Element[i].vCGCoords.x*Element[i].vCGCoords.x); 

Izz += Element[i].vLocallnertia.z + Element[i].fMass * 
(Element[i].vCGCoords.x*Element[i].vCGCoords.x + 
Element[i].vCGCoords.y*Element[i].vCGCoords.y); 

Ixy += Element[i].fMass * (Element[i].vCGCoords.x * 
Element[i].vCGCoords.y); 

Ixz += Element[i].fMass * (Elementfi].vCGCoords.x * 
Element[i].vCGCoords.z); 


310 | Chapter 15: Aircraft 


www.it-ebooks.info 




Iyz += Element[i].fMass * (Element[i].vCGCoords.y * 

Element[i].vCGCoords.z); 

} 

// Finally, set up the airplane's mass and its inertia matrix and take the 
// inverse of the inertia matrix. 

Airplane.fMass = mass; 

Airplane.mlnertia.ell = Ixx; 

Airplane.mlnertia.el2 = -Ixy; 

Airplane.mlnertia.el3 = -Ixz; 

Airplane.mlnertia.e21 = -Ixy; 

Airplane.mlnertia.e22 = Iyy; 

Airplane.mlnertia.e23 = -Iyz; 

Airplane.mlnertia.e31 = -Ixz; 

Airplane.mlnertia.e32 = -Iyz; 

Airplane.mlnertia.e33 = Izz; 

Airplane.mlnertialnverse = Airplane.mlnertia.Inverse(); 

} 

Among other things, this function essentially completes step 1 (and part of step 2) of 
our modeling method: discretize the airplane into a number of smaller pieces, each with 
its own mass and lift and drag properties. For this model we chose to use eight pieces, 
or elements, to describe the aircraft. Our comments at the beginning of the function 
explain what each element represents. 

The very first thing this function does is initialize the elements with the properties that 
we’ve defined to approximate the aircraft. Each element is given a mass, a set of design 
coordinates to its center of mass, a set of moments of inertia about each elements center 
of mass, an initial incidence angle, a planform area, and a dihedral angle. 

The design coordinates are the coordinates of the element with respect to an origin 
located at the very tip of the aircraft’s tail, on its centerline and at its baseline. The x-axis 
of this system points toward the nose of the aircraft, while the y-axis points toward the 
port side. The z-axis points up. You have to set up your elements in this design coordinate 
system first because you don’t yet know the location of the whole aircraft’s center of 
mass, which is the combined center of mass of all of the elements. Ultimately, you want 
each element referenced from the combined center of mass because it’s the center of 
mass that you’ll track during the simulation. 

The dihedral angle is the angle about the x-axis at which the element is initially set. For 
our model, all of the elements have a 0 dihedral angle; that is, they are horizontal, except 
for the tail rudder, which has a 90° dihedral since it is oriented vertically. 

After we’ve set up the elements, the first calculation that this function performs is to 
find the unit normal vector to each element’s surface based on the element’s incidence 
and dihedral angles. You need this direction vector to help calculate the angle of attack 
between the airflow and the element. 


Modeling | 311 


www.it-ebooks.info 



The next calculation is the total mass calculation, which is simply the sum of all element 
masses. Immediately following that, we determine the combined center of gravity lo¬ 
cation using the technique we discussed in Chapter 1. The coordinates to the combined 
center of gravity are referenced to the design coordinate system. You need to subtract 
this coordinate from the design coordinate of each element in order to determine each 
element’s coordinates relative to the combined center of gravity. After that, you’re all set 
with the exception of the combined moment of inertia tensor, which we already dis¬ 
cussed in Chapter 11 and Chapter 12. 

Step 2 of our modeling method says you need to collect the airfoil performance data. 
For the example program, we used a cambered airfoil with plain flaps to model the wings 
and elevators, and we used a symmetric airfoil without flaps to model the tail rudder. 
We didn’t use flaps for the tail rudder since we just made the whole thing rotate about 
a vertical axis to provide rudder action. 

For the wings, we set up two functions to handle the lift and drag coefficients: 

//-.// 

// Given the attack angle and the status of the flaps, this function 
// returns the appropriate lift coefficient for a cambered airfoil with 
// a plain trailing-edge flap (+/- 15 degree deflection). 

//-.// 

float LiftCoefficient(float angle, int flaps) 

1 

float clf0[9] = {-0.54f, -0.2f, 0.2f, 0.57f, 0.92f, 1.21f, 1.43f, 1.4f, 

i.0f}; 

float clfd[9] = {0.0f, 0.45f, 0.85f, 1.02f, 1.39f, 1.65f, 1.75f, 1.38f, 
1.17f}; 

float clfu[9] = {-0.74f, -0.4f, 0.0f, 0.27f, 0.63f, 0.92f, 1.03f, l.lf, 
0.78f}; 

float a[9] = {-8.0f, -4.0f, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 

24.0f}; 

float cl; 
int i; 

cl = 0; 

for (i=0; i<8; i++) 

{ 

if( (a[i] <= angle) && (a[i+l] > angle) ) 

1 

switch(flaps) 

{ 

case 0:// flaps not deflected 

cl = clf0[i] - (a[i] - angle) * (clf0[i] - clf0[i+l]) / 

(a[i] - a[i+l]); 
break; 

case -1: // flaps down 

cl = clfd[i] - (a[i] - angle) * (clfd[i] - clfd[i+l]) / 

(a[i] - a[i+l]); 
break; 


312 | Chapter 15: Aircraft 


www.it-ebooks.info 





case 1: // flaps up 

cl = clfu[l] - (a[1] - angle) * (clfu[l] - clfu[i+l]) / 
(a[1] - a[i+l]); 
break; 

} 

break; 

} 

} 


return cl; 


} 

//.// 

// Given the attack angle and the status of the flaps, this function 
// returns the appropriate drag coefficient for a cambered airfoil with 
// a plain trailing-edge flap (+/- 15 degree deflection). 

//.// 

float DragCoefficient(float angle, int flaps) 


{ 


float cdf0[9] 

float cdfd[9] 

float cdfu[9] 

float a[9] 

float cd; 
int i; 


{0.01f, 0.0074f, 0.004f, 0.009f, 0.013f, 0.023f, 0.05f, 
0.12f, 0.21f}; 

{0.0065f, 0.0043f, 0.0055f, 0.0153f, 0.0221f, 0.0391f, 0.1f, 
0.195f, 0.3f}; 

{0.005f, 0.0043f, 0.0055f, 0.02601f, 0.03757f, 0.06647f, 

0.13f, 0.18f, 0.25f}; 

= {-8.0f, -4.0f, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 

24.0f}; 


cd = 0.5; 

for (i=0; i<8; i++) 

{ 

if( (a[i] <= angle) && (a[i+l] > angle) ) 

{ 

switch(flaps) 

{ 

case 0:// flaps not deflected 

cd = cdf0[i] - (a[i] - angle) * 
(a[i] - a[i+1]); 
break; 

case -1: // flaps down 

cd = cdfd[i] - (a[i] - angle) * 
(a[i] - a[i+1]); 
break; 

case 1: // flaps up 

cd = cdfu[i] - (a[i] - angle) * 
(a[i] - a[i+1]); 
break; 

} 

break; 


(cdf0[i] - cdf0[i+l]) / 


(cdfd[i] - cdfd[i+l]) / 


(cdfu[i] - cdfu[i+l]) / 


Modeling | 313 


www.it-ebooks.info 





} 

return cd; 


} 

Each of these functions takes the angle of attack as a parameter along with a flag used 
to indicate the state of the flaps—that is, whether the flaps are in neutral position, de¬ 
flected downward, or deflected upward. Notice that the lift and drag coefficient data is 
given for a set of discrete attack angles, thus we use linear interpolation to determine 
the coefficients for attack angles that fall between the discrete angles. 

The functions for determining the tail rudder lift and drag coefficients are similar to 
those shown here for the wings, with the only differences being the coefficients them¬ 
selves and the fact that the tail rudder does not include flaps. Here are the functions: 

//-.// 

// Given the attack angle, this function returns the proper lift coefficient 
// for a symmetric (no camber) airfoil without flaps. 

//-.// 

float RudderLiftCoefficient(float angle) 

{ 

float clf0[7] = {0.16f, 0.456f, 0.736f, 0.968f, 1.144f, 1.12f, 0.8f}; 
float a[7] = {0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f}; 

float cl; 
int i; 

float aa = (float) fabs(angle); 

cl = 0; 

for (i=0; i<8; i++) 

{ 

if( (a[i] <= aa) && (a[i+1] > aa) ) 

{ 

cl = elf0[i] - (a[i] - aa) * (clf0[i] - clf0[i+l]) / 

(a[i] - a[i+1]); 
if (angle < 0) cl = -cl; 
break; 

} 

} 

return cl; 

} 

//-.// 

// Given the attack angle, this function returns the proper drag coefficient 
// for a symmetric (no camber) airfoil without flaps. 

//-.// 

float RudderDragCoefficient(float angle) 

{ 

float cdf0[7] = {0.0032f, 0.0072f, 0.0104f, 0.0184f, 0.04f, 0.096f, 0.168f}; 
float a[7] = (0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f}; 

float cd; 
int i; 


314 | Chapter 15: Aircraft 


www.it-ebooks.info 










float 


aa = (float) fabs(angle); 


cd = 0.5; 

for (1=0; i<8; i++) 

{ 

lf( (a[1] <= aa) && (a[i+l] > aa) ) 

{ 

cd = cdf0[l] - (a[i] - aa) * (cdf0[i] - cdf0[i+l]) / 

(a[i] - a[i+l]); 
break; 

} 

} 

return cd; 

} 

With steps 1 and 2 out of the way, steps 3,4, and 5 are handled in a single function called 
CalcAirplaneLoads: 

//-.....// 

// This function calculates all of the forces and moments acting on the 
// plane at any given time. 

//-.// 

void CalcAirplaneLoads(void) 

{ 

Vector Fb, Mb; 

// reset forces and moments: 

Airplane.vForces.x = 0.0f; 

Airplane.vForces.y = 0.0f; 

Airplane.vForces.z = 0.0f; 

Airplane.vMoments.x = 0.0f; 

Airplane.vMoments.y = 0.0f; 

Airplane.vMoments.z = 0.0f; 

Fb.x = 0.0f; Mb.x = 0.0f; 

Fb.y = 0.0f; Mb.y = 0.0f; 

Fb.z = 0.0f; Mb.z = 0.0f; 

// Define the thrust vector, which acts through the plane's CG 
Thrust.x = 1.0f; 

Thrust.y = 0.0f; 

Thrust.z = 0.0f; 

Thrust *= ThrustForce; 

// Calculate forces and moments in body space: 


Vector 

vLocalVelocity 

float 

fLocalSpeed; 

Vector 

vDragVector; 

Vector 

vLiftVector; 

float 

fAttackAngle; 

float 

tmp; 

Vector 

vResultant; 


Modeling | 315 


www.it-ebooks.info 






int i; 

Vector vtmp; 

Stalling = false; 

for(i=0; l<7; 1++) // loop through the seven lifting elements 
// skipping the fuselage 

{ 

if (i == 6) // The tail/rudder is a special case since it can rotate; 
{ // thus, you have to recalculate the normal vector, 

float in, di; 

in = DegreesToRadians(Element[i].fIncidence); // incidence angle 
di = DegreesToRadians(Element[i].fDihedral); // dihedral angle 
Elementfi].vNormal = Vector( (float)sin(in), 

(float)(cos(in)*sin(di)), 
(float)(cos(in)*cos(di))); 

Element[i].vNormal.Normalize(); 

} 

// Calculate local velocity at element 

// The local velocity includes the velocity due to linear 

// motion of the airplane, 

// plus the velocity at each element due to the 
// rotation of the airplane. 

// Here's the rotational part 

vtmp = Airplane.vAngularVelocity A Element[i].vCGCoords; 

vLocalVelocity = Airplane.vVelocityBody + vtmp; 

// Calculate local air speed 
fLocalSpeed = vLocalVelocity. MagnitudeQ; 

// Find the direction in which drag will act. 

// Drag always acts inline with the relative 
// velocity but in the opposing direction 
if(fLocalSpeed >1.) 

vDragVector = -vLocalVelocity/fLocalSpeed; 

// Find the direction in which lift will act. 

// Lift is always perpendicular to the drag vector 
vLiftVector = (vDragVector A Element[i].vNormal) A vDragVector; 
tmp = vLiftVector. MagnitudeQ; 
vLiftVector.Normalize(); 

// Find the angle of attack. 

// The attack angle is the angle between the lift vector and the 

// element normal vector. Note, the sine of the attack angle 

//is equal to the cosine of the angle between the drag vector and 

// the normal vector. 

tmp = vDragVector*Element[i].vNormal; 

if(tmp > 1.) tmp = 1; 


316 | Chapter 15: Aircraft 


www.it-ebooks.info 



lf(tmp < -1) tmp = -1; 

fAttackAngle = RadlansToDegrees((float) asin(tmp)); 

// Determine the resultant force (lift and drag) on the element, 
tmp = 0.5f * rho * fLocalSpeed*fLocalSpeed * Element[i].fArea; 
if (i == 6) // Tail/rudder 
{ 

vResultant = (vLiftVector*RudderLiftCoefficient(fAttackAngle) + 
vDragVector*RudderDragCoefficient(fAttackAngle)) 

* tmp; 

} else 

vResultant = (vLiftVector*LiftCoefficient(fAttackAngle, 

Elementfi].iFlap) + 

vDragVector*DragCoefficient(fAttackAngle, 

Elementfi].iFlap) ) * tmp; 

// Check for stall. 

//We can easily determine stall by noting when the coefficient 
//of lift is 0. In reality, stall warning devices give warnings well 
// before the lift goes to 0 to give the pilot time to correct, 
if (i<=0) 

{ 

if (LiftCoefficient(fAttackAngle, Element[i].iFlap) == 0) 

Stalling = true; 

} 

// Keep a running total of these resultant forces (total force) 

Fb += vResultant; 

// Calculate the moment about the CG of this element's force 
// and keep a running total of these moments (total moment) 
vtmp = Element[i].vCGCoords A vResultant; 
lib += vtmp; 

} 

// Now add the thrust 
Fb += Thrust; 

// Convert forces from model space to earth space 
Airplane.vForces = QVRotate(Airplane.qOrientation, Fb); 

// Apply gravity (g is defined as -32.174 ft/s A 2) 

Airplane.vForces.z += g * Airplane.fliass; 

Airplane.vMoments += Mb; 

} 

The first thing this function does is reset the variables that hold the total force and 
moment acting on the aircraft. Next, the thrust vector is set up. This is trivial in this 
example since we’re assuming that the thrust vector always points in the plus x-axis 
direction (toward the nose) and passes through the aircraft center of gravity (so it does 
not create a moment). 


Modeling | 317 


www.it-ebooks.info 



After calculating the thrust vector, the function loops over the model elements to cal¬ 
culate the lift and drag forces on each element. We’ve skipped the fuselage in this model; 
however, if you want to account for its drag in your model, this is the place to add the 
drag calculation. 

Going into the loop, the first thing the function does is check to see if the current element 
is element number six, the tail rudder. If it is, then the rudders normal vector is recal¬ 
culated based on the current incidence angle. The incidence angle for the rudder is 
altered when you press the X or C keys to apply rudder action. 

The next calculation is to determine the relative velocity between the air and the element 
under consideration. As we stated earlier, this relative velocity consists of the linear 
velocity as the airplane moves through the air plus the velocity of each element due to 
the airplane’s rotation. Once you’ve obtained this vector, you calculate the relative air 
speed by taking the magnitude of the relative velocity vector. 

The next step is to determine the direction in which drag will act. Since drag opposes 
motion, it acts inline with, but opposite to, the relative velocity vector; thus, all you need 
to do is take the negative of the relative velocity vector and normalize the result (divide 
it by its magnitude) to obtain the drag direction vector. Since this vector was normalized, 
its length is equal to 1 (unity), so you can multiply it by the drag force that will be 
calculated later to get the drag force vector. 

After obtaining the drag direction vector, this function uses it to determine the lift 
direction vector. The lift force vector is always perpendicular to the drag force vector, 
so to calculate its direction you first take the cross product of the drag direction vector 
with the element normal vector and then cross the result with the drag direction vector 
again. Here again, the function normalizes the lift direction vector. 

Now that the lift and drag direction vectors have been obtained, the function proceeds 
to calculate the angle of attack for the current element. The attack angle is the angle 
between the lift vector and the element normal. You can calculate the angle by taking 
the inverse cosine of the vector dot product of the lift direction vector with the element 
normal vector. Since the drag vector is perpendicular to the lift vector, you can get the 
same result by taking the inverse sine of the vector dot product of the drag direction 
vector with the element normal vector. 

Now with all the lift and drag vector stuff out of the way, the function goes on to calculate 
the resultant force acting on the element. The resultant force vector is simply the vector 
sum of the lift and drag force vectors. Notice that this is where the lift and drag coefficient 
functions are called and where the empirical lift and drag formulas previously discussed 
are applied. 

After calculating the resultant force, the function checks to see if the calculated lift 
coefficient is 0. If it is, then the stall flag is set to warn us that the plane is in a stalled 
situation. 


318 | Chapter 15: Aircraft 


www.it-ebooks.info 



Finally, the resultant force is accumulated in the total force vector variable, and we 
calculate the moment by taking the cross product of the element coordinate vector with 
the resultant force. The resulting moment is accumulated in the total moment vector 
variable. After exiting the loop, the function adds the thrust vector to the total force. 

So far, all of these forces and moments have been referenced in the body-fixed- 
coordinate system. The only thing left to do now is apply the gravity force, but this force 
acts in the negative y-axis direction in the earth-fixed-coordinate system. To apply the 
gravity force, the function must first rotate the body force vector from body space to 
earth space coordinates. We used a quaternion rotation technique in this example, which 
we already discussed in Chapter 11 and Chapter 12. 

That’s pretty much it for the flight model. We encourage you to play with the flight model 
in this program. Go ahead and tweak the element properties and watch to see what 
happens. Even though this is a rough model, the flight results look quite realistic. 


Modeling | 319 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 16 


Ships and Boats 


The physics of ships is a vast subject. While the same principles govern canoes and super 
tankers, the difference between the two scales is not trivial. Our goal in this chapter will 
be to explain some of the fundamental physical principles to allow you to develop re¬ 
alistic simulations. The typical displacement-type ship lends itself well to illustrating 
these principles; however, many of these principles also apply to other objects sub¬ 
merged or partially submerged in a fluid, such as submarines and air balloons. Re¬ 
member, air is considered a fluid when we are considering buoyancy. 

While surface ships or ships that operate on the water’s surface (at the air water interface) 
are similar to fully submerged objects like submarines or air balloons in that they all 
experience buoyancy, there are some very distinct differences in their physical nature 
that we’ll highlight in this chapter. These differences affect their behavior, so it is im¬ 
portant to be aware of them if you intend to simulate such objects. 

Ships have an entire language of their own, so we’ll be spending a lot of time just getting 
the vocabulary right. This will allow you to do further research on any topics that are 
of particular interest. There are many ways to classify ships and boats, but in regards to 
the physics governing them, there are three basic types. Displacement vessels, semi¬ 
displacement vessels, and planing vessels are named after the forces that keep the boat 
afloat while it is at cruising speed. When not moving, all vessels are in displacement 
mode. 

The term displacement in this context means that the ship is supported solely by buoy¬ 
ancy—that is, without dynamic or aerostatic lift as you would see on a high-speed racing 
boat or a hovercraft. The word displacement itself refers to the volume of water displaced 
or “pushed” out of the way by the ship as it sits floating in the water. We’ll discuss this 
more in the next section. 

A planing vessel is one that is not supported by buoyancy, but by hydrodynamic lift. 
This includes the everyday speedboats that most boaters own. When the boat isn’t mov- 


321 


www.it-ebooks.info 




ing, it just floats in the water, bobbing up and down. However, when the boat begins 
traveling at high speed, the force of the water hitting the bottom of the boat causes the 
boat to rise up. This is known as planing, and it greatly reduces the resistance of the 
vessel. Semi-displacement vessels are those that straddle the two categories, with some 
support coming from buoyancy and some coming from planing forces. Before we con¬ 
tinue discussing this, let’s go over some vocabulary. 

The hull of the ship is the watertight part of the ship that actually displaces the water. 
Everything in or on the ship is contained within the hull, which is partially submerged 
in the water. The length of the ship is the distance measured from the bow to the stern. 
In practice, there are several lengths used to denote the length of a ship, but here we’ll 
refer to the overall length of the hull. The bow is the front of the ship, while the stern is 
the aft part. When you are on the ship facing the bow, the port side is to your left and 
the starboard side is to your right. The overall height of the hull is called the depth, and 
its width is called breadth or beam. When a ship is floating in the water, the distance 
from the water surface to the bottom of the hull is called the draft. Figure 16-1 illustrates 
these terms. 


Stern 


Depth ~t 


Draft 

I 


Beam 


Bow 


Hull 


Profile 


Port 


Starboard 

— Length— 

Plan 


Figure 16-1. Ship geometry 


Given that ship design is a diverse subject, we’ll limit ourselves to discussing those 
aspects of ships that make for realistic models. These subjects include stability and 
sinking, resistance characteristics, propulstion, and manuverability. Most of these sub¬ 
jects cannot be fully simulated in real time, so we’ll show you some general rules that 
ships follow instead of full numerical simulation. 


322 | Chapter 16: Ships and Boats 


www.it-ebooks.info 
















Stability and Sinking 

If you have boats in your video game, the first step to making them realistic physically 
is allowing them to sink if they become damaged. To understand why boats sink and 
how they do so, you must first understand stability. 

Stability 

Most boats are least stable about their longitudinal axis—that is, they are easier to heel 
port and starboard than they are to flip end over end. If the vessel heels over so far that 
it is upside down, this is called capsizing. This is how most boats sink due to wind, waves, 
or in some cases of side damage. One of the most famous examples of a sinking ship, 
the Titanic, shows that when a boat is sinking from damage, it can sink end over end, 
sometimes with the ship breaking in two. We’ll discuss both here so that you can animate 
realistic sinking in your simulation. 

In Chapter 3 we introduced the concept of buoyancy and stated that the force on a 
submerged object due to buoyancy is a function of the submerged volume of the object. 
Archimedes’s principle states that the weight of an object floating in a fluid is equal to 
the weight of the volume of fluid displaced by the object. This is an important principle. 
It says that a ship of a given weight must have sufficient volume to displace enough 
water, an amount equal to the weight of the ship, in order for it to float. Further, this 
principle provides a clever way of determining the weight of a ship: simply measure or 
calculate the amount of water displaced by the ship and you can calculate the weight of 
the ship. In the marine field, displacement is synonymous with the weight of the ship. 

As discussed in Chapter 3, we can calculate the buoyant force on any object by using 
the following formula: 


F B = p g V 

Here, V is the submerged volume of the object, p is the density of the fluid within which 
the object is submerged, and g is the acceleration due to gravity. Since buoyancy is a 
force, it has both magnitude and direction, and always acts straight up through the 
center of buoyancy. The center of buoyancy is the geometric center of the submerged 
part of the object. 

When a ship is floating in equilibrium on the surface of the water, its center of buoyancy 
must be located directly below the ship’s center of gravity. The weight of the ship, a force, 
acts straight down through the center of gravity, opposing the force due to buoyancy. 
When the ship is in equilibrium, these two forces, weight and buoyancy, are equal in 
magnitude and opposite in direction. 

Now, when an external force causes the ship to roll or pitch, the portion of the hull below 
the water is changed and the center of buoyancy moves to the new geometric centroid 


Stability and Sinking | 323 


www.it-ebooks.info 



of the underwater portion of the hull. For example, if the ship rolls to the starboard side, 
then the center of buoyancy shiwfts out toward the starboard side. When this happens, 
the lines of action of the weight of the ship and the buoyant force are no longer in line, 
which results in a moment (torque) that acts on the ship. This torque is equal to the 
perpendicular distance between the lines of action of the forces times the weight of the 
ship. 

Now here’s where we get to the floating upright part that we mentioned earlier. When 
a ship rolls, for example, you don’t want it to keep rolling until it capsizes. Instead, you 
want it to gently return itself to the upright position after whatever force caused it to 
roll—the wind, for example—has been removed. In short, you want the ship to be stable. 
For a ship to be stable, the line of action of the buoyant force must cross the vessel’s 
centerline at a point, called the metacenter, above the center of gravity. When this hap¬ 
pens, the moment developed when the ship rolls tends to restore the ship to the upright 
position. If the metacenter is located below the center of gravity, then the moment 
developed would tend to capsize the ship. The distance between the center of gravity 
and the metacenter is called GM. This is also known as the stability index, as a positive 
value means the floating body is stable and a negative GM means the body is unstable. 
Figure 16-2 illustrates these two scenarios. 




Figure 16-2. Ship stability 


324 | Chapter 16: Ships and Boats 


www.it-ebooks.info 
















If you’re a sailor, then you know how important it is to keep the center of gravity of your 
boat low. This helps increase the height of the metacenter above the center of gravity, 
and thus helps with stability. 

In the case of fully submerged objects, like submarines, the situation is different. The 
buoyant force still acts through the geometric centroid of the object, but for stability, 
the center of buoyancy must be located above the center of gravity. This way, when the 
object rotates, the lines of action of the weight of the object and the buoyant force are 
separated and form a moment that tends to restore the object to its upright position. If 
it’s the other way around, then the object would be unstable, like trying to balance one 
bowling ball on top of another. In this case, the slightest disturbance would upset the 
balance and the object would flip upside-down such that the center of gravity is located 
below the center of buoyancy. 

Sinking 

In general, boats protect their stability by compartmentalizing the hull into several wa¬ 
tertight sections, fittingly called compartments. This way, if the side of a vessel hits an 
iceberg, only the compartment damaged will flood with seawater. If enough compart¬ 
ments are damaged, the vessel will not have enough buoyancy to support its weight and 
it will sink. The end with the flooded compartments will sink first, causing a large angle 
about the transverse axis. This is what happened to the Titanic. In fact, in that ship’s 
case, the angle, called trim, was so large that the stern was lifted out of the water. The 
hull could not support the weight of the stern section that was no longer being supported 
by buoyancy, and the structure ripped in two. 

It should be noted that ships can sink in the matter of minutes, or it can take hours. For 
instance, the Titanic took about three hours to sink. The Lusitania sank in 18 minutes. 
The time it takes depends heavily on the type of damage and the construction of the 
vessel. We don’t suggest trying to get players to wait three hours for their game to end; 
however, it is possible to continue fighting/propelling a vessel that is terminally dam¬ 
aged. In many cases where terminal damage is suspected, captains endeavor to ground 
their vessels to prevent the ship from actually going under. 

If side damage occurs, especially in high wind and waves, then it could be that the vessel 
can still have enough buoyancy to float, but no longer enough stability to remain upright. 
As damage usually occurs only on one side of a vessel, the center of buoyancy will no 
longer be on centerline. This means that the restoring moment in one direction is di¬ 
minished by whatever amount the center has moved to that side. A big wave comes 
along and pushes the vessel over to the point where the righting arm is no longer positive. 
The vessel will flip 180 degrees with the bottom pointed skyward but will still float 
(capsizing). Once rolled over, the remaining compartments will tend to fill with water 
as vents or other openings fail over time. In the case of recreational boats, they are usually 


Stability and Sinking | 325 


www.it-ebooks.info 



only a single compartment. If they capsize, they will sink readily; indeed, this is the way 
that most small boats sink. 

As we mentioned before, accurately computing all degrees of freedom for a nontrivial¬ 
shaped body in real time would be difficult to accomplish with todays computer hard¬ 
ware. In general, you want to follow a few high-level rules: 

• The higher the center of gravity, the more likely it is that the boat will tip over. 

• Large vessels are always compartmentalized. Damage should be limited to the wa¬ 
tertight compartment in which it occurred. 

• The vessel will heal or trim in the direction of damage. If damage occurs on the 
starboard side, the boat will heel to starboard. If the damage occurs in the bow, the 
boat will list forward. 

• A boat will remain floating as long as the undamaged compartments have a volume 
in cubic meters of at least the weight of the hull in metric tons divided by 1.025. 

• After being damaged, even if a vessel has enough undamaged volume to remain 
afloat, it doesn’t necessarily mean it will float upright. 

• Sinking almost never occurs as quickly as depicted in video games; however, cap¬ 
sizing can occur rapidly and is probably a more realistic way to model a stability 
failure. 


Ship Motions 

Closely related to ship stability is the subject of ship motions. Knowing how vessels 
work in a random set of waves will greatly help you to increase realism in your games. 
The most important aspect of this is coupled motions, which we will talk about shortly. 
First, some more vocabulary! As discussed before, there are six degrees of motion any 
rigid body is capable of; for boats, some of these have special names and are described 
next and illustrated in Figure 16-3. 



326 | Chapter 16: Ships and Boats 


www.it-ebooks.info 





Roll, pitch, and yaw are the terms also used for airplanes. The translation degrees of 
freedom are called surge, heave, and sway. Surge, sway, and yaw are not that apparent 
when vessels are moving forward, so it is acceptable to limit your model to heave, pitch, 
and roll. Heave is the up-and-down motion of the boat caused by the change in elevation 
of the water’s surface as a wave passes. If a vessel is stationary, it would be referred to as 
bobbing. Pitch is the rotation about the transverse axis of the vessel due to increased 
buoyancy on one end of the ship as a wave passes. This motion is most pronounced 
when the waves are traveling in the same direction (or 180 degrees) from the vessel. Roll 
is like pitch, but about the longitudinal axis. 

Heave 

As stated before, heave is displacement in the vertical direction from the static equili¬ 
brium draft. This degree of freedom is straightforward to model as a hydrostatic spring 
acting in the vertical direction. Assuming we have a barge that is 30 meters long and 10 
meters wide, we’ll develop an equation that can govern our heave simulation. 

Commonly, a vessel’s hydrostatics include something called tons per centimeter im¬ 
mersion (TPCM)—that is, for every centimeter you press the boat down, a certain 
number of tons of buoyancy force is created. For our barge, this is a relatively straight¬ 
forward calculation. 

Given that the water plane area is a constant 300 square meters, 1 centimeter of im¬ 
mersion would result in a volume of 3 cubic meters. As 1 cubic meter of saltwater weighs 
1,027 kg, 3 cubic meters would be 3,081 kg, and (assuming this boat is on Earth), would 
result in a buoyant force of 3,081 kg x 9.81 m/s 2 , or 30.2 kN. Therefore, 30.2 kN per cm 
would make a good starting value for a spring constant to model the heave response of 
this vessel in waves. 

Roll 

For us to simulate realistic roll motions, it is important that the ship take time to com¬ 
plete the motion. This time is called the roll period. This defines the angular velocity 
that a ship rolled to one side will experience when it recovers. We can estimate it by the 
following equation: 


T = 


2 nk 

■s/gxGM 


Where k is the radius of gyration and GM is the distance from the metacenter to the 
center of gravity. A good estimate for the radius of gyration is often taken as 30% of the 
beam of the vessel. A vessel with a shorter roll period will respond quicker to a wave 
and try to assume the wave slope. This is known as being “stiff” and can cause passenger 
discomfort and damage via higher angular accelerations. Conversely, vessels with higher 


Ship Motions | 327 


www.it-ebooks.info 





roll periods are known as “tender” and lag behind the waves. These vessels generally 
heel farther over but are more comfortable for passengers. 

Pitch 

Likewise, there is a pitch period that measures the speed at which the vessel responds 
to a wave. This is highly dependent on the length of a ship and can be estimated as 
follows: 


T = (2it / g 1/2 )(k/(GM) 1/2 ) 

Where k is the radius of gyration and is commonly taken as 30% of the beam. Note that 
pitch period is normally one-third to one-half that of roll period, so that the bow of a 
vessel will rise and fall with the wave more in phase than in a roll event. 

Coupled Motions 

The real trick to getting motions to look right is to understand that for most boats the 
motions are coupled. For instance, heave and pitch are strongly coupled. This means 
that if a wave causes your boat to heave, it will most likely also cause it to pitch. This is 
because the distribution of buoyancy along the hull is not constant. If the waterline is 
raised some constant value, there is usually more buoyancy provided aft than there is 
forward for the same change in waterline. This will cause the vessel to pitch forward to 
move the center of buoyancy to the longitudinal location of the center of gravity. Sim¬ 
ilarly, a pitch event will cause the vessel to heave because if the stern is lifted from the 
water, there is usually a loss of total buoyancy, and the boat will sink farther into the 
water. 

Resistance and Propulsion 

Resistance is the amount of force it takes to move a body through the water. Propulsion 
is the method by which you create that force. 

General Resistance 

In Chapter 3, we discussed drag forces on objects moving through a fluid. Specifically, 
we discussed frictional and pressure drag. Ships moving on the water’s surface experi¬ 
ence these drag forces; however, at the air-water interface, there are other drag compo¬ 
nents that you have to consider. If you were to write an equation breaking up the total 
resistance acting on a ship into its three main components, that equation would look 
something like this: 


Rtotal — Rfriction + R| 


pressure 


+ R\> 


328 | Chapter 16: Ships and Boats 


www.it-ebooks.info 



We’ll describe each of these components and give you some empirical formulas in just 
a moment. First, however, we want to qualify the material to follow by saying it is very 
general in nature and applicable only when little detail is known about the complete 
geometry of the particular ship under consideration. In the practice of ship design, these 
formulas would be used only in the very early stages of the design process to approximate 
resistance. That said, they are very useful for getting in the ballpark, so to speak, and 
(sometimes more importantly) in performing parametric studies to see the effects of 
changes in major parameters. 

The first resistance component is the frictional drag on the underwater surface of the 
hull as it moves through the water. This is the same as the frictional drag that we dis¬ 
cussed in Chapter 3. However, for ships there’s a convenient set of empirical formulas 
that you can use to calculate this force: 


Rfriction — (1/2) p V - S Cf 


In this formula, p is the density of water, V is the speed of the ship, S is the surface area 
of the underwater portion of the hull, and C f is the coefficient of frictional resistance. 
You can use this empirical formula to calculate C f : 

C f = 0.075 /(loglORn- 2)2 

Here, Rn is the Reynolds number, as defined in Chapter 6, based on the length of the 
ship’s hull. This formula was adopted in 1957 by the International Towing Tank Con¬ 
ference (ITTC) and is widely used in the field of naval architecture for estimating fric¬ 
tional resistance coefficients for ships. 

To apply the formula for R friction , you’ll also have to know the surface area, S, of the 
underwater portion of the hull. You can directly calculate this area using numerical 
integration techniques, similar to those for calculating volume, or you can use yet an¬ 
other empirical formula: 

S = C ws V(VL) 

In this formula, V is the displaced volume, L the length of the ship, and C ws is the wetted 
surface coefficient. This coefficient is a function of the ship’s shape—its breadth-to-draft 
ratio—and statistically it ranges from 2.6 to 2.9 for typical displacement hull forms. 

The pressure drag experienced by a ship is the same as that experienced by projectiles 
as discussed in Chapter 3. Remember, this drag is due to the viscous effects causing a 
region of relatively low pressure behind the ship. Quantifying this force is difficult for 
ships of arbitrary geometry. We can use computational fluid dynamics algorithms to 
approximate this force, but this requires detailed knowledge of the hull geometry and 
a whole lot of time-consuming computations. An alternative is to rely on scale-model 


Resistance and Propulsion | 329 


www.it-ebooks.info 



test data where results from the model test are extrapolated to approximate drag on the 
full-size ship. 

Just like pressure drag, wave drag is difficult to compute, and we usually rely on model 
testing in practice. Wave drag is due to the energy transfer, or momentum transfer, from 
the ship to the fluid, or in other words, it’s a function of the work done by the ship on 
the surrounding fluid to generate the waves. The visible presence of wave resistance is 
evident in the large bow wave that builds up at the front of the ship as well as the wave 
system that originates at the stern of the ship as it moves through the water. These waves 
affect the pressure distribution around the ship and thus affect the pressure drag, which 
makes it difficult for us to separate the wave drag component from pressure drag when 
performing an analysis. 

When scale model tests are performed, pressure drag and wave drag are usually lumped 
together in what’s known as residual resistance. Analogous to the coefficient of frictional 
drag, you can determine a coefficient of residual resistance, such that: 


R r — Rpressure + 


= (1/2) p V 2 S C r 


Here R, is the total residual resistance, and C r is the coefficient of residual resistance. 

There are many resistance estimation methods available that allow you to estimate the 
coefficient of residual resistance for a ship; however, they are usually presented for 
specific ship types. For example, one method might give empirical formulas for C r for 
destroyer-type ships, while another might give formulas for C r for large oil tankers. The 
trick, of course, is to choose a method appropriate for the type of ship you are analyzing. 
1 Generally, C r increases as the displacement and speed of the ship increase. A typical 
range for C r for large displacement hulls is from 1.0e-3 to 3.0e-3. 

While these three resistance components—friction, pressure, and wave—are the most 
important for typical displacement-type ships, they aren’t the only ones. Since a ship 
operates at the air-water interface, a large part of its structure is above the water surface, 
exposed to the air. This means that the ship will also experience air resistance. You can 
approximate this air resistance using the following formula: 

R air = (1/2) p V 2 Ap C a j r 


Here, C air is the coefficient of air resistance, p is the density of air, V is the speed of the 
ship, and A p is the projected transverse (profile) area of the ship. C air typically ranges 
from 0.6 to 1.1, depending on the type of ship. Tankers and large cargo ships tend to be 
near the upper end of the range, while combatant ships tend to be near the lower end. 


1. These methods are quite involved and there are far too many to discuss here, so we’ve included some references 
in the Bibliography for you. 


330 | Chapter 16: Ships and Boats 


www.it-ebooks.info 



In lieu of enough information to calculate the projected transverse area of the ship, you 
can approximate it by: 


A p = B 2 /2 

where B is the breadth (width) of the ship. 

Planing craft 

Planing craft are different than displacement vessels in that when they reach their cruis¬ 
ing speed they are not supported by buoyancy. Unlike a super tanker, a recreational 
speedboat has a much “flatter” hull form. It almost looks like a very fat foil, which it is! 
When a speedboat is just sitting in the water it is fully supported by its buoyancy, just 
like a tanker. However, as the boat starts moving forward, the hull is at an angle of attack 
to the water. Like a super tanker, the boat is also creating a wave in front of it as it moves, 
called the bow wave. However, similar to an airplane breaking the sound barrier, a 
planing craft is fast enough to catch up to this wave. As it reaches its own bow wave, the 
vessel will start to tilt backward. This tilting increases the resistance by virtue of in¬ 
creasing the angle of attack of the vessel’s hull. However, if the vessel has additional 
power to overcome this increased resistance, the lift force generated from the hull foil 
will begin to lift the hull out of the water. At this point, the forces in Figure 16-4 begin 
to dominate. 



As you can see, compared to when the boat is at rest, very little of the hull is in the water 
now. This, in turn, provides positive feedback because it reduces the wetted surface area 
and skin friction and allows the craft to go faster, generating more lift and reducing the 
skin friction yet again. Simultaneously, the drag created by the foil moving through the 
fluid increases until eventually the available power is exhausted and top speed is attained. 
If we plot the resistance versus speed, it might look something like Figure 16-5. 


Resistance and Propulsion | 331 


www.it-ebooks.info 










Notice the hump region. This is where the vessel trims aft in the transition mode and 
there is a rise in the resistance. There have been embarrassing cases where a vessel, 
although having enough power to make the design speed once over the humps, lacked 
the power to make the transition. 

Virtual mass 

The concept of virtual mass is important for calculating the acceleration of a ship in a 
real-time simulator. Virtual mass is equal to the mass of the ship plus the mass of the 
water that is accelerated with the ship. 

Back in Chapter 3 we told you about the viscous boundary layer, and we said that the 
relative velocity (relative to the moving body) of the fluid particles near the moving 
body’s surface is 0 at the body surface and increases to the free stream velocity as distance 
from the body surface increases. Essentially, some of the fluid sticks to the body as it 
moves and is accelerated with the body. Since the velocity of the fluid varies within the 
boundary layer, so does the acceleration. The added mass, the mass of water that gets 
accelerated, is a weighted integration of the entire mass of fluid that is affected by the 
body’s acceleration. 


332 | Chapter 16: Ships and Boats 


www.it-ebooks.info 














For a ship, the viscous boundary layer can be quite thick, up to several feet near the end 
of the ship depending on its length, and the mass of water that gets accelerated is sig¬ 
nificant. Therefore, when doing any sort of analysis that involves the acceleration of the 
ship, you need to consider added mass, too. The calculation of added mass is beyond 
the scope of this book. We should also point out that, unlike mass, added mass is a tensor 
—that is, it depends on the direction of acceleration. Further, added mass applies to 
both linear and angular motion. 

Added mass is typically expressed in terms of an added mass coefficient, which equals 
the added mass divided by the mass of the ship. Some methods actually integrate over 
the actual hull surface, while others approximate the hull as an ellipsoid with proportions 
matching the ship’s. Using this approximation, the ellipsoids length corresponds to the 
ship’s length while its width corresponds to the ship’s breadth. For longitudinal motion 
(that is, linear motion along an axis parallel to the ship’s length), the added mass coef¬ 
ficient varies nearly linearly from 0.0 at a breadth-to-length ratio of 0 (the ship is in¬ 
finitely thin) up to 0.5 at a breadth-to-length ratio of 1 (a sphere). 

When the added mass coefficient is expressed as a percentage of the ship’s mass, virtual 
mass can be calculated as mv = m (1 + xa), where m is mass, and xa is the added mass 
coefficient—for example, 0.2 for 20%. For typical displacement ship proportions, the 
longitudinal added mass ranges from about 4% to 15% of the mass of the ship. Con¬ 
servative estimates generally use 20%. 

Guidance speeds 

To provide some guidance, Table 16-1 provides common ship types and appropriate 
speed ranges. This will help guide you in properly simulating the resistance of your 
vessel. 


Table 16-1. Some vessels and their speeds 


1 Vessel type 

Speed (knots) 

Horsepower (hp) 1 

Aircraft carrier 

31.5 

260,000 

Cruiser 

30 

80,000 

Oil tanker 

15-20 

20,000-60,000 

Containership 

21 

100,000 

200-foot yacht 

15.5 

4,000 

35-foot recreational boat 

30 

420 

35-foot speedboat 

70 

1,200 

40-foot sailboat 

8.5 

N/A 


Note that at a certain speed, for non-planing hulls, there is a theoretical limit to how 
fast a boat can go. This speed is called the hull speed. At the hull speed the bow and stern 
waves reinforce each other, and there is a rise in wave-making resistance. This can be a 


Resistance and Propulsion | 333 


www.it-ebooks.info 






barrier for some fuller hulls. Note that the speed for the 40-foot sailboat is the hull speed 
of a 40-foot full-formed (not slender) hull. We can calculate the hull speed with the 
following formula: 


Vhull ~ 1.34 xjLWL 

Where V hull is the hull speed in knots and L wl is the length on the water line. Some 
modern displacement boats, especially racing kayaks, can exceed their hull speed if they 
have very fine ends, long hulls with narrow beams, or some other optimized hull form. 

Propulsion 

There are a variety of methods to propel a boat through the water. The oldest is by way 
of sails using the wind. The physics of sailing could fill several chapters on its own, so 
we won’t go into detail here. If you are interested in that topic, The Physics of Sailing 
Explained (Sheridan House), by Bryon Anderson, is a good starting point. You can also 
check out the airplane chapter in this book and note that a sail is just a vertical wing. 
We will say this: if you choose to put a sailing vessel in your simulation, make sure to 
remember the golden rule! You cannot generally sail within 45 degrees of the direction 
the wind is coming from. 

There are many different kinds of propulsion: rudders, shafted fixed-pitch propellers, 
shafted CPP propellers, azimuthing thrusters, propellers in nozzles, water jets, pump 
jets, contra-rotating, and the very odd Voith Schneider type. We can’t get into all of them 
here, but the aforementioned list should get you started if you are interesting in mod¬ 
eling the specifics of different propulsor types. 

The maj or propulsion relationship for your simulation would be the thrust-to-propeller 
RPM or thrust-to-throttle curve. The fly in the ointment here is that thrust is also de¬ 
pendent on forward speed. As the boat moves faster and faster through the water, the 
inflow velocity of the water into the propeller is higher and higher. This means that the 
difference between the velocity of the intake and the velocity of the output is smaller, 
reducing the amount of thrust. In general, the thrust curve versus boat speed will look 
like Figure 16-6. 


334 | Chapter 16: Ships and Boats 


www.it-ebooks.info 





An important physical phenomenon concerning propulsion that you may want to in¬ 
corporate is cavitation. Cavitation occurs when a propeller is moving fast enough that 
the low-pressure side of the blade starts spontaneously creating vapor bubbles. These 
bubbles exist for a short while, and then as the propeller turns, the static pressure 
changes. This higher static pressure causes the bubbles to collapse violently. This collapse 
is so fast and furious that it can cause metal erosion at a high rate. It will eat away at a 
propeller until it is no longer producing thrust. It is also very noisy. That is why sub¬ 
marine propellers are shaped very differently than other ships’ propellers. They seek to 
limit cavitations so they’re not heard by enemy vessels. The damage caused by cavitation 
also creates a speed limit on RPMs for a propeller. Cavitation is a real-life phenomenon 
you can exploit to penalize the player for driving around at high speed all the time. 

Maneuverability 

Another aspect of ships and boats that is often oversimplified is maneuverability. Ma¬ 
neuverability is also a very complex topic whose numerical simulation is beyond the 
current realm of real-time simulation. However, with some simplifications and as¬ 
sumptions, it can be more accurately modeled than if you do not know the underlying 
framework. Almost all vessels maneuver by way of two methods: rudders or thrust 
vectoring. The users generally won’t care about the differences, so you can model both 
by angling the thrust vector off-center. 


Maneuverability | 335 


www.it-ebooks.info 







Rudders and Thrust Vectoring 

Although rudders and thrust vectoring have the same result, there are some important 
differences. A thrust vectoring system, like a jet boat, can steer only when the vessel is 
producing thrust. A rudder, on the other hand, works only when the vessel has forward 
speed. If the boat isn’t moving forward with enough speed, then the rudder can’t produce 
a turning moment. 

If you keep in mind those differences, you can model both systems the same way. The 
most important thing to keep in mind when modeling larger ships in your games is that 
they take significant time to respond to control inputs. Figure 16-7 tracks the heading 
of a ship over time during what is called the 10/10 maneuver. 



Figure 16-7. 10/10 zig-zag test 

A vessel is moving in a straight line, and the rudder is put over 10 degrees in one di¬ 
rection. Once the vessel’s heading changes 10 degrees, the rudder is moved to the op¬ 
posite side at the same angle. The initial turning time is the time it took for the vessel 
to change its heading 10 degrees. As large ships have enormous momentum, they will 
continue to turn even though the rudder is in the opposite direction. The maximum 
deviation from the original heading minus the 10 degrees at which the rudder was 
flipped is called the overshoot angle. The size of this angle is one measure of how slow 
the vessel is to respond to the helm. For larger ships, this can be between 15 degrees 
when light and 45 degrees when loaded with cargo. 

The time to check yaw is the time in seconds it takes for the overshoot angle to be 
achieved and the vessel to start changing its heading again. This is repeated for the other 
side to detect any bias a vessel may have for turning in a particular direction. The moral 
of the story is that for anything other than a high-speed small craft, boats and ships can 
take a significant amount of time to respond to the helm. Your simulation should strive 
to reproduce a turning ability that matches Figure 16-7 for extra realism. 


336 | Chapter 16: Ships and Boats 


www.it-ebooks.info 























A special kind of thrust vectoring is called throttle steering. Imagine that a boat has two 
engines. If one is run in forward and the other in reverse, the vessel will turn quite 
rapidly. For a twin-engine vessel operating in close quarters, the rudders are often cen¬ 
tered and the vessel maneuvered solely by altering the throttle settings of the two props. 

Propeller walk 

Another interesting maneuvering phenomenon that is closely related to thrust vectoring 
is called propeller walk, or prop walk. This is especially important for vessels with only 
one propeller moving in tight spaces. The cause of propeller walk is related to the fact 
that most propellers are installed at an angle to the horizon. This angle causes the thrust 
to be greater when the blades are moving down than when the blades are moving up¬ 
ward. In a propeller that turns clockwise, this creates a push to the right. 

In forward gear the rudder is very effective at countering the propeller walk, but in 
reverse the rudder is much less effective, making the propeller walk much more no¬ 
ticeable. This can add a significant amount of realism when you are simulating vessels 
in docking maneuvers. 


Maneuverability | 337 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 17 


Cars and Hovercraft 


What cars and hovercraft have in common is that they operate in an essentially 2D 
manner. Unless they have jumped a ramp, both vehicles remain on the ground or water 
plane. In this chapter we’ll discuss the forces behind each vehicle’s method of travel and 
discuss how to accurately model them in your simulations. 

Cars 

In the following sections we want to discuss certain aspects of the physics behind au¬ 
tomobile motion. Like the previous four chapters, the purpose of this chapter is to 
explain, by example, certain physical phenomena. We also want to give you a basic 
understanding of the mechanics involved in automobile motion in case you want to 
simulate one in your games. In keeping with the theme of this book, we’ll be talking 
about mechanics in the sense of rigid-body motion, and not in the sense of how an 
internal combustion engine works, or how power is transferred through the transmis¬ 
sion system to the wheels, etc. Those are all internal to the car as a rigid body, and we’ll 
focus on the external forces. We will, however, discuss how the torque applied to the 
drive wheel is translated to a force that pushes the car along. 

Resistance 

Before we talk about why cars move forward, let’s talk about what slows them down. 
When a car drives down a road, it experiences two main components of resistance that 
try to slow it down. The first component is aerodynamic drag, and the second is called 
rolling resistance. The total resistance felt by the car is the sum of these two components: 

Rtotal = Rair + ^rolling 


339 


www.it-ebooks.info 




The aerodynamic drag is primarily skin friction and pressure drag similar to that ex¬ 
perienced by the projectiles discussed in Chapter 6, and the planes and boats discussed 
in earlier chapters. Here again, you can use the familiar drag formula: 


R air = (1/2) p V 2 S p C d 

Here p (rho) is the mass density of air, V is the speed of the car, S p is the projected frontal 
area of the car normal to the direction of V, and C d is the drag coefficient. Typical ranges 
of drag coefficients for different types of vehicles are 0.29 to 0.4 for sports cars, 0.43 to 
0.5 for pickup trucks, 0.6 to 0.9 for tractor-trailers, and 0.4 to 0.5 for the average economy 
car. Drag coefficient is a function of the shape of the vehicle—that is, the degree of 
boxiness or streamline. Streamlined body styles have lower drag coefficients; for ex¬ 
ample, the Chevy Corvette has a low drag coefficient of 0.29, while the typical tractor- 
trailer without fairings has a high drag coefficient of up to 0.9. You can use these coef¬ 
ficients in your simulations to tune the behavior of different types and shapes of vehicles. 

When a tire rolls on a road, it experiences rolling resistance, which tends to retard its 
motion. Rolling resistance is not frictional resistance, but instead has to do with the 
deformation of the tire while rolling. It’s a difficult quantity to calculate theoretically 
since it’s a function of a number of complicated factors—such as tire and road defor¬ 
mation, the pressure over the contact area of the tire, the elastic properties of the tire 
and road materials, the roughness of the tire and road surfaces, and tire pressure, to 
name a few—so instead you’ll have to rely on an empirical formula. The formula to use 
is as follows: 


^rolling — C r W 

This gives you the rolling resistance per tire, where w is the weight supported by the 
tire, and C r is the coefficient of rolling resistance. C r is simply the ratio of the rolling 
resistance force to the weight supported by the tire. Luckily for you, tire manufacturers 
generally provide the coefficient of rolling resistance for their tires under design con¬ 
ditions. Typical car tires have a C r of about 0.015, while truck tires fall within the range 
of 0.006 to 0.01. If you assume that a car has four identical tires, then you can estimate 
the total rolling resistance for the car by substituting the total car weight for w in the 
preceding equation. 

Power 

Now that you know how to calculate the total resistance on your car, you can easily 
calculate the power required to overcome the resistance at a given speed. Power is a 
measure of the amount of work done by a force, or torque, over time. Mechanical work 
done by a force is equal to the force times the distance an object moves under the action 
of that force. It’s expressed in units such as foot-pounds. Since power is a measure of 


340 | Chapter 17: Cars and Hovercraft 


www.it-ebooks.info 



work done over time, its units are, for example, foot-pounds per second. Usually power 
in the context of car engine output is expressed in units of horsepower, where 1 horse¬ 
power equals 550 ft-lbs/s. 

To calculate the horsepower required to overcome total resistance at a given speed, you 
simply use this formula: 


P = (RtotalV)/550 

Here P is power in units of horsepower, and i? total is the total resistance corresponding 
to the car’s speed, V. Note, in this equation Jf total must be in pound units and V must be 
in units of feet per second. 

Now this is not the engine output power required to reach the speed V for your car; 
rather, it is the required power delivered by the drive wheel to reach the speed V. The 
installed engine power will be higher for several reasons. First, there will be mechanical 
losses associated with delivering the power from the engine through the transmission 
and drive train to the tire. The power will actually reach the tire in the form of torque, 
which given the radius of the tire will create a force f' w that will overcome the total 
resistance. This force is calculated as follows: 

Fw = T w /r 

Here F w is the force delivered by the tire to the road to push the car along, T w is the 
torque on the tire, and r is the radius of the tire. The second reason the installed engine 
power will be greater is because some engine power will be transferred to other systems 
in the car. For example, power is required to charge the battery and to run the air 
conditioner. 

Stopping Distance 

Under normal conditions, stopping distance is a function of the braking system and 
how hard the driver applies the brakes: the harder the brakes are applied, the shorter 
the stopping distance. That’s not the case when the tires start to skid. Under skidding 
conditions, stopping distance is a function of the frictional force that develops between 
the tires and the road, in addition to the inclination of the roadway. If the car is traveling 
uphill, the skidding distance will be shorter because gravity helps slow the car, while it 
will tend to accelerate the car and increase the skidding distance when the car is traveling 
downhill. 

There’s a simple formula that considers these factors that you can use to calculate skid¬ 
ding distance: 


d s = V 2 / [2g ( p cos cp + sin cp)] 


Cars | 341 


www.it-ebooks.info 



Here d s is the skidding distance, g the acceleration due to gravity, p the coefficient of 
friction between the tires and road, V the initial speed of the car, and cp the inclination 
of the roadway (where a positive angle means uphill and a negative angle means down¬ 
hill). Note that this equation does not take into account any aerodynamic drag that will 
help slow the car down. 

The coefficient of friction will vary depending on the condition of the tires and surface 
of the road, but for rubber on pavement the dynamic friction coefficient is typically 
around 0.4, while the static coefficient is around 0.55. 

When calculating the actual frictional force between the tire and road, say in a real-time 
simulation, you’ll use the same formula that we showed you in Chapter 3: 

F f = p W 

Here F f is the friction force applied to each tire, assuming it’s not rolling, and W is the 
weight supported by each tire. If you assume that all tires are identical, then you can use 
the total weight of the car in the preceding formula to determine the total friction force 
applied to all tires. 

Steering 

When you turn the steering wheel of a car, the front wheels exert a side force such that 
the car starts to turn. In terms of Euler angles, this would be yaw, although Euler angles 
aren’t usually used in discussions about turning cars. Even if the car’s speed is constant, 
it experiences acceleration due to the fact that its velocity vector has changed direction. 
Remember, acceleration is the time rate of change in velocity, which has both magnitude 
and direction. 

For a car to maintain its curved path, there must be a centripetal force (“center seeking” 
in Greek) that acts on the car. When riding in a turning car, you feel an apparent 
centrifugal acceleration, or force directed away from the center of the turn. This accel¬ 
eration is really a result of inertia, the tendency of your body and the car to continue on 
their original path, and is not a real force acting on the car or your body. The real force 
is the centripetal force, and without it your car would continue on its straight path and 
not along the curve. 

One of the most important aspects of racing is taking turns as fast as possible but without 
losing control. The longer you can wait to decelerate for the turn, and the sooner you 
can start accelerating again, the higher your average speed will be. It is interesting to 
note that when people ride in racecars, what really surprises them isn’t the acceleration 
but the massive decelerations they can create through braking forces. A Formula One 
car regularly experiences decelerations of 4g, with 5-6g being the extreme value for 
certain race courses. Most road-legal sports cars can achieve about lg of braking force. 
This allows the racecars to maintain speed until just entering the corner. 


342 | Chapterl7:CarsandHovercraft 


www.it-ebooks.info 



When you turn the steering wheel in a car, the tires produce a centripetal force toward 
the center of the curve via friction with the surface of the road. It follows that the max¬ 
imum static frictional force between the tires and the road must exceed the required 
centripetal force. Mathematically, this takes on the following inequality: 


p S N > mv 2 /r 


Centripetal acceleration is the square of the tangential velocity, v, divided by the radius 
of the turn, r. This multiplied by mass of the vehicle, m, gives the force required to make 
a turn. The available force is the static coefficient of friction times the normal force, N. 
Rewriting this formula, we can develop a simplified maximum cornering speed as fol¬ 
lows: 



If this speed is exceeded, the cornering force will exceed the static coefficient of friction 
and the tires will begin to slide. It may be tempting to replace the normal force, N, with 
the weight of the vehicle (mass times gravity) and cancel out the mass of the car, but the 
normal force may not always be simplified as such, as we’ll discuss in a moment. Also, 
in real life, the weight of a vehicle is rarely evenly distributed among all four tires and 
is definitely not when the car is acceleration or decelerating. In general, acceleration 
causes a weight shift to the aft tires, and deceleration causes weight to shift to the forward 
tires. This is important because, depending on where the weight is, the front or back 
tires will tend to have less available friction. If one or the other sets of tires begins to 
slide, the car will either understeer or oversteer (see Figure 17-1). 



Figure 17-1. Understeer on right, oversteer on left 


Cars | 343 


www.it-ebooks.info 






If the front wheels slide, the car understeers and the arc is larger than the driver intended. 
This is commonly caused by traveling too fast through a corner and trying to take the 
corner too tightly. However, if the driver breaks hard or even just lets off the gas, there 
will be a weight shift forward. This will keep the forward wheels from slipping but if 
too aggressive will cause the rear wheels to slip as weight is transferred away from them. 
This causes the car to turn more than the driver intended, and can even result in a spin. 
These two conditions limit the speed at which a car can complete a turn and also the 
amount of deceleration the car can handle once the turn is initiated. 

To increase the limit speed, v limit , we must increase the normal force. We could do so by 
increasing the car’s mass, but this would have negative effects on the car’s ability to 
accelerate or decelerate. A better solution is the use of aerodynamic features to create 
what is called downforce. You may have seen racecars or even street cars with large wing¬ 
like features called spoilers on their trunks. Formula 1 cars also have wing-like appen¬ 
dages on the front of the car. These are like the wings of an airplane but inverted so that 
instead of pulling the vehicle up, they actually push the vehicle down. These wings, 
therefore, increase the normal force, and their effects are proportional to speed so that 
more downforce is available at higher speeds...just when you need it. In fact, some very 
fast cars create so much downforce that if the road were inverted, the car would remain 
glued to the pavement and be able to drive upside-down. 

The trade-off for this increased cornering limit speed is increased drag caused by the 
airfoils. This limits the top speed of the vehicle in areas of road that have no corners. It 
is good practice to allow users to select an angle of attack for their vehicle’s airfoils. This 
forces them to choose between the option of higher top speed with slower cornering or 
faster cornering with lower top speed. 

You may notice that on some raceways, the corners are not flat. This is called roadway 
bank or superelevation. In a corner where the car would normally skid, the supereleva¬ 
tion helps keep the car in the turn because as the car is inclined, a force component 
develops that acts toward the center of curvature of the turn (see Figure 17-2). 



Figure 17-2. Superelevation 


344 | Chapter 17: Cars and Hovercraft 


www.it-ebooks.info 








The following simple formula relates the superelevation angle of a roadway to the speed 
of the car and the coefficient of friction between the tires and road: 

tan (p = V t 2 /(g r) - p s 

Here, cp is the superelevation angle (as shown in Figure 17-2), V t is the tangential com¬ 
ponent of velocity of the car going around the turn, g is the acceleration due to gravity, 
r is the radius of the curve, and p s is the static coefficient of friction between the tires 
and the road. If you know cp, r, and p, then you can calculate the speed at which the car 
will begin to slip out of the turn and off the road. 

Vehicle dynamics is a complex field, and if you are interested in a highly realistic driving 
simulation game, we recommend reading up on the subject. A good starting place is 
Fundamentals of Vehicle Dynamics by Thomas Gillespie (Society of Automobile Engi¬ 
neers). 

Hovercraft 

Hovercraft, or air cushion vehicles (ACVs), have made their way into a video game or 
two recently. Their appeal seems to stem from their futuristic aura, high speed, and 
levitating ability, which lets them go anywhere. In real life, hovercraft have been around 
since the 1950s and have been used in combat, search and rescue, cargo transport, 
ferrying, and recreational roles. They come in all shapes and sizes, but they all pretty 
much work the same, with the basic idea of getting the craft off the land or water to 
reduce its drag. In Chapter 9, we touched on what forces you have to model when 
considering hovercraft, and now we’ll talk about them in more detail. 

How Hovercraft Work 

The first hovercraft designs pumped air through an annular nozzle around the periphery 
of the craft (see Figure 17-3). Large fans are used to feed the air through the nozzle under 
the craft. This jet of air creates a region of relatively high pressure over the area under¬ 
neath the craft, which results in a net lifting force. The lifting force must equal the weight 
of the craft if it is to attain hovering flight. This sort of lifting is known as aerostatic lift. 
The hover height is limited by the amount of power available and the lifting fan’s ability 
to pump enough air through the nozzle: the higher the hover height, the greater the 
power demand. 


Hovercraft | 345 


www.it-ebooks.info 



» T » T T 

Fan 


Nozzle 


Jet • 


Y\\ \ * } i * / 

J y -..Air cushion y y 


Ground 


t t ♦ t » 

Fan 


* / 

V * < 

/4/r cushion 


Plenum chamber 

\\ \ k ; 


S/r/rf 


Ground 


Figure 17-3. Hovercraft configurations 


This approach proved impractical because hover heights were very limited and made 
the clearance between the hard structure of the craft and the ground (or water) too small 
to overcome all but the smallest obstacles. The solution to this problem was to fit a 
flexible skirt around the craft to contain the air cushion in what’s called the plenum 
chamber (see Figure 17-3). This approach extended the clearance between the ground 
and the hard structure of the craft significantly even though the gap between the bottom 
of the skirt and the ground was very small. This is the basic configuration of most 
hovercraft in operation today, although there are all sorts of skirt designs. Some of these 
skirts are simple curtains, while others are sophisticated pressurized bag and finger 
arrangements. The end result is that hovercraft fitted with skirts can clear relatively large 
obstacles without damage to their hard structure, and the skirt simply distorts and 
conforms to the terrain over which the craft operates. 

The actual calculation of the aerostatic lift force is fairly complicated because the pres¬ 
sure distribution within the air cushion is nonuniform and because you must also take 
into account the performance of the lift fan system. There are theories available to treat 
both the annular jet and plenum chamber configurations, but they are beyond the scope 
of this book. Besides, for a game simulation, what’s important is that you realize that the 
lift force must equal the weight of the craft in order for it to maintain equilibrium in 
hovering flight. 


346 | Chapter 17: Cars and Hovercraft 


www.it-ebooks.info 

















Ideally, the ability of a hovercraft to eliminate contact with the ground (or water) over 
which it operates means that it can travel relatively fast since it no longer experiences 
contact drag forces. Notice we said ideally. In reality, hovercraft often pitch and roll, 
causing parts of the skirt to drag, and any obstacle that comes into contact with the skirt 
will cause more drag. At any rate, while eliminating ground contact is good for speed, 
it’s not so good for maneuverability. 

Hovercraft are notoriously difficult to control since they glide across the ground. They 
tend to continue on their original trajectory even after you try to turn them. Currently, 
there are several means employed in various configurations for directional control. 
Some hovercraft use vertical tail rudders much like an airplane, while others actually 
vector their propulsion thrust. Still others use bow thrusters, which offer very good 
control. All of these means are fairly easy to model in a simulation; they are all simply 
forces acting on the craft at some distance from its center of gravity so as to create a 
yawing moment. The 2D simulation that we walked you through in Chapter 9 shows 
how to handle bow thrusters. You can handle vertical tail rudders as we showed you in 
Chapter 15. 

Resistance 

Let’s take a look now at some of the drag forces acting on a hovercraft during flight. To 
do this, we’ll handle operation over land separately from operation over water since 
there are some specific differences in the drag forces experienced by the hovercraft. 

When a hovercraft is operating over smooth land, the total drag acting against the 
hovercraft is aerodynamic in nature. This assumes that drag induced by dragging the 
skirt or hitting obstacles is ignored. The three components of aerodynamic drag are: 

• Skin friction and viscous pressure drag on the body of the craft 

• Induced drag when the craft is pitched 

• Momentum drag 

In equation form, the total drag is as follows: 

Rtotal = ^viscous T ^induced + ^momentum 

The first of these components, the viscous drag on the body of the craft, is the same sort 
of drag experienced by projectiles flying through the air, as explained in Chapter 6. This 
drag is estimated using the by-now-familiar formula: 

^viscous = (1/2) p V - Sp Cjj 


Hovercraft | 347 


www.it-ebooks.info 



Here p is the mass density of air, V the speed of the hovercraft, S p the projected frontal 
area of the craft normal to the direction of V, and C d the drag coefficient. Typical values 
of C d for craft in operation today range from 0.25 to 0.4. 

The next drag component, the induced drag, is a result of the craft assuming a pitched 
attitude when moving. When the bow of the craft pitches up by an angle t, there will 
be a component of the aerostatic lift vector that acts in a direction opposing V. This 
component is approximately equal to the weight of the craft times the tangent of the 
pitch angle: 


^induced ~ W (tan t) 


Finally, momentum drag results from the destruction of horizontal momentum of air, 
relative to the craft entering the lift fan intake. This component is difficult to compute 
unless you know the properties of the entire lifting system such that the mass flow rate 
of air into the fan is known. Given the mass flow rate, k mnmcntLlm is equal to the mass flow 
rate times the velocity of the craft: 

^momentum = (dm fan /dt) V 

Mass flow rate is expressed in units such as kg/s, which when multiplied by velocity in 
m/s yields N. 

In Chapter 9 we mentioned that it is beneficial to have the center of this drag be behind 
the center of gravity. This gives directional stability, as the vessel will tend to try to point 
into the apparent wind. Consider if the vessel yaws some angle, the forward velocity is 
creating a wind that is now hitting the side of the hovercraft. If the center of effort of 
this force is forward of the center of gravity, it will want to yaw the vessel more, increasing 
the side force and causing even greater drag until the vessel spins 180 degrees! If the 
center of effort of the wind is aft of the center of gravity, the vessel will spin back into 
the wind. You don’t want the center of effort so far aft that it is too difficult to turn the 
vessel, but it is generally better to have the vessel naturally straighten out than to require 
constant steering input to maintain a steady course. This is also true of sailboats and is 
called weather helm. This also occurs in airplanes. The solution in airplanes is similar 
to that of hovercraft: to fit tail fins that move the center of the area aft, increasing its 
directional stability. If you choose to model damage in your simulation, the loss of a tail 
fin will cause the vessel to be very difficult to control. 

In addition to these three drag components, hovercraft will experience other forms of 
resistance when operating over water. These additional components are wave drag and 
wetted drag. The equation for total drag can thus be revised for operation over water as 
follows: 


R. i ■ 


348 | Chapter 17: Cars and Hovercraft 


www.it-ebooks.info 



When a hovercraft operates over water, its air cushion creates a depression in the water 
surface due to cushion pressure (see Figure 17-4). At zero to low speeds, the weight of 
this displaced volume of water is equal to the weight of the craft, just as if the craft were 
floating in the water supported by buoyancy. As the craft starts to move forward, it tends 
to pitch up by the bow. When that happens, the surface of the water in the depressed 
region is approximately parallel to the bottom of the craft. As speed increases, the de¬ 
pression is reduced and the pitch angle tends to decrease. 



Figure 17-4. Hovercraft over water 

Wave drag is a result of this depression and is equal to the horizontal components of 
pressure forces acting on the water surface in the depressed region. As it turns out, for 
small pitch angles and at low speeds, wave drag is on the same order of magnitude as 
the induced drag: 


Rwave ~ W (tan t) 

Since wave drag is proportional to the size of the depression, it tends to be highest at 
low speeds and decreases at higher operational speeds. If you were to plot the wave drag 
curve as a function of speed for a typical hovercraft, you’d find that it is not a straight 
or even parabolic curve, but rather it has a hump in the curve at the lower speed range, 
as illustrated in Figure 17-5. 


Hovercraft | 349 


www.it-ebooks.info 







There are several theoretical treatments of wave drag in the literature that aim to predict 
the speed at which this hump occurs along with its magnitude. These theories indicate 
that the hump depends on the planform geometry of the hovercraft, and it tends to 
occur at speeds in the range of *JgL 1 2 to *jgL , where g is the acceleration due to gravity 
and L is the length of the air cushion. In practice, the characteristics of a particular 
hovercraft’s wave drag are usually best determined through scale model testing. 

The so-called wetted drag is a function of several things: 

• The fact that parts of the hull and skirt tend to hit the water surface during flight 

• The impact of spray on the hull and skirt 

• The increase in weight as the hovercraft gets wet and sometimes takes on water 

Wetted drag is difficult to predict, and in practice model tests are relied on to determine 
its magnitude for a particular design. It’s important to note, however, that this tends to 
be a significant drag component, sometimes accounting for as much as 30% of the total 
drag force. 

Steering 

In Chapter 9, the hovercraft was steered using a bow thruster that pushed transversely 
forward of the center of gravity. In reality, most hovercraft are steered by vectoring the 
thrust of the propulsion fan via rudders attached directly aft of the fans. This can be 
modeled by angling the propulsive thrust. 

The most important characteristic to remember about steering hovercraft is that they 
will not turn like a car or boat. The hovercraft, because it has lower friction with its 
environment, will take longer to turn and tends to continue in the direction it was 
heading while rotating. Once rotated, the thrust acts along a new vector. One possible 
maneuver in a hovercraft is to quickly rotate the vessel and then shut down the pro- 


350 | Chapter 17: Cars and Hovercraft 


www.it-ebooks.info 










pulsive thrust. This would allow you to travel in one direction and point in another for 
as long as your momentum carries you. This could be very useful in strafing enemies 
or just racking up style points. 


Hovercraft | 


351 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 18 


Guns and Explosions 


One of the most widely successful video game genres is the venerable first-person 
shooter. Ever since the breakthrough games of Wolfenstein 3D and Doom, the first- 
person shooter has received the lion’s share of research and development budgets. It is 
amazing that the physics of aiming a gun and of a bullet traveling through the air are 
rarely modeled accurately. In general, game designers treat guns like laser beams so that 
wherever you point them, the bullet goes in an infinitely straight line. In this chapter 
we’ll discuss how to more accurately model both aiming and the trajectory of bullets, 
which is known as ballistics. 

Projectile Motion 

There are actually four subtopics of ballistics. Internal ballistics is the study of what 
happens to the bullet inside the barrel of the gun; transitional ballistics is the study of 
what happens as the bullet exits the barrel. Once the bullet has fully exited the barrel, it 
is in the realm of external ballistics. At this point the only acceleration is that of gravity, 
and the same forces discussed in Chapter 6 take over. The last topic is terminal ballis¬ 
tics, which is the study of what happens when the bullet hits its target. The last two topics 
are the ones we’ll discuss here. The other phases are more important to firearm man¬ 
ufacturers and not so much to the shooter. If you don’t recall the material in Chap¬ 
ter 6, we highly recommend that you review it before continuing. 

While we aren’t very concerned about what happens in the barrel of the gun, there are 
a few tidbits we do need to know about the system. The first is where the barrel is pointed. 
This is referred to as the gun’s aim, and is almost universally controlled by where the 
mouse is on the screen. 


353 


www.it-ebooks.info 




The next is the initial velocity of the bullet. The bullet here refers to the actual metal 
projectile that leaves the barrel; the thing that you load into the gun is called a round 
and contains a casing, gunpowder, a primer, and, of course, the bullet. The initial velocity 
is usually measured just after the bullet leaves the muzzle (the end of the barrel) and is 
appropriately called the muzzle velocity. Every kind of ammunition is tested at the fac¬ 
tory and given a muzzle velocity. You can add realism to your game by giving different 
ammunition different muzzle velocities. This way, a handgun round won’t have the same 
range as a rifle round. Ammunition also comes with a bullet weight measured in either 
grams or grains. One grain is equal to 0.0648 grams and is an old unit based on the 
weight of a single seed of wheat! 

Last, but not least, we need some approximation for the way air resistance will affect 
the flight of a bullet. This is where things start to get interesting for people studying 
ballistics, but we’ll stay away from exotic aerodynamics and use our existing drag model. 
First, we should review the current state of first-person-shooter physics. 

Firearms in games present a unique problem to the game developer. If you have ever 
been to the firing range, you know that in reality it takes a good deal of practice and 
concentration to hit a target reliably. Considering that target shooting is hard enough 
to be an Olympic sport under very controlled circumstances, the ability for in-game 
characters to spring from cover and shoot five enemies with five bullets is somewhat 
superhuman. We have all played games where you find yourself shooting a target very 
far away, and the procedure is as simple as pointing the crosshair where you want the 
bullet to go and clicking the mouse button. In reality, the skill needed to get a bullet 
weighing a few grams to hit something a few hundred meters away is so complicated it 
is amazing that anyone does it with regularity. For those developers wishing to actually 
model firearm performance in their game, there is a double-edged sword to consider. 

The physics of what happens to the bullet in its flight are not simple to boil down. 
However, the behavior of the bullet as it flies downrange is important in the practical 
art of marksmanship. There has been considerable work done to find a way to compare 
ammunition so that a hunter or marksman can predict the performance of a particular 
ammunition. The result is a pseudophysical factor called the ballistic coefficient (BC). 
The BC is a ratio that determines the ability of a particular bullet to retain its downrange 
velocity compared to some standard bullet. The most common form is that of the G1 
reference projectile. However, this number has limited use, as it does not take into 
account modern bullet shapes that provide very low drag. There are updated models 
whose designations are G2, G3, and ECT. If you are interested in the details of highly 
accurate ballistic modeling, there are a few free programs that can provide you in-depth 
models such as Remington’s Shoot! and the GNU Ballistics program. Given that most 
first-person shooters don’t yet include wind effects or bullet drop, we’ll limit ourselves 
to a simplified method of turning the existing parameters in the Chapter 6 projectile 
algorithm. 


354 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



Taking Aim 

When discussing aim, we’ll primarily be talking about rifles or carbines here, as hand¬ 
guns are not usually used for long-distance shooting. Similarly, shotguns, given that 
they fire many small projectiles, are generally not carefully aimed but instead pointed. 
Both of these weapons are what are known as point-blank weapons. Rifles have a point- 
blank range, which we will discuss, but for handguns and shotguns this really refers to 
the fact that at the ranges where these weapons are effective, you can reasonably expect 
to hit where you the point the gun. That is not to say that these weapons don’t need to 
be aimed to be effective, but in the fast-paced combat central to most first-person 
shooters it would be tedious to have the player use the sights on a handgun to effectively 
hit anything. Instead, most games use a “shoot from the hip” or free aim model, where 
the gun is not even in line with the camera. The careful programmer might still check 
to see if the target is within the effective range of the bullet before counting it as a hit 
even when auto-aiming in this manner. The effective range is the distance the bullet can 
travel before hitting the ground. Determining this is a straightforward application of 
the equations in Chapter 2 and Chapter 6. 

To discuss firearms, we’ve adapted the code from the Cannon2 example in Chapter 6 
to run in a Java program called Marksman. In our example, the player is looking through 
a scope at a target of 1 meter by 1 meter. We’ve provided him an adjustable level of zoom 
so that as the range increases, he can still see the target. The aiming point is shown as 
an empty circle, and the bullet hole as a black filled circle. The method we’ve used to 
determine where the user is aiming in the model world converts the pixel-based location 
of the mouse to a coordinate in the model world. This distance and the range are then 
used to find the angles required to aim the gun. The code to do this is shown next, where 
alp and gm are the angles of inclination and bearing. These are measured from hori¬ 
zontal and the line of view: 

alp = 90-Math. toDegrees(Math.atan(((200-airiY)*(targetH/(drawH)))/range)); 

gmm = Math.toDegrees(Math.atan(((200-almX)*(targetH/(drawH)))/range)); 

where targetH/drawH is just the ratio of the target height to the height of the target in 
pixels on the screen. This allows the mouse coordinate given in pixels to be converted 
to meters. The arctangent then converts the ratio of these distances to an angle for the 
gun. The constant 200 refers to the pixel coordinate system, which is 200 pixels away 
from the center of the target. If you were to adapt this for a full 3D rendering system, 
you could remove a lot of these conversions we have to do. 


Taking Aim | 355 


www.it-ebooks.info 



At the 10-meter range shown in Figure 18-1, we are within point-blank range and the 
bullet hole lines up with the sights. 



Figure 18-1. Point-blank range 


In Figure 18-2, with the target at 100 meters, we see that for some reason the bullet is 
not hitting the target where we have pointed the weapon. At 300 meters, the bullet hole 
isn’t even on the target. You can see that by simply accounting for projective motion 
and idealized drag, we are already having trouble hitting the bull’s eye. The process by 
which these differences are accounted for is called zeroing the sights. 


356 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 






Figure 18-2. Hitting lower than expected 


Zeroing the Sights 

The idea of zeroing the sights is probably the most important thing to model if you want 
to have realistic gunplay in your game. As we mentioned before, when players are run¬ 
ning from room to room, they probably don’t want to be thinking about the wind and 
the range. However, for a hunting simulation or a sniper game, it may be appropriate 
to introduce this. 

When a person is looking through a scope, her body and the rifle become a rigid body 
so that to change the aim of the weapon, she must rotate her entire body. This is con¬ 
venient for us, because the player generally controls the shooter’s position with his left 
hand via the keyboard and the direction of aim with the right hand. Other methods of 
aiming, briefly described previously as free aim, don’t really have a counterpart in the 
real world, so we’ll be limiting ourselves to this solid-body aiming. 

Bullet drop: Gravity and air resistance 

If you are aiming a rifle horizontally, you might expect that the bullet leaves the muzzle 
horizontally, and that gravity and air resistance cause it to drop from there. Figure 18-3 


Taking Aim | 357 


www.it-ebooks.info 








shows a rifle and scope combination that is mounted perfectly parallel. Ignoring all other 
factors for a minute, we see that the bullet will never hit where the scope is pointed. It 
will always be a few centimeters low. 



Figure 18-3. Zero-elevation scope 


By adjusting the elevation control of the scope, we can make the rifle hit where the scope 
is pointed. (See Figure 18-4.) The range at which the bullet will cross the line defined 
by the scope is called the zero range. If a target is at the zero range, you simply point the 
crosshairs and pull the trigger. 


Scope Axis 


—---— 

Barrel Axis 


Zero Ranae 


Figure 18-4. Scope with elevation 

If we remove the target and graph the trajectory, it would look something like 
Figure 18-5. 



Here we can see there is a second point in which the bullet will cross the line made by 
the scope’s crosshairs. This is called the far zero, or second zero. This is generally where 
the thing you will be shooting at will be. This diagram is often available from ammu- 


358 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



























nition suppliers. More often, they provide ballistic tables of downrange heights. It is 
important when using these charts that you remember they assume the scope to be 
horizontal and that the bullet starts with a negative height below the scope line. 
Table 18-1 shows data from Remington’s website and assumes the rifle was zeroed at 
100 yards; it tells you how far the bullet is below the horizontal at every 50 yards past 
that 0. You can tune the drag coefficient in the projectile simulation to match these 
elevations. 

Table 18-1. Long-range trajectory Remington Express .45-70 Govt 

Range in yards 100 150 200 250 300 400 500 

Drop in inches 0 -4.6 -13.8 -28.6 -50.1 -115.47 -219.1 

From this table you can see that the bullet drop is over two feet at 250 yards. This means 
that if the target is at 250 yards and your scope is zeroed at 100 yards, then you would 
have to aim two feet above your target to hit it. That might be high enough that you 
can’t even see the target in the scope anymore! 

To counteract this problem, most rifles come with scopes that have elevation adjust¬ 
ments. This is a knob on the side of the scope that can be rotated to discrete settings 
called clicks. Most scopes use a 1/4 minute of angle adjustment per click although some 
use 1/8,1/2, or even full minutes. A minute of angle is simply 1/60 of a degree. Therefore, 
when adjusting for elevation, the shooter can turn a knob on the scope, and as she hears 
the clicks, she knows that she has adjusted her scope however many minutes of angle. 
N ow when she re - aims the crosshairs on the target, the barrel will have a slightly different 
angle than it did before, essentially aiming higher to accommodate the longer distance. 

To achieve high accuracy in the field, the shooter would know that she zeroed her rifle 
to a certain range. Then, when attempting a shot, she would estimate the range to her 
target and adjust the scope however many clicks up or down. The biggest cause of error 
is an inaccurate estimate of range. Modern shooters often use laser range finders to 
determine exactly what elevation offset is required. In long-distance shooting situations, 
you can provide the range to the users and let them adjust the rifle’s scope from the 
current zero range to a new zero range. 

Most games today don’t model even the effect of gravity on a bullet, so adding elevation 
adjustment to a sniper or hunting portion of your game will add much-needed accuracy. 

Wind 

Just like in the Chapter 6 projectile example, our target shooting game’s bullets are 
affected by wind. Just as before, a bullet’s susceptibility to wind largely depends on its 
lateral drag coefficient. In our simulation, you can tune the bullet’s susceptibility to the 
wind by adjusting the factor Cw. This, again, will apply only to rifles shooting at long 
ranges. At 20 meters, the wind will have little to do in determining where a bullet will 
hit. At 600 meters, it can cause the bullet to be off by a meter! The adjustment for wind 


Taking Aim | 359 


www.it-ebooks.info 



is similar to the adjustment for elevation. By turning a knob, you can adjust your scope 
or sights to be slightly to the right or left of the barrel’s centerline. This angle, called 
gamma in our simulation, enables you to cancel out the effect of wind. 

To deal with wind in the field, we require simple calculations that depend on the par¬ 
ticular performance of the shooter’s ammunition. It may work something like this: if 
the wind is blowing directly across your shot, the adjustment in inches is going to be 
half the wind speed in miles per hour. Of course, there are many other rules of thumb 
that differ for each caliber of ammunition, but for our simulation you can tune the wind 
drag coefficient to whatever value you want your shooter to encounter. He will have to 
spend some time at the range, just like a real shooter, figuring out how much the wind 
affects his shots. As the wind changes, he will have to adjust in real time and either aim 
to the left or right of the target or readjust the windage settings for the scope. 

Breathing and Body Position 

Although most games don’t model gravity and wind when calculating bullet trajectories, 
many do attempt to regulate the accuracy with which you initially fire the bullet. Most 
commonly, game developers accomplish this by approximating the crosshairs with four 
lines that do not intersect. When fired, the bullet will land anywhere within the circle 
described by the inner endpoints of these four lines. Different weapons have different 
accuracies, and the lines can move in or out to reflect that. Usually the first shot is the 
most accurate, and once the weapon is fired you must “resight” the target, and this takes 
time. Therefore, shots fired in quick succession usually become less and less accurate. 

In our simulation, we modeled a few things that affect accuracy in the real world and 
will give you some suggestions for other factors you could easily include. As our game 
was most interested in long-distance shooting via rifles, the most common source of 
error is breathing. As discussed before, when a shooter is looking through a scope on a 
rifle, she essentially becomes a fixed body. As she breathes, the rifle is essentially breath¬ 
ing too. When making difficult shots, it is very common for the shooter to take a breath 
and hold it while firing. In our simulation, we’ve modeled this with a breathing class 
that adjusts the point of aim up and down with time to mimic how a scope moves when 
the shooter is breathing deeply. This works via a timer started in our initCompo 
nentsQ function that fires every 100 ms. In the code that follows, you’ll see that this 
leads to a breath every two seconds. 

timer = new Timer(100, TargetPanel); 

timer.start(); 

That function causes the aim point (aimX, aimY) to be moved independently of the 
cursor via the following algorithm: 

if (direction == true) { 

breathHeight = breathHeight + 1; 
if (breathHeight == 5) { 


360 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



direction = false; 
breathHeight = breathHeight + 1; 

} 

} 

if (direction == false) { 

breathHeight = breathHeight - 1; 
if (breathHeight == -5) { 
direction = true; 

} 

} 

if (breathing) { 

aimY = aimY + breathHeight; 

} 

Here we are simply moving it up to some limit—in our case, 5 pixels—and then moving 
it back down. A better implementation would increase the unsteadiness as the user 
zooms in, as shakes are magnified also. There is no limit to the innovative functions you 
can use to move the aiming circle away from the cursor to simulate the reality of having 
to aim a gun. Yet this is certainly an area of first-person shooters that is lacking in variety. 

When he is ready to fire, the user can left-click to hold his breath, the variable breath 
ing becomes false, and the crosshairs will stop moving. This simple addition makes 
the game much more challenging and engaging. It should be noted that if the shooter 
holds his breath too long in real life, the aim will again become unsteady as his body 
reacts to not having fresh oxygen. Another improvement to this algorithm would be for 
the aim to become unstable after the left mouse button is pressed for some amount of 
time. 

Many games also change the accuracy of a weapon depending on body position. There 
are three basic types of shooting positions: standing, kneeling, and prone. Standing is 
—you guessed it—standing up. Kneeling is some form of squatting rather than just 
kneeling on your knees. Prone is laid flat on the ground. Because the rifle is locked to 
your body, the less unstable your body is, the less unstable the aim. When standing, 
your body’s muscles have to do a lot of work to remain upright. When kneeling, they 
do less so, and when prone, your muscles don’t have to worry about keeping you standing 
at all. 

You can add these parameters as random twitches in the aim and tune them to change 
the relative advantage of each position. However, prone should always be more stable 
than kneeling, and kneeling more stable than standing. 

Recoil and Impact 

Now that we’ve aimed, fired, and figured out where the bullet is at any given moment, 
let’s talk about the last phase, terminal ballistics. To really understand what happens at 


Recoil and Impact | 361 


www.it-ebooks.info 



the end of a bullet’s flight, let’s revisit the beginning. Earlier we talked about recoil as 
the result of Newton’s conservation of momentum. Everyone has seen a cheesy movie 
where the hero shoots the bad guy and the bullets cause the bad guy to be blown off his 
feet. There is a big problem with this! If the bullets were powerful enough to knock the 
person they hit off his feet, then the person shooting the gun would also be blown off 
his feet! In reality, the force felt by the person being shot is nearly the same as the force 
felt when the weapon recoils. For a 9 mm bullet weighing 7.45 g and leaving the barrel 
at 390 m/s, the gun will experience recoil such that its momentum is equal to the moment 
of the bullet. 

One interesting way to incorporate recoil into a video game is in space. On Earth, a gun’s 
recoil is pretty quickly transferred to the ground by friction between the player and the 
big bad earth. In space, the shooter has no planetary body to push against, so the recoil 
of the gun becomes the recoil of the gun/person system. Next time your character needs 
to move from one ship to another in a micro-gravity environment, you can make her 
spend some ammo to get herself moving. 

Now, if you get shot you will probably fall down pretty quickly, but this has more to do 
with biology than physics. However, ignoring living targets, if you want to simulate the 
damage done by a bullet hitting something, it is more important to look at the bullet’s 
kinetic energy. In fact, bullets and artillery shells are called kinetic weapons, as their 
primary means of destroying a target is by transferring their kinetic energy to the target. 
This is different than, say, a bomb that transfers its chemical energy into heat and kinetic 
energy after impact. 

Explosions 

Accurately modeling explosions involves multiphysics fluid simulations like the kind 
discussed in Chapter 14 through Chapter 16. One of our pet peeves is that video games 
usually have a collection of barrels lying around that, if shot once, explode violently 
enough to blow up nearby vehicles. While this makes for an easy out against multiple 
enemies, it is actually pretty hard to get everyday objects to blow up. Shooting a gas can 
with a handgun will almost never result in a fire, much less an explosion. Indeed, even 
shooting a propane tank with a rifle won’t give you fireworks. It would take something 
like a tank of 1/4 propane mixed with 3/4 oxygen to explode, and those aren’t usually 
lying around. Regardless, when we play video games we’re often thankful that we have 
an occasional red barrel to shoot, so we’ll review how to make the resulting explosion 
more accurate even if the ignition is improbable. 


362 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



Particle Explosions 

For most in-game explosions, it will be sufficient to implement a particle-type explosion 
that we covered way back in Chapter 2. Now, in Chapter 2 the particles were simply 
dots, but they don’t have to be limited to such simple sprites. In some cases, such as 
sparks from a bullet hitting a metal container, it would be very accurate to model ex¬ 
plosions as particles; however, by making our particles look like bits of cars, we can also 
make it appear that the car itself exploded. The reason this is easier is because the particle 
explosions don’t have any angular motion. Although you can assign different parts of 
the cars to different particles, when they fly off due to the explosion, they won’t be 
rotating. The good news is that a particle explosion will still give you a realistic distri¬ 
bution of fragments of something on the ground. 

To talk about how to link bullets and particle explosions in detail, we’ll consider some¬ 
thing more physically accurate than a bullet blowing up a car. Let’s consider a bullet 
hitting some loose gravel. This will generally cause the gravel to be thrown up into the 
air from the bullet collision. Instead of trying to calculate the complex collisions during 
impact, we’ll generate a particle explosion based on the code in Chapter 2: 


void CreateParticleExplosion(int x, int y, int Vlnit, int life, 

float gravity, float angle) 


{ 


Int l; 
Int m; 
float f; 


Explosion.Active = TRUE; 

Explosion.x = x; 

Explosion.y = y; 

Explosion.V0 = Vlnit; 

for(l=0; 1<_MAXPARTICLES; 1++) 

{ 

Explosion.p[l].x = 0; 

Explosion.p[l].y = 0; 

Explosion.p[l].vl = tb_Rnd(Vlnlt/2, Vlnit); 

lf(angle < 999) 

{ 

lf(tb_Rnd(0,l) == 0) 
m = -1; 

else 

n = 1; 

Explosion.p[l] .angle = -angle + pi * tb_Rnd(0,10); 
} else 

Explosion.p[l].angle = tb_Rnd(0,360); 
f = (float) tb_Rnd(80, 100) / 100.0f; 


Explosions | 363 


www.it-ebooks.info 



Explosion.p[i].life = tb_Round(llfe * f); 
Explosion.p[i]. r = 255;//tb_Rnd(225, 255); 
Explosion.p[i].g = 255;//tb_Rnd(85, 115); 
Explosion.p[i].b = 255;//tb_Rnd(15, 45); 
Explosion.p[i].tine = 0; 

Explosion.p[i].Active = TRUE; 

Explosion.p[i].gravity = gravity; 


} 


} 


As you can see, the initial velocity V0 controls the strength of the explosion. In Chap¬ 
ter 2, we chose this value randomly. Now that we have a bullet flying through the air, 
we can make a better estimate of how strong of an explosion to create. As you recall 
from earlier in the chapter, a bullet has an energy associated with it at any time, t, in its 
flight. This energy is its kinetic energy and is equal to half the bullet mass times its 
velocity squared. 

In our proj ectile simulation, it is simple to calculate this energy as the bullet flies through 
the air. It should be noted that a big bullet moving slowly is just as powerful as a smaller 
bullet moving quickly. Our upcoming code is going to assume that 100% of the kinetic 
energy is delivered to the target. This would not be true if a bullet shot straight through 
something. A way to visualize this is to imagine two targets, both hanging from the 
ceiling. One is made from paper and one is made from steel. When shot at, the steel 
target swings from its support, while the paper target stays still. This is because the bullet 
is passing straight though the paper and not transferring its kinetic energy to the target. 
To make things simple, we’ll transfer all of the bullet’s kinetic energy to the gravel. In 
equation form, this would look like: 


1/2 mb v“bullet — 211/2 mg v"g rave j 


Note that this is the sum of the individual bits of gravel’s velocities. In, Chapter 2, each 
particle was just given a random velocity anywhere from Vinit/2 to Vinit. This could 
lead to creating a set of particles whose energies exceed the input energy. To prevent 
this, we’ll add a variable to our explosion class like so: 


typedef struct _TPartlcle 
{ 


float 

float 

float 

float 

int 


x; 

y; 

vt; 


angle; 

life; 


// x-coordlnate of the particle 
// y-coordlnate of the particle 
// initial velocity 
// initial trajectory (direction) 

// duration in milliseconds 
// red component of particle's color 
// green component of particle's color 
// blue component of particle's color 
// keeps track of the effect's time 
// gravity factor 


int 

int 

int 

int 


r; 

g; 

b; 


time; 

gravity; 


float 


364 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



BOOL 


Active; 


float mass; 

} TParticle; 

#define _MAXPARTICLES 50 

#define _MASSOFPARTICLE .25 


// indicates whether this particle 
// is active or dead 

//for calculating the particle's energy 


typedef struct _TParticleExplosion 
{ 


TParticle 


p[_MAXPARTICLES]; // list of particles 



// making 

up this effect 

int 

x; 

// initial x location 


int 

y; 

// initial y location 


float 

float 

KE; 

//Available kinect energy 


BOOL 

Active; // indicates whether 

this effect is 


//active or dead 


} TParticleExplosion; 

Notice that V0 is no longer required, as the available kinetic energy will govern the 
strength of the explosion. Assuming that the bullet’s kinetic energy is given as a variable 
KEb, our new CreateParticleExplosion function would look like the following: 


void CreateParticleExplosion(int x, int y, int KEb, int life, 

float gravity, float angle) 


{ 


int i; 

int m; 

float f; 


Explosion.Active = TRUE; 

Explosion.x = x; 

Explosion.y = y; 

Explosion.KE = KEb; 

for(i=0; i<_MAXPARTICLES; i++) 

{ 

Explosion.p[i].x = 0; 

Explosion.p[i].y = 0; 

Explosion.p[i].m = _MASSOFPARTICLE; //Mass of a single gravel 

Explosion.p[i].vt = tb_Rnd(0, sqrt(Explosion.KE/(_MASSOFPARTICLE* 

_MAXPARTICLES)); 

Explosion.KE = Explosion.KE - ((l/2)*(Explosion.p[i].m)* 

(Explosion.p[i].vi)); 


if(angle < 999) 

{ 

if(tb_Rnd(0,1) == 0) 
m = -1; 

else 

n = 1; 


Explosions | 365 


www.it-ebooks.info 



Explosion.p[1].angle = -angle + m * tb_Rnd(0,10); 
} else 

Explosion.p[1].angle = tb_Rnd(0,360); 

f = (float) tb_Rnd(80, 100) / 100.0f; 

Explosion.p[i].life = tb_Round(life * f); 

Explosion.p[1].r = 255;//tb_Rnd(225, 255); 

Explosion.p[i].g = 255;//tb_Rnd(85, 115); 

Explosion.p[i].b = 255;//tb_Rnd(15, 45); 

Explosion.p[i].tine = 0; 

Explosion.p[i].Active = TRUE; 

Explosion.p[i].gravity = gravity; 


} 

As you can see, we’ve altered the statements that set the initial velocity of the particles 
to be a random-number generator in a range anywhere from 0 to a velocity that would 
consume the entire explosions kinetic energy. The next line reduces the available kinetic 
energy in the explosion by the amount just assigned to the particle. This way, you can 
be sure that the outgoing explosion is never more powerful then the input. A more 
interesting way to handle this would be to first initialize the particles with some given 
mass distribution and to assign the velocities not randomly, but with a normal distri¬ 
bution. Numerical recipes in C can help you accomplish this. 

Even though the preceding code does not take into account some of the more subtle 
aspects of the transfer of kinetic energy, it will ensure that a small, slow-moving bullet 
produces a smaller explosion than a big, fast-moving one. This is something that is 
lacking in todays video games. 

Polygon Explosions 

While particle explosions are appropriate for small, uniform objects, they fail to give 
appropriate realism when something is blown into identifiable chunks. This is why in 
video games you rarely see a car explode and the door fly away to land next to you. 
Instead, games usually handle objects like this with a particle explosion that obscures 
the object while it is re-rendered in its now-exploded state with the missing pieces having 
been apparently blown to smithereens. 

If you do want to model a full explosion of solid bodies, you can reuse the particle code 
for the translation aspects. Essentially the particles will now describe the center of gravity 
of each solid body. You will have to add in an initial angular velocity and let the simu¬ 
lation, as described in Chapter 12, handle their motion after that initial angle. 

While we don’t have room to go over another example here, we’ll talk a little about the 
input energy to such an explosion to help you bridge the gap. While we are on that 
subject, let’s recall that a bullet just doesn’t have the energy required to blow something 
apart. Even when you hit something with a tank-mounted gun, it really isn’t the kinetic 


366 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



energy of the bullet that blows apart the thing you hit, but some secondary explosion. 
In the case of a tank hitting another tank, the molten slag from the impact is usually 
peppered all over the inside of the tank, causing the fuel or ammunition to explode. 
That is where you get the big booms—it’s the conversion of chemical energy to heat, 
light, and pressure! 

The most common method of quantifying the chemical energy in weapons is called 
TNT equivalency. This is how much TNT it would take to cause the same explosion 
regardless of what you are actually exploding. Now, explosion modeling of, say, gasoline 
and air is pretty complex, so let’s stick with TNT. A kilogram of TNT contains 4.184 
Mega joules of energy; a 9 mm round has 400 J. You can see from that comparison why 
it is hard to blow something up by shooting at it, but easy to do with a block of TNT. 

For the purposes of this discussion, let’s say you have an open box (five polygon sides) 
into which your player just tossed a 1 kg block of TNT. When the TNT is detonated, 
you can give each polygon side an initial velocity (translational and angular) and let the 
kinematic equations take over. Those velocities can be based on two simple rules. 

• The velocity vector can be defined by two points: the center of the block of TNT 
and the center of area of the polygon. 

• The sum of all the kinetic energy must be less than the available chemical energy 
in the TNT. This can be prorated by the square of the distance from the polygon to 
the block of TNT. 

The use of the center of area in our first rule will impart some rotation into our polygon, 
as it will cause a moment about the center of gravity unless the two coincide. If this is 
the case, as it would be for our box, aerodynamic drag and unevenness of the explosion 
will still cause rotation, so you should either model these explicitly or impart some 
rotational velocity manually. 

Now that we have a velocity direction, we need to define its magnitude. The force on 
objects near an explosion is caused by the rapid expansion of gasses due to the heat 
generated by the detonation of the explosive. However, not all the chemical energy is 
transferred to the objects—a lot of it is converted into heat, light, and sound. Typically, 
only one-third of the available chemical energy is converted in the initial detonation. 
Let’s call this the efficiency of the explosion, which we’ll denote by (. Therefore, we can 
write the relationship between velocities of the polygons as follows: 

CE chemical = 2 y(m,.v , 2 + W) 

i=0 ^ 

Here, we can tune (to give the polygons realistic velocities in the event of an explosion 
(i.e., not sending them off at the speed of light). If the energy from the explosion is 


Explosions | 367 


www.it-ebooks.info 



divided up equally, you can see that lighter objects will have higher velocities, as you 
might expect. You can also adjust the amount of explosion energy available to each 
object by weighting the objects imparted energy by its distance from the explosion. This 
should also be tuned in the program, but in general, pressure from an explosion de¬ 
creases with the cube of distance and exponentially with time. 

If you want to model more complex explosion-structure interactions, there are many 
good references for how, say, buildings, react to bomb blasts. FEMA, as well as the Army 
and Navy, have several papers on the subject, such as FEMA 426 Reference Manual to 
Mitigate Potential Terrorist Attacks Against Buildings. The general concepts laid out in 
such documents can increase the realism of the building damage due to explosions. 


368 | Chapter 18: Guns and Explosions 


www.it-ebooks.info 



CHAPTER 19 


Sports 


The topic of sports is nearly as vast as all of the subjects we’ve covered combined. There 
is a sport for everyone, and a sport that takes advantage of each of the physical models 
we’ve discussed so far. The topic ranges from games full of accessories, such as golf or 
polo, to running, where all you need are your own two feet. 

One of the most attractive aspects of sports for the game programmer is that they take 
place in a limited physical space by design. Unlike a first-person shooter where the player 
will eventually reach an artificial boundary, in a sports game the player will not expect 
to be able to walk out of the court. Almost all sports have defined dimensions that are 
relatively easy to model. Table 19-1 lists a few sports and their professional field di¬ 
mensions. 


Table 19-1. Various field dimensions 


1 Sport 

Field size J 

Soccer (football) 

90-120 m long by 45-90 m wide 

Football (including end zones) 

109.7 m long by 48.8 m wide 

Baseball 

27.4 m between bases; 18.39 from pitcher's mound to home base; outfield varies 

Basketball (international) 

28 m by 15 m 

Ice hockey (international) 

61 m by 30 m 


As you can see, other than baseball—where the shape of the outfield changes depending 
on what stadium you are in—modeling these field sizes is a rather straightforward ex¬ 
ercise. 

Additionally, the one thing that sports have in common is that they have a human actor. 
In this chapter we’ll explore how the human action can be simulated as input for the 
other physical simulations we’ve discussed. Specifically, we’ll show you an example of 
how to model a person swinging a golf club using accurate physiological models. This 
is called biomechanics. Before we get into that, another important thing to understand 


369 


www.it-ebooks.info 







when you’re modeling sports is the limits of the human body. Although records are 
broken in every Olympics, no human being is able to jump 10 feet vertically into the 
air. Unless you are breaking the limits of biomechanics on purpose, doing so will de¬ 
crease the realism of your game. The biomechanical statistics of what would be con¬ 
sidered an outstanding athlete are given in Table 19-2. 


Table 19-2. Table of human performance 


1 Physical attribute 

Average value 

Record value 1 

Jump from standstill (vertical) 

81 cm 

155 cm 

Running jump height (high jump) 

1.83 m 

2.45 m 

Jump distance 

5.0 m 

8.95 m 

Throwing speed 

24.5 m/s 

46.0 m/s 

Running speed over 100 m 

7.5 m/s 

10 m/s 

Running speed over 10,000 m 

3.7 m/s 

6.3 m/s 


Almost all sports records are available online somewhere, so Table 19-2 is by no means 
exhaustive. However, it is a good idea to use these values to limit your simulations of 
human actions in your video games. Obviously, part of the excitement of playing video 
games is to be able to jump higher and run faster than you otherwise could, but a good 
survey of biomechanics will at least let you know what is extraordinary and what is not. 
Now let’s take a look at how we would model a human actor in a sports game. 

Modeling a Golf Swing 

Let’s say you’re writing a golf game and you want include a little realism. An obvious 
important element of the game is the golf swing. Another is the club-to-ball impact, and 
still another is the trajectory of the ball in flight. You can use the projectile motion 
modeling techniques discussed earlier in Chapter 2, Chapter 4, and Chapter 6 to model 
the ball’s flight, and the collision response techniques in Chapter 5 to model the club- 
to-ball impact. But what about the golf swing? 

Well, before we show you one way to model a golf swing, let’s talk about why you would 
want to do so in the first place. To model club-to-ball impact, you need to know the club 
head velocity at the time of impact. That velocity is a function of the swing. The golfer 
raises the club through his backswing, torques his body, and brings the club head down 
in an arc while applying a torque with his wrists. As the club swings down, the wrist 
torque reverses, and the club whips through the downswing until the club head collides 
with the ball. (Or, in our case, collides with the ground!) Now, there are many subtle 
details we’ve omitted here with regard to technique and the physics, but you get the 
idea. At any rate, the swing determines the club head velocity at the moment of impact, 
which in turn determines the velocity of the ball after impact. 


370 | Chapter 19: Sports 


www.it-ebooks.info 






If you were writing a game for the Wii or some other platform that can capture a player’s 
motion, then you can relate the player’s swing motion to the initial torque applied to a 
virtual golf club, thus determining, through some model, the swing dynamics and re¬ 
sulting club head velocity. 

Golfers take swing technique seriously and so do scientists who study golf swing dy¬ 
namics. In an effort to understand what makes a good swing or how to improve a swing, 
there are many scientists out there actively studying the golf swing physics. As a result, 
there are many mathematical models of varying degrees of realism and complexity that 
aim to examine the golf swing. One example is the so-called two-rod model as described 
in Theodore P. Jorgensen’s book The Physics of Golf. In his book, Dr. Jorgensen describes 
the two-rod model in detail, including assumptions and simplifications, and provides 
the resulting equations that must be solved to simulate a golf swing based on this model. 
He even provides empirical data used to validate the results of the mathematical model. 
As shown in Figure 19-1, the two-rod model assumes that the golfer’s arm is one rod 
that extends from the shoulders to the wrists. This is the arm rod. The club is represented 
by another rod that extends from the wrist end of the arm rod to the club head. 



This model is essentially a double pendulum. More specifically, it is a driven double 
pendulum since the model assumes a torque applied at the shoulder end of the arm rod, 
and another torque applied at the wrist joint connecting the arm rod to the club rod. 


Modeling a Golf Swing | 371 


www.it-ebooks.info 







We won’t repeat Dr. Jorgensen’s development of the model here; instead, we’ll show you 
how to solve the resulting equations: 

Those equations can be found in the Technical Appendix—Section 4 of Dr. Jorgensen’s 
book—but are listed here for convenience. 

Equation 1: 

(J+I+M c R 2 +2RScos(p))a-(I+RS-cos(p))'p+ 

+( P 2 -2ap)RSsin( p)-S[gsin( 9+fi)-a-cos( 6+P) ]- 
-(S A +M c R)(g-sin(9)-a-cos(9))=Q a 

Equation 2: 


iP-[I+RS-cos(P)]a+a 2 RS-sin(P)+S[g-sin(6+P)-a-cos(6+P)]=Q p 

Table 19-3 explains what each symbol represents. 

Table 19-3. Symbols used in golf swing model 


Symbol Meaning 


J Mass moment of inertia of the rod representing the arm. Units are kg-m 2 . 

I Mass moment of inertia of the rod representing the dub. Units are kg-m 2 . 

M c Mass of the club. Units are kg. 

R Length of the rod representing the arm. Units are m. 

S First moment of the rod representing the club about the wrist axis (where the club rod connects to the arm rod). Units 

are kg-m. 

a Angle swept by arm rod from initial backswing position. Units are radians. 

(5 Wrist-cock angle. Units are radians, 

g Acceleration due to gravity. Constant 9.8 m/s 2 . 

0 Angle between arm rod and vertical axis. Units are radians, 
a Horizontal acceleration of the shoulder. Units are m/s 2 . 

S A First moment of the arm rod about the shoulder axis. Units are kg-m. 

Q„ Torgue applied at the shoulder to the arm rod. Units are N-m. 

Qp Torgue applied at the wrist joint to the club rod. Units are N-m. 

These equations represent a coupled system of nonlinear differential equations. They 
are coupled in that they both depend on the unknown quantities a and (J. They are 
clearly differential equations, as they both include time derivatives of the unknown 


372 | Chapter 19: Sports 


www.it-ebooks.info 






quantities. And they are nonlinear because they include sines and cosines of one of the 
unknowns along with derivatives of the other unknown raised to some power greater 
than 1. 

So, how do we solve these equations? Well, we can’t do so in closed form and must resort 
to numerical means. There are a number of ways to proceed, but the approach we’ll use 
is to first solve Equation 2 for [3 and substitute the result into Equation 1. Then, we’ll 
numerically integrate the result using a fourth-order Runge-Kutta scheme, as described 
in Chapter 7. 

More specifically, at each time step Equation 1 with j3 replaced by the expression derived 
from Equation 1 will be solved for a. Once a is found, we can find ft using the second 
equation previously solved for (3. Next, we can integrate a and [3 to find a and (3. This 
process then repeats for each time step. 

Again, this is only one method of solving these equations. Normally, when faced with 
a system of equations, practitioners use matrix schemes to solve the equations simul¬ 
taneously. This is almost necessary for systems of equations that involve more than two 
equations. However, with just two equations, as we have here, we can avoid expensive 
matrix inversion computation by using the technique we just described. 

Solving the Golf Swing Equations 

Now we’ll show you how to implement the solution we described in a simple console 
application. The example solves the two governing equations for a and (3 over time, the 
results of which can then be used to determine the club head velocity at any time instant 
using kinematic equations as described in Chapter 2 (see the section “Rigid-Body Kin¬ 
ematics” on page 61). Alternatively, you can use the following equation, which Dr. Jor¬ 
gensen gives for the club head velocity in his book: 

V 2 =[« 2 +Lr +2itZ’Cos(/?)]cr +L 2 j3 2 - 2 [z . 2 -i- AL ■ cos(/3 )]«>0 
We’ll use Jorgensen’s equation in this example. 

Since the angles of interest are computed in units of radians, but we want to report them 
in units of degrees, we first create a few defines to make the conversions for us: 

#define RADIANS(d) (d/180.0*3.14159) 

#define DEGREES(r) (r*180.0/3.14159) 

Next, we declare and initialize all of the variables. The initial values used here are some 
typical values that we assumed. You can change these values to simulate different swings: 

// Variables 
double alpha = 0.0; 
double alpha_dot = 0.0; 
double alpha_dotdot = 0.0; 
double beta = RADIANS(120.0); 


Modeling a Golf Swing | 373 


www.it-ebooks.info 



double beta_dot = 0.0; 
double beta_dotdot =0.0; 

double 3 = 1.15; //kg m A 2 
double I = 0.08; //kg m A 2 
double Me = 0.4; // kg 
double R = 0.62; // n 
double L = 1.1; // m 
double S = 0.4*1.1*0.75; // kg m 
double g = 9.8; // m/s A 2 
double gamma = RADIANS(135.0); 
double theta = gamma - alpha; 
double SA = 7.3*0.62*0.5; // kg m 
double Qalpha = 100; // N m 
double Qbeta = -10; // N m 
double a = 0.1*g; // m/s A 2 
double dt = 0.0025; // s 
double time =0; // s 
double Vc = 0; 

Next we define two functions that we will use to compute the second time derivatives 
of a and (3 (i.e., a and ji ). These functions simply use Equations 1 and 2 solved for a and 
jS, respectively. 

ComputeAlphaDotDot, which solves for a, is shown here: 

double ComputeAlphaDotDot(vold) 

{ 

double A, B, C, D, F, G; 

double num, denom; 

A=(J+I+Mc*R*R+2*R*S* cos(beta)); 

B = -(I + R * S * cos(beta)); 

F = Qalpha - (beta_dot * beta_dot - 2 * alpha_dot * beta_dot) * R * S * 
sin(beta) + S * (g * sin(theta + beta) - a * cos(theta + beta)) 

+ (SA + Me * R) * (g * sln(theta) - a * cos(theta)); 

C = B; 

D = I; 

G = Qbeta - alpha_dot * alpha_dot * R * S * sln(beta) - 
S * (g * sin(theta + beta) - a * cos(theta + beta)); 

num = (F - (B * G / D)); 

denom = (A-(B*C/D)); 

return (F - (B * G / D)) / (A-(B*C/D)); 

} 

The local variables A, B, C, D, F, and G are convenience variables used to organize the 
terms in Equation 1. This function returns the second derivative of a. 

ComputeBetaDotDot, shown next, is very similar to ComputeAlphaDotDot but solves 
Equation 2 instead. This function returns the second derivative of (3: 


374 | Chapter 19: Sports 


www.it-ebooks.info 



double ComputeBetaDotDot(vold) 

{ 

double C, D, G; 

C = -(I + R * S * cos(beta)); 

D = I; 

G = Qbeta - alpha_dot * alpha_dot * R * S * sln(beta) - 
S * (g * sin(theta + beta) - a * cos(theta + beta)); 

return (G - C * alpha_dotdot) / D; 

} 

The solution to Equations 1 and 2 follows the Runge-Kutta scheme we showed you in 
Chapter 7. Four intermediate steps are taken for each time step. The time step size is 
controlled by dt, which we’ve set to 0.0025s. If you simply used Euler’s method, you’d 
have to reduce this step size quite a bit to obtain a stable solution. We implemented the 
solution in the main function of our console example. The code is as follows: 

Int _tnaln(lnt argc, _TCHAR* argv[]) 

{ 

double a, at; 

double b, bt; 

int 1; 

FILE* fp; 

double phi; 

double Vc2; 

double akl, ak2, ak3, ak4; 

double bkl, bk2, bk3, bk4; 

FILE* fdebug; 

fp = fopen("results.txt", "w"); 
fdebug = fopen("debug.txt", "w"); 

for(l = 0; i<200; 1++) 

{ 

tine += dt; 

if(tine>=0.1) 

{ 

Qbeta = 0; 

} 

// save results of previous tine step 

a = alpha; 

b = beta; 

at = alpha_dot; 

bt = beta_dot; 

// integrate alpha'' and beta 1 ' 


Modeling a Golf Swing | 375 


www.it-ebooks.info 



// The K1 Step: 

alpha_dotdot = ComputeAlphaDotDot(); 
beta_dotdot = ComputeBetaDotDot(); 

akl = alpha_dotdot * dt; 
bkl = beta_dotdot * dt; 

alpha_dot = at + akl/2; 
beta_dot = bt + bkl/2; 

// The K2 Step: 

alpha_dotdot = ComputeAlphaDotDot(); 
beta_dotdot = ComputeBetaDotDot(); 

ak2 = alpha_dotdot * dt; 
bk2 = beta_dotdot * dt; 

alpha_dot = at + ak2/2; 
beta_dot = bt + bk2/2; 

// The K3 Step: 

alpha_dotdot = ComputeAlphaDotDot(); 
beta_dotdot = ComputeBetaDotDotQ; 

ak3 = alpha_dotdot * dt; 
bk3 = beta_dotdot * dt; 

alpha_dot = at + ak3; 
beta_dot = bt + bk3; 

// The K3 Step: 

alpha_dotdot = ComputeAlphaDotDot(); 
beta_dotdot = ConputeBetaDotDot(); 

ak4 = alpha_dotdot * dt; 
bk4 = beta_dotdot * dt; 

alpha_dot = at + (akl + 2*ak2 + 2*ak3 + ak4) / 6; 
beta_dot = bt + (bkl + 2*bk2 + 2*bk3 + bk4) / 6; 

alpha = a + alpha_dot * dt; 
beta = b + beta_dot * dt; 

theta = gamma - alpha; 

Vc2 = (R*R + L*L + 2 * R * L * cos(beta)) * ( alpha_dot * alpha_dot) 
+ L*L * beta_dot * beta_dot 

- 2 * (L*L + R * L * cos(beta)) * alpha_dot * beta_dot; 

Vc = sqrt(Vc2); 
phi = theta + beta; 

fprintf(fp, "%f, %f, %f, %f, %f, %f\n", time, DECREES(theta), 


376 | Chapter 19: Sports 


www.it-ebooks.info 



DEGREES(alpha), DEGREES(beta), DEGREES(phi), Vc); 


fprintf(fdebug, "%f, %f, %f, %f, %f, %f , %f\n", tine, DEGREES(alpha), 

alpha_dot, alpha_dotdot, DEGREES(beta), beta_dot, beta_dotdot); 

} 

fclose(fp); 
fclose(fdebug); 
return 0; 

} 

Local variables a, at, b, and bt are used to temporarily store the previous time step’s 
results for a and (3 and their first derivatives, i is a counter variable, f p is a file pointer 
that we’ll use to write results out to a text file, phi is used to store the sum of 0 + (3. And 
Vc2 is the square of the club head velocity calculated according to Jorgensen’s equation. 
The variables akl through ak4, and bkl through bk4, are used to store intermediate 
results of the Runge-Kutta integration scheme, f debug is a file pointer to a file we used 
for writing debugging information. 

After the output and debug files are opened, the function enters a loop to perform the 
integration over 200 time steps. You can change the number of time steps as you see fit 
for your application. Keep in mind that the swing event, from start to striking the ball, 
takes place over a very short period of time—only fractions of a second long. 

Upon entering the loop, you’ll see some code that checks how much time has elapsed; 
if that time is greater than 0.1s, the wrist torque, Qbeta, is set to 0. This is a crude model 
of how the wrist torque that’s initially applied is released, allowing the club to swing past 
the arm. Depending on the swing you’re modeling, this torque could actually reverse 
direction, forcing the club past the arm even more. Dr. Jorgensen’s book explains all this 
in detail, even giving experimental results. 

Next, results of the previous time step are saved in the variables a, b, at, and bt. The 
first time step simply stores the initial values. Now, the integration starts for the first 
step, kl (see Chapter 7). Each of these steps involves computing a and ft using the 
functions ComputeAlphaDotDot and ComputeBetaDotDot. The kl results are then cal¬ 
culated and used to compute intermediate results for the first time derivatives of a and 
(3. All four intermediate steps are carried out in a similar manner. 

Finally, the current time step’s results for alpha_dot and beta_dot, along with alpha 
and beta, are computed. Also, the square of the club head velocity, Vc2, is computed 
using Jorgensen’s equation shown earlier; and the club head velocity, Vc, results from 
the square root of Vc2. 


Modeling a Golf Swing | 377 


www.it-ebooks.info 



Results of interest are then written to the output and debug files. So, that’s pretty much 
it. After the loop finishes, the files are closed and the application terminates. 

If this were an actual game, you would use the club head velocity results along with the 
collision response method we showed in Chapter 3 to determine the golfball’s trajectory. 
You could model the flight path of the golf ball using the methods we showed you in 
Chapter 6. 

Billiards 

Now let’s take a look at a different example. You may not think of billiards as a sport, 
but it is recognized internationally as a cue sport. Cue sports are a family of sports that 
include billiards, pool, snooker, and other related variations. For simplicity, we’ll stick 
with the term billiards, although the topics presented apply to all cue sports. 

Billiards is a good example of an activity that takes place over a limited physical space. 
Thus, when writing a billiards video game you need only concern yourself with a very 
finite space composed of well-established geometry. Billiard tables are typically 1.37 m 
x 2.74 m (4.5 ft x 9 ft), with some longer and some smaller depending on the game, 
style, and space available. Tables are typically cloth-covered slate. Balls vary in size be¬ 
tween games and regions, with American-style pool balls measuring about 57 mm (2.25 
inches) in diameter. Balls used to be made of wood, clay, or ivory, but nowadays they 
are plastic. 

All these characteristics are important little details that you must consider if you’re going 
to make a realistic billiards video game. The slate table and hard plastic balls have certain 
impact characteristics. The cloth-covered table provides some resistance to rolling. Side 
bumpers are not as hard as the slate table, thus yielding different impact characteristics. 
Fortunately, data on billiard tables and balls is readily available on the Web. And sim¬ 
ulating billiards in a video game is fairly straightforward. 

Billiards makes an interesting example because collisions are the heart of the game, and 
such an example also gives us an opportunity to demonstrate rolling contact. Figure 19-2 
and Figure 19-3 illustrate the example we’ll focus on. We have three object balls (the 
ones that get struck with the cue ball) set up in the middle of the table in a loose triangle 
configuration. 


378 | Chapter 19: Sports 


www.it-ebooks.info 




Figure 19-2. Elapsed time = 0.398s 

The cue ball comes from the right at a set speed (see Figure 19-2) and then impacts the 
eight ball (see Figure 19-3). 



Figure 19-3. Elapsed time = 0.440s 


Billiards | 379 


www.it-ebooks.info 





























After the initial impact between the cue ball and the eight ball, the eight ball moves to 
the left and impacts two more balls. These balls then shoot off diagonally. Most of the 
energy from the eight ball is transferred to the two other balls, so the eight ball quickly 
comes to rest while being kissed by the cue ball. The other two balls continue rolling 
away diagonally (see Figure 19-4). 



Figure 19-4. Elapsed time = 0.566s 


In this example, we’ll show you how to handle ball-ball collisions, ball-table collisions, 
ball-table contact, aerodynamic drag on the ball, rolling resistance, friction between 
balls at the time of impact, and friction between the balls and table. 

Implementation 

If you’ve read and studied the examples presented in Chapter 7 through Chapter 13, 
then the implementation of this billiards example will be very familiar to you; we use 
the same basic approach. During each simulation time step, we calculate all the forces 
acting on each ball; integrate the equations of motion, updating each ball’s position and 
velocity; and then check for and deal with collisions. 


380 | Chapter 19: Sports 


www.it-ebooks.info 










The rigid-body class used in this example is very similar to that used for the airplane 
example in Chapter 15. Even though the balls are compact and round, and it’s tempting 
to treat them as particles, you must treat them as 3D rigid bodies in order to capture 
rolling and spinning, which are important elements of billiard ball dynamics. The rigid- 
body class adopted for this billiards example is as follows. 

typedef struct _RtgidBody { 

float fMass; // Total mass (constant) 

Matrlx3x3 mlnertia; // Mass moment of inertia in body coordinates 

Matrix3x3 mlnertialnverse;// Inverse of mass moment of inertia matrix 
Vector vPosition; // Position in earth coordinates 

Vector vVelocity; // Velocity in earth coordinates 

Vector vVelocityBody; // Velocity in body coordinates 
Vector vAcceleration; // Acceleration of eg in earth space 
Vector vAngularAcceleration; //Angular acceleration in body coordinates 
Vector vAngularAccelerationGlobal; // Angular acceleration 

// in global coordinates 

Vector vAngularVelocity; // Angular velocity in body coordinates 
Vector vAngularVelocityGlobal; // Angular velocity in global coordinates 
Vector vEulerAngles; // Euler angles in body coordinates 
float fSpeed; // Speed (magnitude of the velocity) 

Quaternion qOrientation; // Orientation in earth coordinates 

Vector vForces; // Total force on body 

Vector vMoments; // Total moment (torque) on body 

Matrix3x3 mlelnverse; // Inverse of moment of inertia in earth coordinates 

float fRadius; // Ball radius 

} RigidBody, *pRigidBody; 

As you can see, this class looks very similar to the rigid-body classes we’ve used through¬ 
out this book, and in particular that used in the airplane example. All the usual suspects 
are here, and the comments in this code sample state what each class member represents. 
One particular property you have not seen yet is fRadius —this is simply the billiard 
ball’s radius, which is used when we are checking for collisions and calculating drag 
forces. 

As we discussed in Chapter 14, since there are multiple objects in this simulation that 
may collide, we’re going to iterate through all the objects, checking for collisions while 
storing the collision data. Since there are not that many objects in this simulation, we 
don’t really need to partition the game space in order to optimize the collision detection 
checks (refer to Chapter 14). The data we need to store for each collision is included in 
the following Collision structure: 

typedef struct _Collision { 


Int 

bodyl; 

int 

body2; 

Vector 

vCollisionNormal; 

Vector 

vCollisionPoint; 

Vector 

vRelatlveVeloctty; 

Vector 

vRelatlveAcceleration; 


Billiards | 381 


www.it-ebooks.info 



Vector vCollislonTangent; 

} Collision, *pCollision; 

The first two properties are indices to the two bodies involved in the collision. The next 
property, vCollisionNormal, stores the normal vector at the point of contact of the 
collision with the vector pointing outward from body2. The next property, vCollision 
Point, stores the coordinates of the point of contact in global coordinates. Since we’re 
dealing with spheres (billiard balls), the collision manifold will always consist of a single 
point for each ball-ball or ball-table collision. The next two properties store the relative 
velocity and acceleration between the two bodies at the point of collision. The data is 
stored in vRelativeVelocity and vRelativeAcceleration, respectively. To capture 
friction at the point of contact, we need to know the tangent vector to the bodies at the 
point of contact. This tangent is stored in vCollisionTangent. 

We set up several global defines to hold key data, allowing us to easily tune the simu¬ 
lation: 


#define 

BALLDIAMETER 

0.05715f 

#define 

BALLWEIGHT 

1.612f 

#define 

GRAVITY 

-9.87f 

#define 

LINEARDRAGCOEFFICIENT 

0.5f 

#define 

ANGULARDRAGCOEFFICIENT 

0.05f 

#define 

FRICTIONFACTOR 

0.5f 

#define 

COEFFICIENTOFRESTITUTION 

0.8f 

#define 

COEFFICIENTOFRESTITUTIONGROUND 0.1f 

#define 

FRICTIONCOEFFICIENTBALLS 

0.1f 

#define 

FRICTIONCOEFFICIENTGROUND 

0.1f 

#define 

ROLLINGRESISTANCECOEFFICIENT 0.025f 


The first three defines represent the billiard ball diameter in meters, the ball weight in 
newtons, and the acceleration due to gravity in m/s 2 . The ball diameter and weight are 
typical values for American-style billiard balls (i.e., 2.25 inches and 5.8 oz on average). 

The remaining defines are self-explanatory and represent nondimensional coefficients 
such as drag coefficients and coefficients of restitution. The values you see are what we 
came up with after tuning the simulation. You’ll surely tune these yourself if you develop 
your own billiards game. 

We use three important global variables for this simulation, as shown here: 

RigidBody Bodies[NUMBODIES]; 

Collision Collisions[NUMB0DIES*8]; 

int NumCollisions = 0; 

Bodies is an array of RigidBody types and represents the collection of the billiard balls. 
Here we’ve defined NUMBODIES as 4, so there are four billiard balls in this simulation. 
We’ve adopted the convention that the cue ball will always be Bodies [0]. 


382 | Chapter 19: Sports 


www.it-ebooks.info 



Initialization 

At the beginning of the simulation, we have to initialize all four billiard balls. We use 
one function, InitializeObjects, for this task. It’s a long function, but it’s really simple. 
The code is shown on this and the following pages. Bodies [0] is the cue ball, and it is 
positioned 50 ball diameters along the negative x-axis away from the object balls. There’s 
no magic to this number; we picked it arbitrarily. Now, we did deliberately set the z- 
position of the cue ball (all the balls, for that matter) to one-half the diameter so that 
the balls would be just touching the table at the start of the simulation. 

To have the cue ball roll from right to left, we gave it an initial velocity of 7 m/s along 
the positive x-axis. With this initial velocity, the cue ball will begin sliding across the 
table for some short distance as it also starts to roll due to the friction between the ball 
and table. You can see in the upcoming code sample that all the other kinematic prop¬ 
erties are set to 0 for the cue ball. For the object balls, all of their kinematic properties 
are set to 0. 

We encourage you to experiment with different initial values for the cue ball’s kinematic 
properties. For example, try setting the angular velocity about any of the coordinate 
axes to something other than 0. Doing so will allow you to see how a spinning ball may 
move slightly left or right depending on the spin. It’s also fun to see how spin affects the 
object balls upon collision with the cue ball. 

Aside from setting the positions and kinematic properties of the balls, InitializeOb 
jects also initializes mass properties. We used the previously defined BALLWEIGHT 
divided by the acceleration due to gravity to determine the ball mass. For mass moment 
of inertia, we simply used the equations for a solid sphere we showed you way back in 
Chapter 1: 

void InitializeObjects(int configuration) 

{ 

float iRoll, iPitch, iYaw; 

int i; 

float Ixx, Iyy, Izz; 

float s; 


///////////////////////////////////////////////////// 

// Initialize the cue ball: 

// Set initial position 

Bodies[0].vPosition.x = -BALLDIAMETER*50.0f; 

Bodies[0].vPosition.y = 0.0f; 

Bodies[0].vPosition.z = BALLDIAMETER/2.0f; 


// Set initial velocity 
s = 7.0; 

Bodies[0].vVelocity.x = s; 
Bodies[0].vVelocity.y = 0.0f; 
Bodies[0].vVelocity.z = 0.0f; 
Bodies[0].fSpeed = s; 


Billiards | 383 


www.it-ebooks.info 



// Set initial angular velocity 

Bodies[0].vAngularVelocity.x = 0.0f; // rotate about long'l axis 

Bodies[0].vAngularVelocity.y = 0.0f; // rotate about transverse axis 

Bodies[0].vAngularVelocity.z = 0.0f; // rotate about vertical axis 

Bodies[0].vAngularAcceleration.x = 0.0f; 

Bodies[0].vAngularAcceleration.y = 0.0f; 

Bodies[0].vAngularAcceleration.z = 0.0f; 

Bodies[0].vAcceleration.x = 0.0f; 

Bodies[0].vAcceleration.y = 0.0f; 

Bodies[0].vAcceleration.z = 0.0f; 

// Set the initial forces and moments 
Bodies[0].vForces.x = 0.0f; 

Bodies[0].vForces.y = 0.0f; 

Bodies[0].vForces.z = 0.0f; 

Bodies[0].vMoments.x = 0.0f; 

Bodies[0].vMoments.y = 0.0f; 

Bodies[0].vMoments.z = 0.0f; 

// Zero the velocity in body space coordinates 
Bodies[0].vVelocityBody.x = 0.0f; 

Bodies[0].vVelocityBody.y = 0.0f; 

Bodies[0].vVelocityBody.z = 0.0f; 

// Set the initial orientation 
iRoll = 0.0f; 
iPitch = 0.0f; 
iYaw = 0.0f; 

Bodies[0].qOrientation = MakeQFromEulerAngles(iRoll, iPitch, iYaw); 

// Set the mass properties 
Bodies[0].fMass = BALLWEIGHT/(-g); 

Ixx = 2.0f * Bodies[0].fMass / 5.0f * (BALLDIAMETER/2*BALLDIAMETER/2); 
Izz = Iyy = Ixx; 

Bodies[0].mlnertia.ell = Ixx; 

Bodies[0],mlnertia.el2 = 0; 

Bodies[0],mlnertia.el3 = 0; 

Bodies[0],mlnertia.e21 = 0; 

Bodies[0],mlnertia.e22 = Iyy; 

Bodies[0],mlnertia.e23 = 0; 

Bodies[0],mlnertia.e31 = 0; 

Bodies[0],mlnertia.e32 = 0; 

Bodies[0],mlnertia.e33 = Izz; 

Bodies[0].mlnertialnverse = Bodies[0].mlnertia.lnverse(); 


384 | Chapter 19: Sports 


www.it-ebooks.info 




Bodies[0] .fRadlus = BALLDIAMETER/2; 


///////////////////////////////////////////////////// 
// Initialize the other balls 
for(i=l; i<NUMBODIES; i++) 

{ 

// Set initial position 

if(i==l) 

{ 


Bodies[i].vPosition.x 
Bodies[i].vPosition.y 
Bodies[i].vPosition.z 
} else if(i==2) { 

Bodies[i].vPosition.x 
Bodies[i].vPosition.y 
Bodies[i].vPosition.z 
} else { 

Bodies[i].vPosition.x 
Bodies[i].vPosition.y 
Bodies[i].vPosition.z 


0 . 0 ; 

-(BALLDIAMETER/2.0f+0.25*BALLDIAMETER); 
BALLDIAMETER/2.0f; 

0 . 0 ; 

BALLDIAMETER/2,0f+0.25*BALLDIAMETER; 
BALLDIAMETER/2.0f; 

-BALLDIAMETER; 

0.0f; 

BALLDIAMETER/2.0f; 


} 

// Set initial velocity 
Bodies[i].vVelocity.x = 0.0f; 
Bodies[i].vVelocity.y = 0.0f; 
Bodies[i].vVelocity.z = 0.0f; 
Bodies[i].fSpeed = 0.0f; 


// Set initial angular velocity 
Bodies[i].vAngularVelocity.x = 0.0f; 
Bodies[i].vAngularVelocity.y = 0.0f; 
Bodies[i].vAngularVelocity.z = 0.0f; 


Bodies[i].vAngularAcceleration.x = 0.0f; 
Bodies[i].vAngularAcceleration.y = 0.0f; 
Bodies[i].vAngularAcceleration.z = 0.0f; 


Bodies[i].vAcceleration.x = 0.0f; 
Bodies[i].vAcceleration.y = 0.0f; 
Bodies[i].vAcceleration.z = 0.0f; 


// Set the initial forces and moments 
Bodies[i].vForces.x = 0.0f; 

Bodies[i].vForces.y = 0.0f; 

Bodies[i].vForces.z = 0.0f; 


Bodies[i].vMoments.x = 0.0f; 
Bodies[i].vMoments.y = 0.0f; 
Bodies[i].vMoments.z = 0.0f; 


// Zero the velocity in body space coordinates 


Billiards | 


385 


www.it-ebooks.info 



Bodies[i].vVelocityBody.x = 0.0f; 

Bodies[i].vVelocityBody.y = 0.0f; 

Bodies[i].vVelocityBody.z = 0.0f; 

// Set the initial orientation 
iRoll = 0.0f; 
iPitch = 0.0f; 
iYaw = 0.0f; 

Bodies[i].qOrientation = MakeQFromEulerAngles(iRoll, iPitch, iYaw); 

// Set the mass properties 
Bodies[i].fMass = BALLWEIGHT/(-g); 

Ixx = 2.0f * Bodies[i].fHass / 5.0f * (BALLDIAMETER*BALLDIAMETER); 

Izz = Iyy = Ixx; 

Bodies[i].mlnertia.ell = Ixx; 

Bodies[i].mlnertia.el2 = 0; 

Bodies[i].mlnertia.el3 = 0; 

Bodies[i].mlnertia.e21 = 0; 

Bodies[i].mlnertia.e22 = Iyy; 

Bodies[i].mlnertia.e23 = 0; 

Bodies[i].mlnertia.e31 = 0; 

Bodies[i].mlnertia.e32 = 0; 

Bodies[i].mlnertia.e33 = Izz; 

Bodies[i].mlnertialnverse = Bodies[i].mlnertia.InverseQ; 

Bodies[i].fRadius = BALLDIAMETER/2; 

} 

} 

Stepping the Simulation 

During each time step, the simulation’s main loop makes a call to StepSimulation. This 
function, shown next, is almost identical to the StepSimulation functions we covered 
in the other examples shown throughout this book, so there really are no surprises here. 
StepSimulation first makes a call to CalcObjectForces, which we’ll discuss momen¬ 
tarily, and then proceeds to integrate the equations of motion for each ball. We use a 
basic Euler scheme here for simplicity. After integrating, StepSimulation makes a few 
function calls to deal with collisions. We’ll cover those shortly. 

void StepSimulation(float dtlme) 

{ 


Vector 

Ae; 

int 

i; 

float 

dt = dtlme; 

int 

check = NOCOLLISION; 

int 

c = 0; 


// Calculate all of the forces and moments on the balls: 
CalcObjectForces(); 


386 | Chapter 19: Sports 


www.it-ebooks.info 



// Integrate the equations of notion: 
for(i=0; i<NUMBODIES; i++) 

{ 

// Calculate the acceleration in earth space: 

Ae = Bodies[i].vForces / Bodies[i].fMass; 

Bodies[i].vAcceleration = Ae; 

// Calculate the velocity in earth space: 

Bodies[i].vVelocity += Ae * dt; 

// Calculate the position in earth space: 

Bodies[i].vPosition += Bodiesfi].vVelocity * dt; 

// Now handle the rotations: 
float nag; 

Bodies[i].vAngularAcceleration = Bodiesfi].nlnertialnverse * 

(Bodies[i].vMonents - 
(Bodies[i].vAngularVelocity* 

(Bodies[i].nlnertia * 

Bodies[i].vAngularVelocity))); 

Bodies[i].vAngularVelocity += Bodiesfi].vAngularAcceleration * dt; 

// Calculate the new rotation quaternion: 

Bodies[i].qOrientation += (Bodies[i].qOrientation * 

Bodies[i].vAngularVelocity) * 

(0.5f * dt); 

// Now nornalize the orientation quaternion: 
nag = Bodiesfi] .qOrientation.MagnitudeQ; 
if (nag != 0) 

Bodies[i].qOrientation /= nag; 

// Calculate the velocity in body space: 

Bodies[i].vVelocityBody = QVRotate(~Bodies[i].qOrientation, 

Bodies[i].vVelocity); 

// Get the angular velocity in global coords: 

Bodies[i].vAngularVelocityGlobal = QVRotate(Bodies[i].qOrientation, 

Bodies[i].vAngularVelocity); 

// Get the angular acceleration in global coords: 

Bodies[i].vAngularAccelerationGlobal = QVRotate(Bodies[i].qOrientation, 

Bodies[i].vAngularAcceleration); 

// Get the inverse intertia tensor in global coordinates 
Matrix3x3 R, RT; 

R = MakeMatrixFronQuaternion(Bodies[i].qOrientation); 

RT = R.Transpose(); 

Bodies[i].nlelnverse = R * Bodies[i].nlnertialnverse * RT; 


Billiards | 387 


www.it-ebooks.info 



// Calculate the air speed: 

Bodies[i] .fSpeed = Bodies[i]. vVelocity .MagnitudeQ; 

// Get the Euler angles for our information 
Vector u; 

u = MakeEulerAnglesFromQ(Bodies[i].qOrientation); 

Bodies[i].vEulerAngles.x = u.x; // roll 
Bodies[i].vEulerAngles.y = u.y; // pitch 

Bodies[i].vEulerAngles.z = u.z; // yaw 

} 

// Handle Collisions : 
check = CheckForCollisions(); 
if(check == COLLISION) 

ResolveCollisions(); 

} 

Calculating Forces 

The first function call made by StepSinulation is a call to CalcOb jectForces, which 
is responsible for computing all the forces on each ball except collision forces. This is 
the same approach used in previous examples. The entire CalcObjectForces source 
code is included here: 

void CalcObjectForces(void) 

{ 

Vector Fb, Mb; 

Vector vDragVector; 

Vector vAngularDragVector; 

tnt I, j; 

Vector ContactForce; 

Vector pt; 

int check = NOCOLLISION; 

pCollision pCollisionData; 

Vector FrictionForce; 

Vector fDir; 

double speed; 

Vector FRn, FRt; 

for(i=0; i<NUMBODIES; i++) 

{ 

// Reset forces and moments: 

Bodies[i].vForces.x = 0.0f; 

Bodies[i].vForces.y = 0.0f; 

Bodies[i].vForces.z = 0.0f; 

Bodies[i].vMoments.x = 0.0f; 

Bodies[i].vMoments.y = 0.0f; 

Bodies[i].vMoments.z = 0.0f; 


388 | Chapter 19: Sports 


www.it-ebooks.info 



Fb.x = 0.0f; Mb.x = 0.0f; 

Fb.y = 0.0f; Mb.y = 0.0f; 

Fb.z = 0.0f; Mb.z = 0.0f; 

// Do drag force: 

vDragVector = -Bodiesfi].vVelocityBody; 
vDragVector.Nornalize(); 

speed = Bodiesfi] .vVelocityBody.MagnitudeQ; 

Fb += vDragVector * ((1.0f/2.0f)*speed * speed * rho * 
LINEARDRAGCOEFFICIENT * pow(Bodies[i].fRadius,2) * 

Bodies[i].fRadius*pi); 

vAngularDragVector = -Bodies[i].vAngularVelocity; 
vAngularDragVector.Normalize(); 

Mb += vAngularDragVector * (Bodies[i].vAngularVelocity.Magnitude() * 

Bodies[i.].vAngularVelocity.Magnltude() * rho * ANGULARDRAGCOEFFICIENT 
* 4 * pow(Bodies[i].fRadius,2)*pi); 

// Convert forces from model space to earth space: 

Bodies[i].vForces = QVRotate(Bodies[i].qOrientation, Fb); 

// Apply gravity: 

Bodies[i].vForces.z += GRAVITY * Bodiesfi].fMass; 

// Save the moments: 

Bodies[i].vMoments += Mb; 

// Handle contacts with ground plane: 

Bodies[i].vAcceleration = Bodiesfi].vForces / Bodies[i].fMass; 

Bodies[i].vAngularAcceleration = Bodies[i].mlnertialnverse * 

(Bodies[i].vMoments - 
(Bodies[i],vAngularVelocity A 
(Bodies[i].mlnertia * 

Bodies[i].vAngularVelocity))); 


// Resolve ground plane contacts: 

FlushCollisionData(); 
pCollisionData = Collisions; 

NumCollisions = 0; 
if(DOCONTACT) 

check = CheckGroundPlaneContacts(pCollisionData, i); 
if((check == CONTACT) && DOCONTACT) 

{ j = 0; 

{ 

assert(NumCollisions <= 1); 

ContactForce = (Bodies[i].fMass * (-Bodies[i].vAcceleration * 
Collisions[j].vCollisionNormal)) * 

Collisions[j].vCollisionNormal; 

if(DOFRICTION) 


Billiards | 389 


www.it-ebooks.info 



double vt = fabs(Colltsions[j].vRelativeVeloclty * 
Collisions[j].vCollisionTangent); 
if(vt > VELOCITYTOLERANCE) 

{ 

// Kinetic: 

FrictionForce = (ContactForce.MagnitudeQ * 
FRICTIONCOEFFICIENTGROUND) * 

Collisions[j].vCollisionTangent; 

} else { 

// Static: 

FrictionForce = (ContactForce.MagnitudeQ * 
FRICTIONCOEFFICIENTGROUND * 2 * 
vt/VELOCITYTOLERANCE) * 

Collisions[j].vCollisionTangent; 

} 

} else 

FrictionForce.x = FrictionForce.y = FrictionForce.z = 0; 

// Do rolling resistance: 

if(Bodies[i].vAngularVelocity.MagnitudeQ > VELOCITYTOLERANCE) 

{ 

FRn = ContactForce.MagnitudeQ * 

Collisions[ j].vCollisionNomal; 

Collisions [ j ]. vCollisionTangent. NornalizeQ; 

Vector n = (Collisionsfj].vCollisionTangent 
*(ROLLINGRESISTANCECOEFFICIENT * 

Bodies[i].fRadius)) A FRn; 
double nag = n.MagnitudeQ; 

Vector a = Bodies[i].vAngularVelocity; 
a.NornalizeQ; 

Bodies[i].vMonents += -a * nag; 

} 

// accunlate contact and friction forces and noments 
Bodies[i].vForces += ContactForce; 

Bodies[i].vForces += FrictionForce; 

ContactForce = QVRotate(~Bodies[l].qOrientation, ContactForce); 
FrictionForce = QVRotate(~Bodies[i].qOrientation, 

FrictionForce); 

pt = Collisions[j].vCollisionPoint - Bodies[i].vPosition; 
pt = QVRotate(~Bodies[i].qOrientation, pt); 

Bodies[i].vMonents += pt A ContactForce; 

Bodies[i].vMonents += pt A FrictionForce; 


} 


} 


} 


} 


390 | Chapter 19: Sports 


www.it-ebooks.info 



As you can see, upon entering CalcObjectForces the code enters a loop that cycles 
through all the billiard ball objects, computing the forces acting on each. The first force 
computed is simple aerodynamic drag. Both linear and angular drag are computed. We 
compute the magnitude of the linear drag by multiplying the linear drag coefficient by 
l/2p V2r2nr, where p is the density of air, V is the ball’s linear speed, and r is the ball’s 
radius. We compute the magnitude of the angular drag moment by multiplying the 
angular drag coefficient by cop4r2Tt, where to is angular speed. Since drag retards motion, 
the linear drag and angular drag vectors are simply the opposite of the linear and angular 
velocity vectors, respectively. Normalizing those vectors and then multiplying by the 
respective drag magnitudes yields the linear and angular drag force and moment vec¬ 
tors. 

The next set of forces calculated in CalcObjectForces is the contact forces between the 
table top and each ball. There are three contact forces. One is the vertical force that 
keeps the balls from falling through the table, another is the friction force that arises as 
the balls slide along the table, and the third is rolling resistance. These forces arise only 
if the ball is in contact with the table. We’ll address how to determine whether a ball is 
in contact with the table later in this chapter. For now, we’ll assume there’s contact and 
show you how to compute the contact forces. 

To compute the vertical force required to keep the ball from falling through the table, 
we must first compute the ball’s linear acceleration, which is equal to the sum of forces 
(excluding contact forces) acting on the ball divided by the ball’s mass. Next, we take 
the negative dot product of that acceleration and the vector perpendicular to the table 
surface and multiply the result by the ball’s mass. This yields the magnitude of the contact 
force, and to get the vector we multiply that magnitude by the unit vector perpendicular 
to the table’s surface. The following two lines of code perform these calculations: 

Bodtes[t].vAcceleration = Bodles[i].vForces / Bodies[l].fMass; 

ContactForce = (Bodiesfi].fMass * (-Bodiesfi].vAcceteration * 

Collisions!j].vCollisionNormal)) * 

Collisions!j]•vCollisionNormal; 

The vCollisionNormal vector is determined by CheckGroundPlaneContacts, which 
we’ll cover later. As with collisions, CheckGroundPlaneContacts fills in a data structure 
containing the point of contact, relative velocity between the ball and table at the point 
of contact, and the contact normal and tangent vectors, among other data. 

To compute the sliding friction force, we must first determine the tangential component 
of the relative velocity between the ball and table. If the ball is sliding or slipping as it 
rolls, then the relative tangential velocity will be greater than 0. If the ball is rolling 
without sliding, then the relative velocity will be 0. In either case, there will be a friction 
force; in the former case, we’ll use the kinetic friction coefficient, and in the latter we’ll 
use the static friction coefficient. Friction force is computed in the same way we showed 
you in Chapter 3. The following lines of code perform all these calculations: 


Billiards | 391 


www.it-ebooks.info 



ContactForce = (Bodiesfi].fMass * (-Bodies[1].vAcceleration * 
Colllsions[j].vCollislonNormal)) * 

Collisionsfj] .vCollislonNormal; 

double vt = fabs(Colllslons[j].vRelatlveVeloclty * 

Collisions[j].vCollisionTangent); 
if(vt > VELOCITYTOLERANCE) 

{ 

// Kinetic: 

FrictionForce = (ContactForce.Magnitude() * 
FRICTIONCOEFFICIENTGROUND) * 

Collisions[j].vCollisionTangent; 

} else { 

// Static: 

FrictionForce = (ContactForce.Magnitude() * 
FRICTIONCOEFFICIENTGROUND * 2 * 
vt/VELOCITYTOLERANCE) * 

Collisions[j].vCollisionTangent; 

} 

Keep in mind that these forces will create moments if they do not act through the ball’s 
center of gravity. So, after computing and aggregating these forces, you must also resolve 
any moments created and aggregate those using the same formulas we’ve shown through 
this book. The following lines of code take care of these tasks: 

// accunlate contact and friction forces and moments 
Bodies[i].vForces += ContactForce; 

Bodies[i].vForces += FrictionForce; 

ContactForce = QVRotate(~Bodies[i].qOrientation, ContactForce); 
FrictionForce = QVRotate(~Bodies[i].qOrientation, 

FrictionForce); 

pt = Collisionsfj].vCollisionPoint - Bodies[i].vPosition; 
pt = QVRotate(~Bodies[i].qOrientation, pt); 

Bodiesfi].vMoments += pt A ContactForce; 

Bodies[i].vMoments += pt A FrictionForce; 

Rolling resistance arises by virtue of small deformations in the cloth-covered table cre¬ 
ating a little divot that the ball must overcome as it rolls. This divot shifts the center of 
application of the contact force just a little bit in the direction of rolling. That small 
offset results in a moment when multiplied by the contact force. The resulting moment 
opposes rolling; otherwise, without some other resistance the ball would continue roll¬ 
ing unrealistically. The following code computes the rolling resistance: 

// Do rolling resistance: 

if(Bodies[i] .vAngularVelocity.MagnitudeQ > VELOCITYTOLERANCE) 

{ 

FRn = ContactForce.Magnitude() * 

Collisions[j].vColllsionNormal; 

Collisions[j].vCollisionTangent.Normalize(); 

Vector m = (Collisions[j].vCollisionTangent 
*(ROLLINGRESISTANCECOEFFICIENT * 


392 | Chapter 19: Sports 


www.it-ebooks.info 



Bodles[i].fRadius)) A FRn; 
double nag = m.MagnitudeQ; 

Vector a = Bodles[l].vAngularVelocity; 
a.NornalizeO; 

Bodies[i].vMoments += -a * nag; 


Handling Collisions 

Earlier you saw where StepSimulation makes a few function calls to deal with collision 
checking and response. You also saw where CalcObjectForces makes a function call 
that checks for contacts. The functions that check for collisions or contacts make use of 
the Collisions array we showed you earlier. This array stores all the relevant informa¬ 
tion pertaining to collisions or contacts—the collision or contact manifold, normal and 
tangent vectors, relative velocity, etc. 

The first function we’ll consider is CheckForCollisions, which is called toward the end 
of StepSimulation. CheckForCollisions checks for ball-ball collisions; we have a sep¬ 
arate function to check for ball-table collisions that we’ll get to later. CheckForColli 
sions relies on concepts we’ve already discussed and showed you in earlier chapters, so 
we’ll summarize its action here. Basically, two billiard balls are colliding if 1) they are 
headed toward each other, and 2) the distance separating their centers is less than or 
equal to the sum of their radii. Ifboth of these criteria are met, then a collision is recorded 
and all relevant data is stored in the Collisions array: 


int 

1 


CheckForCollisions(void) 


int 

int 

Vector 

pCollision 

int 

float 

float 

Vector 


status = NOCOLLISION; 

i, j; 

d; 

pCollisionData; 
check = NOCOLLISION; 
r; 
s; 

trip; 


FlushCollisionData(); 
pCollisionData = Collisions; 
NupiCollisions = 0; 


// check object collisions with each other 
for(i=0; i<NUMBODIES; i++) 

{ 

for(j=0; j<NUMBODIES; j++) 

if((j!=i) && !CollisionRecordedAlready(i, j)) 

{ 

// do a bounding sphere check 
d = Bodiesfi].vPosition - Bodies!j].vPosition; 
r = Bodies[i].fRadius + Bodies[j].fRadius; 
s = d.Magnitude!) - r; 


Billiards | 393 


www.it-ebooks.info 



if(s < COLLISIONTOLERANCE) 

{// possible collision 

Vector ptl, pt2, veil, vel2, n, Vr; 
float Vrn; 

ptl = (Bodies[i].vPosition + Bodies[j].vPosition)/2; 
tmp = pt2 = ptl; 

ptl = ptl-Bodies[i].vPosition; 
pt2 = pt2-Bodies[j].vPosition; 

veil = Bodiesfi].vVelocity + 

(Bodies[i].vAngularVelocityGlobal A ptl); 
vel2 = Bodies[j].vVelocity + 

(Bodies[j].vAngularVelocityGlobal A pt2); 


n = d; 

n.Normalize(); 

Vr = (veil - vel2); 

Vrn = Vr * n; 

if(Vrn < -VELOCITYTOLERANCE) 

{ 

// Have a collision so fill the data structure 
assert(NumCollisions < (NUMB0DIES*8)); 
if(NumCollisions < (NUMB0DIES*8)) 

{ 

pCollisionData->bodyl = i; 
pCollisionData->body2 = j; 
pCollisionData->vCollisionNormal = n; 
pCollisionData->vCollisionPoint = tmp; 
pCollisionData->vRelativeVelocity = Vr; 
pCollisionData->vCollisionTangent = (n A Vr) A n; 
pCollisionData->vCollisionTangent.Normalize(); 

pCollisionData++; 

NumCollisions++; 
status = COLLISION; 


for(i=0; i<NUMBODIES; i++) 

{ 

check = NOCOLLISION; 

assert(NumCollisions < (NUMB0DIES*8)); 

check = CheckGroundPlaneCollisions(pCollisionData, i); 

if(check == COLLISION) 

{ 


394 | Chapter 19: Sports 


www.it-ebooks.info 



status = COLLISION; 
pColltsionData++; 

NumCollisions++; 

} 

} 

return status; 

} 

Since CheckForCollisions loops through all of the balls checking for collisions with 
every other ball, it is possible that a collision would be recorded twice. For example, the 
ith ball may be found to be colliding with the jth ball, and later the jth ball would also 
be found to be colliding with the ith ball. We don’t want to record that information twice, 
so we use the following function to check if a collision between two particular balls is 
already recorded. If so, we skip re-recording the data: 

bool CollisionRecordedAlready(int i, int j) 

1 

int k; 
int bl, b2; 

for(k=0; k<NumCollisions; k++) 

{ 

bl = Collisionsfk].bodyl; 
b2 = Collisionsfk].body2; 


if( ((bl == i) && (b2 == j)) | | 

((bl == j) && (b2 == i» ) 
return true; 

} 

return false; 

1 

Checking ball-table collisions is fairly straightforward as well. If 1) a ball is found to be 
headed toward the table with some velocity greater than 0 (or some small threshold), 
and 2) the ball’s vertical position to its center is less than or equal to its radius, then we 
record a collision. CheckGroundPlaneCollisions handles this for us: 

int CheckGroundPlaneCollisions(pCollision CollisionData, int bodyl) 

1 


Vector 

top; 

Vector 

veil; 

Vector 

ptl; 

Vector 

Vr; 

float 

Vrn; 

Vector 

n; 

int 

status = NOCOLLISION; 


if(Bodiesfbodyl].vPosition.z <= (Bodiesfbodyl].fRadius)) 
1 

ptl = Bodiesfbodyl].vPosition; 


Billiards | 395 


www.it-ebooks.info 



ptl.z = COLLISIONTOLERANCE; 
tnp = ptl; 

ptl = ptl-Bodies[bodyl].vPosition; 
veil = Bodies[bodyl].vVeloclty/*Body*/ + 

(Bodiesfbodyl].vAngularVelocityGlobal A ptl); 

n.x = 0; 
n.y = 0; 
n.z = 1; 

Vr = veil; 

Vrn = Vr * n; 

if(Vrn < -VELOCITYTOLERANCE) 

{ 

// Have a collision so fill the data structure 
assert(NutnCollisions < (NUMBODIES*8)); 
if(NunCollisions < (NUMB0DIES*8)) 

{ 

CollisionData->bodyl = bodyl; 
CollisionData->body2 = -1; 
CollisionData->vCollisionNormal = n; 
CollisionData->vCollisionPoint = trip; 
CollisionData->vRelativeVelocity = Vr; 

CollisionData->vCollisionTangent = (n A Vr) A n; 
CollisionData->vCollisionTangent.Reverse(); 

CollisionData->vCollisionTangent.Normalize(); 
status = COLLISION; 

} 

} 

} 


return status; 

} 

Resolving collisions, whether ball-ball or ball-table collisions, uses the same approach 
we’ve already shown you. Thus, we won’t go over the code again, and will instead just 
show you the function that implements collision response: 

void ResolveCollisions(void) 

{ 

int i; 

double j; 

Vector ptl, pt2, vBlV, vB2V, vBlAV, vB2AV; 
float fCr = COEFFICIENTOFRESTITUTION; 

int bl, b2; 

float Vrt; 

float PluB = FRICTIONCOEFFICIENTBALLS; 

float nuG = FRICTIONCOEFFICIENTGROUND; 

bool dofriction = DOFRICTION; 


396 | Chapter 19: Sports 


www.it-ebooks.info 



for(i=0; i<NumCollisions; i++) 

{ 

bl = Collisions[i.] .bodyl; 
b2 = Colllsions[l],body2; 

If( (bl != -1) && (bl != b2) ) 

{ 

if(b2 != -1) // not ground plane 

{ 

ptl = Collisions[l].vColllsionPoint - Bodies[bl].vPositlon; 

pt2 = Collisions[l].vColllsionPoint - Bodies[b2].vPosition; 

// Calculate impulse: 

j = (-(1+fCr) * (Collisions[i].vRelativeVelocity * 
Collisions[i].vCollisionNormal)) / 

((l/Bodies[bl].fMass + l/Bodies[b2].fMass) + 
(Collisions[i].vCollisionNormal * ( ( (ptl A 
Collisions[i].vCollisionNormal) * 

Bodies[bl].mlelnverse ) A ptl) ) + 

(Collisions[i].vCollisionNormal * ( ( (pt2 A 
Collisions[i].vCollisionNormal) * 

Bodies[b2].mlelnverse ) A pt2) ) ); 

Vrt = Collisions[i].vRelativeVelocity * 

Collisions[i].vCollisionTangent; 

if(fabs(Vrt) > 0.0 && dofriction) { 

Bodies[bl].vVelocity += 

((j * Collisionsfi].vCollisionNormal) + 

((muB * j) * Collisions[i].vCollisionTangent)) / 
Bodies[bl].fMass; 

Bodies[bl].vAngularVelocityGlobal += 

(ptl A ((j * Collisions[i].vCollisionNormal) + 
((muB * j) * Collisions[i].vCollisionTangent))) 
Bodies[bl].mlelnverse; 

Bodies[bl].vAngularVelocity = 

QVRotate(-Bodies[bl].qOrientation, 

Bodies[bl].vAngularVelocityGlobal); 

Bodies[b2].vVelocity += 

((-j * Collisions[i].vCollisionNormal) + ((muB * 
j) * Collisions[i].vCollisionTangent)) / 
Bodies[b2].fMass; 

Bodies[b2].vAngularVelocityGlobal += 

(pt2 A ((-j * Collisions[i].vCollisionNormal) + 
((muB * j) * Collisions[i].vCollisionTangent))) 

* Bodies[b2].mlelnverse; 

Bodies[b2].vAngularVelocity = 

QVRotate(~Bodies[b2].qOrientation, 

Bodies[b2].vAngularVelocityGlobal); 


Billiards | 


397 


www.it-ebooks.info 



} else { 

// Apply impulse: 

Bodies[bl].vVelocity += 

(j * Collisions[i].vColllsionNomal) / 
Bodies[bl].fMass; 

Bodies[bl].vAngularVelocityGlobal += 

(ptl A (j * Collisions[i].vCollisionNormal)) * 
Bodies[bl].mlelnverse; 

Bodies[bl].vAngularVelocity = 

QVRotate(-Bodies[bl].qOrientation, 

Bodies[bl].vAngularVelocityGlobal); 

Bodies[b2].vVelocity -= 

(j * Collisions[i] .vColllsionNomal) / 
Bodies[b2].fMass; 

Bodies[b2].vAngularVelocityGlobal -= 

(pt2 A (j * Collisions[i] .vColllsionNomal)) * 
Bodies[b2].mlelnverse; 

Bodies[b2].vAngularVelocity = 

QVRotate(-Bodies[b2].qOrientation, 

Bodies[b2].vAngularVelocityGlobal); 


} else { // Ground plane: 

fCr = COEFFICIENTOFRESTITUTIONGROUND; 

ptl = Collisions[i].vCollisionPoint - Bodies[bl].vPosition; 

// Calculate impulse: 

j = (-(1+fCr) * (Collisions[i].vRelativeVelocity * 
Collisionsfi].vCollisionNormal)) / 

( (l/Bodies[bl].fMass) + 

(Collisions[i].vCollisionNormal * 

( ( (ptl A Collisions[i].vCollisionNormal) * 

Bodies[bl].mlelnverse ) A ptl))); 

Vrt = Collisions[i].vRelativeVelocity * 

Collisions[i].vCollisionTangent; 

if(fabs(Vrt) > 0.0 && dofriction) { 

Bodiesfbl].vVelocity += 

( (j * Collisions[i].vCollisionNormal) + ((muG * 
j) * Collisions[i].vCollisionTangent) ) / 
Bodies[bl].fMass; 

Bodies[bl].vAngularVelocityGlobal += 

(ptl A ((j * Collisions[i].vCollisionNormal) + 
((muG * j) * Collisions[i].vCollisionTangent))) * 
Bodies[bl].mlelnverse; 

Bodies[bl].vAngularVelocity = 

QVRotate(-Bodies[bl].qOrientation, 

Bodies[bl].vAngularVelocityGlobal); 

} else { 


398 | Chapter 19: Sports 


www.it-ebooks.info 



// Apply impulse: 

Bodies[bl].vVelocity += 

(j * Collislons[i].vCollisionNomal) / 
Bodtes[bl].fMass; 

Bodies[bl].vAngularVelocityGlobal += 

(ptl A (j * Collisions[i] .vCollisionNomal)) * 
Bodies[bl].mlelnverse; 

Bodies[bl].vAngularVelocity = 

QVRotate(~Bodies[bl].qOrientation, 

Bodies[bl].vAngularVelocityGlobal); 


The final function we need to showyou is CheckGroundPlaneContacts. Recall that this 
function is called from CalcObjectForces in order to determine if a ball is in resting 
contact with the table. If the ball’s vertical position is less than or equal to its radius plus 
some small tolerance, and if the ball’s vertical velocity is 0 (or nearly so within some 
small tolerance), then we consider the ball in contact with the table. If there’s a contact, 
the relevant data gets stored in the Collisions array and used to resolve the contact, 
not the collision, in CalcObjectForces: 

int CheckGroundPlaneContacts(pCollision CollislonData, int bodyl) 

{ 


Vector 

vl[8]; 

Vector 

tmp; 

Vector 

u, v; 

Vector 

f[4]; 

Vector 

veil; 

Vector 

ptl; 

Vector 

Vr; 

float 

Vrn; 

Vector 

n; 

int 

status = NOCOLLISION 

Vector 

Ar; 

float 

Arn; 


lf(Bodies[bodyl].vPosltion.z <= (Bodiesfbodyl].fRadius + COLLISIONTOLERANCE)) 

{ 

ptl = Bodlesfbodyl].vPosition; 
ptl.z = COLLISIONTOLERANCE; 
tmp = ptl; 

ptl = ptl-Bodles[bodyl].vPosition; 
veil = Bodles[bodyl].vVeloclty/*Body*/ + 

(Bodlesfbodyl].vAngularVelocltyGlobal A ptl); 

n.x = 0; 
n.y = 0; 


Billiards | 399 


www.it-ebooks.info 



n.z = 1; 


Vr = veil; 

Vrn = Vr * n; 

if(fabs(Vrn) <= VELOCITYTOLERANCE) // at rest 

{ 

// Check the relative acceleration: 

Ar = Bodies[bodyl].vAcceleration + 

(Bodies[bodyl].vAngularVelocityGlobal A 
(Bodies[bodyl].vAngularVelocityGlobal A ptl)) + 

(Bodies[bodyl].vAngularAccelerationGlobal A ptl); 

Arn = Ar * n; 

if(Arn <= 0.0f) 

{ 

// We have a contact so fill the data structure 
assert(NunCollisions < (NUMB0DIES*8)); 
if(NumCollisions < (NUMB0DIES*8)) 

{ 

CollisionData->bodyl = bodyl; 

CollisionData->body2 = -1; 

CollisionData->vCollisionNornal = n; 
CollisionData->vCollisionPoint = trip; 
CollisionData->vRelativeVelocity = Vr; 
CollisionData->vRelativeAcceleration = Ar; 

CollisionData->vCollisionTangent = (n A Vr) A n; 

CollisionData->vCollisionTangent.Reverse(); 

CollisionData->vCollisionTangent .NortnalizeO; 

CollisionData++; 

NumCollistons++; 
status = CONTACT; 

} 

} 

} 

} 

return status; 

} 

That’s all there is to this billiards example. As you can see, we used substantially the 
same methods shown in other examples throughout this book to implement this ex¬ 
ample. About the only new information we’ve shown here is how to compute rolling 
resistance. With a little effort, you can combine the material presented in this example 
with the projectile motion material presented in Chapter 6 to model all sorts of sports 
balls. Whether you’re modeling a billiard ball bouncing off a table or a basketball 
bouncing off a backboard, the methods are the same. The only things that will change 
are the empirical coefficients you use to model each ball and surface. Have fun. 


400 | Chapter 19: Sports 


www.it-ebooks.info 



PART IV 


Digital Physics 


Part IV covers digital physics in a broad sense. This is an exciting topic, as it relates to 
the technologies associated with mobile platforms, such as smartphones like the iPhone, 
and groundbreaking game systems like the Wii. Chapters in this part of the book will 
explain the physics behind accelerometers, touch screens, GPS, and other gizmos, 
showing you how to leverage these elements in your games. We recognize that these 
topics are not what most game programmers typically think about when they think of 
game physics; however, these technologies play an increasingly important role in 
modern mobile games, and we feel it’s important to explain their underlying physics in 
the hope that you’ll be better able to leverage these technologies in your games. 


www.it-ebooks.info 



www.it-ebooks.info 


CHAPTER 20 


Touch Screens 


It is hard to deny that we are currently moving toward a post-PC computing environ¬ 
ment. The proliferation of smartphones, tablets, and other mobile computing platforms 
will have far-reaching implications for how people interact with computers. These form 
factors do not allow for the more traditional mouse and keyboard of input for games 
and therefore rely heavily on the use of touch screens. This chapter aims to give you 
some background on the different types of touch screens, how they work, and their 
technical limitations. Note that we will extend our particle simulator to work with the 
iPhones capacitive touch screen; the final product is very similar to the mouse-driven 
version but provides a starting point for a touch-driven physics simulator. 

While this chapter will primarily deal with the most two most common types of touch- 
sensitive screens, resistive and capacitive, the following section gives an overview of 
many different types. In the future we may see a move to more exotic devices, especially 
for large-format computing devices. 

Types of Touch Screens 

Resistive 

Resistive touch screens are basically a giant network of tiny buttons. Some of them have 
4,096 x 4,096 buttons in a single square inch! OK, so they are not quite just normal 
buttons, but they come close. Resistive touch screens have at least two layers of con¬ 
ductors with an air gap between them. As you press on the screen, you close the gap. 
Bam, circuit complete, button pressed. We will flesh out that simplified description 
shortly. 


403 


www.it-ebooks.info 




Capacitive 

Also a topic we’ll soon discuss in detail, capacitive touch screens are very common on 
todays smartphones. These touch screens operate by calculating the change in electrical 
capacitance at the four corners of the screen when your finger influences the capacitive 
nature of the circuits under the glass. The limitation is that whatever touches the screen 
must be electrically conductive. If you insulate your fingers with gloves, the screen will 
no longer be able to locate your touch. However, this can be solved with a few stitches 
of conductive thread. 

Infrared and Optical Imaging 

Infrared touch screens use arrays of infrared LED and photodetectors to detect and 
interpret an object breaking the path of a LED-photodetector pair. This uses line¬ 
scanning techniques and is a very robust design. 

Optical imaging techniques are relative newcomers to the touch screen scene whose big 
advantage is that they are extremely scalable. They use imaging devices and light sources 
to detect where the screen is being touched by interpreting any shadows cast by an object 
through the thickness of the material. 

Exotic: Dispersive Signal and Surface Acoustic Wave 

Several other exotic touch screen technologies exist. We won’t get into detail here, but 
3M has a system that detects mechanical energy in glass caused by a touch. The amount 
of vibration energy that reaches each sensor determines the position. 

Another example of exotic screen input, surface acoustic wave technology detects 
changes in the pattern of ultrasonic waves traveling along the surface of the screen. 

Step-by-Step Physics 

Resistive Touch Screens 

Resistive touch screens are classified as a passive touch screen technology because the 
screen registers a touch without any active participation by the object touching the 
screen. This is their major benefit over active technologies, such as capacitive touch 
screens, as resistive screens can be activated by nonconductive objects like a pen or 
gloved finger. In the past, resistive screens were limited to a single input, and that’s the 
type we’ll describe, but they can be made to work with two or more simultaneous inputs, 
also known as multitouch. 


404 | Chapter 20:Touch Screens 


www.it-ebooks.info 



One-dimensional resistive touch sensor 


To ease ourselves into this discussion, we will begin by looking at a one-dimensional 
touch screen. Let’s imagine we have built the machine described in Figure 20-1. 



Figure 20-1. Linear resistive touch sensor 


As you can see, our sensor has two states, an open circuit state and a closed circuit 
state. In the open circuit state, the controller is supplying a 5 V signal to pin 2 and waiting 
for any return voltage on pin 1. With no touch to bring the wires together, the circuit 
is open. No voltage is present at pin 1, and therefore no touch is sensed. When the wires 
are touched, they are brought together and the circuit is closed. A voltage will then be 
present at pin 1. A touch event is registered. 

This type of sensor, which looks only for the presence or absence of voltage without 
regard to its value, is called a digital sensor. It can detect only two states: on or off (1 or 
0, respectively). OK, so it’s not quite a touch screen yet; essentially at this point all we 
have is a simple button. Moving forward, let’s say that we not only want to trigger an 
event when we press our button, but we also want to simultaneously input a value based 
on the location along the wire, L, that we pressed. 

To accomplish this, the controller patiently waits for a voltage at pin 1. When it senses 
a voltage, that digital “on” switch causes the controller to then probe the voltage that is 
present, which we have labeled V x . Now we get to the reason it is called a resistive touch 
sensor. Current, voltage, and resistance are all interrelated by Ohm’s law. This physical 
relationship is expressed as: 


V = IR 


Where V is voltage, I is current, and R is resistance. The exact physical meaning of each 
of these is less important right now than how they are related, so don’t get too worried 
if you can’t recall their definitions. In the case of our circuit, I, or current, is going to be 


Step-by-Step Physics | 405 


www.it-ebooks.info 





















constant. As the controller measures the voltage, V, at pin 1, we can now solve for 
resistance: 


R = V/l 

With our constant current, I, and our known voltage, V x , we can calculate the resistance 
of the circuit by inputting (5 - V x ) for V as follows: 

R = (5-Vx)/I(l) 

Note that we have to have the change in voltage across our resistor (the wire), so be sure 
to use the difference between the two values. Every conductor has an inherent internal 
resistance, and through testing we can determine what the resistance is, measured in 
ohms per unit length, and use that to determine our total resistance described by: 

R = 2rL 

where r is the aforementioned ohms per unit length and R is the total resistance of our 
circuit. Note that we have multiplied L by 2 to account for both the wire run to the point 
of contact and back. If we substitute this for R in our earlier equation, we now have: 

2rL = (5 - Vx) /1 


And finally: 


L = (5 - Vx) / (2rl) 

where L is the only unknown. To illustrate, let us assume the measured voltage is 4.95V 
and the wires are 24-gauge copper wires. A quick look in a standard electrical engi¬ 
neering book gives the resistance as 0.08422 ohms per meter. When we designed our 
constant current source, let’s say we picked 50 milliamps: 

L = (5 - 4.95V) / ((2)(.08422 ohms/meter)(.05A)) 

L = 5.9 meters from the controller 

As you can see, the material’s resistance per meter, the constant current supplied, and 
the sensitivity of the voltage-sensing circuit must all be finely tuned to ensure that the 
controller is capable of sensing touch events in the appropriate dimensions. In a resistive 
touch screen, the wires are microscopic so that the resistance per meter is much higher. 
This allows the screen to detect smaller distances. 

Four-wire resistive touch screen 

With some modification, we can expand our previous model to two dimensions. In the 
four-wire touch screen, there are four basic layers and four wires, three of which will be 


406 | Chapter 20:Touch Screens 


www.it-ebooks.info 



used at any given time. The general layout is given in Figure 20-2. The squares containing 
the X and Y wires would actually be overlapped but are shown skewed here for clarity. 



Figure 20-2. Four-wire touch screen 


The reason for calling it a. four-wire touch screen should now be obvious; however, 
remember that only three of the wires will be active at any time. The basic structure is 
shown in Figure 20-3. 


FLEXIBLE CONDUCTOR -Y AXIS_ 

_ FLEXIBLE INSULATING GAP 

SOLID CONDUCTOR-X AXIS _+5v 

GLASS 


Figure 20-3. Four-wire touch screen profile 

The first layer of the screen comprises a flexible conductor separated by an insulating 
gap. Under the gap lies a solid conductor. When a finger presses down on the outer layer 
of flexible conductor, it crosses the gap and makes contact with the solid conductor. The 
conductors are thin layers of indium-tin oxide (ITO) with silver bus bars on either end 
of the sheet, shown as black lines in Figure 20-2. 


Step-by-Step Physics | 407 


www.it-ebooks.info 







































To condense the description of its operation, we’ve outlined the three possible states in 
Table 20-1. 


Table 20-1. Possible states for four-wire touch screen 


1 Activity 

Pin 1 

Pin 2 

Pin 3 

Pin 4 1 

Waiting for touch detection 

Open 

Open 

Digital input [pullup] 

Ground 

Read A position 

Voltage probe 

Ground 

Voltage source 

Open 

Read K position 

Voltage source 

Open 

Voltage probe 

Ground 


Voltage probe means the chip is sensing the voltage on that pin, voltage source is the pin 
supplying a voltage to ground, and open means it is unused. The sequence of a touch 
event begins with pin 1 and pin 2 open. Pin 3 is configured to digital input with pullup 
signifying a voltage is supplied to the pin. When a finger presses on the outer layer and 
makes contact with the lower layer, pin 3 goes to ground. When the controller senses 
the voltage fall on pin 3, it moves to the second row and reads the X position. 

To read the X position, the lower layer is energized from pin 3 to pin 2. The voltage 
source creates a gradient along the layer. Pin 1, connected to the upper layer, delivers a 
voltage to the controller when a touch pushes it down to make contact with the lower 
energized layer. The value of this voltage depends on where the contact is made in the 
gradient, much like the previous linear example. Once the X position is known, the 
controller moves to the next row and reads the Y position. 

The method of obtaining the Y position is much the same but in reverse. The voltage 
supply is switched to pin 1, which develops a voltage gradient with pin 4. Then pin 3 is 
probed and the voltage corresponds to the distance along the voltage gradient. As the 
controller is capable of repeating the detect, read X, and read Y cycles approximately 
500 times a second, the user is not aware that the screen doesn’t actually register the X 
and Y coordinates at the same time. 

While the four-wire resistive touch screen is the simplest two-dimensional touch sensor, 
there are issues with durability. The main drawback of this type of touch screen is that, 
because the layers must be separated by an insulating gap, at least one of the layers must 
be flexible. In the four-wire type, the constant flexing of the first conductive layer in¬ 
troduces microcracks in the coating, which lead to nonlinearities and reduce the accu¬ 
racy. Other models of resistive touch screens overcome this issue with additional layers 
that remove the need for the flexible conductor. They have also been adapted to provide 
multitouch capability. We will discuss multitouch and how it works with capacitive 
touch screens in greater detail shortly. 

Capacitive Touch Screens 

A capacitive screen uses a piece of glass coated in a transparent conductor. When your 
finger or other conductor comes into contact with the screen, the electrostatic field is 


408 | Chapter 20: Touch Screens 


www.it-ebooks.info 






disturbed, causing a change in the capacitance. To understand how capacitive screens 
work, let’s quickly review capacitance in general. 

A capacitor in its simplest form is two conductors, usually thin plates, separated by an 
insulator. If you apply a voltage across the two conductors, a current will flow and charge 
will build up. Once the voltage across the plates is equal to the supply voltage, the current 
will stop. The amount of charge built up in the plates is what we measure as the capac¬ 
itance. Previously, we noted that one issue with resistive screens is that one part must 
always flex to close a insulating gap and complete a circuit. This repetitive action even¬ 
tually leads to mechanical failure. A capacitor can be dynamically formed by any two 
conductors separated by an insulator. Noting that glass is a good insulator, it is easy to 
see that a finger separated from a conductor by glass can change the capacitance of a 
system. In this way, the finger or stylus doesn’t have to cause any mechanical action, yet 
it can still effect changes to the sensors, which are then used to measure the location of 
the touch. 

The methods of determining location based on capacitance on mobile devices are self¬ 
capacitance and mutual capacitance. 

Self-capacitance 

Anyone who has lived in a dry winter has felt the shock of a static electricity discharge. 
This zap is possible because the human body is a pretty good capacitor with a capacitance 
of about 22 pico-farads. This property is known as body capacitance. Self-capacitance 
screens take advantage of a physical property defined by the amount of electrical charge 
that must be added to an isolated conductor to raise its potential by one volt. When the 
fingers act as a conductor of the body’s inherent capacitance, the sensors on the other 
side of the glass experience a rise in electric potential. Given that the sensors are on the 
other side of a good insulator, glass, there won’t actually be any discharge of energy, 
unlike when you touch your metal car door and get “zapped.” Self-capacitance in this 
manner produces a very strong signal but lacks the ability to accurately resolve multiple 
touches. Therefore, it is often used in conjunction with the next type of touch screen 
we’ll discuss, mutual capacitance. 

Mutual capacitance 

The other form of capacitance-sensing screen, mutual capacitance, is formed by a grid 
of independent capacitors. A probing charge is sent over the rows or columns. As the 
capacitors charge and discharge, the system can sense the capacitance of each individual 
capacitor. As just discussed, the body is a good capacitor, and bringing part of it close 
to the capacitor grid changes the local electric field. Those capacitors that are under a 
finger or other conductor will read lower values than normal. Each capacitor can be 
scanned independently, enabling high resolution of where the touch event is occurring. 
Additionally, because they act independently of one another, it is possible to accurately 
register multiple touches. Think of this system as taking a picture of the capacitance on 


Step-by-Step Physics | 409 


www.it-ebooks.info 



the skin of the screen. Using algorithms similar to image processing and edge detection, 
this system can compute the extent of a touch event. 

Example Program 

Included in the source code accompanying this book is an example of the particle ex¬ 
plosion program from Chapter 8 that uses touch screen input instead of a mouse click. 

The code for a Cocoa touch Objective-C event is as follows: 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 

UITouch* touch = [[event touchesForViewrself] anyObject]; 
firstTouch = [touch tocationlnView:self]; 
self.status = YES; 

[self trigger]; 

} 

where firstTouch is defined by CGPoint firstTouch; in the header file. The CGPoint 
is a Cocoa touch object capable of storing an (x,y) coordinate in the display view’s co¬ 
ordinate system. We can then use firstTouch. x and firstTouch. y later in our program 
to give a location to the particle explosion. 

As you can see, it is very similar to a mouse-based event. One big difference is that you 
could adapt the code to handle multitouch events. Computers recognize only one mouse 
cursor at a time, but with a touch screen you can register multiple clicks simultaneously. 

Multitouch 

In iOS you must first enable delivery of multiple touch events by setting the multiple 
TouchEnabled property of your view to YES; the default is NO. Next you must create a 
class to keep track of multiple TParticleExplosion structures. Then it is as simple as 
polling the position of the start points of multiple touches to trigger multiple explosions. 
The Objective C code to store the start points of multiple touch events would look like: 

- (void)storeTouchPoints:(NSSet *)touches{ 

If ([touches count] > 0) { 

for (UITouch *touch in touches) { 

CGPoint *point = (CGPoint 

*)CFDtctionaryGetValue(touchBeginPoints, touch); 
if (point == NULL) { 

point = (CGPoint *)malloc(sizeof(CGPoint)); 
CFDictionarySetValue(touchBeginPoints, touch, point); 

} 

*point = [touch tocationlnView:view.superview]; 

} 

} 


410 | Chapter 20:Touch Screens 


www.it-ebooks.info 



where CFDictionaryRef is an immutable dictionary object that allows the copying of 
the object and its key value. One last consideration for this example is that as you are 
now creating multiple physics simulations simultaneously, you may have to decrease 
the frequency of the time steps to allow the animations to proceed smoothly. Multitouch 
can become programmatically complex, but the physics are pretty simple. The event¬ 
handling guide for your particular development language should give detailed guidance 
on handling the event chain. 

Other Considerations 

One of the major advantages of touch screens is that their layout and actions are entirely 
software based. That is to say, if a certain button does not pertain to the current layout, 
it can be discarded and the freed space used for additional relevant controls. We will 
discuss other less obvious considerations in the following sections. 

Haptic Feedback 

The flip side of the advantage of not being locked into a set of physical buttons is that 
the user must rely almost entirely on vision to interact with the controls. At least one of 
the authors of this book uses a keyboard with no letters on it at all, instead relying totally 
on the physical position of the keys to determine which key to strike. This would be 
much harder without the tactile and audio cues to signify that the correct key has been 
pressed. Indeed, it is easy to tell when he is typing poorly because the backspace key is 
much louder than the rest! 

The method of including physical feedback to assist a user in interaction with entirely 
virtual objects is known as haptic feedback. The first use of haptic feedback in games 
was limited to arcade games such as Motocross, in which the handlebars shook after an 
in-game impact. It is now considered standard on video game controllers, which vibrate 
to inform the user of some event. 

In the realm of touch screens, haptic feedback is used to inform the user of a successful 
key strike or other touch-based event. Some touch screens even incorporate some 
movement of the entire screen when pressed. This feedback still doesn’t allow touch 
typing, as it only dynamically responds and provides no static tactile feedback for dif¬ 
ferent buttons. 

Modeling Touch Screens in Games 

Given their planar nature and the lack of inherent haptic feedback, touch screens can 
be an easy way to implement controls with which a character in a game can interact. 
The amount of physical modeling required to create a realistic in-game keyboard is 
pretty intense. Thus, there are very few examples of an in-game character having to sit 
down and type a code in to a terminal via a standard keyboard. 


Other Considerations | 411 


www.it-ebooks.info 



By using touch screens for in-play control of objects, you can avoid an additional phys¬ 
ical model while retaining realism. It would also be interesting to see games use realistic 
touch screen interfaces so that a character would have to remove his gloves to use a 
capacitive screen. Lastly, the exotic screen technologies mentioned earlier provide many 
creative avenues of modeling those types of screens in games. For example, for screens 
measuring sound waves in the glass or other mechanical energy, low-grade explosions 
could be used to trigger these in-game input devices. 

Difference from Mouse-Based Input 

One important consideration for game developers in regards to touch screens is the 
difference from traditional mouse- and keyboard-based gaming. As console game de¬ 
velopers have long been aware, it is hard to compete with the speed and accuracy of the 
mouse/keyboard combination. Many first-person shooters segregate their online gam¬ 
ing between controllers and mouse/keyboard setups, as the accuracy and speed of the 
mouse gives those players an unfair advantage. Upon using touch screens on many 
different gaming devices and mobile computing platforms, we feel that this advantage 
is even more pronounced. 

A touch by a finger is an elliptical shape whose contact patch depends on the specific 
finger being used, the pressure applied, and the orientation of the finger. The user gen¬ 
erally perceives the point of touch to be below where the actual center of contact is, so 
adjustments must be made. This is generally all handled automatically by the operating 
system so that a single touch point is computed and handed to the game via an API. 
However, this generic approach to computing touches must obviously sacrifice accuracy 
for universality so that it is not calibrated for one specific user. 

Another inherent drawback to touch screens is the need to touch the screen. This means 
a large portion of your hand will be blocking the screen when you are controlling that 
element. One can imagine that in a first-person shooter, this would be a great disad¬ 
vantage over someone who is playing with a keyboard and mouse. 

Lastly, mouseover is not available to touch-screen-based input. Consider a game where 
you would trigger actions by merely moving a mouse cursor over an object. These 
actions could be distinct from clicking on the same object. However, with touch-screen- 
based input, that object would be obscured by whatever is triggering the screen, there¬ 
fore rendering the mouseover action invisible to the user. 

Custom Gestures 

As a last note, another possibility for touch input to a game is the use of custom gestures. 
These allow the user to draw a shape on the screen that the program recognizes as a 
gesture. It can then execute arbitrary code based on that input. As this is more pattern 
recognition then physics, we won’t cover it here, but we can recommend the book 
Designing Gestural Interfaces by Dan Saffer (O’Reilly) as a detailed look at this subject. 


412 | Chapter 20: Touch Screens 


www.it-ebooks.info 



CHAPTER 21 


Accelerometers 


Accelerometers are a good introduction to a class of electronic components called 
microelectromechanical systems (MEMS). An accelerometer can either be one-axis, two- 
axis, or three-axis. This designates how many different directions it can simultaneously 
measure acceleration. Most gaming devices have three-axis accelerometers. 

As far as game development is concerned, acceleration values are typically delivered to 
your program via an API with units in multiples of g. One g is equal to the acceleration 
caused by gravity on the Earth, or 9.8 m/s 2 . Let’s pretend that we have a one-axis accel¬ 
erometer and we orient it such that the axis is pointing toward the center of the earth. 
It would register \g. Now, if we travel far away from any mass, such that there is no 
gravity, the accelerometer will read 0. If we then accelerate it such that in one second it 
goes from 0 m/s to 9.8 m/s, the accelerometer will read a steady Ig during that one- 
second interval. Indeed, it is impossible to tell the difference between acceleration due 
to gravity and acceleration due to changing velocity. 

Real-life motion is generally nonsteady. Depending on your application’s goals, you 
might have to apply different smoothing functions such as high-pass or low-pass fil¬ 
ters. This amounts to digital signal processing, a topic that has consumed entire texts. 
One example we can recommend is Digital Signal Processing: A Computer Science Per¬ 
spective by Jonathan Y. Stein (Wiley). 

Also, many accelerometers have a method to set the polling rate, or the number of times 
per second that the program requests updates from the accelerometer. This is called 
frequency and is given in hertz (Hz). This parameter can be used to enhance the per¬ 
formance of the program when fine resolution of the acceleration over time is not 
needed. 

When you accept input from an accelerometer—or do any other kind of signal pro¬ 
cessing—you have to accept that input won’t come precisely when you want it. The 
operating systems normally used for gaming—Windows, OS X, Linux—are not real- 


413 


www.it-ebooks.info 




time environments. This means that although you set the polling rate at once a second, 
this guarantees only that the data will be delivered no sooner than once a second. If 
something distracts the operating system, such as the arrival of packets on the network, 
the signal you get from the accelerometer may be delayed. 

Accelerometer Theory 

The way in which MEMS measure accelerometers is more basic in principle than you 
may think. The major accomplishment is miniaturizing the technology until it can fit 
inside a computer chip! To clearly illustrate the basic principle, we will first show you 
the mechanics of it in the macro-scale version of a known mass and spring. Let’s say 
you build something like the contraption shown in Figure 21-1 and take it on an elevator 
in an area where there is no gravity. We’ll worry about the effects of gravity in a minute. 



Figure 21-1. Simple accelerometer in absence of acceleration 


414 | Chapter 21: Accelerometers 


www.it-ebooks.info 
















As you can see, the device consists of a known mass at the end of a spring next to a 
measuring stick. When the elevator is not accelerating, the mass is at the 0 mark. When 
the elevator accelerates up or down, the mass at the end of the spring resists that accel¬ 
eration and tends to stay at rest. This is Newton’s first law in action. Inertial loading 
causes the spring to stretch or compress. If the elevator is accelerating upward, the mass 
will cause the spring to stretch downward. Recall from Chapter 3 that the force acting 
on a spring is linearly dependent on the displacement of the mass via the equation: 

F n = kd 

We can directly measure the displacement, d, so we can determine the force in that 
direction, n. As the mass is known, voila! 

a n = m/F n 

As an aside, the fact that you can tell that you are accelerating without having to look 
outside the elevator is what makes this a “noninertial frame of reference,” as discussed 
in Chapter 2. No worries if you don’t totally understand that; it isn’t important for what 
we are discussing here. 

Now, let’s put our elevator back on earth. With the same device, the mass will not be at 
0 even if the elevator is not accelerating because gravity is pulling it down. Previously 
we used units of inches, which we then converted to force and finally to acceleration. 
However, we now have a direct measure of the acceleration due to gravity and could 
easily place a mark on where the mass is and call it Ig. Also we could place marks along 
the ruler at the same intervals. Now, we accelerate the elevator upward at 9.8 m/s 2 . The 
mass should move down the scale to 2 g, and anyone standing in the elevator would feel 
twice as heavy as normal. 

Let’s say we wanted to accelerate the elevator downward at 9.8 m/s 2 . We could easily do 
this by just releasing the brakes and letting gravity do the work. Now in freefall we don’t 
feel gravity at all, right? That’s because the downward acceleration is canceling the ac¬ 
celeration due to gravity. The mass will be back at 0 just like out in space, far from any 
gravitational bodies. It is for this reason, and not a lack of gravity, that astronauts float 
around. They are in freefall around the earth. 

Lastly, if we accelerate the elevator downward at 2 g, the mass would move to the -1 g 
mark on the ruler. This is because the downward acceleration is now overwhelming 
gravity. Those in the elevator would find themselves standing on the ceiling feeling 
exactly as they would standing on the ground! In fact, one of Einstein’s accomplishments 
was showing that it is impossible to distinguish gravity from inertial accelerations. We’ll 
leave the details of that for independent study and get back to accelerometers in the 
form of MEMS. 


Accelerometer Theory | 415 


www.it-ebooks.info 



MEMS Accelerometers 

Micro-scale accelerometers are not that much different from the machine previously 
described but generally use a cantilevered beam instead of a spring. To track more than 
one axis, sometimes three discrete accelerometers are placed out of plane with respect 
to one another. Alternatively, more complex models use elements that can sense all three 
directions within a single integrated sensor. These generally give better results. 

The only important difference from the aforementioned examples, besides MEMS being 
thousands of times smaller in scale than the mass and spring, is how to measure the 
deflection of the test mass. There are three common methods employed in accelerom¬ 
eters. For most game devices where extreme accuracy isn’t required, the deflection is 
usually measured as a change in capacitance. This is somewhat the same way that ca¬ 
pacitive touch screens work, as described in Chapter 20, and is shown in Figure 21-2. 



The beam deflects under the influence of the external accelerations of the test mass and 
brings two charged plates farther or closer together. This changes the capacitance of the 
system. This change can then be calibrated to the imposed acceleration. 

Other methods include integrating a piezo resister in the beam itself so that the deflection 
of the beam changes the resistance of the circuit. Although this ultimately gives better 
results, these are harder to manufacture. For the most demanding applications, there 
are accelerometers using piezoelectric elements based on quartz crystals. These are very 
sensitive even during high-frequency changes in acceleration but are generally not used 
in sensing human-input motion. 


416 | Chapter 21: Accelerometers 


www.it-ebooks.info 





























Common Accelerometer Specifications 

To help you better experiment with accelerometers, we’ve collected the specifications 
on a few of the most common accelerometers in use at the time of writing. The future 
may hold cheap accelerometers based on quantum tunneling that can provide almost 
limitless accuracy, but Table 21-1 outlines what you’ll generally be working with for 
now. 


Table 21-1. Current common accelerometers 


1 Device 

Accelerometer chip 

Sensor range 

Sampling rate I 

iPhone/iPad/ Motorola Droid 

LIS331D 

±2g* 

100 Hz or 400 Hz 

Nintendo Wii 

ADXI330 

±3 g 

x-/y-axis: 0.5 Hz to 1600 Hz 
z-axis: 0.5 Hz to 550 Hz 

Sony Six Axis 

Not published 

1+ 

U) 

100 Hz 


- 

M>?> 4 » 

ti t*, 


The chip LIS221D is actually capable of two modes. One mode is ±2 g 
and the other is ±8g. This is dynamically selectable according to the 
chips datasheet; however, neither iOS nor Android allows developers 
to change the mode through the API. 


The 2 g limit for phones can cause problems when you’re attempting to record motion. 
This limitation will be discussed later in this chapter. The larger range of Wii and Sony 
controllers demonstrate that they are dedicated to gaming where larger accelerations 
are expected. 

Data Clipping 

The human arm is capable of exceeding the ±2g range of the iPhone’s sensor easily. The 
values reported by the API will actually exceed 2 g up to about 2.3 g. The accuracy of 
these values that exceed the specification is unknown. Regardless, they are probably at 
least as accurate as the option of trying to recreate the data, so if required they can be 
used. All values above this upper limit will be reported as the upper limit such that if 
you graphed the values, they would look like Figure 21-3. 


Accelerometer Theory | 417 


www.it-ebooks.info 









There are several different ways to handle data clipping. One is to discard the data and 
alert the user that he has exceeded the available range. Another is to attempt to recreate 
the missing data. If you are recording the data for later processing, you can use both 
segment 1 and segment 2 to fit the curve between the point at which the data began to 
be clipped and the point in which meaningful data collection is resumed. This is highly 
application dependent, and the curve used to fit the data will have to be matched to the 
activity at hand. If you are recording the data for later processing, you can use both 
segment 1 and segment 2 to give your data. 

If you are attempting to process the signal in real time, you’ll have only segment 1 to 
work from. This could result in a discontinuity when meaningful data collection re¬ 
sumes, and you’ll have to decide how to deal with that given the particulars of what you 
are doing with the data. 

Sensing Orientation 

Sensing rotation in three degrees of freedom amounts to sensing a rigid body’s orien¬ 
tation and is a complex problem that cannot be fully resolved using only accelerometers. 


418 | Chapter 21: Accelerometers 


www.it-ebooks.info 








Think about holding the device vertically. If you rotate the device about the axis de¬ 
scribed by the gravity vector, none of the accelerometers will measure any change in the 
force acting on their test masses. We can’t measure that degree of freedom. To do so, 
we’d need to fix a gyroscope to the device, and even these run into problems when a 
body is free to rotate about all three axes. See Chapter 11 for a discussion on Euler angles. 

Now let’s discuss what we can accomplish. First, Figure 21-4 demonstrates the coordi¬ 
nate system we’ll use; the actual coordinate system used will be determined by the man¬ 
ufacturer of your device, so make sure to check its documentation. 


♦Y 



Figure 21-4. Accelerometer coordinate system 

Now if we make some assumptions based on how a user will hold our device, we can 
determine some “gross” orientations. For illustration, Table 21-2 gives some idea of what 
each value would be for each gross direction, assuming the coordinate system shown 
in Figure 21-4. 

Table 21-2. Gross acceleration values and orientations 


1 Device orientation 

X Y 

* 1 

Facedown on table 

0 

0 

1 

Face up on table 

0 

0 

-1 

Horizontal on table, right side down 

1 

0 

0 

Horizontal on table, left side down 

-1 

0 

0 

Vertical on table, bottom down 

0 

-1 

0 

Vertical on table, top down 

0 

1 

0 


There are a few things to note here. First, if you were to hold the phone in these orien¬ 
tations with your hand, the accelerometer is sensitive enough to pick up small deviations 


Sensing Orientation | 419 


www.it-ebooks.info 











from true vertical. We are considering these the “gross” orientations such that these 
small deviations should be ignored. 

Sensing Tilt 

Although we can’t determine exactly what angle the user is holding the phone about all 
three axes, we can pick one axis, assume that it is pointing down, and then find the 
change in the angle from that assumption over time. For instance, if the phone is lying 
on a table, the average acceleration in the z-direction will be -1, and in the other di¬ 
rections, 0. Even if the user spins the phone, the values will remain as previously indi¬ 
cated and we cannot sense that rotation. However, if the user lifts one edge from the 
table—we’ll call this tilting it—then the accelerometer will register different values. 
Some of the acceleration due to gravity will act on the other two axes. By sensing this 
change, an accelerometer will allow us to determine at what angle the device is tilted. 

Using Tilt to Control a Sprite 

Here we will show you how to implement code for a simple game that asks the user to 
move an avatar to a target by tilting the phone. First, we will briefly show an example 
of determining the rotation about a single axis. Let’s assume we have an accelerometer 
rotated at some arbitrary angle, a, which is what our algorithm will solve for. As previ¬ 
ously discussed, accelerometers generally report values as multiples of near earth gravity, 
g. For the following example, we are concerned only with the x- and y-axis values, a x 
and a y , respectively. If the device were in the “upright” position, then a x would equal 0 
and a y would equal 1. After rotating the device, we’d see different values that are related 
to our angle a by use of the arctangent function. In this case, because the single-argument 
atan function included in most programming languages doesn’t differentiate between 
diametrically opposed directions, it is beneficial to use the two-argument function. The 
relevant C code is as follows: 

tfdefine PI 3.14159 

float ftnd2dAngle(votd){ 

//LOCAL VARIABLES 
float alpha, 
double ax, ay; 

//POLL ACCELEROMETER FOR ACCELERATIONS, API SPECIFIC 
ax = getXaccelerationQ; 
ay = getYacceleratlon(); 

//FIND ANGLE 

alpha = atan2(ay,ax); 

if (alpha >= 0){ 


420 | Chapter 21: Accelerometers 


www.it-ebooks.info 



(180/PI); 


alpha = alpha * 
else { 

alpha = alpha * (-180/PI) + 180; 

} 

return alpha; 

} 

This is pretty straightforward, but there are a few things to point out. First, the way in 
which your program will get results from the accelerometer will vary greatly between 
platforms, so we have encapsulated that API-specific code in a getXaccelerationQ 
function. In fact, most operating systems will be continuously polling the accelerometer 
in a separate thread, so you’ll have to have a logical operator that tells your accelerometer 
object when you actually want to see those values passed to your program. Example 
Objective-C code for the accelerometer in the iPhone will be shown later. Secondly, 
you’ll notice that we are using an if statement that changes the radians to degrees in 
such a way as to return proper 0°-360° answers. This avoids having to pay attention to 
the sign, as atan2 returns only answers between 0° and 180°, using a negative value to 
represent the other half of the range. For example, an output of 0° means the device is 
vertical, an output of 90° means the device is rotated 90° to the left, and an output of 
180° means the device is upside down. 

Now let’s extend this to two dimensions. This will tell us not only how far the phone is 
from vertical about one axis, but its inclination about the y-axis as well. 

Two Degrees of Freedom 

Now let’s say that we want to develop a game in which we control a sprite moving in a 
2D world. The user would hold the device as if it were lying on a table and look down 
from above. He or she would then tilt the phone out of that plane to get the sprite to 
move in the desired direction. The fraction of gravity that the accelerometer is now 
experiencing in the x- and y-directions will be inputs into our simulation. 

The example will be demonstrated using Objective-C code for the iPhone, and we’ll be 
using the Qwartz2D graphics framework. If you aren’t familiar with Objective-C, don’t 
worry—we’ll explain what we are doing in each step, and you can port that code to 
whatever language you are working in. 

The first step will be to set up our accelerometer. In this case we are going to initialize 
it in our tiltViewController.m file so that we have: 

- (void)viewDidLoad 
{ 

UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; 
accelerometer.delegate = self; 
accelerometer.updatelnterval = kPollingRate; 

[super viewDidLoad]; 

} 


Sensing Tilt | 421 


www.it-ebooks.info 



The important concept here is that we have defined a name for our accelerometer object, 
accelerometer, and we have set its updatelnterval property to kPollingRate. This 
constant was defined in tiltViewController.h as (1.0f/60.0f), which corresponds to 60 
Hz. In other words, this tells the operating system to update our program’s accelerometer 
object 60 times a second. Also in tiltViewControiler, m, we write what happens when the 
accelerometer object gets updated via the accelerometer’s dldAccelerate: function as 
follows: 

- (void)accelerometer:(UIAcceleropieter *)accelerometer 
dldAcceterate:(UIAcceleration *)acceleration{ 

[(SpriteView *)self.view setAcceleratlon:acceleration]; 

[(SpriteView *)self.view draw]; 

} 

This function is called every time the acceleration object is updated and does two things. 
First, it takes the acceleration data from the accelerometer and passes it to the Sprite 
View class, which we’ll talk about in a second. Then it tells the SpriteView to go ahead 
and redraw itself. 

The SpriteView class is where the action happens and consists of a header file, Sprite 
View.h, where we define the following global variables: 

UHmage *sprite 

A pointer to the image that will be used to represent our sprite on the screen. 
currentPos 

The position on the screen where we want the sprite to be drawn. 
prevPos 

The previous position of the sprite on the screen. We will use this to tell the draw 
function what parts of the screen need to be redrawn. 

UIAcceleration *acceleration 

A special Objective-C data type to hold data from the accelerometer. 

CGFloat xVelocity and CGFloat yVelocity 

Float variables to hold the current velocity in the x-direction and y-direction, re¬ 
spectively. 

CGFloat convertX and CGFloat convertY 

Float variables to hold the ratios for converting our physics engine’s results in meters 
to pixels based on an assumed world size. 

Additionally, we’ve defined the following global constants: 

9 

Near earth gravity value, set at 9.8 m/s 2 . This will convert the accelerometer’s values 
from g to m/s 2 for use in calculating velocity. This can also be tuned to represent an 


422 | Chapter 21: Accelerometers 


www.it-ebooks.info 



arbitrary acceleration instead of just using gravity as the force (e.g., percent of jet 
engine thrust). 

kWorldHeight and kWorldWidth 

These values are used to allow the programmer to change the assumed world di¬ 
mensions. Higher values mean each pixel is a greater distance in meters. The world 
will always be scaled to fit on the screen, so a large world means the sprite will appear 
to move slower (a few pixels at a time) for a given acceleration. Note that our current 
code doesn’t scale the sprite. 

Now we’ll show you how we use these variables in SpriteView. m to move our sprite on 
our screen as a result of the accelerometer values. First, we have some initialization to 
do, which takes place in the initWithCoder: method that runs the first time the view 
is loaded: 

-(id)initWithCoder:(NSCoder *)coder { 

if((setf = [super inttWithCoder:coder])){ 

self.sprite = [Ullmage imageNapied:@"sprite.png"]; 

self.currentPos = CGPointMake((self.bounds.size.width / 2.Of) + 

(sprite.size.width / 2.0f), (self.bounds.size.height /2.0f)+(sprite.size.height /2.Of)); 
xVelocity = 0.0f; 
yVelcoity = 0.0f; 

convertX = self.bounds.size.width / kWorldWidth; 
convertY = self.bounds.size.height / kWorldHeight; 


} 

return self; 

} 

Most of this is pretty straightforward. We tell our program where to find the sprite image 
we’ve chosen and set its initial position to the center of the screen. We also set its initial 
velocity to 0 in both directions. We then go ahead and initialize our convertX and 
convertY variables based on the self. bounds. size property, which gives the bounds 
of the view in pixels. We’ll show exactly how this affects our program later. Next, we’ll 
write a custom mutator for the CurrentPos variable: 

- (vold)setCurrentPos:(CGPoint)newPos { 
prevPos = currentPos; 
currentPos = newPos; 

lf(currentPos.x <0){ 
currentPos.x = 0; 
xVelocity = 0.0f; 

} 

lf(currentPos.y <0){ 
currentPos.y = 0; 
yVelcoity = 0.0f; 

} 

lf(currentPos.x > self.bounds.size.width - sprite.size.width){ 


Sensing Tilt | 423 


www.it-ebooks.info 



currentPos.x = self.bounds.size.width - sprite.size.width; 
xVelocity = 0.0f; 

} 

if(currentPos.y > self.bounds.size.height - sprite.size.height){ 
currentPos.y = self.bounds.size.height - sprite.size.height; 
yVelocity = 0.0f; 

} 

CGRect curSpriteRect = CGRectMake(currentPos.x, currentPos.y, 
currentPos.x+sprite.size.width, currentPos.y+sprite.size.height); 

CGRect prevSpriteRect = CGRectMake(prevPos.x, prevPos.y, 
prevPos.x+sprite.size.width, currentPos.y+sprite.size.height); 

[self setNeedsDisplaylnRect:CGRectUnion(curSpriteRect, prevSpriteRect)]; 


} 

In case you are unfamiliar with Objective-C, when you define a class instance variable 
it will automatically define a mutator that simply updates the value of the variable to 
the value you are passing it. However, in the preceding example we are overriding that 
mutator to do some additional work. The first thing we do is to set the prevPos variable 
to the current position of the sprite and then update the currentPos with the value the 
mutator was given. However, our physics engine isn’t going to include collision response 
with the screen boundaries, so we go on to check if the sprite has reached the screen 
edge. If so, we simply tell the program to leave it on the edge and to set the velocity in 
that direction to 0. Lastly, we define a couple of rectangles based on the new position of 
the sprite and the old position of the sprite. After we union those rectangles together, 
we tell the operating system to redraw the screen in that area with the setNeedDis 
playlnRect: method. As you might recall, our accelerometer object is calling the draw 
method every time it updates, and it is in this method that we will put our physics engine: 

- (vold)draw { 

static NSDate *lastllpdateTime; 

if (lastUpdateTine != nil) { 

NSTlmelnterval secondsSlncetlpdate = - ([lastUpdateTine 
tlmelntervalSlnceNow]); //calculates Interval In seconds from last update 

//Calculate displacement 

CGFloat deltaX = xVelocity * secondsSlncetlpdate + 

((acceleration .x*g*secondsSlncetlpdate*secondsSlncetlpdate)/2); // METERS 
CGFloat deltaY = yVelocity * secondsSlncetlpdate + 

((acceleration .y*g*secondsSlncetlpdate*secondsSlncetlpdate)/2); // METERS 

//Converts from meters to pixels based on defined World size 
deltaX = deltaX * convertX; 
deltaY = deltaY * convertY; 

//Calculate new velocity at new current position 

xVelocity = xVelocity + acceleration.x * g * secondsSlncetlpdate; //assumes 
acceleration was constant over last update Interval 


424 | Chapter 21: Accelerometers 


www.it-ebooks.info 



yVelocity = yVelocity - (acceleration.y * g * secondsSinceUpdate); //assumes 
acceleration was constant over last update interval 

//Mutate currentPos which will update screen 
self.currentPos = CGPointMake(self.currentPos.x + deltaX, 
self.currentPos.y + deltaY); 

} 

[lastUpdateTime release]; 
lastllpdateTime = [[NSDate alloc] init]; 


} 

Previously, we discussed issues with timing when working with accelerometer data. In 
this case, Objective-C makes it very easy to get the correct elapsed time in seconds. We 
first define a static variable, lastUpdateTime, as an NSDate type. This type has a built- 
in function to give the time interval in seconds from now, which we assign to an NSTime 
Interval variable. Skipping down to the last two lines, we are simply updating the last 
update time by releasing and reinitializing the variable. As it is static, it will remain even 
after the function returns. If you are using a lower-level language, you might have to 
write your own timelntervalSinceNow function that takes into account the particular 
clock frequency of the system. 

Now that we have our time interval in seconds, we can calculate our new position. Recall 
from Chapter 2: 


S 2 = si + vi t + (a t 2 )/2 
which we have rearranged to be: 

As = S 2 - si = vj t + (a t 2 )/2 


This gets programmed as: 

CGFloat deltaX = xVelocity * secondsSinceUpdate + 

((acceleration.x*g*secondsSinceUpdate*secondsSinceUpdate)/2); // METERS 

We then convert this displacement in meters to displacement in pixels using an appro¬ 
priate ratio for the size of our world. Before we can move on, we have to calculate our 
new velocity at our new position. So we again assume the acceleration as constant over 
the update interval, and recalling: 


v 2 — v i + a At 

from Chapter 2, we can solve for the new xVelocity with: 

xVelocity = xVelocity + acceleration.x * g * secondsSinceUpdate; 


Sensing Tilt | 425 


www.it-ebooks.info 



As you can see from the complete method description, the code of the y-direction is 
similar. Finally, we call the currentPos mutator to set the new position based on the 
change in displacements. Recall that this is a custom mutator that also tells the operating 
system to update the display. After the draw method is finished, the accelerometer waits 
1/60 of a second and then calls it again. You could extend this program by adding in 
friction, fluid resistance, and collisions with the screen boundaries using the methods 
outlined in the other chapters of this book. 


426 | Chapter 21: Accelerometers 


www.it-ebooks.info 



CHAPTER 22 


Gaming from One Place to Another 


Once a tool meant to help the United States guide intercontinental ballistic missiles, the 
Global Positioning System (GPS) has evolved to be a part of our everyday lives. The 
current generation will never have known a world where getting lost was something 
that couldn’t be fixed by trilaterating their position between satellites orbiting the planet. 
Although GPS has become commonplace in the navigational world, the proliferation 
of smartphones is just now opening the doors to GPS gaming. While this genre is just 
emerging, we’d like to give you an introduction to the physics behind GPS and the 
current applications in the gaming world. 

Let’s recall that positions near the earth’s surface are generally given in the geographic 
coordinate system, more often described as latitude, longitude, and altitude. Latitude is 
a measure in degrees of how far north or south you are from the equator. Longitude is 
the measure in degrees of how far east or west you are from the prime meridian. A 
meridian is a line of constant latitude that runs from the North Pole to the South Pole. 
The prime meridian is arbitrarily defined as the meridian that passes through the 
Greenwich Observatory in the UK. Altitude is usually given as the measure of how far 
above or below sea level you are at the point described by latitude and longitude. 

Location-Based Gaming 

Before getting to the physics behind GPS, we’d like to take a moment to discuss how 
GPS is being implemented into games. Right now, this is an emerging market that is 
just starting to gain traction. There are several broad categories into which games fall. 
Another step beyond what the accelerometer did, GPS enables users to move computer 
games not only off the couch but also out into the world. 


427 


www.it-ebooks.info 




Geocaching and Reverse Geocaching 

Geocaching is the oldest form of gaming involving GPS. It originated after selective 
availability was removed from GPS, making it more accurate, in the year 2000. In its 
most basic form, it is the process of hunting down a “cache” using provided GPS coor¬ 
dinates. The cache usually has a logbook and may contain other items such as coins 
with serial numbers that the finder can move to another cache and track online. 

Because of the large amount of setup involved in implementing a geocaching game on 
a commercial scale, most implementations are community based. However, reverse ge¬ 
ocaching has more promise for the gaming industry. In this variation there is nothing 
at the supplied coordinates, but traveling to them is required to execute some action. 
Think of it as carrying around a cache that cannot be unlocked until it is within range 
of some specific coordinate. This could be used to force users to travel in order to unlock 
a game item. For instance, perhaps to gain the ability to use a sword in a game, the user 
must travel to the nearest sporting goods store. The commercial possibility of corporate 
tie-ins is an obvious plus. 

Mixed Reality 

Mixed-reality games are similar to geocaching. They go beyond just using the coordi¬ 
nates of the user to trigger events, to using reality-based locals. A current example is 
Gbanga’s Famiglia. In this game your movement in the real world allows you to discover 
virtual establishments in the game world. This divorces it from the actual physical lo¬ 
cations that your GPS is reporting but requires moving between locations in the real 
world to move your character in the virtual world. Popular right now is the Foursquare 
app on mobile devices. This is the simplest possible implementation of mixed-reality 
gaming. Foursquare allows a user to become the mayor of a place if she “checks in” at 
the locale more than anyone else. 

Street Games 

Street games are another step beyond mixed reality. These turn the environment around 
the user into a virtual game board. One example is the recent Pac-Manhattan multi¬ 
player game using GPS in smartphones to play a live version of Pac-Man in Washington 
Square Park. In general, the idea is to create a court for game play using the environment 
surrounding the user. The relationship between users is tracked in the virtual space of 
the game and provides the interactive elements. 


428 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 



What Time Is It? 

The story of GPS really begins with a prize offered by the British government in 1717 
for a simple way to determine your longitude. Awarded in 1773, the accepted solution 
was to compare local noon to the official noon sighted at the Greenwich Observatory. 
The difference between these two times would allow you to tell how far around the 
world you were from the observatory. Fast-forward three centuries, and we have satel¬ 
lites orbiting the earth, broadcasting time-stamped messages. By calculating the differ¬ 
ence between the time the message was received and the time it was transmitted, we can 
calculate our distance from the satellite. In both cases you need an accurate way to keep 
or measure time. For sailors in the 1800s, the device was the newly invented chronom¬ 
eter. For us, it is the atomic clock. 

Because the signals from a GPS satellite are moving at the speed of light, you need a very 
accurate clock to keep track of how long it took to travel to you. For instance, if the clock 
you are using to time when the signal arrives is 1 microsecond off, you will estimate a 
distance over 900 miles in error. On the supply side of the signal, each satellite has an 
atomic clock, and internal GPS time is accurate to about 14 nanoseconds. The problem 
is that you also need a very accurate clock in the receiver, and it would be pretty hard 
to fit an atomic clock into a phone economically. To get around this, the receiver must 
figure out the correct current time based on the signals from the satellites. 

Two-Dimensional Mathematical Treatment 

This section will give you a good idea of how GPS systems determine their location. 
This background will help you in many applications of geometry in games in general, 
but most GPS devices do the heavy lifting and report through an API your current 
latitude and longitude. Some APIs may include more information—for example, the 
current iOS API, called Core Location, gives the current latitude and longitude, the 
direction of travel, the distance traveled, and the distance in meters to a given coordinate. 
It also gives an estimate for the error associated with its position fix in meters. 

One way to get your position via the kind of information that GPS provides is a technique 
called trilateration. We are going to give this problem a mathematical treatment in two 
dimensions. You could extend this to three dimensions by using spheres instead of 
circles. 

To begin, we can list our unknowns: our x coordinate and y coordinate in space, and 
the error in our receiver’s clock (or bias), b. In a two-dimensional plane, trilateration 
among three circles gives you an exact position; in three-dimensional space, four 
spheres are required to determine all three special coordinates. Note that if we included 
an assumption about being on the surface of some geometric shape, such as the earth, 


What Time Is It? | 429 


www.it-ebooks.info 



we could reduce the number of unknowns. No such simplification is used here to pro¬ 
vide you with the most general case. 

In our example, we are somewhere on the surface of the two-dimensional earth, shown 
in Figure 22-1 as a light gray solid disk. This diskis being orbited by several GPS satellites. 
The satellites’ orbits are regular, and their positions at any time are tabulated in an 
almanac that is stored in the receiver. The time of transmission is encoded in the signal 
so that the givens are x t , y„ and f, with i =1,2,3. 



To make things easier for us, we are going to abandon the coordinate system of the earth 
and use the coordinate system defined by our three satellites. The origin will be at satellite 
1, the x-axis going directly from satellite 1 straight to satellite 2 and the y-axis being 
perpendicular to that. This is shown in Figure 22-2. 


430 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 








The equations of the three circles are therefore: 

9 9 9 

r i = x“+y z 
r 2 2 = (x-d) 2 +y 2 
r 2 3 = (x-i) 2 +(y-j) 2 

Each radius is found by subtracting the transmission time, f, from the current time and 
multiplying by the speed of light. As the speed of light is very large, and our current 
time is only a rough estimate, these radii are commonly referred to as pseudoranges to 
remind us they are still approximate. The x and y values that satisfy these equations are 
our current location in two-dimensional space. We now subtract the second equation 
from the first: 

r 1 2 -r 2 2 = x 2 + y 2 -(x-d) 2 -y 2 
rj 2 - r 2 2 = x 2 - (x-d) 2 

Solving for x gives: 


x = ( ri 2 - r 2 2 +d 2 ) / 2d 


What Time Is It? | 431 


www.it-ebooks.info 














where d is the distance between the known locations of satellite 1 and satellite 2. We 
now substitute our x coordinate back into the first circle’s equation: 


y 2 = rj 2 _ [(( rj 2 _ p,2 + d 2)2) / ( 4d 2)] 


and finally after we take the square root: 


y 


^ V' 1 


r 2 + d 2 f 
4 d 2 


notice that they value is now expressed as a positive or negative square root. This means 
there can be zero, one, or two real-number solutions. If the circles do not intersect, then 
the quantity under the square root will be negative and the y value will have zero real 
solutions. This is unlikely for the first two satellites because you have already received 
pseudoranges to them in the form of r 1 and r 2 , which the algorithm assumes to have 
zero error. If the two circles happen to intersect at only a single tangent point, they will 
have one solution and will be equal to 0. This is also unlikely. The most likely result will 
be that y will be the set of two values, plus or minus the square root of a positive value, 
and that those two points will be widely separated. 

Now if we included the assumption that we were on the earth’s surface, we could already 
break the tie between the two points by picking whichever was closest to the earth’s 
surface. However, we still would have to deal with the likelihood that there is a large 
error in our position given the imprecise clock in the receiver. 

We can fix our position ( x,y) with no assumptions and account for clock bias by intro¬ 
ducing the third point and its pseudorange. Now, it was very likely that the circles 
obtained from the first two satellites would intersect because of the way that GPS sat¬ 
ellites are arranged around the earth. However, because our calculations use pseudor¬ 
anges, it is relatively unlikely that the third circle will pass directly through one of the 
two points defined by the intersection of the first two circles. To remove such clock- 
related distance errors, we first calculate which point (x,y) or (x,-y) is closer to ( i,j ) and 
choose that to be our assumed location. The difference between the smaller of these two 
distances and the pseudorange r 3 is then our distance correction, d a . As the signal is 
traveling at the speed of light, the following quotient provides an estimate of the error 
between the correct time and the receiver’s time: 

b = d a /c 

As all the GPS satellites have synchronized atomic clocks, the same bias exists for each. 
This means that the bias we calculated would actually affect the first pseudoranges we 
used to find our initial bias. Therefore an iterative approach is required to adjust all the 
variables in real time until they converge. A more direct, but less obvious, algebraic 


432 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 





solution that requires no iteration was developed by Stephen Bancroft. It is detailed in 
his paper “An Algebraic Solution of the GPS Equations” in the IEEE Transactions on 
Aerospace and Electronics Systems journal. 

Besides clock errors, other errors are introduced by the atmosphere, signals bouncing 
off the ground and back to the receiver, relativistic effects (discussed in Chapter 2), and 
atomic clock drift. These are all accounted for in mathematical models applied to the 
raw position data. For instance, the GPS clocks lose about 7,214 nanoseconds every day 
due to their velocity according to special relativity. However, because they are higher 
up in the earth’s gravity well, they gain 45,850 nanoseconds every day according to 
general relativity. The net effect is found by adding these values together: they run 38,640 
nanoseconds faster each day, which would cause about 10 kilometers inaccuracy to build 
each day they are in orbit. To account for this, the clocks in the GPS receivers are pre¬ 
adjusted from 10.23 MHz to 10.22999999543 MHz. The fact that we are giving you a 
number to 11 decimal places demonstrates the amount of accuracy the modern age 
enjoys in its time keeping. 

Once the bias is taken care of and all the other possible errors adjusted for, the converged 
solution can be translated back into whatever coordinate system is convenient to give 
to the end user. Usually this is latitude, longitude, and altitude. Next, we will learn how 
to calculate different quantities based in the geographic coordinate system. 

Location, Location, Location 

Let’s take a minute to discuss distance between two latitude and longitude coordinates. 
You might be tempted to calculate it as the distance between two points. For very small 
distances, this approximation is probably accurate enough. However, because the earth 
is actually a sphere, over great distances the calculated route will be much shorter than 
the actual distance along the surface. 

The shortest distance between two points on a sphere, especially in problems of navi¬ 
gation, is called a great circle. A great circle is the intersection of a sphere and a plane 
defined by the center point of the sphere, the origin, and the destination. The resulting 
course actually has a heading that constantly changes. On ships, this is avoided in favor 
of using a rhumb line, which is the shortest path of constant heading. This makes nav¬ 
igation easier at the expense of time. Airplanes, however, do follow great-circle routes 
to minimize fuel burn. 

Distance 

There are several ways of calculating the distance along a great circle. The one we will 
discuss here is the haversine formula. There are other methods like the spherical law of 
cosines and the Vincenty formula, but the haversine is more accurate for small distances 


Location, Location, Location | 433 


www.it-ebooks.info 



than the spherical law of cosines while remaining much simpler than the Vincenty 
formula. 

The haversine formula for distance is: 


d = (R)(c) 

where R = earths radius and c is the angular distance in radians given by: 

c — 2 arcsin (V«) 

Here, a is the square of half the chord length between the two points, calculated as: 
a = sin 2 (Ai at /2) + cos(lati)cos(lat 2 )sin 2 (Ai ong IT) 

Finally: 

A^g = long 2 - long! 

Ajat = lat 2 - lat! 


Remember to first convert the angles to radians before using them in the trig function. 
Next we will begin showing you an implementation of several different formulas in 
Objective-C; however, these should translate to C with little modification. These all use 
the following data structure to hold latitude and longitude information: 

typedef enum { 
float lat; 
float Ion; 

} Coordinate2D; 

Given this, the haversine implementation would look like: 

float dlstanceGreatClrcle(Coordlnate2D startPoint, Coordinate2D endPolnt){ 

//Convert location from degrees to radians 
float latl = (M_PI/180.) * startPoint.lat; 
float lonl = (M_PI/180.) * endPoint.longi; 
float lat2 = (M_PI/180.) * endPoint.lat; 
float lon2 = (M_PI/180.) * endPoint.longi; 

//Calculate deltas 
float dLat = lat2 - latl; 

float dLon = lon2 - lonl; 

//Calculate half chord legnth 

float a = sin(dLat/2) * sin(dLat/2) + cos(latl) * cos(lat2) * sin(dLon/2) 

* sin(dLon/2); 


434 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 



//Calculate angular distance 

float C = 2 * atan(sqrt(a)/sqrt(l-a)); 

//Find arclength 

float distance = 6371 * C; //6371 Is radius of earth in kn 
return distance; 

} 

One limitation of the preceding method is that if the two locations are nearly antipodal 
—that is, on opposite sides of the earth—then the haversine formula may have round¬ 
off issues that could results in errors on the order of 2 km. These, however, will be over 
a distance of20,000 km. If extreme accuracy is required for nearly antipodal coordinates, 
you can fall back to the spherical law of cosines, which is best suited for large distances 
such as the antipodal case. 

Great-Circle Heading 

As discussed before, to follow the shortest path between two points on a sphere you 
must travel along a great circle. However, this requires that your heading be constantly 
changing with time. The formula to calculate your initial heading, or forward azi¬ 
muth, is: 


©i = atan2[sin(Ai ong )cos(lat2), cos(lati)sin(lat 2 ) - 
sin(lati)cos(lat 2 )cos(Ai ong )] 

Recall that atan2 is the two-argument variation of the arctangent function. It returns 
a normalized angle in radians between -tt and tt (-180° and 180°). The code that cal¬ 
culates the value and returns the compass bearing is as follows: 

float initialBearing (Coordinate2D startPoint, Coordinate2D endPoint){ 

//Convert location from degrees to radians 
float latl = (M_PI/180.) * startPoint.lat; 
float lonl = (M_PI/180.) * startPoint.longi; 
float lat2 = (M_PI/180.) * endPoint.lat; 
float lon2 = (M_PI/180.) * endPoint.longi; 

//Calculate deltas 
float dLat = lat2 - latl; 

float dLon = lon2 - lonl; 

// Calculate bearing in radians 

float theta = atan2f( sin(dlon) * cos(lat2), cos(latl)*sin(lat2)-sin(latl)*cos(lat2) 

*cos(dlon)); 


//Convert to compass bearing 

Float bearing = theta * (180 / M_PI); //radians to degrees 
bearing = ( bearing > 0 ? bearing : (360.0 + bearing)); //fix range 
return bearing; 

} 


Location, Location, Location | 435 


www.it-ebooks.info 



A negative angle involves starting at 0° and rotating in the decreasing-heading direction, 
but compasses aren’t labeled with negative values! To fix this, the line that has the com¬ 
ment “fix range” is using a ternary operator to say that if the bearing is less than 0, return 
the value the compass would read. For example, if the bearing were -10°, then the 
compass bearing is -10° + 360° = 350°. If the value is positive, then it just returns the 
same value. 

To find the final bearing, we simply take the initial bearing going from the end point to 
the start point and then reverse it. The code is produced as follows: 

float flnalBeartng (Coordlnate2D startPoint, Coordinate2D endPoint){ 

//Convert location from degrees to radians 
float latl = (M_PI/180.) * endPoint.lat; 
float lonl = (M_PI/180.) * endPoint.longi; 
float lat2 = (M_PI/180.) * startPoint.lat; 

float lon2 = (M_PI/180.) * startPoint.longi; 

//Calculate deltas 
float dLat = lat2 - latl; 

float dLon = lon2 - lonl; 

//Calculate bearing in radians 

float theta = atan2f( sin(dlon) * cos(lat2), cos(latl)*sin(lat2)-sin(latl)*cos(lat2) 

*cos(dlon)); 


//Convert to compass bearing 

float bearing = theta * (180 / M_PI); //radians to degrees 
bearing = ( bearing > 0 ? bearing : (360.0 + bearing)); //fix range 
bearing = ((bearing + 180) % 360) //reverse heading 
return bearing; 

} 

The difference here is that we have flipped latl, longi and lat2, long2 while converting 
the locations to radians. Also, before we return the bearing value, we reverse it by adding 
180° degrees to it. The modulo operator (%) ensures that values over 360° are rolled over 
into compass coordinates. For example, if we calculate a bearing of 350° and add 180° 
to it, we get 530° degrees. If you start at 0° and go around 530°, you’ll end up at 170°. 
The modulo operator will result in the bearing being calculated with this correct com¬ 
pass value. 

Rhumb Line 

As discussed before, it is sometimes preferable to take a longer path of constant heading, 
called a rhumb line, as compared to constantly changing your heading to follow a great 
circle path. The rhumb line will be longer than the great circle, and the distance you are 
from the great circle route at any moment is called the cross track error. To cross the 
Atlantic is about 5% longer if you follow a rhumb line. The extreme example of going 
from the East Coast of the United States to China is about 30% longer. However, such 


436 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 



large penalties are rarely encountered because ships have to alter course to avoid land! 
This makes “as the crow flies” examples unrealistic. 

If your game is providing navigation information to anyone but pilots, it will probably 
be using rhumb lines. The following are the formulas used to calculate distance and 
bearing between two coordinates on a rhumb line. The easiest way to begin is to flatten 
the globe. In a Mercator projection, rhumb lines are straight. In fact, this makes graph¬ 
ically solving the problem very simple. You use a ruler. Mathematically, things get a bit 
more complicated. The following equation gives Acp, which is the difference in latitude 
after taking into account that we have stretched them in order to flatten the sphere: 

Acp = ln[tan(lat2/2 + jt/4) / tan(latl/2 + tc/4)] 

The distance between two points on a rhumb line is given by: 


D — ^Alat + q 2 * Allng * R 


The variable q is a value whose formula depends on Acp. If Acp is equal to 0, that means 
that the calculated course is going to be either directly east or west. If that is the case, 
then the intermediate value of q is: 


q = cos(latl) 


if Acp is not equal to 0, then: 


4 = Ai a t/Acp 


You can see that if not properly implemented, a direct east or west course would result 
in division by 0. Finally, the constant bearing is: 


®rhumb — a.tan2(A] on g, Acp) 

There are, in fact, an infinite number of rhumb lines that will get us to our end point. 
However, the longer ones will either take us the wrong way around the globe, or spiral 
around the globe before hitting our end point. At any rate, the shortest route will be the 
one in which A long is less that 180°. The preceding is implemented in Objective-C as 
follows: 

float rhumbBearing ( Coordinate2D startPolnt, Coordinate2D endPoint){ 

//Convert location from degrees to radians 
float latl = (M_PI/180.) * startPoint.lat; 

float lonl = (M_PI/180.) * startPoint.longi; 
float lat2 = (M_PI/180.) * endPoint.lat; 
float lon2 = (M_PI/180.) * endPoint.longi; 


Location, Location, Location | 437 


www.it-ebooks.info 




//Calculate deltas 
float dLat = lat2 - latl; 

float dLon = lon2 - lonl; 

//find delta phi 

float deltaPhi = log(tan(lat2/2+(M_PI)/4)/tan(latl+M_PI/4)) 

float q=(deltaPhi==0 ? dlat/deltaPhi : cos(latl); //avoids division by 0 

if (abs(dLon) > M_PI){ 

dLon = (dLon>0 ? -(2*(H_PI-dLon):(2*M_PI+dLon)); 

} 

float D = sqrt(dLat*dLat + q*q*dLon*dLo)* 6371; 
float theta = atan2f(dLon, deltaPhi); 

//now convert to compass heading 

float bearing = theta * (180 / M_PI); //radians to degrees 
bearing = ( bearing > 0 ? bearing : (360.0 + bearing)); //fix range 

return bearing; 

} 

There are a few things worth pointing out. First is that we are using a ternary function 
in the line commented by “avoids division by 0” to take care of the case when delta 
Phi is equal to 0. If it is 0, q is set to cos(latl); if not, then it is set to dlat/deltaPhi. 
The If statement immediately following ensures that if dLon is greater than it (180°), 
hence putting us on a longer-than-required rhumb line, then we should correct the 
value to correspond to the shortest route. This is achieved via the ternary, which ensures 
that dLon is less than it and nonnegative. Lastly, we convert from a normalized radian 
answer to a compass direction. 

Now that you have a good idea about how to calculate position and distance in the 
geographic coordinate system, you can use the earlier chapters to determine other 
quantities like speed and acceleration. 


438 | Chapter 22: Gaming from One Place to Another 


www.it-ebooks.info 



CHAPTER 23 


Pressure Sensors and Load Cells 


Pressure sensors are an evolution of the simple button. A simple button has two states, 
on or off, which can be used to trigger simple atomic actions in a video game such as 
firing a gun or opening a door. However, simple buttons are not capable of informing 
the program how you, the user, hits that button. Did you hit it quickly? Did you barely 
touch it at all? The only thing the program can interpret is that you did in fact hit the 
button. 

With pressure sensors, the program has the ability to discern how the user pressed the 
button. This information can be used as incremental input, such as the player raising a 
firearm before pressing the button harder to actually fire. Additionally, pressure sensors 
can be used to create novel forms of human-input devices. While pressure sensitivity is 
not uncommon in the more traditional console gaming markets, there is also a recent 
push to move the sensors into touch-screen devices like the Nintendo DS and cell phone 
gaming market. Pressure-sensitive touch screens are currently beyond state of the art, 
however, so we’ll primarily discuss the traditional methods already in widespread adop¬ 
tion. 

In addition to pressure sensors, some new gaming consoles use load cells to allow the 
player to use shifts in his or her body weight as input. The method by which this data 
is collected and how the center of gravity is determined will be discussed in this chapter. 
Lastly, some smartphones now include a barometer, a pressure sensor that measures the 
pressure of the atmosphere. What it is used for and the type of information it can provide 
will also be discussed. 


439 


www.it-ebooks.info 




Under Pressure 

As discussed in Chapter 3, pressure is a force applied over an area. Imagine a concrete 
block sitting on a steel plate. The weight of the block will be evenly distributed over the 
area of contact, creating a pressure on the steel plate. Gas and liquid can apply pressure 
as well. The weight of the air pressing down on us is what is known as atmospheric 
pressure. 

Let’s cover a quick example of how to calculate pressure just to illustrate the concepts 
involved. Pressure has many different units, but all of them can be equated to a force 
divided by an area. For this chapter we’ll stick with Newtons per square meter, as this 
is easiest to visualize. The SI derived unit (a unit of measure made up of other funda¬ 
mental units) is called a Pascal, which is just 1 N/m 2 . 

Example Effects of High Pressure 

In Chapter 3, we discussed the concept of buoyancy and how it arises from hydrostatic 
pressure. Here, we’ll show the tremendous forces that hydrostatic pressure can cause 
on a submerged object. Let’s imagine we have a steel ball filled with normal atmospheric 
pressure at sea level, or about 101,000 N/m 2 . While this seems like a lot, your body is 
used to dealing with this pressure, so you don’t even notice it on a daily basis! Now we 
are going to take this ball and drop it into the Marianas trench, the deepest known part 
of the ocean. The water depth here is approximately 10,900 meters. The formula for 
calculating the pressure due to water (hydrostatic pressure) is: 

P(h) = p X g X h 

where p is the mass density of water, g is force due to gravity, and h is the height of the 
water column above the object. 

Here we take the standard density for saltwater, 1025 kg/m 3 , and calculate what the 
pressure is: 


P(10,900) = (1025 kg/m 3 ) x (9.8 m/s 2 ) X (10,900 m) = 
109,490,500 N/m 2 

Figure 23-1 shows how the pressures act against our steel ball. 


440 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 




/ / --—"" 

*Y Air 

r pressure / 

4 r~ 


Hydrostatic pressure 



Figure 23-1. Pressure differential 


It is clear that the water pressure acting on the sphere is much larger than the air pressure 
we trapped inside before sinking it. Also, note that pressure always acts normal to the 
surface. If you happen to apply a force to the vertex of an object, you’ll have trouble 
modeling the right effect because a vertex does not have a well-defined normal. We can 
overcome this only by applying pressure to the faces of polygons or by averaging the 
direction of the pressure on either side of the vertex. Returning to our example, the net 
pressure differential on the steel ball is: 

P(water) - P(air) = 10,949,100 N/m 2 - 101,000 N/m 2 = 

10,848,100 N/m 2 

This is the pressure you would feel if 1,870 elephants were standing on a 1 -square-meter 
plate on top of you. If our steel ball had walls that were too thin to withstand this pressure 
differential, it would implode. To put this all into perspective, a steel ball in space would 
have a pressure differential of only 1 atmosphere pushing out. It is thus much harder to 
design a structure to go to the bottom of the sea than it is to go to the moon. Indeed, 
more men have stepped foot on the lunar surface than have visited the bottom of the 
sea. 


Under Pressure | 441 


www.it-ebooks.info 






If the ball were open to the sea, then the pressure would act equally on each side of the 
steel boundary. Without a pressure differential, there would be no force to crush the 
ball; however, there would still be compression of the steel shell itself. 

Button Mashing 

While the preceding example highlights some important concepts about pressure in 
general, it is not usually the type of pressure used as input to a game. The most common 
types of pressure sensors you’ll experience in video games are pressure-sensitive buttons 
that indirectly measure the amount of pressure the user is exerting on the button and 
convert this to a relative value. Both Sony and Microsoft have incorporated pressure- 
sensitive (also known as analog) buttons into their controllers for the PlayStation and 
Xbox series of consoles. 

The method by which you can detect how hard a user is pressing a button varies from 
very simple to very complex. We’ll focus on Sony’s method, which is very elegant. A 
typical push button is just two contacts separated by an insulator, most commonly air. 
When the button is pushed, the upper contact moves down and touches the lower 
contact. This completes a circuit, causing a voltage spike, which the device interprets as 
a button press. This is another example of a digital sensor—it is either on or off. The 
buttons in Sony’s controller work a bit differently. In State A in Figure 23-2, we can see 
that the button is not yet pressed and an air gap exists between the solid conductor and 
the domed flexible conductor. In State B the button is depressed with minimal pressure, 
and the dome just barely makes contact. The button is now activated. If the user con¬ 
tinues to press down harder on the button, the dome deflects and increases the area of 
contact with the fixed conductor; the larger the contact area, the greater the conductivity 
of the connection. This causes a rise in the current flowing in the circuit. 


442 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 




By measuring this increase in current, the controller knows how far down the button 
is being pressed. In State D in Figure 23-2, the button is at its limit of travel and the 
dome has deflected to its maximum contact area. The difference between this maximum 
and the minimum required to detect contact determines the absolute lowest and highest 
pressure the button is able to differentiate. For instance, let us assume that if the button 
were depressed completely, the current would register at f max . If the button were not 
pressed at all, of course, the current would be 0. If we call the current J(f) for any time, 
t, we see that the ratio f(f)/I max gives a nondimensional quantity for how far down the 
button is pressed. During this operation, the hardware converts the analog voltage to a 
digital representation suitable for input to a program. For the Sony example, this value 
is calculated by the hardware and passed as part of the data stream from the controller 
with hex values between 0x00 to OxFF, or in other words, integers 0 to 255 in decimal. 
This means that each buttons travel is divided into 255 parts that your program can 
register. 

While 255 individual increments are beyond the human ability to control fingertip 
pressure, different ranges of pressure have practical uses in games. For example, you 
could program your button to raise a weapon with a half-press (0 to 127), bring the 
weapon to the shoulder with more pressure (127 to 250), and to fire when totally de¬ 
pressed (250 to 255). Of course, those values would have to be tuned for the desired 


Button Mashing | 443 


www.it-ebooks.info 






































level of sensitivity. Another example would be to control the throttle on a car by using 
the values of 0 to 255 as thrust multipliers. 

Another use of knowing a buttons position would be tracking it over time. With a time 
history of position, you can differentiate to get velocity and again to get acceleration. 
This would allow the program to differentiate between a button that is either slowly 
depressed or quickly depressed. Most hardware doesn’t help you here, so you’ll have to 
store the values and calculate the velocities in whatever increments are appropriate for 
your program. As real-time velocity sensing might be taxing to the user as real-time 
input, the best use would be as input to something that the user doesn’t have to control 
constantly. Imagine having to keep a button pressed down at the correct pressure for 
your gameplay for longer than a few minutes; I can feel my wrist cramping now. How¬ 
ever, the pressure button is useful for many inputs. For example, how far a button is 
pressed down might be used to draw back the head of a putter, while the speed at which 
the button is released could be used to determine the speed at which the putter is brought 
back to the ball. 

Load Cells 

Beyond simple buttons, there are other novel ways to use pressure sensors to allow a 
user to interact with your games. For example, Nintendo’s Wii uses a balance board 
peripheral based on load cells to detect a person’s stance. 

a * 

r»«y— 

Ms 

M>?’ 4 « 

71 a* 


Tiny scales 

Load cells work differently than the pressure-sensitive buttons described previously, but 
like pressure-sensitive buttons, they come in different types, all of which measure the 
load pressing on them. The most common way, and the one used in the Nintendo 
balance board we’ll discuss shortly, is through what is called a strain gauge. 

A strain gauge, as you might be able to guess, does not measure force directly but instead 
measures how much strain the gauge is experiencing. Strain is a measure of how much 
a rigid body has deformed independent of its rigid-body motion. While there are several 
notions of strain in continuum mechanics, the one we are concerned with here is often 
referred to as engineering strain. This type of strain quantifies how much a structural 
element has deformed compared to its original, or rest, length. We normalize this by 
dividing the change in length over the rest length. By testing the material, one can 
develop a stress versus strain curve that relates how much stress it takes to cause a certain 


The original idea for the Nintendo balance board came to video game 
designer Shigeru Miyamoto after he was inspired by watching sumo 
wrestlers weigh themselves with each leg on a different scale. They are 
too heavy to use one scale! 


444 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 





amount of strain. Once the pressure that causes an amount of strain is known, it is 
possible to determine the amount of load. Now you might be wondering how the strain 
gauge measures the amount that the Wii’s legs compress when you stand on them. 

One of the most common electronic strain gauges is th e piezoresistive strain gauge. The 
simplest example of a piezoresistive strain gauge would be a single wire. If you were to 
elongate a wire from its rest length, the cross-sectional area decreases. This causes a rise 
in the electrical resistance of the wire. After measuring the rest resistance, you can use 
the difference to determine how much the wire has elongated. Knowing the mechanical 
properties of the wire, you can also determine how much force it takes to stretch the 
wire. 

To make strain gauges sensitive without having long linear wire elements, the conductive 
material is often arranged in a strain-sensitive pattern, as shown in Figure 23-3. This 
looping back and forth of the conductor allows for great sensitivity without increasing 
the physical space the sensor occupies. Here the rest length would be 18 times longer 
than the physical length of the sensor. 



Figure 23-3. Typical strain-sensitive pattern 


Center of gravity 

The board has four legs, each of which houses a load sensor. The board uses strain gauges 
similar to those discussed earlier. These gauges elongate when a force is applied to them. 
The elongation changes the electrical resistance of the circuit of which the strips are a 
part, and this is reported back to the controller. Figure 23-4 shows two sensor outputs. 
The first is with the user standing so that her center of gravity is over the center of the 
board. The second state shows what the board’s sensors would measure after the user 
has shifted her center of gravity. 


Button Mashing | 445 


www.it-ebooks.info 






25 25 



15 30 



Figure 23-4. Balance board example 

It is easy to intuitively recognize that the center of gravity must be over the center of the 
board in State A and toward the lower-right corner in State B. However, to get the exact 
location of the center of gravity in State B, we’ll have to do a little more work. First things 
first: we have to define a coordinate system. This is shown in Figure 23-5. 



Figure 23-5. Balance board coordinate system 


446 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 






















This coordinate system is arbitrary. If the board isn’t a perfect square, such as with the 
Wii board, then the coordinates of the load cells must be changed accordingly. Now that 
we have defined the location of the center of the board and the position of the load cells, 
we can use a weighted average to compute the location of the user’s center of gravity. 
The weight that we give each value will depend on how much of the user’s weight is on 
each of the four corners. That weight will “pull” the center of gravity toward the location 
of the load cells as defined in our coordinate system. How much each load cell mathe¬ 
matically pulls the center of gravity will be based on the weight supported at that location. 
This is most easily determined via two tables, one for the x coordinate (Table 23-1) and 
one for the y coordinate (Table 23-2). 

Table 23-1. x coordinate weighted average 


Load cell 

Weight 

Arm 

Weight x Arm 

(1,1) 

30 

1 

30 

(-1,1) 

15 

-1 

-15 

(-1,-1) 

20 

-1 

-20 

(1,-D 

35 

1 

35 

Total: 

100 


30 



Average: 

30/100 = 0.30 


Table 23-1 takes the weight in each corner and multiplies that value by the value of its 
x coordinate. This is equivalent to a moment. Taking the sum of those moments (30) 
and dividing by the total weight gives the average value of 0.30, or .3 units to the right 
in our coordinate system. The y-axis is treated similarly. 

Table 23-2. y coordinate weighted average 


1 Load cell 

Weight 

Arm 

Weight x Arm 1 

(i,D 

30 

1 

30 

H,D 

15 

1 

15 

(-1,-d 

20 

-1 

-20 

(i,-D 

35 

-1 

-35 

Total: 

100 


-10 



Average: 

-10/100 = -0.10 


Using a similar weighted average as shown in Table 23-2, we see that the user’s center 
of gravity is -0.10, or 0.1 units behind the center. If we were using this to control an 
onscreen sprite, we could define a 2D direction vector based on this information. 

In addition to just determining the center of gravity, you can use this information to 
make educated guesses on what else the user is doing to cause the load distributions. 
After computing the center of gravity, the Wii uses what Nintendo calls a motion- 
identifying condition table to guess what movements the user is making. The table cor- 


Button Mashing | 447 


www.it-ebooks.info 









relates the ratio of the sum of the load values to the body weight of the user and the 
position of the center of gravity to determine body orientation. For example, the Wii 
can tell if both of the user’s feet are on the board, or if the user is accelerating part of his 
leg. The table provided in the Wii patent is reproduced in Table 23-3. 


Table 23-3. Motion-identifying condition table 


| Motion 

Ratio of load value to body weight value 

Position of the center of gravity 1 

Right foot riding 

25 to 75% 

+0.01 to+1.0 

Both feet riding 

More than 95% 

-0.7 to +0.7 

Left foot riding 

25 to 75% 

-1.0 to-0.01 

Left thigh lifting 

More than 100% 

+0.01 to+1.0 

Right thigh lifting 

More than 100% 

-1.0 to-0.01 

Both feet putting down 

Less than 5% 

Not considered 


Barometers 

Continuing our exploration of new user input methods, especially in the rapidly ma¬ 
turing mobile device gaming market, now we’ll discuss an interesting inclusion in the 
latest smartphones: a barometer. Unlike buttons and balance boards, whose pressure 
sensors only indirectly handle pressure, barometers directly measure the fluid pressure 
that the atmosphere exerts on the sensor. 

The sensors used in mobile phones today are piezoresistive microelectromechanical 
systems (MEMS) and are very accurate. As shown in Figure 23-6, the sensors consist 
of a void machined into a piece of silicon. The diaphragm is then bonded to a stiff 
material such as steel or glass. As we are trying to measure absolute pressure, this bond 
is airtight. Using a material called monocrystalline semiconductor silicon to form the 
void ensures that the entire diaphragm acts much like a piezoresistive strain gauge. 


Piezoresitive material 


Void at reference pressure 



Glass or other stiff backing 


Figure 23-6. MEMS piezoresistive pressure sensor 


448 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 

















Now we have a situation similar to the steel ball in the ocean, only this time it is a tiny 
silicon ball in the ocean of air surrounding the earth. When the sensor is moved deeper 
or shallower in the atmospheric ocean, the pressure on the outside of the diaphragm 
changes. This causes the pressure differential to change and a force to be exerted on the 
silicon diaphragm. This force causes a deflection that changes the resistance of the pie- 
zoresistive material and can therefore be measured by the sensor. This part will be taken 
care of by the hardware and the encoded value sent to the operating system. 

To give you an example, in the Android operating system, the API has a public method, 
getAltitude(float p0, float p), to determine altitude, in meters, between the sen¬ 
sor pressure and the pressure at sea level. It usually reads the current atmospheric pres¬ 
sure, p, from the sensor by listening to sensor manager callback interface method ab 
stract void onSensorChanged(SensorEvent event). Here the class event holds the 
sensor values, the accuracy of those values, a reference to the sensor itself, and a time- 
stamp for when the event occurred. The pressure is reported in hectoPascals (hPa) or 
100 N/m 2 . The sea-level pressure, p0, that this is compared to is either obtained from 
an online database or is set at the constant SensorManager. PRESSURE_STANDARD_ATMOS 
PHERE. As pressure at sea level changes with different weather conditions, we obtain 
higher accuracy by retrieving it from a nearby airport or other weather station via the 
Internet. To get the change in altitude between two points, you must repeat this process 
twice as follows: 

float altitude_difference = 

getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, 
pressure_at_point2) - 

getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, 
pressure_at_polntl); 

At first it may seem strange for your cell phone to have a barometer in it; however, the 
barometer’s ability to detect the air pressure allows you to make a good guess on your 
altitude. As shown in Chapter 22, in order to determine your position via GPS you have 
to solve a four-dimensional set of linear equations. The time required to solve these 
equations can be dramatically decreased if you know approximately where you are to 
begin with. Currently, the position of which cell phone tower your phone is connected 
to is used as a starting point. Using a barometer allows the device to guess its altitude 
to further reduce the time to obtain a GPS fix. 

While the sensor was included for a specific purpose, it can also be adapted as an input 
device. For instance, the Bosch BMP 180 currently being included in devices is accurate 
to plus or minus one meter. In fact, Google Maps now provides indoor directions, in¬ 
cluding knowing what floor you are on in airports and shopping malls. This function¬ 
ality could be used to aid in the location-based gaming discussed in Chapter 22 by giving 
it greater resolution in the vertical dimension. It could also be used to determine if the 
user is holding the phone near her feet or her head, further augmenting the orientation 


Barometers | 449 


www.it-ebooks.info 



sensing discussed in Chapter 21. Of course, it can also be used to help weather fore¬ 
casting and allow you to have real-life changes in pressure affect in-game events. 


450 | Chapter 23: Pressure Sensors and Load Cells 


www.it-ebooks.info 



CHAPTER 24 


3D Display 


For all the work we’ve done to make programs’ graphics more realistic, the best we can 
do is project our realistic simulations onto a two-dimensional screen. Although graphics 
libraries such as Microsoft DirectX and OpenGL can provide photorealistic renderings 
in real time, they still lack the ability to truly immerse the user in the works you have 
so carefully created. Three-dimensional display is something that the entertainment 
industry has attempted to make standard for some time. In reality, almost all “three- 
dimensional” display technologies are what are technically called stereoscopic displays. 
These displays use the way in which your eyes perceive depth to trick your brain into 
thinking it is seeing a three-dimensional image while the display remains two- 
dimensional. In contrast, displays that actually involve creating a rendering in three 
dimensions are called volumetric displays. We’ll cover these later as part of our effort to 
discuss emerging technologies. 

Binocular Vision 

The trick to displaying objects so that they appear to be three-dimensional depends on 
the method by which the human brain perceives the world around it. Indeed, animals 
that have two eyes engage in what is called binocular vision. Because each eye is in a 
slightly different position relative to the objects it is viewing, the left and right eye provide 
an image that is distinct to the brain. This is called binocular disparity. There are three 
possible results when the brain encounters these two different images: suppression, 
fusion, or summation. Suppression is when the brain ignores one of the images, sum¬ 
mation is when the brain tries to perceive both images at the same time (double vision), 
and finally fusion is mixing the two images to create a depth of field. The process of 
binocular fusion is something our brain learns to do when we are first born. 


www.it-ebooks.info 



0 % 

«>r m « 

_TL-v 


Given the way that eyes focus light, we are born seeing the world upside 
down! After a few days, our brains instinctively flip the images over so 
that the motion of our hands matches the motion that we observe. There 
have even been tests where people wearing glasses that invert your vi¬ 
sion will eventually see the images right side up. When they take off the 
glasses, everything looks upside down again until their brain has time 
to correct the image. 


Binocular fusion is also a learned behavior of the brain. The visual cortex takes the 
independent visual information from each eye and fuses it into a single image. Your 
brain does this as a way of organically calculating the distance to objects so that you can 
efficiently interact with the three-dimensional world. The exact process by which your 
brain accomplishes this is an area of active research. In fact, researchers have found that 
two images need not have any geometrical disparity in order to be fused. That is, if you 
take the exact same photograph of the same object and the same angle, but with different 
lighting, the shadows being cast can also cause the brain to recreate the object in three 
dimensions. 

Parallax is the distance an object moves between the left- and right-eye images. You can 
easily demonstrate it by holding your thumb six inches from your face and closing one 
of your eyes. Block some of the words on this page with your thumb. Now open that 
eye and close the other one. The words that were behind your thumb should now be 
visible. This is because your eyes are not in the same position, so the different angles 
provide slightly different pictures of the page. This distance your thumb appeared to 
move is the parallax at that distance from your eye. 

Fusion is a little harder to achieve, but Figure 24-1 provides an interesting example. The 
two circles are set a specific distance apart and show the top of a truncated cone coming 
out of the page. The top of the cone is offset compared to the bottom. This offset is in 
opposite directions, mimicking how your eyes would see it if you were directly over the 
cylinder. 



Figure 24-1. Cone stereopair 


The best way to view the stereopair shown in Figure 24-1 is to begin by looking above 
this book at a far-off object. Now lower your gaze without refocusing your eyes and 
stare between the two sets of circles. With some trying, your brain should be able to fuse 
the images so that there are now three sets of circles. The original two will be out of 


452 | Chapter 24:3D Display 


www.it-ebooks.info 


452 









focus, and the center set should appear to be three-dimensional. You can also get the 
sets to fuse by crossing your eyes; however, this is much less comfortable than using 
your eyes in their distance-viewing configuration. 

Given that your brain is excellent at real-time pattern recognition, it can also compare 
visual information over time to get a sense of size and relative distance. This is called 
movement parallax, and it causes objects that are closer to you to appear to move faster 
when you move your head than objects that are farther away. For example, if you are 
driving in a car, you’ll notice that the trees appear to move faster than the moon. This 
is because the trees are very close in comparison to the moon. Your brain uses this 
apparent speed disparity to help conclude that the moon is very far away indeed. In the 
next chapter we’ll discuss how computer algorithms attempt this sort of pattern recog¬ 
nition. 

In fact, according to Flight Simulation (edited by J. M. Rolfe and K. J. Staples; Cambridge 
University Press), the process of 3D visualization depends on the following eight major 
factors. 

• Occlusion of one object by another 

• Subtended visual angle of an object of known size 

• Linear perspective (convergence of parallel edges) 

• Vertical position (objects higher in the scene generally tend to be perceived as far¬ 
ther away) 

• Haze, desaturation, and a shift to bluishness 

• Change in size of textured pattern detail 

• Stereopsis 

• Accommodation of the eyeball (eyeball focus) 

A standard 3D graphics library is capable of giving the appearance of three dimensions 
on the screen, just as any good painter on a canvas. Both standard 3D libraries and 
painters do their job by recreating the first six items in the preceding list. To further the 
illusion, 3D display technology simulates the seventh, stereopsis. Stereopsis is impres¬ 
sion of depth generated by the fact that you have two eyeballs looking at slightly different 
angles. In short, the graphics library renders two different images, one for each eye, that 
have a parallax shift. These images are then delivered to each eye separately. The method 
by which the images are segregated varies from technology to technology. We will dis¬ 
cuss these in a little bit. 


Binocular Vision | 453 


www.it-ebooks.info 



The last item on the list, accommodation of the eyeball, is the process by which your 
eye changes shape to focus at different distances. By correlating the shape of your eye 
with the distance to the object, accommodation works as one of the pieces of information 
your brain uses to determine depth. As current 3D displays still use a 2D screen, the 
eyes are still focusing on the same plane regardless of the object’s perceived depth; 
therefore, the eighth item in the list is not recreated. This is why most 3D displays still 
do not seem completely real. Some technologies, such as holograms and volumetric 
displays, allow for accommodation of the eyeball, but usually at the expense of some 
other factor. We’ll touch on these beyond state-of-the-art technologies near the end of 
the chapter. 

Stereoscopic Basics 

There are some extra considerations when it comes using today’s 3D display technolo¬ 
gies to recreate the images that would usually be provided to the visual cortex by bin¬ 
ocular vision. Normally two eyes create two images that the brain combines with a 
biological depth map. The earliest stereoscopic images were generated in the 1800s from 
two photographs taken from slightly different positions. The viewer would then look at 
the photos through what came to be known as a stereoscope. This device was essentially 
an early example of the View-Master that some of you might remember from childhood. 
While the principle of showing unique images to each eye is straightforward in this case, 
it doesn’t allow group viewing and requires that the user have something pressed against 
his eyes. To make 3D display something that a group of people can all experience to¬ 
gether and in some cases even without the aid of any headgear, we must look at some 
more sophisticated methods of segregating the right and left images. 

The Left and Right Frustums 

If you are familiar with computer graphics, the concept of the viewing frustum is not 
alien to you. If you aren’t, we’ll take a second to go over it, but it might be worthwhile 
to read about it in detail before you continue. The viewing frustum is the region of space 
in the model world that the camera can see from its given position in that world. In a 
normal 3D graphic rendering, the frustum is clipped by a near plane that represents the 
screen distance. In essence, you cannot render something closer to the user than the 
screen plane. If you remember things jumping out of the screen in the last 3D movie 
you saw, you can probably guess that when we are using stereoscopic rendering, this no 
longer holds true. A normal computer graphics frustum is shown in Figure 24-2. 


454 | Chapter 24:3D Display 


www.it-ebooks.info 




Figure 24-2. Normal viewing frustum 

When using a stereoscopic 3D display library, we no longer have a single viewing frus¬ 
tum. Instead we have two cameras that are horizontally displaced from the 2D camera, 
as shown in Figure 24-3. 



Stereoscopic Basics | 455 


www.it-ebooks.info 
















These two cameras, offset from the monocular camera, generate a left and right frus¬ 
tums. As you can see, there is a location where these two frustums intersect; this is called 
the convergence distance. Objects that are placed at the convergence distance will have 
the same appearance to both cameras. Note that the cameras are all pointed in the same 
direction; this is called the off-axis method. This requires the frustums to be asymmetric, 
which most modern graphics libraries support. Now, at first glance, it might be tempting 
to toe-in the two frustums so that each camera’s frustums are symmetrical, as shown in 
Figure 24-4. 



Figure 24-4. Toe-in method (incorrect) 

This will create workable stereopairs, but along with the horizontal parallax will intro¬ 
duce some vertical parallax. This can cause eyestrain to the viewer and should be avoi¬ 
ded. Instead, the off-axis technique should be used; it is illustrated in Figure 24-5. One 
of the objects is beyond the screen in the background, and one is in front of the screen. 


456 | Chapter24:3D Display 


www.it-ebooks.info 









You can see that if you wish to move something to greater than screen depth, the object 
must be shown farther to the left than if it were at screen depth for the left eye image. 
For the right eye image, the object must be shown farther to the right. If you want to 
show something coming out of the screen, the opposite is true. The left eye will see the 
object as farther to the right than if it were at screen depth. Also note that each object 
will have a slightly different angle as well. Again, the distance between the right eye 
image placement and the left eye image placement is referred to as parallax. The amount 
and relative orientation of parallax is the chief way your brain creates 3D images. In 
fact, the most important aspect of the physics of stereoscopic display for programmers 
to understand is that there is a parallax budget that they must use wisely in developing 
programs that take advantage of 3D display. This budget defines the ranges of parallax 
that your viewer’s brain will be able to accept comfortably. We’ll discuss this in detail at 
the end of the chapter. 

For now, we’ll consider that if we were to just show the right and left images on a screen 
without further work, you’d end up seeing two images with both eyes and no 3D effect 
would be produced. It is paramount that the image intended for the left eye is seen only 
by the left eye and vice versa. These two channels, the left and right eye, must be kept 


Stereoscopic Basics | 457 


www.it-ebooks.info 










as separate as possible. Let’s see what the current options are for achieving such sepa¬ 
ration. 

Types of Display 

As just explained, 3D display technology depends on providing two distinct images, 
one to each eye. In the next sections we’ll discuss the common techniques used today. 

Complementary-Color Anaglyphs 

Anyone who saw a 3D movie in the 80s remembers the cheap red and blue glasses one 
had to wear to get the effect. These were complementary-color anaglyphs. An anaglyph 
is the technique of encoding the separate images in a single photograph or video frame 
using color filters. The method calls for two horizontally shifted images to be viewed 
simultaneously. The images will contain the two images tinted in opposite colors of the 
scheme. While there are many color combinations that can be used, the most common 
today are red and cyan. These colors are chosen because the cyan and red filters are the 
most exclusive. Red and green filters were used earlier, but the green filter allows too 
much red light to leak through. This can cause what is called binocular rivalry, where 
your brain has a hard time figuring out which depth map to use. One way to illustrate 
this is via the simple drawing of a transparent cube, as shown in Figure 24-6. 



Figure 24-6. Cube demonstrating binocular rivalry 


If you focus on the cube in Figure 24-6, your brain may start to flip between interpreting 
the upper face as forward of the lower face, and the lower face being forward. While 
this is caused by incomplete depth cues, the same uneasy feeling can be caused when 
your brain receives leaks across the two channels in a stereoscopic display. As you can 
imagine, this would be pretty annoying during a video game. 

As the glasses don’t require any electronics to do this, it is an example of passive 3D 
technology. The major drawback of this method is that the red component of the images 
is muted to the viewer. There are many improvements that can be made to the system 


458 | Chapter24:3D Display 


www.it-ebooks.info 












to correct the color and account for some fuzziness. One example is the patented Col- 
orCode 3D, which uses amber and blue filters. The advantage of this system is a nearly 
full color space and a fairly good image when not viewed with the glasses. 

Anaglyphs fell out of favor with movie and game producers when polarization techni¬ 
ques came into maturity. These produce better color reproduction and reduce eyestrain. 
However, given the relatively inexpensive glasses required and that nothing special is 
required of the display other than that it be capable of displaying colors, anaglyphs have 
had a resurgence in printed material and online. 

Linear and Circular Polarization 

As polarized light plays a very important part in the largest 3D displays, movie screens, 
we’ll review what polarization of light means and how to accomplish it. Light can be 
thought of as an electromagnetic wave traveling through space. Let’s begin our discus¬ 
sion by considering a common light bulb. It emits electromagnetic waves in all directions 
and is nominally “white.” An electromagnetic wave oscillates perpendicularly to its line 
of travel. This is called a transverse wave. In comparison, sound waves oscillate in the 
same direction they travel, creating regions of higher density. These are called longitu¬ 
dinal waves. Only transverse waves can be polarized because only transverse waves have 
oscillation in multiple orientations. Going back to our light bulb, it is emitting “dirty” 
light in that the electromagnetic waves are all at random orientations. 

Most sources of electromagnetic radiation (i.e., light) are composed of many molecules 
that all have different orientations when they emit light, so the light is unpolarized. If 
that light passes through a polarization filter, it leaves the filter with the oscillations in 
only one direction. In fact, there are two types of filters. Linear filters produce oscillations 
in one direction. Circular filters (a special case of elliptical filters) create circularly po¬ 
larized light that rotates in an either righthand or lefthand direction. As circular filters 
depend on linear filters first, we’ll discuss those now. 

The simplest and most common linear filter is the wire-grid polarizer. Imagine many 
very fine wires running parallel to one another with small gaps between them, as shown 
in Figure 24-7. When unpolarized light hits the wires, the oscillations that are parallel 
to the waves excite the electrons in the wire and move them along the length of the wire. 
This phenomenon causes that component of the oscillations to be reflected. However, 
the electrons cannot easily move perpendicular to the length of the wires, so the reflec¬ 
tion phenomenon doesn’t occur. What we are left with on the far side of the filter is a 
beam of light with the oscillations all in the same direction. 


Types of Display | 459 


www.it-ebooks.info 




Figure 24-7. Wire-grid polarization 

Early 3D display systems used linearly polarized light to separate the right eye channel 
from the left eye channel. However, there is one problem with using linear polarizers. 
It follows that ifyou place another wire-grid polarizer after the first, with its wires rotated 
90 degrees, no light will pass through! In fact, if you have an old pair of sunglasses or 
3D glasses and you hold the right eye lens against the left eye lens, you won’t be able to 
see anything. That is because each filter is blocking out one direction of oscillations, 
preventing any light from coming through. If you rotated one of the lenses, then the 
combined lens will lighten as you align the polarization directions. The problem with 
these types of lenses is that if you were watching a movie and tilted your head to one 
side, the same effect would occur and the image would be greatly dimmed. This means 
your date could no longer rest his or her head on your shoulder while watching the 
movie. Something had to be done. 

Circular polarization is another form of filtering out certain orientations so that you 
can control which light beams pass through which lens. However, in this case the di¬ 
rection of oscillation is not a single orientation but more accurately a pattern of oscil¬ 
lations parameterized by time. The first step to achieve circular polarization is to send 
the light through a linear polarizer as just discussed. That light is then sent through what 
is known as a quarter-wave filter. A typical arrangement is shown in Figure 24-8. 


460 | Chapter 24:3D Display 


www.it-ebooks.info 



















Figure 24-8. Circular polarization filter (public domain image by Dave3457; http:// 
commons.wikimedia.org) 


First a linear polarizer rotated to 45 degrees accepts incoming light and polarizes as we 
discussed earlier. The circular polarization effect is accomplished when a light wave 
polarized at 45 degrees hits the filter that accepts both 0- and 90-degree oscillations. As 
previously noted, this is called a quarter-wave filter. The resulting combination of 0- 
and 90-degree components of the intermediate 45-degree beam results in oscillations 
that turn right or left in a regular pattern. Patterns that turn counterclockwise are called 
left-handed. Patterns that turn clockwise are called right-handed. 

The main benefit is that the lenses create the same pattern regardless of their rotation 
about the center of the lens. In other words, if you rotated the assembly shown in 
Figure 24-8, meaning both lenses about the center axis, there will be no change in the 
polarization. This reduces the effect of head position on the viewer’s ability to fuse the 
right and left eye channels, reducing eyestrain and increasing comfort. As a side note, 
it is also required for use in digital cameras, as linear polarization would affect the 
autofocus and light-metering features of SLRs. 

Like anaglyphs, polarized 3D systems also use glasses to separate two channels that are 
projected at the same time. The first systems used two projectors, each with a different 
linear polarization filter projecting on to the same screen with precise timing. As the 
glasses would ahow only the correctly polarized light to be seen by either eye, the viewer 
perceived binocular disparity. However, the precise timing between the projectors 
would be subject to errors that cause eyestrain and binocular rivalry. Newer systems, 
including RealD, use an active polarization filter fitted to the projector. However, this 
is still classified as a passive system, because the glasses the user has are just normal 
passive filters. In this system, there is a single filter that can change its polarization up 
to 200 times a second. Every other frame is separately polarized, and binocular disparity 
is experienced without the complexity of an additional projector. Although this system 


Types of Display | 461 


www.it-ebooks.info 



















uses an active filter, the glasses don’t have to actively change to separate the two channels, 
so this is another example of passive technology. 

The main benefit of polarized systems over anaglyphs is that they provide full-color 
viewing and avoid binocular rivalry. This can increase the viewers’ comfort when they 
are watching feature-length films. The disadvantages are cost and dimness. The glasses 
cost much more, and the complexity of projection is increased. It is impossible to create 
the effect in static media like print or web pages using standard displays. Also, because 
the lens on the projector is blocking out the portions of the light that don’t have the 
correct polarization, the images appear dimmer to the viewer. This can cause up to 30% 
reduction in brightness and is the main point of contention for many directors. 

Liquid-Crystal Plasma 

The other display technologies discussed were passive technologies. The projection 
carries the two channels and the glasses separate the channels, one for each eye, without 
active participation from the glasses. Active technologies require that the glasses do the 
work of separating the channels while the display is less important. As the gaming in¬ 
dustry is more sensitive to adapting 3D display technologies to work with existing 
computer monitors or TVs, it has generally focused on active technologies. The most 
common active technologies are based on liquid-crystal shutter glasses, or LC glasses. 
The LC glasses work by exploiting a property of liquid crystals that causes them to turn 
black when a voltage is applied to them. This is the same technology that creates the 
eight-segment digits on a simple calculator. 

Basically, every other frame being displayed is shown only to one eye, as the LC glasses 
cause the lens to darken when the opposing eye’s frame is being displayed. To make sure 
the glasses are preventing the correct image from being seen by the corresponding eye, 
the computer broadcasts a timing signal to the glasses either over a wire or wirelessly. 
At the appropriate time, the right eye lens has a voltage applied to it and the entire lens 
quickly turns black. As light can enter only the left eye, that eye sees the image on the 
screen. As the video being displayed moves to the next frame, this time for the right eye, 
the glasses simultaneously are triggered to remove the voltage from the right lens and 
apply it to the left lens. With the left lens now darkened, only the right eye sees the right 
eye image. As long as this is happening very quickly,—on the order of 60 times per 
second per eye, or a total refresh rate of 120 Hz—your brain can’t detect that only one 
eye is seeing the information on the display at a time. Instead, it interprets it as each eye 
seeing distinct images continuously, and as long as the image follows the rules we dis¬ 
cussed earlier, it interprets it as having depth. 


462 | Chapter 24:3D Display 


www.it-ebooks.info 



As you can imagine, the main disadvantage of this technology for gaming would be that 
you have to ensure the frame rate stays relatively high. You are now rendering twice as 
many images as you normally would require. We’ll discuss more about the rendering 
pipeline later. Also related to frame rate is the refresh rate of the display. As each eye is 
really seeing only half the frames, the overall frame rate is half whatever the refresh rate 
is on the screen. Older displays have refresh rates at 60 Hz and effectively halving that 
can create issues with eyestrain; however, new displays support 120 Hz refresh rates so 
that halving it still allows for smooth display. Also, the display will seem much dimmer 
with the glasses on, as your eyes are seeing, on average, only half the light they normally 
would. As you can see, dimness is a common problem among 3D display technologies. 

The main advantage is that you don’t need a special display. As long as your display is 
capable of the required refresh rate, then you can retrofit it with a pair of LC shutter 
glasses and get 3D display out of it. Nvidia released such a kit in 2008, called 3D Vision, 
that is relatively popular. Graphics cards are capable of automatically converting the 
depth of the object in the model world into a parallax so that older games can also be 
rendered in stereoscopy. This is something to consider as you design your next game 
and something we’ll touch on again in a moment. 

Autostereoscopy 

While the newer 3D technologies are a far cry from the 3D of several decades ago, they 
still rely on people wearing glasses to view the image. This means the displays can never 
be used in a casual setting such as an arcade or street advertisement. Also, the younger 
segment of the gaming population might break or lose the glasses. Having to put on 
glasses to view the 3D images also provides a signal to your brain that what you are 
about to view is optical illusion. Put on the glasses, and your brain is already thinking 
that this isn’t really in 3D. 

Autosterescopy endeavors to create the illusion of depth without the aid of any glasses 
or other wearable device. The first and most common way it does this is by introducing 
a parallax barrier between the display and the user. As discussed earlier, parallax—and 
by extension, binocular disparity—is what gives our brain a main source of information 
on depth. A parallax barrier uses the fact that each of your eyes sees things from a slightly 
different angle to separate the two channels required for stereoscopy. Physically, the 
barrier is a layer placed in or on the screen with a series of very precisely cut slits. Because 
your eyes are not in the same spot, the slits reveal different pixels on the screen to each 
eye. A basic illustration of this method is shown in Figure 24-9. 


Types of Display | 463 


www.it-ebooks.info 




As shown in this figure, older screens used the slits to bar certain pixels from being seen 
by placing them above the screen. Newer screens like the one on the Nintendo DS place 
the barrier lower than the pixels, but before the backlight. This prevents your eyes from 
receiving the light from those pixels that are being shaded by the solid spaces between 
the slits. This results in a clearer image and a wider viewing angle. 

Speaking of viewing angle, if the method works because your eyes aren’t in the same 
spot, it is obvious that if you move your whole head then you’ll also be seeing a different 
set of pixels. This is the drawback: that there is a relatively small area called the “sweet 
spot” that the user must position his head relative to the screen to perceive the 3D effect. 
It makes it inappropriate for movies, as only a portion of the seats would be in the sweet 
spot, but it is in use for handhelds where only one user will be viewing the screen at any 
given time. Another drawback is that because the slits are eliminating half the pixels 
from each eye, the system reduces the effective pixel count by one-half. This causes a 
reduction in resolution that can be countered by even higher pixel density. 

Another method very similar to the parallax method is replacing the layer of slits with 
a series of lenses that direct light from certain pixels to a certain eye. These are called 
lenticular lenses and are illustrated in Figure 24-10. 


464 | Chapter24:3D Display 


www.it-ebooks.info 















Here microscopic domed lenses are placed between the viewer and the screen. The lens 
focuses the light such that only certain pixels are seen by each eye, due to the slightly 
different angles by which the eyes view the lens. Benefits over the parallax barrier are 
that the position of the user is less restricted and the image is brighter. With both parallax 
barriers and lenticular lens arrays, it is possible to retrofit current screens with remov¬ 
able slide-in-place filters that allow for viewing of 3D content designed for use with 
those filters. At the time of writing, several large TV manufacturers are doing active 
research into widening the field of view of these technologies for use in a home enter¬ 
tainment environment. 

Advanced Technologies 

The displays we have discussed so far have all lacked some level of realism. For one, the 
eye doesn’t have to refocus to observe objects at different depths, so your brain isn’t 
totally fooled. Additionally, when you move around the object being projected and it 
doesn’t change view, you still see the object at whatever angle the object was recorded. 
If you were viewing the world through a window, you could walk to the right and see 
more of the left-handed view. However, try as you might, you can’t see around the corner 
of a building in a video game by moving your head at an angle of the screen. While it 
might be possible to recreate that effect with some sort of head tracking, there are some 
beyond-state-of-the-art technologies that could take this steps further. 

One technology that is commonly thought of being able to produce 3D images is the 
holograph, a staple of science fiction. It seems like we should be able to just whip up 


Types of Display | 465 


www.it-ebooks.info 






























some dynamic holographs and be done with screens all together. Who wouldn’t like to 
play a sports game as if it were a table-top miniature? However, due to the way they are 
recorded, holographs as we know them are static images. Once recorded, holographic 
images cannot be changed. Due to their ability to encode multiple angles of viewing, 
they would make wonderful display technology, and research is under way to find a 
material that can hold holographic data and be rewritten fast enough to induce the 
illusion of motion to the viewer. From time to time, you may see in the news some event 
incorporating computer-generated imagery displayed in what is called holographic dis¬ 
play. These are not true holographs, but usually just a projection on a semitransparent 
screen. The images are still completely flat, and the illusion of 3D comes solely from the 
brain not registering the presence of the screen. 

Another technology being actively researched is called integral photography. This is a 
lot like the use of a lenticular lens; however, instead of linear cylinders in an array, the 
lens field is more like a fly’s eye. Each lens in the array captures a complete picture from 
a slightly different angle. Now, when projected through a similar integral lens, the light 
forms a 4D field that the viewer sees as a 3D scene appropriate for his or her viewing 
angle. If the view moves to the side, then he or she will see a new portion of the object 
that wasn’t visible previously. This type of movement parallax creates very realistic 3D 
experiences. The advanced displays so accurately recreate the light that recorded the 
images that the eye can focus on different parts of the object (this is called the wave 
front) and therefore experience accommodation of the eyeball. Recall that this is the 
eighth item in our list from earlier in the chapter, and it is something the other displays 
are lacking. Some crude demonstrations of this technology have been presented, and it 
will be exciting to see how the research progresses. 

Beyond any other method, the last one we’ll talk about takes the bull by the horns. If 
you want a 3D image, just make the image three-dimensional. The other displays we 
discussed all attempt to recreate 3D screens using projection from a 2D surface. There 
is a group of display technologies known as volumetric that dispense with any 2D ele¬ 
ments and attempt to create a light field with well-defined x, y, and z coordinates. These 
displays are far enough away from consumers that the definition of a volumetric display 
is still being argued. One of the biggest problems with the technology will be occlusion 
—that is, when an object passes in front of another object, you can’t see the object behind 
the object that is closer to you. Pretty basic depth information, right? Well, if you are 
attempting to create a 3D light field, it is difficult to get the light to be blocked out when 
another rendered object passes in front of the original object. Simply not creating light 
there won’t work, as each viewer would expect the farther object to be blocked at different 
angles. There are some existing demonstrators that use lasers to excite electrons in the 
air. When the lasers are focused on the same three-dimensional point, the combined 
energy creates a small pocket of plasma that gives off light. These small volumes of light 
are often referred to as voxels and correspond to pixels in 2D display technology. The 
current resolution and refresh rate is not going to be wowing any gamers in the near 


466 | Chapter 24:3D Display 


www.it-ebooks.info 



future, but I for one can’t wait for the day I can watch the New Orleans Saints play as a 
three-dimensional table-top game. 

Programming Considerations 

Now that you have a background in how the current 3D display technologies work, 
there are some aspects of each that you as the programmer should consider when writing 
games. There are two ways to add 3D stereoscopic content to games: active stereoization 
and passive stereoization. These are not to be confused with the passive and active 
technologies for viewing the 3D images. The stereoization process is the method by 
which the 3D images get created in the first place. 

Active stereoization is the process by which the programmer creates two cameras, ren¬ 
dering separate images for each eye. Passive stereoization removes the requirements for 
two cameras, and adds the stereoization at the GPU level. Either method is going to cost 
something in performance. The worst-case cost is twice a monocular scene; however, 
some elements of the scene, like the shadow map, will not require recalculation for each 
eye. 

Active Stereoization 

Active stereoization is conceptually simpler and offers greater control over the process 
of stereoization. The most naive implementation is to simply have two cameras that 
render complete scenes and then pass the buffers labeled one for each eye. The buffers 
are then swapped in and out with the traditional definition of frame rate being half the 
actual frame rate. However, this simple implementation duplicates some elements of 
the scenes that are not eye dependent. 

The advantage of this technique is precise control of what each eye is seeing. This allows 
the programmer to determine eye separation for each frame and could be used to ac¬ 
tually disorient the user as a game element. Consider a flash-bang grenade going off: 
the programmer could alter the position of the cameras such that it would disorient the 
user in 3D for a short period after detonation. However, this technique would cause 
very real discomfort to the user, so it should be not used frequently! 

The disadvantages are that the programmer is now responsible for managing an extra 
camera that must be rendered for each frame. For commercial titles, this method can 
be difficult considering that most games already have to be careful about how many 
times they invoke the render pipeline in order to maintain playable frame rates. Having 
to manage two cameras creates additional runtime burden on the program and makes 
the use of existing game engines a little more difficult. 

Also due to the fact that not everyone’s eyes have the same separation (intraocular dis¬ 
tance) and not everyone’s brain is willing to accept fabricated binocular disparity, the 
program must also provide options for the user to adjust the depth and complexity of 


Programming Considerations | 467 


www.it-ebooks.info 



the stereo effect. If you do not provide a way for the user to tune the experience, a vocal 
minority will claim your game gives them a splitting headache. However, as stated be¬ 
fore, if you are a curious amateur, the process of moving the camera and rendering 
stereoscopic images gives you a lot of insight into how the process works. 

As discussed previously, we must take into account the intraocular distance of the viewer. 
This is the amount of parallax we want to give objects at infinity. This distance usually 
ranges between 3 cm and 6.5 cm. The large differences can arise when considering that 
you must consider both adults and children when creating your 3D scene. Now it is 
useful to develop a normalized measure of intraocular distance. Nvidia calls this real 
eye separation and gives the following formula for the value: 

Real eye separation = intraocular distance / real screen width 

Note that this value will change depending on the width of the user’s screen. This value 
is important because it is used as a reference for the maximum camera separation when 
rendering your stereoscopic images. Separations higher than this value will cause dis¬ 
comfort in the viewer. In fact, for computer screens where the user is relatively close to 
the screen, most people don’t feel comfortable when the camera separation is more than 
half the real eye separation. This is why it is a good practice to allow the user to change 
the separation as a parameter of the program. It is also important to remember that the 
separation of the cameras is also the parallax value at an infinite distance. When two 
images display parallax equal to separation, it is as if your eyes are perfectly parallel. 
This is something that happens only when you are looking at something very far away, 
like a mountaintop. If you increase parallax beyond separation, you would essentially 
be asking your viewer to diverge her eyes beyond parallel. This is sort of the opposite 
of crossing your eyes, and obviously is going to cause some discomfort. 

As we now have an upper bound to our parallax, we can begin to create a parallax 
budget. Recall that the distance at which the two frustums intersect is called convergence. 
Well, at 100 times this distance, the value of parallax is 99% of separation. That means 
that for objects in the scene being rendered at that depth value, they will appear flat and 
all similarly far away. This is analogous to not being able to tell which peak of a faraway 
mountain range is the closest. 

Objects between 10 and 100 times the convergence distance have parallax that varies by 
about 10%. This results in a subtle but perceptible depth differentiation. As you ap¬ 
proach convergence, the parallax exponentially decreases. At the convergence distance, 
the parallax is equal to 0. At a distance closer to the viewer than the screen, the parallax 
is negative. A distance out of the screen half that of the convergence distance creates a 
negative parallax that is equal to the separation. If the object is any closer to the viewer, 
her eyes verge on crossing and eyestrain becomes a problem. Now we can draw what 
our budget looks like (see Figure 24-11). 


468 | Chapter 24:3D Display 


www.it-ebooks.info 




Figure 24-11. Parallax budget 

The budget scales with convergence distance and separation. You should make sure as 
much of the important 3D action occurs between convergence and 10 times conver¬ 
gence. Your entire scene should be contained with negative convergence/2 to positive 
100 times convergence. 

In general, you must be most careful when trying to execute an out-of-screen effect. 
These effects are very impressive to the viewer but cause the most eyestrain due to the 
rapid change in parallax. Having the object first appear farther away than the screen and 
then moving it closer to the user provides a context for the brain and encourages fusion. 
If an object is going to be closer to the user than the screen, it is also important to prevent 
that image from being clipped by the edge of the screen. That would make a portion of 
the 3D object disappear, and the clipping always occurs at the convergence point. This 
will give conflicting cues to the viewer and cause the 3D effect to be diminished. Given 
the amount of control you need in order to prevent out-of-screen effects from causing 
viewer discomfort, it is often best to use in non-player-controlled scenes. 

Another difficult part of the game to render is the 2D elements. The user interface or 
other menu items that have no depth are normally rendered at convergence depth. 
However, there are some elements that are 2D but should be rendered at some nonzero 
depth. The most important of these are mouse pointers and crosshairs. These should 
be rendered at the depth of the object below them. This change in depth of the user- 
controlled pointer helps maintain the idea that the objects are at different depths. 

Passive Stereoization 

Passive stereoization takes the responsibility for managing the stereoization process out 
of the programmer s hands. The programmer sends the render pipeline a single render 
command as usual, and the GPU handles generating the stereo images. Most systems 
rely on heuristic subroutines in the driver to take the monocular scene and generate 
binocular images. A heuristic subroutine is one that attempts to give a computer “com- 


Programming Considerations | 469 


www.it-ebooks.info 















mon sense” about what it is trying to do to avoid having to do an exhaustive search for 
solutions to an existing problem. They are algorithms not based on rigid mathematical 
formulas but more like neural networks; they must be trained to do what you want them 
to. These algorithms decide which elements of the scene are eye dependent and which 
are not in a process that occurs entirely in the render pipeline. 

It is possible for the programmer to defeat the “common sense” rules the computer is 
using in the pipeline so the method is not entirely fire-and-forget but does reduce a lot 
of the workload for development. One of the biggest benefits for larger game studios is 
that it avoids anyone having to reprogram existing game engines. By the same token, it 
allows existing games to be easily played in stereoscopic 3D. All of the preceding rec¬ 
ommendations apply to passive stereoization except that there should be no user- 
adjustable settings in the game. Passive stereoization relies on third-party profiles that 
help the GPU do the work. The user will have set up a profile with whatever stereoization 
software he or she is using, such as NVIDIA’s 3D Vision. Other recommendations may 
be specific to the stereoizer, and manufacturers usually publish a best practices guide. 
The NVIDIA one is very helpful, and we recommend you read it if you are interested 
in using stereoization in your games. 


470 | Chapter24:3D Display 


www.it-ebooks.info 



CHAPTER 25 


Optical Tracking 


In previous chapters we discussed how accelerometers have changed the way that people 
interact with video games. The same sort of innovation is occurring with optical sensors. 
Cameras, both in visual and infrared spectrums, are being used to generate input for 
games. This chapter will focus on the Microsoft Kinect for Windows SDK and give an 
overview of how to make a simple game that combines optical tracking with physics. 
First we’ll give a short introduction on the technologies these systems use to turn a 
camera into a tracking device. 

Without getting too detailed, we should start by discussing a few things about digital 
cameras. First, most of us are familiar with the “megapixel” metric used to describe 
digital cameras. This number is a measure of how many pixels of information the camera 
records in a single frame. It is equal to the height of the frame in pixels multiplied by 
the width of the frame in pixels. A pixel, or picture element, contains information on 
intensity, color, and the location of the pixel relative to some origin. The amount of 
information depends on the bits per pixel and corresponds to the amount of color 
variation a particular pixel can display. Perhaps you’ve seen your graphics set to 16-bit 
or 24-bit modes. This describes how many colors a particular pixel can display. A 24- 
bit pixel can be one of 16.8 million different colors at any instant. It is commonly held 
that the human eye can differentiate among about 10 million colors; 24-bit color is called 
“true color,” as it can display more colors than your eye can recognize. You might also 
see 32-bit color modes; these include an extra 8 bits for a transparency channel that tells 
the computer what to do if this image were put on top of another image. This is some¬ 
times referred to as opacity or alpha. 

Optical tracking and computer vision, in general, work by detecting patterns in this 
wealth of pixel data. Pattern recognition is a mature field of computer science research. 
The human brain is an excellent pattern recognizer. For instance, look at Figure 25-1. 
Most of us can’t help but see a face in what is in reality a collection of three random 


471 


www.it-ebooks.info 




shapes. Our brains are so primed to recognize the basic pattern of a human face that we 
can do it even when we don’t want to! 


o o 

7 \ 



Figure 25-1. Four unrelated geometric entities 

Computers, on the other hand, have a harder time looking at two circles and a few lines 
and saying, “Hey, this is a smiling face.” 


Sensors and SDKs 


The modern interest in computer vision as a consumer input for computer games has 
led to the development of several SDKs for performing computer-vision pattern rec¬ 
ognition. One such system is Kinect for Windows. Although Microsoft provides a very 
high-level API with the Kinect, the downside is that you are locked into its hardware. 
The popular open source alternative is OpenCV, a library of computer-vision algo¬ 
rithms. Its advantage is that it can use a wide variety of camera hardware and not just 
the Kinect sensor. 


Kinect 


The Kinect was originally developed for the Xbox 360 but has recently been rebranded 
to include Kinect for Windows. As console game design has high entrance requirements, 
the Kinect for Windows allows more casual developers to try their hand at creating 
games with optical input. The system has a hardware component, called the Kinect 
sensor, and the previously mentioned Kinect SDK that does a lot of the heavy lifting for 
us in terms of pattern recognition and depth sensing. The hardware component consists 
of an infrared projector, infrared camera, visible light camera, and an array of micro¬ 
phones. The two cameras and the projector form the basis of the optical tracking system. 
The projector sends out infrared light that is invisible to humans. This light bounces off 
objects and is reflected back to the Kinect. The infrared camera records the reflected 
light pattern, and based on how it has been distorted, calculates how far the object is 
from the sensor. This exact method is carried out in the hardware of the sensor and is 
proprietary. However, the patent applications reveal that a special lens projects circles 
that, when reflected, become ellipses of varying shapes. The shape of the ellipse depends 
on the depth of the object reflecting it. In general, this is a much-improved version of 


472 | Chapter 25: Optical Tracking 


www.it-ebooks.info 




depth from focus, in which the computer assumes that blurry objects are farther away 
than objects in focus. 

As for object detection, the Kinect comes with a great set of algorithms for skeleton 
direction. It can also be trained to detect other objects, but skeleton detection is really 
its forte. The skeleton detection is good because of the massive amount of training 
Microsoft used for the algorithms when creating the SDK. If you were to use an average 
computer to run the Kinect skeleton training program, it would take about three years. 
Luckily, Microsoft had 1,000 computers lying around, so it takes them only a day to run 
the training simulation. This gives you an idea of the amount of training you need to 
provide for consumer-level tracking in your own algorithms. The Kinect can track up 
to six people with two of them being in “active” mode. For these 2 people, 20 individual 
joints are tracked. The sensor can also track people while standing or sitting. 

OpenCV 

The OpenCV method for 3D reconstruction is, well, more open! The library is designed 
to work with any common webcam or other camera you can get connected to your 
computer. OpenCV works well with stereoscopic cameras and is also capable of at¬ 
tempting to map depth with a single camera. However, those results would not be ac¬ 
curate enough to control a game, so we suggest you stick with two cameras if you’re 
trying to use regular webcams. 

Indeed, finding depth is relatively straightforward using OpenCV. The built-in function 
ReprojectImageTo3D calculates a vector for each pixel (x,y) based on a disparity map. 
A disparity map is a data set that describes how pixels have changed from one image to 
the next; if you have stereoscopic cameras, this essentially is the reverse of the technique 
we use in Chapter 24 when dealing with 3D displays. To create a disparity map, OpenCV 
provides the handy function FrndStereoCorrespondenceGC(). This function takes a 
set of images, assumes them to be from a sterescopic source, and generates a disparity 
map by systematically c