Improved Collision detection and Response Kasper Fauerby [email protected] http://www.peroxide.dk 25th July 2003

Contents 1 Intro duction

3

1.1 Previous work . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 The algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 How to read this doc ocu ument . . . . . . . . . . . . . . . . . . . . 2 Vector spaces

2.21 2. 2.2 2.3 2.4

5

De ﬁ tiudy: ony:of R a v e.ct.or. s.pa. c.e .. Ca Case senistud st 3 Coordinates . . . . . . . . . Ellipsoid space . . . . . . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

.. . .

3 Collision detection

3.1 3.2 3.3 3.3 3.4 3.5

Overview . . . . . . . . . . . . . . . . Checking a single triangle . . . . . . Coll olliding with the inside of a triang nglle The sweep test . . . . . . . . . . . . In summary . . . . . . . . . . . . . . The sliding plane Sliding the sphere Gravity . . . . . In summary . . .

65 7 7 9

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

4 Collision resp onse

4.1 4.2 4.3 4.4

3 3 4

9 11 13 14 16 18

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

18 20 22 23

5 Conclusions

25

A Calculating the normal to a regular surface

27

B The plane class

32

C Utility functions

34

1

D Solving quadratic equations

35

E Co de for collision step

37

F Co de for response step

44

2

Chapter 1 Introduction 1.1 1. 1

Prev Previo ious us work ork

This paper describes an updated version of the collision detection and response algorithm I ﬁrst presented in [Fau00]. Some of the material has been copied directly from that article but the entire section on the collision detection step has been rewritten using a swept sphere technique as described in [Rou03] [Rou 03].. Thi Thiss paper has b been een writ written ten in a wa way y so it sho should uldn’t n’t be ness nessesar esary y to read to any of the referenced papers but if something seems unclear, in particular regarding the swept sphere technique, then I encourage you to read Rouwés paper as it might go into more details on certain aspects of the algorithm. The response step is still based partly on the ideas ﬁrst presented in [Net00] and partly from my own work. This Th is ti time me a de demo mo wi with th fu full ll so sour urce ce wi will ll ev even entu tual ally ly be availa ailabl blee at at:: http://www htt p://www.dr-c .dr-code.com. ode.com. The demo will mostly be done by a friend of mine, Matt Ostlund also known by some as “Rhone Ranger”, with probably just a little intervention by myself in the core collision code. So keep an eye on his site as well. A huge thanks to him for taking on this task!

1.2 1. 2

The The algo lgorith rithm m

The algorithm presented in this paper handles collision detection against arbitr arb itrary ary meshes meshes store stored d as a soso-cal called led polygo polygon n sou soup. p. When a col collis lision ion is detected the algorithm will slide the moving entity along the obstacles as it is typically seen in 3d computer games. The moving entity is approximated with an ellipsoid which gives a fairly tight ﬁt for most humanoid or animal shapes. shape s. Ell Ellips ipsoids oids hav havee a very very “frie “friendl ndly” y” shape that allo allows ws them to slide slide smoothly of the obstacles they collides against which is a good thing in a 3

game where the player does not want to get stuck against a hard egde in the middle of a fast-paced battle. This updated version of the algorithm ﬁxes in particular the problem where colliding against triangle thethe original fail resulting in the player being edges stuck could or fall cause through worldalgorithm geometry.to

1.3 1. 3

How How to to rea read d thi thiss docu docume men nt

First of all let me say: this stuﬀ is certainly not easy! It’ll take a long time to understand understand correctly and probably sev several eral reading readingss of this text. So give yourself time to fully understand what’s written in a section before moving on to the nex next. t. To ful fully ly unders understan tand d the theor theory y pres presen ented ted you will need to havee a fai hav fairly rly good unde underst rstand anding ing of lin linear ear algebr algebraa - i.e. i.e. ve vector ctors, s, mat matric rices, es, ve vect ctor or spac spaces es and and th thee li lik ke. Th This is paper is spl split it up into into tw twoo majo majorr par parts ts one on col collis lision ion detec detectio tion n and one on colli collisio sion n res response ponse.. No Now w what what’s ’s the diﬀerence?

• Collision detection deals with ﬁnding out whether or not we’ll bump into something when we move our ellipsoid though 3d space and if so, what do we hit and where? • Collision response deals with what to do when a collision do occur. Do we stop? Do we contin continue ue move movement ment in another dire direction ction ? What do we do? The collision response step is very important for the overall feel of your game. I’ll assume that the mesh being checked for collision is placed in the same spacee as the pla spac playe yerr - in wo world rld spac space. e. In other wor words ds I’ll assum assumee tha thatt eac each h mesh has the identity matrix as its world matrix. If this is not the case then it’s easy to apply the actual world matrix to the vertices before we check the triangles triang les for collis collision. ion.

4

Chapter 2 Vector spaces This algorithm makes heavy use of non-standard vector spaces to simplify certain cert ain calcul calculati ations ons.. Thos Thosee of you alr already eady fami familia liarr wit with h the deﬁnit deﬁnition ion of vector spaces and most importantly with change-of-basis matrices to move between spaces can skip most of this chapter and only cast a glance on the section sect ion on the “ell “ellips ipsoid oid space space”. ”. The rest of you you rea read d on but be aw aware are that th this is is onl only y a very ery qu quic ick k crash crash-c -cour ourse se on th thee subj subject ect.. A ful fulll ex expl plana anati tion on would include too much math and is beyond the scope of this paper anyway.

2.1 2. 1

Deﬁn Deﬁnit itio ion n of a vec vecto torr spac space e

Most of you will never have encountered any other vector spaces than the standard two and three dimensional spaces we usually think of from school math. mat h. Th These ese ar aree call called ed R2 and R3 and are those we use in a “standard” coordinate system (like the one D3D or openGL operates in). As it turns out we can easily deﬁne vector spaces or 4, 5 or even inﬁnitely many dimensions by listing a few rules (or axioms) which every vector space must follow. R2 and R3 follows these rules too! The rules are: multiplicat plication. ion. This means • It must be closed under addition and scalar multi that given two vectors from the vector space, say X and Y , , the then n Z = + Y must also be in the same space. For any real number r if X is X + in the space then so must rX . Informally Informally said we cannot ever “leav “leave” e” the vector space using these operations.

• It must contain a zero-vector V 0 so for all vectors X in the space V 0 + X = X . For all vectors X it must also be true that that 0X = V 0. • It must follow standard mathematical rules such as the associative law, commutative law etc. 5

Now I’ll introduce to you the concept of a linear combination of vectors from a vector space. Said in words it’s what you get if you combine vectors from the space using addition and multiplication with scalars (real numbers). X Z you For example , Y and combine them like this: V = 2X if + +you 4Y have + ( −vectors 3)Z and then V would becould a linear combination of the vectors X , Y and Z . OK, what can we say about V ?? Well ell,, fro from m rul rulee nu numbe mberr 1 abov abovee we can see that V mus mustt belong to the same vecto vectorr space as X , Y and Z . Cool, that’s what we need to deﬁne what a basis for a given vector space is. A basis for a vect vector or space is a collection of vectors vectors,, b belongin elongingg to the space, for which the following holds:

Every ry vector in the vector space is a linear com combinati bination on of vect vectors ors from • Eve the basis.

• Eac Each h of the vecto vectors rs in the basi basiss can not be mad madee fro from m a lin linear ear comb combiination of the other basis vectors. The minimal number of vectors necessary to create a basis for a vector space is equal to the dimention of the space. So how many vectors are in the basis for R3 ? Or R2 ?

2.2

Case study: R3

I think it’s time to take a break from the abstract deﬁnitions above and look at a fami familia liarr exa exampl mple. e. Aft After er rea reading ding and unde underst rstandi anding ng thi thiss exa exampl mplee yo you u should understand the stuﬀ above well enough for this paper. Let us look at the standard 3D vector space we know as R3 . Is it a vector space? Well, we check the rules (very informally). Is it closed under addition? If we have two 4) and Y = (6, 3, 8) 8),, is Z = X + Y = (8, 8, 12) vectors from R 3 , say X = (2, 5, 4) and in R3 ? Yes, we believe this is the case. For any real number r, say r = 2, is rX = (4, 10, 8) 8) in R3 ? Check! First rule holds. Is there a zero vector then? Yes, we use V 0 = (0, 0, 0) 0) and and the rule holds. Checking the third rule involves a lot of tedious checks so I’ll just mention the commutative law saying that X + Y = Y + X . Obviously that holds for vectors from R3 . So R3 is a vector space! What is its basis? The basis for R3 is called the “standard basis” and contains 3 vectors vectors (e1, e2 , e3 ). What are those vectors? They are: e1 = (1, 0, 0), 0), e2 = (0, 1, 0) 0) and e3 = (0, 0, 1) 1)..

6

Well, if that is indeed the basis for R3 then we should be able to derive any vector from R3 as a lin linear ear comb combina inatio tion n of tho those se ve vecto ctors rs right? right? Well ell,, we’ll have to convince ourselves about this so given any vector from R3, say V = (5, 2, 4), , can we 5derive a linear combination of ( of (e1 , e2 , e3 )? Yes, because in4) this case case 5 e1 +2 e2this +4efrom 4).. 3 = 5(1, 0, 0)+2(0, 1, 0)+4(0, 0, 1) = (5, 2, 4) It’s clear that e 1 cannot be made from e2 and e3 because no matter how you combine combi ne them the ﬁrst vector componen componentt would still be zero right? Same can be said for the other two basis vectors.

2.3 2. 3

Coo Coordin rdina ates tes

Now for an important deﬁnition: the coordinate. The coordinate for a point in a vector space is build from the scalars that are multiplied to the basis vectors in the linear combination for the point. In the example above the point 4).. This migh mightt seem obviou obviouss because we’re used V has the coordinate (5, 2, 4) to working with R 3 but make sure you see why that is indeed its coordinate: are (5, 2, 4) 4) - its coordinate. V = 5e1 + 2 e2 + 4 e3 so the scalars are

2.4 2. 4

Elli Ellips psoi oid d spac space e

By now you should be convinced that R3 is a vector space following the axioms axi oms for general vec vector tor space spaces. s. It shoul should d als alsoo be clear clear that other vect vector or spaces spac es could exist - even even other spaces of 3 dim dimensi ensions. ons. For exampl examplee wha whatt about the vector space made from the basis v1 = (2, 0, 0) 0),, v2 = (0, 2, 0) 0) and 2). Which vectors or points does this space contain? The same as v3 = (0, 0, 2). R3 of course but with diﬀerent coordinates! Given a point (2, 2, 2) in R3 - which coordinate would that same point havee if we con hav conve verte rted d it into our new spac space? e? It woul would d hav havee the coordi coordinate nate 2). (1, 1, 1) because: 1) because: 1v1 + 1v2 + 1 v3 = (2, 2, 2). This is exactly the trick we’ll use in this paper to create a very special vector space which has the property that the ellipsoid we’re using to approximate ima te our pla playe yerr wit with h becom becomes es a uni unit-s t-spher pheree in that space! A uni unitt sphe sphere re is a sphere with radius = 1 but it’s also an ellipsoid with radius vector = (1,1,1), right? So how do we create such a space? Well, we’ll have to come up with a basis for the space. If the ellips ellipsoid oid is deﬁned by a rad radius ius vector vector of (x,y,z ) then we’ll just chose the basis to be: v1 = (x, 0, 0) 0),, v 2 = (0, y, 0) 0) and and v 3 = (0, 0, z ). Now in this space the ellipsoids radius vector will be (1, 1, 1) 1) - it’ll be a unit sphere sphe re as we desi desired. red. You can chec check k if that choi choice ce of bas basis is reall really y deﬁn deﬁnes es a

7

vali alid d ve vecto ctorr spa space ce if you want - or you can jus justt tak takee my word word for it. We’l e’lll call our newly deﬁned vector space for the “ellipsoid space”. The last thing we need to know is how to translate a point from R3 into the ellipsoid space. We’re in luck,webecause turnswith out that because a linear combination is a linear function can getitaway just describing what to do with the 3 basis vectors vectors (e1 , e2 , e3 ) (remember these from above?). We ﬁnd that if we use the basis basis (v1 , v2, v3 ) from above, then: e1 =

1 x

v1 + 0 v2 + 0 v3 .

e2 = 0v1 +

1 y

v2 + 0 v3 .

e3 = 0v1 + 0v2 +

1

v3 . z

(2.1)

(2.2)

(2.3)

We list the coordinates for e 1,e2 a and nd e 3 as column vectors in a 3x3 matrix and get a “change of basis” matrix which has the eﬀect of translating any vector from R3 into the ellipsoid space. The matrix looks like this:

C BM =

1

X

0 0

0

0 1 0 Y 1 0 Z

(2.4)

As long as we stick to deﬁning new spaces for which the change of basis matrix looks like above (only has entries on the diagonal) then we can simplify the multiplication of a vector to the matrix into just a component-wise multiplication. For example we translate a vector V into our ellipsoid space like this (remember (x,y,z) is simply the radius vector for the ellipsoid deﬁning the space): 1 1 1 V V e = C BM ∗ V = ( , , )V = x y z (x,y,z )

(2.5)

At mentioned above this only holds for change of basis matrices which only has entries on the diagonal and those spaces just happens to include those you get from R 3 when you multiply each basis vector ( vector ( e1 , e2 , e3 ) with a constant. If you check back, that’s exactly what we do to achieve the ’scaling trick’ above.

8

Chapter 3 Collision detection 3.1 3. 1

Over Overvi view ew

OK, enough enough talk - let letss get sta starte rted! d! So, we hav havee our guy we wish to mov movee around the worl around world. d. He’ He’ss rep repres resen ented ted by an ell ellips ipsoid oid with a cen center ter which which we will consider his position and a radius vector vector deﬁning the ellip ellipsoids soids size along the three axis. See Figure 3.1.

Figure 3.1: Ellipsoid radius vector We move our guy though the world by applying a force to him in some direct dir ection ion.. Thi Thiss is repr represen esented ted by a velocity vector . We wi wish sh to mo mov ve the ellipsoid through the world so its new position equals its current position plus the velocity vector. See Figure 3.2.

9

Figure 3.2: Moving our guy by a velocity

But we don’t know if we can do that though as there might be something in his way - one or more of the triangles making up our world might be obstructing the path. We have no chance of knowing exactly which triangle he’ll hit, so to some degree we’ll have to check them all (it is possible, and recommended, to split up large meshes into an octree which can then be queried to check only those triangles close to the player). Also we cannot stop once we ﬁnd one triangle he’ll hit - we’ll have to check all pote p otent ntial ial colli collider derss to ﬁnd the closes closestt col collis lision ion.. Fig Figure ure 3.3 sho shows ws what happens if we detect a collision with triangle A and then stops without checking the rest, including for example triangle B. First of all we’ll reduce the complexity of the problem greatly by working in the ellipsoid space that I’ve discussed above in section 2.4 - from now on referred as eSpace . As you you’l ’llso l recal re calll now this th is on is awe’ll ve vect ctor or spac space e in whic which h th thee ellipsoid to is really a unit sphere from only consern ourselves with wit h det detecti ecting ng coll collisi ision on bet betwe ween en a tri triang angle le and a uni unitt sphe sphere. re. To wo work rk in eSpace we have to translate the triangles, the velocity vector and the player position from R3 into the space by applying the CBM matrix listed above. Once our collision detection routine has ﬁnished the result will also be in eSpace but we can translate the result back into R3 by applying the inverse of the CBM matrix to the result 1 . As it turns out we need two things for the collision response step in the 1

Where the transition transition from R3 to eSpace was done by a division of the point with the ellipsoid radius vector it turns out that the transition back from eSpace to R3 can be reduced to a multiplication of the point with the ellipsoid radius vector.

10

Figure 3.3: We must check all triangles case of a collision:

• The position where the sphere hits the geometry. • The distance along the velocity vector that the sphere must travel before the collision occurs. So to check a single triangle for collision we’ll ﬁrst have to ﬁgure out if a collision occurs and then if that is the case the algorithm must be able to calculate the two things above.

3.2 3. 2

Chec Checkin king g a sin singl gle e tri trian angl gle e

So given a triangle deﬁned by points p 1 , p 2 and p 3 in eSpace and in clockwise order we want to check for collision against a sphere positioned at basePoint and moving along a vector velocity. If we parameterize the movement of the sphere along the velocity with t then we’ll get a formula for the position of the sphere that looks like this: C (t) = basePoint + t ∗ veloc velocit ity, y, t ∈ [0 , 1]

(3.1)

A sphere in 3d can be deﬁned as a position and a radius (which in our case will be 1 becau because se we’r we’ree wo worki rking ng in eSpa eSpace) ce).. For a mo movin vingg sph sphere ere the 11

radius will remain constant but the position will of course change. Thus the formula above gives us the orientation of the collision sphere at any time t moving along the velocity vector. This is what is meant by a swept sphere . The ﬁrst task is to check if the swept sphere will intersect with the triangle plane . If this is not the case then it certainly can’t collide with the triangle, can it? it? So we con const stru ruct ct the pla plane ne trianglePlane from the points of the tr tria iangl nglee (see (see Ap Appen pendi dix x B fo forr he help lp wi with th th this is). ). If we ha hav ve th thee nor normal maliz ized ed plane normal N and the plane constant C p then we can calculate the signed distance from a point p to the plane as: SignedDistance( p) = N · p + C p

(3.2)

If the swept sphere intersects with the triangle plane then at some time t0 it’ll rest on the front side of of the plane and at some other time t1 it’ll rest on the back side . At all time values t ∈ [ t0 , t1] the swept sphere will intersect wi with th the pla plane ne.. The ti time me t0 is exactly when the signed distance from the swept sphere to the triangle plane is 1 so we can calculate it like this: SignedDistance(C (t0 )) = 1 ⇒ N · (baseP basePoint oint + t0 ∗ velocity ) + C p = 1 ⇒ N · basePoint + t0 ∗ (N · velocity ) + C p = 1 ⇒ t0 ∗ (N · velocity) + S SignedDistan ignedDistance ce(baseP basePoint oint) = 1 ⇒ 1 − S SignedDistan ignedDistance ce(basePoint ) t0 = N · velocity

The time t1 is when the signed distance from the swept sphere position to the triangle plane is -1 so similar to above it can be calculated as: S ignedDistance ce(baseP basePoint oint) t1 = −1 − SignedDistan N · velocity

Now, if both t0 and t1 is outside the range [0, 1] then 1] then we know that the swept sphere will not at any point along the velocity intersect with the plane and thus thus it cann cannot ot col colli lide de with with the the tria triang ngle le.. Ot Other herwi wise se we kn know ow that a collision with the triangle will occur at a time tcollision ∈ [ t0 , t1 ]. Notice that there is a special case if N · velocity = 0 - then we obviously can’tt use the formu can’ formulas las abov above. e. But when does thi thiss happen? That hap happens pens when the velocity vector is perpendicular to the plane normal - in other words when the sph sphere ere is tra trave velli lling ng in parallel parallel to the trian triangle gle plane. In this cas casee there are two possibilities, either the absolute distance from basePoint to the 12

triangle plane is smaller than 1 and the sphere is embedded in the triangle plane. plan e. If this is the case the then n we set t0 = 0 and t1 = 1 as the swept sphere in inter tersect sectss the pla plane ne at all time times. s. If the dis distan tance ce is gre greate aterr than 1 the then n we know that a collision cannot ever happen and we can return early from the function. Now that we have found the two time values t0 and t1 there are three cases for a potential collision: of the triangle. • The sphere can collide with the inside of of the triangle. • The sphere can collide against one of the three vertices of

• The sphere can collide against one of the three edges of the triangle.

3.3 3. 3

Coll Collid idin ing g with with the insi inside de of a tria triang ngle le

The ﬁrst is probably the most common one inside (depending trianglethen size)a and if thecase sphere does indeed collide with the of theon triangle collision against a vertex or edge must happen “further down the velocity” so to speak. So if we can quickly detect collision against the inside then we can skip the more expensive “sweep test” against the vertices and edges. So lets take a look at this case ﬁrst. Note that this case can only happen when the sphere is not embedded in the plane (as discussed above). An embedded sphere can only collide against a vertex or an edge of the triangle. The idea is to calculate the point on the plane where the sphere will ﬁrst make contact contact when moving along the velocity ve vector. ctor. Let call that the already eady kno know w tha thatt the contact contact will happen at planeIntersectionP planeI ntersectionP oint. We alr time t0 because that’s exactly the time when the sphere rests on the front sidee of the pla sid plane, ne, but wher wheree exac exactly tly is the poin point? t? The plane int inters ersecti ection on point is calculated like this: planeIntersectionP planeI ntersectionP oint = ba baseP seP oint − planeNormal + t0 ∗ velocity (3.3)

To see why this must be the case take a look at Figure 3.4 and Figure 3.5. The point on the sphere that’ll ﬁrst hit the plane is given by basePoint − planeN ormal and the intersection happens at time t0. Now all we need to do is check if the planeIntersectionP planeIntersectionP oint is inside the triangle. A function that does this check is listed in Appendix C but you can use what whatev ever er functi function on you lik like. e. If the poin pointt is insid insidee the tria triangle ngle then we have the result for the collision test: 13

Figure 3.4: Sphere intersection point

intersectionP intersec tionPoint oint = planeI planeI ntersectionP ntersectionP oint intersectionDistance = t0 velocity

3.4 3. 4

The The sweep eep test test

If the sphere does not collide with the inside of the triangle then we’ll have to do the “sw “sweep eep test test”” agai against nst the ver vertic tices es and edges of the triangl triangle. e. The t

t0 , t1

idea in both cases is toacheck there ] where the swept sphere collides against either vertexifor edge.is a ∈ [ Lets look at the easiest of the two cases ﬁrst - the sweep against a vertex p. When does a collision between a vertex and the swept sphere take place? Well, if at any time the distance between the swept sphere center and the ve verte rtex x is 1 the then n the tw twoo wil willl collid collide. e. Or rathe rather, r, to mak makee the calcu calculat lation ionss a bit easier, when the squared distance between the swept center and the vertex is is 12 - that’s that’s the same thin thingg rig right ht?? If we use that for any vect vector or V , , V · V = V 2 then we can set up the following equation: (C (t) − p) · (C (t) − p) = 12 The above reduces to a quadratic equation of the form: 14

(3.4)

Figure 3.5: Plane intersection point

At2 + Bt + C = 0

(3.5)

where: A = velocity · velocity B = 2(velocity · (basePoint − p)) C = p − bas baseP eP oint2 − 1

A quadratic equation generally have two solution and this also makes sense sen se in this cas case. e. Th Ther eree wi will ll pro probab bably ly be two times when the distance between the swept sphere and the vertex is 1 - one for each side of the plane. We’re interested in the ﬁrst collision collision against the vertex so we use the smallest solution (because the solutions are exactly the time values for the collisions). For help solving a quadratic equation take a look at Appendix D. If there is a smallest solution x1 then the intersection data that we need is given as: intersectionPoint = p intersectionDistance = x1 velocity

15

Even if a collision occurs with one of the vertices we’ll still have to sweep against the edges of the triangle too to see if the sphere will collide against an edge at sm smal alle lerr time time va valu lue. e. Th Thee sw sweep eep aga again inst st an edg edgee is a bit bit mo more re complicated than the sweep against the vertex but it boils down to the same thing basically. Consider the edge going from p1 to p2 then let edge = p2 − p1 baseToV baseT oV ertex = p1 − basePoint

First we check if there is any time where the swept sphere collides against the inﬁnite line going going thr through ough the edge. Thi Thiss happens when the distan distance ce between the swept sphere center and the line is 1. Aga Again in thi thiss reduc reduces es to a quadratic quadrat ic equati equation on with: 2

2

2

A = edge2 ∗ −velocity + (edge · velocity ) B = edge ∗ 2(velocity · baseToV ertex) −

2((edge · velocity)(edge · baseToV ertex)) 2 2 2 C = edge ∗ (1 − baseToV ertex ) + ( edge · baseToV ertex) If this quadratic equation has a smallest solution x1 then we know that the swept sphere will intersect with the inﬁnite line at some point but we don’t know if that point is within the line segment that that makes out the triangle edge. So if we parameterize the line L by f such that L(0) = p1 and L(1) = p2 then we can calculate f 0 on the line where the intersection takes place as: f 0 =

(edge · velocity )x1 − (edge · bas baseT eT oV ertex) edge2

(3.6)

If f f 0 ∈ [0 , 1] 1] then then the intersection takes place within the line segment and the sphere collides against the triangle edge at time x 1. The intersection data that we need is given as: intersectionPoint = p1 + f 0 edge intersectionDistance = x1 velocity

3.5

In summary

And that’s all there is to it! To recap the whole procedure: 16

• We ﬁrst calculated the triangle plane • Then we found time values t0 and t1 where the swept sphere intersected the plane. checked d if we had a coll collisi ision on inside the trian triangle. gle. If this was • First we checke the case we could skip the sweep because it must take place before any vertex or edge collisions.

• Finally we swept the sphere against the vertices and edges of the triangle. • After all the above we’ll know if a collision takes place against the tr tria iangl nglee and at wh what at poi point nt and di dist stanc ance. e. We can now che check ck if th thee collision is the closest one yet in which case we store it. • Continue to the next triangle until all has been checked. To further help you understand how to implement this step I’ve included a source listing of the whole procedure of checking a triangle against a moving sphere. You can ﬁnd the code listing in Appending E.

17

Chapter 4 Collision response So now you know how to check if your sphere collides with any of the triangles in your world world give given n a cert certain ain vel velocit ocity y vecto vector. r. But what do we do when a collision collis ion actually occurs? The easiest wa way y to handle a colli collision sion is to simply stop is and allow move when move collision ion we is detected. Oncollision the other hand that notnot how the the professionals doaiscollis it? No, want fancy response like sliding along the walls, automatically climbing stairs and automatically bumping over smaller obstacles on the ground. Luckily all these things come automatically from the implementation of sliding that I’m going to show you. So what exactly do we mean by sliding? Well, what we want to do if we collide with a triangle in our world is to move close to it, change the direction of our velocity vector and then continue movement in a new direction. See Figure 4.1.

4.1 4. 1

The The sli lidi ding ng pla plane

The sliding plane is, as the name implies, the plane along which we will contin con tinue ue our mov movemen ement. t. From Figur Figuree 4.1 you mig might ht get the idea tha thatt the sliding plane is identical with the plane on which the colliding triangle lies. In some cases this is also correct but as Figure 4.2 demonstrates it is not always the case: Letss gene Let general ralize ize the ide ideaa of the sli slidin dingg pla plane. ne. What does the two two sliding sliding planes plan es in Fig Figure ure 4.2 hav havee in commo common? n? They are both the tangent plane to the sphere sphere in the poin pointt whe where re it’ll coll collide ide with the tri triangl angle. e. So we have have to ﬁnd a way to calculate the tangent plane for the sphere, given a point on its surface. Remember Reme mber how we rep repres resen entt pla planes? nes? We deﬁn deﬁnee the them m by a poin pointt on the plane and a normal to the plane, right? We already have the point - namely

18

Figure 4.1: Sliding when we hit a triangle

the intersection point from the collision step - so our task at hand is really to calculate the normal to to the tangent plane of the sphere in the intersection point. It turns out that once again our choice of working in the ellipsoid space saves us from a lot of computations because the normal to the tangent plane at any point on a unit sphere is simply the vector going from the point on the surface surface to theshape! cen center terSee of Figure the sph sphere! ere! Thi Thiss is not the case wit with h the more general ellipsoid 4.3. So calculating the sliding plane is easy in ellipsoid space and boils down a few lines of code: VECTOR planeOrig VECTOR planeOrigin in = intersecti intersectionPoi onPoint; nt; VECTOR VECTO R planeNorm planeNormal al = newPositio newPosition n - intersect intersectionPo ionPoint; int; planeNormal.normalize(); PLANE slidingPlane(planeOrigin, slidingPlane(planeOrigin, planeNormal);

Well ell,, thi thiss isn isn’t ’t reall really y a sat satisf isfyin yingg expl explana anatio tion n is it? What if we hadn’ hadn’tt worked work ed in this fancy ellipsoid space? Couldn’ Couldn’tt we hav havee comput computed ed this slidi sliding ng plane anyway? Of course we could and for those interested I’ve included an 19

Figure 4.2: The concept of the “sliding plane”

Appendix which shows a general method for calculating the normal to any regular surface. surface. In that Appendix it’ll also become clear why the calculations calculations are so simple in the case of a unit sphere. See Appendix A for more details.

4.2 4. 2

Slid Slidin ing g the the spher phere e

Now we know how to calculate the sliding plane but what do we do with it?. Here is the idea:

• Mov Movee our sphere as close as possible to the triangle we’re colli colliding ding with. Lets call this position for “newPosition”. • Calculate the sliding plane based on this new position. • Project the original velocity vector to the sliding plane to get a new destination. • Make a new velocity vector by subtracting the polygon intersection point from the new destination point. 20

Figure 4.3: The tangent plane of a unit sphere

• Recursively call the entire collision detection routine with the new position and the new velocity vector. The last step might come as a surprise but yes, collision detection is a recursive function and for each recursion we check all triangles all over again! We continue to recurse until either:

• We do not hit anything, so we just update the position. • The velocity vector gets very small. What about this projecting projecting thin thing? g? Well ell,, it just so happe happens ns that it does exactly what we want. want. It generates a vector on the sliding plane we can mov movee along (a new velocity vector) and the more directly we hit the triangle the less do we slide. See Figure 4.4. The only thing that requires a more in-depth explanation is perhaps how we we’ll ’ll project the as velocit vealocity y vecto ve r to the (the sli sliding ding plane plane.intersection . We hav havee the slidi sliding ng plane calculated point onctor the plane polygon point) and a plane normal. We want to project the original destination point along the direct dir ection ion of the slid sliding ing plane norma normall on onto to the slidin slidingg plan plane. e. To do that we need the signed distance from the original destination point to the sliding plane. The projected point is then given as: float distance distance = slidingPl slidingPlane.d ane.distan istanceTo ceTo(des (destinat tination) ion); ; VECTOR newDestinationPoint newDestinationPoint = destination-distance*planeNorma destination-distance*planeNormal; l;

As outlined above it is now just a matter of calculating a new velocity vector and recursing with the newPosition and newVelocity on the collision detection and response algorithm. 21

Figure 4.4: Angle of intersection aﬀects the amount of sliding

4.3 4. 3

Gra Gravit vity

What if we want gravity in our world? Will that be hard? No not at all, each frame you just make two calls to the collision detection routines - one time with wit h the play player er velocit velocity y and anothe anotherr tim timee wit with h a gra gravit vity y ve vector ctor.. You can combine the two vectors and then just call the routines once with a single velocity vector v = velocity + gravity but that will make climbing stairs become more diﬃcult as the velocity vector must be much longer for the projected vector to slide upwards enough when you hit the edge of a stair (think (th ink about it) it).. In mos mostt case casess mak making ing tw twoo sepa separat ratee cal calls ls wo wont nt even aﬀect the total numbers of calls to the functions because when moving along ﬂat ground if you combine velocity and gravity you will have two recursions as shown in Figure 4.5. If you ﬁrst move along the ground with the velocity velocity you will not hit anything, and the second call with the gravity vector will collide and not recurse because the collision is perpendicular to the surface.

22

4.4

In summary

So to recap the response step and the general collis collision ion detection and response algorithm: • First we convert the input velocity and position from R3 to eSpace.

• Then we call the collision detection routines to ﬁnd the closests intersection point and the distance along the velocity we must move to hit it. • We move the sphere very close to the intersection to get a new position. • We calculate a sliding plane from the returned intersection data. • We project the velocity vector onto the sliding plane to get a new destination point. calculate te a new velocity vector and calls the algori algorithm thm recursiv recursively ely.. • We calcula

• Finally we convert the result back to R3 and updates the character position. • Optionally we do the above again with a gravity vector 1 . To further help you understand this step I’ve included a source listing in Appendix Appendix F for the respon response se step. Ple Please ase note that this is includ included ed for inspiration only and you’ll have to tweak it to match your exact needs. It should also be noted that the code included might slide a bit too much - even the smallest slope and the gravity vector might cause the player to slide. You should implement code to detect when the player is on an almost ﬂat surface surface and onl only y let gra gravit vity y sli slide de when the slope is rea really lly steep. steep. Ho How w exactly you want this to work is up to you.

1

Gravity can be Gravity b e combined with the movement velocity velocity but with a penalty when colliding against stairs.

23

Figure 4.5: Two calls has same number of iterations as one in this case

24

Chapter 5 Conclusions Well, this concludes my updated version of the collision detection and response algorithm algorithm ﬁrst presented in [F [Fau00]. au00]. In practice it has proven to be very stable when implemented correctly. I’ve not had a single case of getting stuck or falling through the geometry in my own implementation in the ERA game engine. As some of you might have noticed the function for checking a single triangle for collision is a bit long this time so you might be wondering how fast the alg algori orithm thm is. Pe Perso rsonal nally ly I have haven’t n’t had any perfor performanc mancee pro proble blems ms with it and one also has to remember that there are two “early out” points in the function which which actuall actually y kicks in quite often often.. Here are some stati statistics: stics: I walked around a few minutes in an ERA test map which consisted of both a terrain (build from a heightmap) and polygon meshes such as houses, stairs etc. In tot total al 1.1 mil millio lion n tri triangl angles es we were re sent to the funct function ion ove overr the whole test period and of those approximately 40% were detected to be backfacing and thus skipped1. Of the rema remain inin ingg 700 700.0 .000 00 tria triangl ngles es 65% we were re able to exit early from the function after just a few cheap tests to calculate the time triangles es that didn’t exit earl early y most had to perform values t0 and t1 . Of those triangl the sweep test but a few could skip the sweep because a collision against the inside of the triangle triangle were detected. detected. All in all only about 20% of the triangl triangles es being sent to the function had to actually be checked for collision against the inside or edge of the triangle and thus payed the full price for the rather long function. One should note of course that these statistics depends a lot on the dataset and on how aggressively the triangles has been culled before being sent to the function but I think the results above represents a pretty average case 1

One would suspect 50% to be backfacing but in my case the statistics were biased by the fact that I had a terrain mesh where most triangles is frontfacing to a velocity along it.

25

where decent culling has been applied through the use of an octree to only send those triangles triangles near the movemen movementt to the functi function. on. I can only encourage you to do your own tests and see how the algorithm behaves on your data. I am aware that this paper presents incomplete code in the sense that it cannot be just cut out from this text and plugged into your own engine directly! However, I believe I’ve presented the material well enough for you to use what is given here as reference and implement your own version of the algorith algorithm. m. The reaso reason n wh why y I str stress ess this fact here is that that I’v I’vee rec reciev ieved ed a lot of questions about my previous version of the document where people complained that they couldn’t ﬁnd the VECTOR class or that they didn’t knew how to apply these techniques on a very speciﬁc type of mesh like the X-ﬁles from Microsoft or .md3 characters from quake or whatever. It is assumed that the reader is able to ﬁgure these things out for himself otherwise reading this document is a bit premature and I’m afraid I cannot be of much help with questions of that type (read: I probably won’t answ answer er your mails mai ls if you you ask). Of cours course, e, if yo you u really think something in the presented code looks wrong or that it’s impossible to understand then I won’t bite if you send me an email anyway ;) On the other hand, if you have questions or comments on the algorithm th then en I wo woul uld d very very mu much ch lik likee to hea hearr th them. em. Es Espec pecia iall lly y if yo you’ u’v ve spo spott tted ed an er erro rorr in th thee al algor gorit ithm hm or in my pres presen enta tati tion on of it it.. Su Such ch ques questi tions ons or comments can be sent to the email address that I’ve listed on the front page of this paper.

26

Appendix A Calculating the normal to a regular surface Again this will have to be a little quick and I cannot cover every detail becausee th becaus then en this wo woul uld d tu turn rn int intoo a ma math th tutor tutoria ial. l. Wh What at I tr try y to do is introduce exactly enough concepts for you to understand the important part of this section - the calculation of the tangent plane for a general regular surface. The answer lies in the theory of diﬀerential geometry of regular surfaces. I will not go into the deﬁnition of regular surfaces but think of them as certain “smooth” surfaces in 3d - like the surface of an ellipsoid or sphere. Ok, ﬁrst lets think about how a tangent plane is deﬁned. Most of you will have an intuitive understanding of what it is but not all have been introduced to a precise deﬁnition before. Lets go one dimension down and look at what we know about tangent tangentss in 2d. From sch school ool we kno know w tha thatt the tange tangent nt to a curve looks like in Figure A.1 and that it is calculated by diﬀerencing its function. In Figure A.1 the curve is in 2d but we could actually consider it as lying on a plane in 3d right? Namely the xy plane in R3 . What if I told you that we could have the curve lying on a regular surface like a sphere or ellipsoid! It would run over the surface and be parameterized by one single variable t. Thi Thiss is jus justt like in 2d where the curv curves es we kno know w are par paramet ameteri erized zed by a single variable x (we often consider a curve in 2d as a function f (x) = y , right?). To do that we will have to change the deﬁnition of the function for the curve but it would still be a function of one variable and we would know how to diﬀerentiate it. In 3d a curve is deﬁned by 3 functions, each one describing the value of one of the 3 coordinates given a parameter t. So if we call the curve A then its function becomes: 27

Figure A.1: The tangent to a curve in 2D

A(t) = (x(t), y (t), z (t))

(A.1)

and to diﬀerentiate it we diﬀerentiate its 3 coordinate functions, so: (A.2) OK, back to the task at hand - to determine the tangent plane of the regular surface. surface. Lik Likee described earlier to deﬁne a plane we’ll need tw twoo vectors lying on the plane as well as a point on it. We already hav havee the point because that’s the point on the surface we’re trying to get the tangent plane for, so what we need are the two vectors. Here is the trick: Say the point is called p. We make 2 distinct curves A and B running on the surface and both passing through p. Now if we diﬀerentiate both A a and nd B we’ll get two vectors A ( p) and B ( p). Those two vectors are both tangents to the surface and they span a plane - exactly the tangent plane! See Figure A.2 A(t) = (x(t), y (t), z (t))

28

Figure A.2: Two curves on the surface deﬁnes the tangent plane

Now the only problem is that we don’t have those two curves A and B . And there really is no easy way of ﬁnding two curves running though any point on a sphere or ellipsoid. It might seem we have a problem but ﬁrst lets take a look at how the equations for a sphere and an ellipsoid looks like: by y the points points ( ( x,y,z ) , where x 2 + y2 + z 2 = • A sphere of radius r is given b r2

vector (a,b,c) is given by the points points (x,y,z) , • An ellipsoid with radius vector y x z where a + b + c = 1. 2

2

2

2

2

2

That makes sense because if you insert a vector vector (r,r,r) in the equation for the ellipsoid you get exactly the equation for the sphere with radius r. Now we are saved by a theorem which says something about a totally diﬀerent thing than what we are looking for. Here is what it says:

29

Theorem 1 If a regular surface is given by S = {(x,y,z) | f(x,y,z) = a}, where f is a diﬀerentiable function from R3 into R and “a” is a constant,

regular value of f - then S is orientable. The formula we need is in the proof of this theorem but ﬁrst we have to makee sur mak suree our ellip ellipsoi soid d ﬁts the theo theorem remss req requir uiremen ements. ts. OK, we kno know w tha thatt an ellipsoi ellipsoid d is a regul regular ar surf surface. ace. What do we use as the functi function on ff?? We let y f (x,y,z ) = xa + b + zc and as described above our ellipsoid is exactly the set: A = { (x,y,z ) |f (x,y,z ) = 1}. From school we know that a function like f is diﬀerentiable and 1 sure is a cons constan tant. t. You’ ou’ll ll have have to trust me when I sa say y that 1 is a reg regula ularr val value ue of f. So, our ellips ellipsoid oid ﬁts the req requir uiremen ements ts of the theor theorem, em, so let letss look at the proof: 2

2

2

2

2

2

• Given any point p = (x0 , y0 , z 0) on the surface we consider any parameterized curve A (t) = (x(t), y (t), z (t)) passing )) passing through p for some value of t, say for t = t 0 . So A(t0 ) = p , right? • Because the curve lies on the surface we know that f (x(t), y (t), z (t)) = a, for all t. (Be (Becaus causee the theo theorem rem talk talkss about a surfac surfacee where for all points on it we have f ( p) = a ) • If we diﬀerentiate the expression f (x(t), y (t), z (t)) = a on both sides with respect to t, then for t = t 0 we get: ) + f z ( p)( dz ) + f y ( p)( dy )=0 f x( p)( dx dt dt dt , where dx,dy and dz all are evaluated at t0 .

• But this is the same as: (f x( p), f y( p), f z ( p)) · ( dx , dy , dz ) = 0 dt dt dt know ow abou aboutt th thee dot prod produc uct? t? We kn know ow tha thatt if the do dott • What do we kn product produ ct is 0 the then n the tw twoo vector vectorss are perpendi perpendicul cular ar to eac each h oth other. er. So we conclude that ( that ( f x( p), f y ( p), f z ( p)) )) is is perpendicular to ( to ( dx , dy , dz ) dt dt dt in particular. is ( dx tangentt vector to the curv curvee • But what is ( , dy , dz )? That is exactly the tangen dt dt dt A, and as it were evaluated at t = t 0 it is exactly the tangent vector to the curve at the point p! Thus it must lie on the tangent plane for the ellipsoid at the point p.

• As the above holds for any curve on the surface we conclude that (f x( p), f y ( p), f z ( p)) must )) must be perpendicular to any vector in the tangent plane, and thus it must be the normal to the tangent plane at p. 30

Cool, now we have exactly what we need! For any point point p on the ellipsoid we now know that the normal to the tangent plane is ( is ( f x( p), f y ( p), f z ( p)) )).. So in the case of an ellipsoid we just have to diﬀerentiate f (x,y,z) = 2

2

2

x a2

y b2

z c2

+

+

with respect to x,y and z. f x =

2x

2x

a

a2

+ 0 + 0 = 2

f y = 0 +

2 y

2y

b

b2

+ 0 = 2

f z = = 0 + 0 +

2z 2z = 2 2 c

c

(A.3)

(A.4)

(A.5)

Voila, what you got is a general normal-function which looks like this: N (x,y,z) = (

2x 2 y 2z , 2 , 2 ) 2 a

b

c

(A.6)

where (x,y,z) is a point on the sphere/ellipsoid and (a,b,c) is the radius vector. You can then normalize the result if you want. As a last interesting point we can now see why the calculations can be simpli sim pliﬁed ﬁed in the case of a uni unitt sphere sphere.. A unit sphere is reall really y an ellip ellipsoi soid d wi with th a radi radius us vect vector or (1,1 (1,1,1 ,1). ). So th thee gener general al for formu mula la can be simp simpli liﬁed ﬁed so given any point on a unit sphere the normal to the tangent plane becomes: just 2( x,y,z ) . What is the length N (x,y,z ) = (2x, 2y, 2z ). But that is really just 2( of that? Well, as as (x,y,z) is on the unit sphere we know that (x,y,z ) = 1 so the length of 2(x,y,z ) mu must st be 2. We wa want nt to normal normalize ize the normal normal,, so we divide each vector component by the length and get that the normalized normal is is ( 22x , 22y , 22z ) = (x,y,z) . So the normal to the tangent plane for a unit sphere at the point p is the point itself, so if we reverse it (which will only aﬀect which side of the plane is front) then we have that al normals to the sphere go from the point all l normals on the sphere to the center center of the sphe sphere. re. That is exact exactly ly what we used in section 4.1 to ﬁnd the sliding plane.

31

Appendix B The plane class Below is the PLANE class that I use my collision detection code:

cl clas ass s PL PLAN ANE E { public: float floa t equation[4 equation[4]; ]; VECTOR VECT OR origin; origin; VECTOR VECT OR normal; normal; PLANE(const PLANE(co nst VECTOR& VECTOR& origin, origin, const const VECTOR& VECTOR& normal); normal); PLANE( PLA NE(con const st VECTOR VECTOR& & p1, const const VECTOR VECTOR& & p2, const const VECTOR VECTOR& & p3); p3); bool isFrontFa isFrontFacingT cingTo(con o(const st VECTOR& VECTOR& direction) direction) const; const; double doub le signedDis signedDistance tanceTo(co To(const nst VECTOR& VECTOR& point) point) const; const; }; PLANE::PLANE(c PLANE::PLA NE(const onst VECTOR& VECTOR& origin, origin, const const VECTOR& VECTOR& normal) normal) { this->no this ->normal rmal = normal; normal; this->or this ->origin igin = origin; origin; equation equa tion[0] [0] = normal.x; normal.x; equation equa tion[1] [1] = normal.y; normal.y; equation equa tion[2] [2] = normal.z; normal.z; equation[3] = -(normal.x*origin.x+normal.y*or -(normal.x*origin.x+normal.y*origin.y igin.y +normal.z*origin.z); } // Constr Construct uct from from triang triangle: le: PLANE::PLA PLANE ::PLANE(c NE(const onst VECTOR& VECTOR& p1,const p1,const VECTOR& VECTOR& p2,

32

const con st VECTOR VECTOR& & p3) { normal norm al = (p2-p1).cr (p2-p1).cross(p oss(p3-p1) 3-p1); ; normal.normalize(); or orig igin in = p1 p1; ; equation[0] equation [0] equation equa tion[1] [1] equation equa tion[2] [2] equation[3]

= = = =

normal.x; normal.x; normal.y; normal.y; normal.z; normal.z; -(normal.x*origin.x+normal.y*or -(normal.x*origin.x+normal.y*origin.y igin.y +normal.z*origin.z);

}

bool PLANE::isF PLANE::isFront rontFaci FacingTo( ngTo(cons const t VECTOR& VECTOR& direction) direction) const const { double doub le dot = normal.d normal.dot(di ot(direct rection) ion); ; }

re retu turn rn (d (dot ot <= 0) 0); ;

double PLANE::si double PLANE::signedD gnedDistan istanceTo( ceTo(const const VECTOR& VECTOR& point) point) const { return retu rn (point.do (point.dot(nor t(normal)) mal)) + equation[3 equation[3]; ]; }

33

Appendix C Utility functions Below is a function that determines if a point is inside a triangle or not. This is used in the collision detectio detection n step. Thanks to Keidy from Mr-Gamemak Mr-Gamemaker er who posted this particular version of the function in a little competition we held about who could post the fastest one. typedef typede f unsign unsigned ed int uint32 uint32; ; #defin #de fine e in(a) in(a) ((uint ((uint32& 32&) ) a) bool checkPoint checkPointInTr InTriang iangle(co le(const nst VECTOR& VECTOR& point, point, const con st VECTOR VECTOR& & pa,con pa,const st VECTOR VECTOR& & pb, const const VECTOR VECTOR& & pc) { VECTOR e10=pb-pa VECTOR e10=pb-pa; ; VECTOR VECT OR e20=pc-pa e20=pc-pa; ; float a = e10.do float e10.dot(e t(e10) 10); ; float flo at b = e10.do e10.dot(e t(e20) 20); ; float flo at c = e20.do e20.dot(e t(e20) 20); ; float ac_bb=(a*c)-(b*b); ac_bb=(a*c)-(b*b); VECTOR VECT OR vp(point. vp(point.x-pa. x-pa.x, x, point.y-pa point.y-pa.y, .y, point.z-p point.z-pa.z); a.z); float float float flo at float flo at float flo at float flo at

d e x y z

= = = = =

vp.dot vp.dot(e1 (e10); 0); vp.dot vp.dot(e2 (e20); 0); (d*c)(d*c)-(e* (e*b); b); (e*a)(e*a)-(d* (d*b); b); x+y-ac x+y-ac_bb _bb; ;

return ret urn (( in(z)& in(z)& ~(in(x ~(in(x)|i )|in(y n(y)) )) ) & 0x8000 0x8000000 0000); 0); }

34

Appendix D Solving quadratic equations Below is a snippet of code that solves a quadratic equation and returns the lowest root, below a certain treshold (the maxR parameter): bool boo l getLow getLowest estRoo Root(f t(floa loat t a, float flo float c, float float maxR, maxR, float* flo at* root) roo t)at { b, float // Ch Chec eck k if a so solu luti tion on ex exis ists ts float flo at determ determina inant nt = b*b - 4.0f*a 4.0f*a*c; *c; // If determ determina inant nt is negati negative ve it means means no soluti solutions ons. . if (deter (determin minant ant < 0.0f) 0.0f) return return false; false; // ca calc lcul ulat ate e th the e tw two o ro root ots: s: (i (if f de dete term rmin inan ant t == 0 th then en // x1==x2 x1==x2 but let’s let’s disreg disregard ard that that slight slight optimi optimizat zation ion) ) float floa t sqrtD = sqrt(deter sqrt(determinan minant); t); floa float t r1 = (-b (-b - sqrt sqrtD) D) / (2*a (2*a); ); floa float t r2 = (-b (-b + sqrt sqrtD) D) / (2*a (2*a); ); // Sort so x1 <= x2 if (r1 > r2) { fl floa oat t te temp mp = r2 r2; ; r2 = r1; r1 = temp temp; ; } // Ge Get t lo lowe west st ro root ot: : if (r1 > 0 && r1 < maxR) { *r *roo oot t = r1 r1; ; return retu rn true;

35

} // It is poss possib ible le that that we want want x2 - this this can can happ happen en // if x1 < 0 if (r2 > 0 && r2 < maxR) { *r *roo oot t = r2 r2; ; return retu rn true; } // No (valid (valid) ) soluti solutions ons return retu rn false; false; }

36

Appendix E Code for collision step Below is a source listing of the whole “triangle vs. moving sphere” procedure I dis discuss cussed ed in Chap Chapter ter 3. Dat Dataa about the mov movee is commi comming ng in thr through ough the “CollisionPacket” “CollisionPack et” and this is also where we put the result of the check against the triangl triangle. e. I appol appologiz ogizee for the forma formatti tting ng but I rea really lly had to comp compres resss things to make them ﬁt into a rather narrow LaTex page. First the structure I use to pass in information about the move and in which I store the result of the collision tests: class Collision CollisionPack Packet et { public: VECTOR VEC TOR eRadiu eRadius; s; // ellipso ellipsoid id radius radius // Inform Informati ation on about about the move move being being reques requested ted: : (in R3) VECTOR VECT OR R3Velocit R3Velocity; y; VECTOR VECT OR R3Positio R3Position; n; // Inform Informati ation on about about the move move being being reques requested ted: : (in eSpace eSpace) ) VECTOR velocity; VECTOR velocity; VECTOR normalizedVelocity; normalizedVelocity; VECTOR VECT OR basePoint basePoint; ; // Hit inform informati ation on bool foundCollision; foundCollision; double nearestDistance; nearestDistance; VECTOR intersectionPoint; intersectionPoint; };

And below a function that’ll check a single triangle for collision: 37

// As Assu sume mes: s: p1 p1,p ,p2 2 an and d p3 ar are e gi give ven n in el elli liso soid id sp spac ace: e: void checkTriangle(CollisionPacket* checkTriangle(CollisionPacket* colPackage, const con st VECTOR VECTOR& & p1,con p1,const st VECTOR VECTOR& & p2,con p2,const st VECTOR VECTOR& & p3) { // Make Make the plane plane contai containin ning g this this triang triangle. le. PLANE trianglePlane(p1,p2,p3); trianglePlane(p1,p2,p3); // // // if

Is triang triangle le frontfront-fac facing ing to the veloci velocity ty vector vector? ? We only only check check frontfront-fac facing ing triang triangles les (your (your choice choice of course course) ) (trianglePlane.isFrontFacingTo( (trianglePlane.isFrontFacingTo( colPackage->normalizedVelocity colPackage->no rmalizedVelocity)) )) {

// Get interv interval al of plane plane inters intersect ection ion: : double dou ble t0, t1; bool embeddedI embeddedInPlan nPlane e = false; false; // Calcul Calculate ate the signed signed distan distance ce from from sphere sphere // positi position on to triang triangle le plane plane double doub le signedDist signedDistToTri ToTriangle anglePlane Plane = trianglePlane.signedDistanceTo trianglePlane. signedDistanceTo(colPackage->bas (colPackage->basePoint); ePoint); // cach cache e this this as we’r we’re e goin going g to use use it a few few time times s belo below: w: float floa t normalDot normalDotVelo Velocity city = trianglePlane.normal.dot(colP trianglePlane. normal.dot(colPackage->velocity ackage->velocity); ); // if sp sphe here re is tr trav avel elli ling ng pa parr rral alle lel l to th the e pl plan ane: e: if (norma (normalDo lDotVe tVeloc locity ity == 0.0f) 0.0f) { if (fabs(sig (fabs(signedDi nedDistTo stToTria TriangleP nglePlane lane) ) >= 1.0f) { // Sp Sphe here re is no not t em embe bedd dded ed in pl plan ane. e. // No collis collision ion possib possible: le: return; } el else se { // sp sphe here re is em embe bedd dded ed in pl plan ane. e. // It in inte ters rsec ects ts in th the e wh whol ole e ra rang nge e [0 [0.. ..1] 1] embeddedIn embed dedInPlane Plane = true; t0 = 0.0; t1 = 1.0; }

38

} el else se { // N do dot t D is no not t 0. Ca Calc lcul ulat ate e in inte ters rsec ecti tion on in inte terv rval al: : t0=(-1.0-signedDistToTrianglePlane)/normalDotV t0=(-1.0-signedDistToTrianglePl ane)/normalDotVelocity; elocity; t1=( 1.0-signedDistToTrianglePlane)/ 1.0-signedDistToTrianglePlane)/normalDotVeloci normalDotVelocity; ty; // Swap so t0 < t1 if (t0 > t1) { do doub uble le te temp mp = t1 t1; ; t1 = t0; t0 = temp temp; ; } // Ch Chec eck k th that at at le leas ast t on one e re resu sult lt is wi with thin in ra rang nge: e: if (t0 > 1.0f || t1 < 0.0f) { // Bo Both th t va valu lues es ar are e ou outs tsid ide e va valu lues es [0 [0,1 ,1] ] // No collis collision ion possib possible: le: return; } // if if if if

Cl Clam amp p (t0 < (t1 < (t0 > (t1 >

to [0 [0,1 ,1] ] 0.0) t0 = 0.0) t1 = 1.0) t0 = 1.0) t1 =

0.0; 0.0; 1.0; 1.0;

}

// OK, OK, at this this poin point t we have have two two time time valu values es t0 and and t1 // betwee between n which which the swept swept sphere sphere inters intersect ects s with with the // tr tria iang ngle le pl plan ane. e. If an any y co coll llis isio ion n is to oc occu cur r it mu must st // happen happen within within this this interv interval. al. VECTOR collisionPoint; bool boo l foundC foundColl olliso ison n = false; false; floa float t t = 1.0; 1.0; // // // // //

Fi Firs rst t we ch chec eck k fo for r th the e ea easy sy ca case se - co coll llis isio ion n in insi side de th the e tr tria iang ngle le. . If th this is ha happ ppen ens s it mu must st be at ti time me t0 as this this is when when the the sphe sphere re rest rests s on the the fron front t side side of th the e tr tria iang ngle le pl plan ane. e. No Note te, , th this is ca can n on only ly ha happ ppen en if th the e sp sphe here re is no not t em embe bedd dded ed in th the e tr tria iang ngle le pl plan ane. e.

39

if (!embedde (!embeddedInPl dInPlane) ane) { VECTOR VECTO R planeInter planeIntersect sectionP ionPoint oint = (colPackage->basePoint-triangl (colPackage->b asePoint-trianglePlane.normal) ePlane.normal) + t0*colPackage->velocity; t0*colPackage->velocity; if (checkPointInTriangle(planeInt (checkPointInTriangle(planeIntersectionPoint, ersectionPoint, p1,p2,p3)) { foundColli found Collison son = true; t = t0; collisionPoint = planeIntersectionPoint; planeIntersectionPoint; } } // if we ha have ven’ n’t t fo foun und d a co coll llis isio ion n al alre read ady y we we’l ’ll l ha have ve to // sw swee eep p sp sphe here re ag agai ains nst t po poin ints ts an and d ed edge ges s of the tr tria iang ngle le. . // Note: Note: A collis collision ion inside inside the triang triangle le (the (the check check above) above) // wi will ll al alwa ways ys ha happ ppen en be befo fore re a ve vert rtex ex or ed edge ge co coll llis isio ion! n! // This This is why why we can can skip skip the the swep swept t test test if the the abov above e // gives gives a collis collision ion! ! if (found (foundCol Collis lison on == false) false) { // some some common commonly ly used used terms: terms: VECTOR VECTO R velocity velocity = colPackage colPackage->vel ->velocity ocity; ; VECTOR VECTO R base = colPackag colPackage->ba e->basePoi sePoint; nt; float velocitySquaredLength = velocity.squaredLength(); velocity.squaredLength(); float flo at a,b,c; a,b,c; // Params Params for equati equation on float newT; newT; // // // //

Fo For r ea each ch ve vert rtex ex or ed edge ge a qu quad adra rati tic c eq equa uati tion on ha have ve to be solved solved. . We parame parameter terize ize this this equati equation on as a*t^2 + b*t + c = 0 and below we calculate the pa para rame mete ters rs a, a,b b an and d c fo for r ea each ch te test st. .

// Check Check agains against t points points: : a = velocityS velocitySquar quaredLen edLength; gth; // P1 b = 2.0*(velo 2.0*(velocity city.dot( .dot(base base-p1) -p1)); ); c = (p1-ba (p1-base) se).sq .squar uaredL edLeng ength( th() ) - 1.0; 1.0; if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { t = newT;

40

foundCollison foundColli son = true; collisionP colli sionPoint oint = p1; } // P2 b = 2.0*(velo 2.0*(velocity city.dot( .dot(base base-p2) -p2)); ); c = (p2-ba (p2-base) se).sq .squar uaredL edLeng ength( th() ) - 1.0; 1.0; if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { t = newT; foundColli found Collison son = true; collisionP colli sionPoint oint = p2; } // P3 b = 2.0*(velo 2.0*(velocity city.dot( .dot(base base-p3) -p3)); ); c = (p3-ba (p3-base) se).sq .squar uaredL edLeng ength( th() ) - 1.0; 1.0; if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { t = newT; foundColli found Collison son = true; collisionP colli sionPoint oint = p3; }

// Check Check agains agains edges: edges: // p1 -> p2: VE VECT CTOR OR ed edge ge = p2 p2-p -p1; 1; VE VECT CTOR OR ba base seTo ToVe Vert rtex ex = p1 - ba base se; ; float edgeSquar edgeSquaredLen edLength gth = edge.squar edge.squaredLen edLength() gth(); ; float edgeDotVe edgeDotVelocit locity y = edge.dot( edge.dot(veloc velocity); ity); float edgeDotBa edgeDotBaseToV seToVertex ertex = edge.dot(b edge.dot(baseTo aseToVert Vertex); ex); // Calcul Calculate ate parame parameter ters s for equati equation on a = edgeSquar edgeSquaredLe edLength* ngth*-vel -velocit ocitySqua ySquaredL redLengt ength h + edgeDotVelocity*edgeDotVelocity; b = edgeSquaredLength*(2*velocity.do edgeSquaredLength*(2*velocity.dot(baseToVertex) t(baseToVertex)))2.0*edgeDotVelocity*edgeDotBaseToVertex; c = edgeSquaredLength*(1-baseToVerte edgeSquaredLength*(1-baseToVertex.squaredLength x.squaredLength())+ ())+ edgeDotBaseToVertex*edgeDotBaseToVertex; // Does Does the swept swept sphere sphere collid collide e agains against t infini infinite te edge? edge?

41

if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { // Check Check if inters intersect ection ion is within within line line segmen segment: t: float f=(edgeDotVelocity*newT-edgeDo f=(edgeDotVelocity*newT-edgeDotBaseToVertex)/ tBaseToVertex)/ edgeSquaredLength; if (f >= 0.0 && f <= 1.0) { // inters intersect ection ion took took place place within within segmen segment. t. t = newT; foundCol foun dCollison lison = true; collis col lision ionPoi Point nt = p1 + f*edge f*edge; ; } } // p2 -> p3: ed edge ge = p3 p3-p -p2; 2; ba base seTo ToVe Vert rtex ex = p2 - ba base se; ; edgeSquaredLength edgeSquaredLeng th = edge.squaredLength(); edge.squaredLength(); edgeDotVelocity = edge.dot(velocity); edge.dot(velocity); edgeDotBaseToVertex edgeDotBaseToVe rtex = edge.dot(baseToVertex); edge.dot(baseToVertex); a = edgeSquar edgeSquaredLe edLength* ngth*-vel -velocit ocitySqua ySquaredL redLengt ength h + edgeDotVelocity*edgeDotVelocity; b = edgeSquaredLength*(2*velocity.do edgeSquaredLength*(2*velocity.dot(baseToVertex) t(baseToVertex)))2.0*edgeDotVelocity*edgeDotBaseToVertex; c = edgeSquaredLength*(1-baseToVerte edgeSquaredLength*(1-baseToVertex.squaredLength x.squaredLength())+ ())+ edgeDotBaseToVertex*edgeDotBaseToVertex; if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { float f=(edgeDotVelocity*newT-edgeDo f=(edgeDotVelocity*newT-edgeDotBaseToVertex)/ tBaseToVertex)/ edgeSquaredLength; if (f >= 0.0 && f <= 1.0) { t = newT; foundCol foun dCollison lison = true; collis col lision ionPoi Point nt = p2 + f*edge f*edge; ; } } // p3 -> p1: ed edge ge = p1 p1-p -p3; 3; ba base seTo ToVe Vert rtex ex = p3 - ba base se; ; edgeSquaredLength edgeSquaredLeng th = edge.squaredLength(); edge.squaredLength(); edgeDotVelocity = edge.dot(velocity); edge.dot(velocity);

42

edgeDotBaseToVertex edgeDotBaseToVe rtex = edge.dot(baseToVertex); edge.dot(baseToVertex); a = edgeSquar edgeSquaredLe edLength* ngth*-vel -velocit ocitySqua ySquaredL redLengt ength h + edgeDotVelocity*edgeDotVelocity; b = edgeSquaredLength*(2*velocity.do edgeSquaredLength*(2*velocity.dot(baseToVertex) t(baseToVertex)))2.0*edgeDotVelocity*edgeDotBaseToVertex; c = edgeSquaredLength*(1-baseToVerte edgeSquaredLength*(1-baseToVertex.squaredLength x.squaredLength())+ ())+ edgeDotBaseToVertex*edgeDotBaseToVertex; if (getLowes (getLowestRoot tRoot(a,b (a,b,c, ,c, t, &newT)) &newT)) { float f=(edgeDotVelocity*newT-edgeDo f=(edgeDotVelocity*newT-edgeDotBaseToVertex)/ tBaseToVertex)/ edgeSquaredLength; if (f >= 0.0 && f <= 1.0) { t = newT; foundCol foun dCollison lison = true; collis col lision ionPoi Point nt = p3 + f*edge f*edge; ; } } }

// Set result result: : if (found (foundCol Collis lison on == true) true) { // di dist stan ance ce to co coll llis isio ion: n: ’t ’t’ ’ is ti time me of co coll llis isio ion n float distToCollision = t*colPackage->velocity.length( t*colPackage->velocity.length(); ); // Do Does es th this is tr tria iang ngle le qu qual alif ify y fo for r th the e cl clos oses est t hi hit? t? // it does does if it’s it’s the the firs first t hit hit or the the clos closes est t if (colPacka (colPackage->f ge->found oundColl Collision ision == false false || distToCo dist ToCollisi llision on < colPackag colPackage->ne e->nearest arestDista Distance) nce) // Collision Collision informatio information n nessesary nessesary for sliding sliding colPackage->nearestDistance colPackage->near estDistance = distToCollision; distToCollision; colPackage->intersectionPoint=c colPackage->inte rsectionPoint=collisionPoint; ollisionPoint; colPackage colPa ckage->fou ->foundCo ndCollisi llision on = true; } } } // if not not back backfa face ce }

43

{

Appendix F Code for response step Below is a source listing for the response step. You will have to tweak this to match your own needs - this lising is just for inspiration. The application calls the “collideA “collideAndSl ndSlide ide”” wit with h veloci velocity ty and gra gravit vity y inp input ut in R3. The functi function on converts this input to eSpace and calls the actual recursive collision and response function “collideWith “collideWithWorld” orld”.. Finall Finally y it convert convertss the result back to R3 and updates the character position. void CharacterE CharacterEntit ntity::c y::collid ollideAnd eAndSlide Slide(cons (const t VECTOR& VECTOR& vel, const cons t VECTOR& VECTOR& gravity) gravity) { // Do collis collision ion detect detection ion: : collisionPackage->R3Position collisionPacka ge->R3Position = position; collisio coll isionPack nPackageage->R3V >R3Veloci elocity ty = vel; // calcul calculate ate positi position on and veloci velocity ty in eSpace eSpace VECTOR VECT OR eSpacePos eSpacePosition ition = collisionP collisionPackag ackage->R e->R3Pos 3Position ition/ / collisionPackage->eRadius; VECTOR VECT OR eSpaceVel eSpaceVelocity ocity = collisionP collisionPackag ackage->R e->R3Vel 3Velocity ocity/ / collisionPackage->eRadius; // It Iter erat ate e un unti til l we ha have ve ou our r fi fina nal l po posi siti tion on. . collisio coll isionRecu nRecursio rsionDep nDepth th = 0; VECTOR finalPosition = collideWithWorld(eSpacePositio collideWithWorld(eSpacePosition, n, eSpaceVelocity);

// Add gravit gravity y pull: pull:

44

// To remove remove gravit gravity y uncomm uncomment ent from from here here ..... ..... // Se Set t th the e ne new w R3 po posi siti tion on (c (con onve vert rt ba back ck fr from om eS eSpa pace ce to R3 collisionPackage->R3Position collisionPacka ge->R3Position = finalPosition*collisionPackage->eRadius; collisionPackage->R3Velocity collisionPacka ge->R3Velocity = gravity; eSpaceVelocity = gravity/collisionPackage->eRadi gravity/collisionPackage->eRadius; us; collisio coll isionRecu nRecursio rsionDep nDepth th = 0; finalPosition = collideWithWorld(finalPosition, collideWithWorld(finalPosition, eSpaceVelocity); // ... to here here

// Co Conv nver ert t fi fina nal l re resu sult lt ba back ck to R3 R3: : finalPosition = finalPosition*collisionPackage-> finalPosition*collisionPackage->eRadius; eRadius; // Move Move the entity entity (appli (applicat cation ion specif specific ic functi function) on) MoveTo(finalPosition); }

// Set this this to match match applic applicati ation on scale. scale.. . const con st float float unitsP unitsPerM erMete eter r = 100.0f 100.0f; ; VECTOR CharacterEntity::collideWithWo CharacterEntity::collideWithWorld(const rld(const VECTOR& pos, const con st VECTOR VECTOR& & vel) vel) { // All hard-c hard-code oded d distan distances ces in this this functi function on is // sc scal aled ed to fi fit t th the e se sett ttin ing g ab abov ove. e.. . float flo at unitSc unitScale ale = unitsP unitsPerM erMete eter r / 100.0f 100.0f; ; float flo at veryCl veryClose oseDis Distan tance ce = 0.005f 0.005f * unitSc unitScale ale; ; // do we need need to worr worry? y? if (collisionRecursionDepth>5) (collisionRecursionDepth>5) return retu rn pos; // Ok, Ok, we need need to worr worry: y: collisio coll isionPack nPackageage->vel >velocity ocity = vel;

45

collisionPackage->normalizedVelocity collisionPackage->normalizedV elocity = vel; collisionPackage->normalizedV collisionPacka ge->normalizedVelocity.normaliz elocity.normalize(); e(); collisio coll isionPack nPackageage->bas >basePoin ePoint t = pos; collisionPackage->foundCollis collisionPacka ge->foundCollision ion = false; // Check Check for collis collision ion (calls (calls the collis collision ion routin routines) es) // Applicatio Application n specific! specific!! ! world->checkCollision(collisionPackage); // If no co coll llis isio ion n we ju just st mo move ve al alon ong g th the e ve velo loci city ty if (collision (collisionPack Packageage->foun >foundCol dCollisi lision on == false) false) { re retu turn rn po pos s + ve vel; l; }

// *** Collis Collision ion occure occured d *** // The origin original al destin destinati ation on point point VECTOR VEC TOR destin destinati ationP onPoin oint t = pos + vel; vel; VECTOR VEC TOR newBas newBasePo ePoint int = pos; pos; // on only ly up upda date te if we ar are e no not t al alre read ady y ve very ry cl clos ose e // an and d if so we on only ly mo move ve ve very ry cl clos ose e to in inte ters rsec ecti tion on.. ..no not t // to th the e ex exac act t sp spot ot. . if (collisionPackage->nearestDista (collisionPackage->nearestDistance>=veryCloseDi nce>=veryCloseDistance) stance) { VECT VECTOR OR V = vel; vel; V.SetLength(collisionPackage-> V.SetLength(co llisionPackage->nearestDistancenearestDistanceveryCloseDistance); newBasePo newB asePoint int = collision collisionPack Packageage->base >basePoin Point t + V; // Adjust Adjust polygo polygon n inters intersect ection ion point point (so slidin sliding g // pl plan ane e wi will ll be un unaf affe fect cted ed by th the e fa fact ct th that at we // move move slight slightly ly less less than than collis collision ion tells tells us) V.normalize(); collisionPackage->intersection collisionPacka ge->intersectionPoint Point -= veryClose very CloseDist Distance ance * V; } // Determ Determine ine the slidin sliding g plane plane VECTOR VECT OR slidePlan slidePlaneOrig eOrigin in =

46

collisionPackage->intersectionPoint; VECTOR slidePlan VECTOR slidePlaneNorm eNormal al = newBasePoint-collisionPackagenewBasePoint-co llisionPackage->intersectionPoi >intersectionPoint; nt; slidePlaneNormal.normalize(); PLANE slidingPlane(slidePlaneOrigin,s slidingPlane(slidePlaneOrigin,slidePlaneNormal) lidePlaneNormal); ; // Again, Again, sorry sorry about about format formattin ting.. g.. but look look carefu carefully lly ;) VECTOR VECT OR newDestin newDestination ationPoint Point = destinatio destinationPoi nPoint nt slidingPlane.signedDistanceTo slidingPlane.s ignedDistanceTo(destinationPoin (destinationPoint)* t)* slidePlaneNormal;

// Ge Gene nera rate te th the e sl slid ide e ve vect ctor or, , wh whic ich h wi will ll be beco come me ou our r ne new w // veloci velocity ty vector vector for the next next iterat iteration ion VECTOR VECT OR newVeloci newVelocityVec tyVector tor = newDestina newDestinationP tionPoint oint collisionPackage->intersectionPoint;

// Recurse: Recurse: // do dont nt re recu curs rse e if th the e ne new w ve velo loci city ty is ve very ry sm smal all l if (newVeloci (newVelocityVe tyVector ctor.leng .length() th() < veryClose veryCloseDista Distance) nce) { return newBasePoint; } collisionRecursionDepth++; return collideWithWorld(newBasePoint, collideWithWorld(newBasePoint,newVelocityVecto newVelocityVector); r); }

47

Bibliography [F [Fau00] au00] Kasper F Fauerb auerby y. Pxdtu Pxdtut10: t10: Colli Collision sion detect detection ion and response. 2000. [Net00]] Pau [Net00 Paull Nettle. Generi Genericc collisi collision on detection for game gamess using ellipsoids. ellipsoids. 2000. [Rou03] Jorr Jorrit it Rouwé. Colli Collision sion detectio detection n with swept spher spheres es and ellips ellipsoids. oids. 2003.

48