5
\$\begingroup\$

I'm working on a basic collision detection system that provides point - OBB collision detection. I have around 200 cubes in my environment and I check (for now) each of them in turn and see if it collides. If it does I return the colliding face's normal, save the old player position and do some trigonometry to return a new player position for my wall sliding.

edit
I'll define my meaning of wall sliding: If a player walks in a vertical slope and has a slight horizontal rotation to the left or the right and keeps walking forward in the wall the player should slide a little to the right/left while continually walking towards the wall till he left the wall. Thus, sliding along the wall.

Everything works fine and with multiple objects as well but I still have one problem I can't seem to figure out: smooth wall sliding. In my current implementation sliding along the walls make my player bounce like a mad man (especially noticable with gravity on and moving forward).

I have a velocity/direction vector, a normal vector from the collided plane and an old and new player position. First I negate the normal vector and get my new velocity vector by substracting the inverted normal from my direction vector (which is the vector to slide along the wall) and I add this vector to my new Player position and recalculate the direction vector (in case I have multiple collisions).

I know I am missing some step but I can't seem to figure it out.

Here is my code for the collision detection (run every frame):

Vector direction;
Vector newPos(camera.GetOriginX(), camera.GetOriginY(), camera.GetOriginZ());
direction = newPos - oldPos; // Direction vector
// Check for collision with new position
for(int i = 0; i < NUM_OBJECTS; i++)
{
    Vector normal = objects[i].CheckCollision(newPos.x, newPos.y, newPos.z, direction.x, direction.y, direction.z);
    if(normal != Vector::NullVector())
    {
        // Get inverse normal (direction STRAIGHT INTO wall)
        Vector invNormal = normal.Negative();
        Vector wallDir = direction - invNormal; // We know INTO wall, and DIRECTION to wall. Substract these and you got slide WALL direction
        newPos = oldPos + wallDir;
        direction = newPos - oldPos;
    }
}

Any help would be greatly appreciated!


FIX I eventually got things up and running how they should thanks to Krazy, I'll post the updated code listing in case someone else comes upon this problem!

for(int i = 0; i < NUM_OBJECTS; i++)
{
    Vector normal = objects[i].CheckCollision(newPos.x, newPos.y, newPos.z, direction.x, direction.y, direction.z);
    if(normal != Vector::NullVector())
    {
        Vector invNormal = normal.Negative();
        invNormal = invNormal * (direction * normal).Length(); // Change normal to direction's length and normal's axis
        Vector wallDir = direction - invNormal;
        newPos = oldPos + wallDir;
        direction = newPos - oldPos;
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ What is "wall sliding"? Should you stop moving as you hit a wall and fall straight downward? Should you be able to slide up walls? \$\endgroup\$
    – Anko
    Feb 24, 2013 at 17:43
  • \$\begingroup\$ A picture or video reference would really help in understanding your problem here. \$\endgroup\$
    – RobCurr
    Feb 24, 2013 at 19:26
  • \$\begingroup\$ @Anko: I'm sorry, I thought wall sliding was a common definition in collision detection circles but appareantly it isn't. I'll edit it in my question :) \$\endgroup\$
    – Joey
    Feb 25, 2013 at 15:08
  • \$\begingroup\$ I find the explanation even more confusing: What does it mean to "walk in a vertical slope"? What is "horizontal rotation"? How can you "walk towards the wall until you've left the wall"? \$\endgroup\$
    – Anko
    Feb 25, 2013 at 16:21
  • \$\begingroup\$ @Anko, The player walks along the -z axis into a wall that is Y aligned and has a normal facing in the +z direction. With horizontal rotation I mean rotating around the Y axis. This video should show some visuals of wall sliding : youtube.com/watch?v=aKqBG9PAMfo Hope it helps. \$\endgroup\$
    – Joey
    Feb 25, 2013 at 16:37

2 Answers 2

6
\$\begingroup\$

I think you need to multiply invNormal by the length of direction before making the subtraction.

Vector invNormal = normal.Negative();
invNormal *= direction.length
Vector wallDir = direction - invNormal;
\$\endgroup\$
5
  • \$\begingroup\$ I'm at work now so can't test it right now but your answer gave me a moment of sudden clarity so that's probably the correct answer. I'll let you know when I'm home! \$\endgroup\$
    – Joey
    Feb 25, 2013 at 15:11
  • \$\begingroup\$ it seemed to fix the problem when I'm only moving in one axis and colliding with my plane (for example, when falling down due to gravity and reaching a plane. I stop bouncing since the length negates the fall velocity). However, I still get a bouncy effect when I'm two axes along the wal (for example, falling and colliding with the floor plane while moving forward along the plane). Did I miss something? \$\endgroup\$
    – Joey
    Feb 25, 2013 at 16:31
  • 2
    \$\begingroup\$ I fixed the problem! In order to account for movement among multiple axes I also multiplied my direction by the normal (to remove the non-significant axis) invNormal = invNormal * (direction * normal).Length(); which made sure the length is calculated only among the significant axis! Thanks for your help Krazy, wouldn't have found it without your suggestion! :) \$\endgroup\$
    – Joey
    Feb 25, 2013 at 16:42
  • \$\begingroup\$ Glad I could help. \$\endgroup\$
    – Krazy
    Feb 26, 2013 at 0:24
  • \$\begingroup\$ This comment section is my hero. \$\endgroup\$
    – GMchris
    Jun 27, 2017 at 18:37
5
\$\begingroup\$

You want to lose all the velocity in the direction of the normal of the wall. To do this, project the current direction onto the wall normal to get the wall part of the velocity/direction.

projected = normal * dot(direction, normal);
direction = direction - projected

Last line might have to have the sign flipped depending on the normals direction (in or out of the wall).

\$\endgroup\$
1
  • \$\begingroup\$ Isn't this just a different implementation for what I already did? The added length section might prove valuable though. I'll test it out! Thanks! \$\endgroup\$
    – Joey
    Feb 25, 2013 at 15:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .