Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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):

aide view of the problem

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 vec3s

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

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

3 Answers 3

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.

iterative solver over 3 iterations

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.

share|improve this answer
    
thank you for nice solution. Its easy to understand. If I couldn't find other way, I would try it. –  yomotsu Jul 16 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 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.

share|improve this answer
    
Thanks! That's a great hint! I also think, a geometric solution should exist... –  yomotsu Jul 16 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 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
point1.copy( normal ).multiplyScalar( -this.radius ).add( this.position );
// 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 );
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.