# How do I resolve a sphere-triangle collision in a given direction?

I am trying my hand at game physics.

I understand that the basic way to pull back a sphere when it collided is to negate the penetration distance:

``````// If collided...
// `distance`: distance form triangle face; a negative number
// `normal`  : triangle face, in vec3
// `position`: sphere center, in vec3
position.x -= normal.x * distance;
position.y -= normal.y * distance;
position.z -= normal.z * distance;
``````

But I don't want to change y coordinate, while the player is on the ground like this (side view):

How can I calculate the expected translation?

I have these values:

• penetration distance, as a negative number (shown in blue)
• triangle face normal, as a `vec3` (shown in red)
• triangle vertices, as 3 `vec3`s

and

• sphere radius, as a number
• sphere center, as a `vec3`

Answers in any programing language are welcome!

updated Jul 17, 2014

I found a hint. It's difficult to explain, I will attach 2 more figures.
It seems, dashed lines in following figures are the translation value what I need, I guess.

and in another case

-
GameDevへようこそ！ Nice first question! The picture is very helpful. Feel free to edit more if my clarifications missed something. – Anko Jul 15 '14 at 10:24
Anko-san, Thankyou for your editing, to be better :) – yomotsu Jul 16 '14 at 18:22

What you have here are two constraints that need to be resolved. On one hand, you need the sphere to stay outside the wall, by pushing it along the normal. On the other hand, you have the constraint that the sphere needs to stay attached to the ground.

If you don't want to try writing fancy solvers, the easiest way to do this is to use an iterative solver.

Essentially, you resolve the position of the sphere by applying the force away from the wall, including the y component. Then you apply the other constraint, and set the y to the correct value to stay on the ground. Now the sphere will intersect the wall again, so you push it away again, place it on the ground again, and so on. It's customary to make the number of iterations configurable, as it will be a tradeoff between performance and correctness.

By the way, I see that you are modifying the position directly in your code. Physics engines typically work with forces, so that if the ball hits the wall it will bounce away. With your code, it will get pushed out but then stay there. That said, if you're working on a character controller, then this approach might work, unless you want to model inertia.

-
thank you for nice solution. Its easy to understand. If I couldn't find other way, I would try it. – yomotsu Jul 16 '14 at 19:20
actually the `work with forces` part is true of simulations that are said to use impulses or split impulses if I'm not mistaken. But since they must be delta_time aware because an impulse is made to be a one-time application to fix a velocity, this is equivalent to a direct position fixing, which I don't find necessarily dirty, as the advocates of impulse based solution would. I say just do your soup, physics IS soup anyway. truely. I personally have build a code that does your exact problem, it has a mini 1-contact iterative solver but I ended up de-activating it, to do just 1 iteration. – v.oddou Jul 17 '14 at 5:56

In case you're looking for a pure geometric solution and not a physics one, i.e. you're not using gravity so that the ball falls down basically on an inclined plane, then I suggest you look at it as finding the position of the center after the collision so that the ball is tangent to both the wall and the ground. Unfortunately I cannot make a fancy drawing, but from my own scribbling on paper I get something like this in 2D: C.x = P.x - r * tan(theta/2) where C is the centre, r is the radius, P is the intersection point between the wall and the ground and theta is the angle between the wall and the ground (you can get it I think with a dot product between the normal and the y axis). I'm sure you can get a similar result for a sphere and two planes in 3D.

-
Thanks! That's a great hint! I also think, a geometric solution should exist... – yomotsu Jul 16 '14 at 19:03
well, while I understand the attractivity of this solution, I think yomotsu, you are trying too much to absolutely stick to the ground. What you are trying to do, is plane-hoovering (navigational-mesh-roaming) and NOT physics simulation. Try to imagine that lifting your sphere may be totally acceptable ! because of inertia, running into an inclined wall is SUPPOSED to make you fly a little bit, next simulation frames are going to re-apply gravity to make you fall back on the ground anyway. You can just accept it like that. – v.oddou Jul 17 '14 at 5:59

Finally, I found the geometric solution!

I will share the code in JavaScript with three.js which is a 3d library, provides math stuff to JavaScript.

``````var face      = contactInfo.face,
normal    = contactInfo.normal,
distance  = contactInfo.distance,
point1    = new THREE.Vector3(),
point2    = new THREE.Vector3(),
direction = new THREE.Vector3(),
plainD,
t,
translate = new THREE.Vector3();

// find point1 using nomal, radius and center position of the sphere
// find horizontal directon from point1 to the wall face
direction.set( normal.x, 0, normal.z ).normalize();
// get plain "d" of the wall face
plainD = face.a.dot( normal );
// t is the Paramater of line which is from point1 to wall face
t = ( plainD - ( normal.x * point1.x + normal.y * point1.y + normal.z * point1.z ) ) / ( normal.x * direction.x + normal.y * direction.y + normal.z * direction.z );
// find point2 on wall face
point2.copy( direction ).multiplyScalar( t ).add( point1 );
// point2 - point1 is the valuse what i needed
translate.subVectors( point2, point1 );
``````
-

I know it's a long time since this thread was active, but if anyone was curious, I think I've got another and quite simple solution.

Since you can calculate the angle (alpha) between the wall and ground by dot product the normal vector of plane and normal vector of ground, you can then calculate beta angle as you can see in the picture:

When you know the distance (d), you can use sin rule and calculate your translation (p). Hopefully this will help someone :)

-