This is probably trivial, but I'm having trouble making it work.

I have a 3-coordinate world of particles simulated with Verlet Velocity. I only care for collision between their centers and a few static AABBs.

Essentially, I can't get a clean way of resolving a collision.

For example, say I have a box with coordinates:

min = (0, -1, -384)
max = (512, 1, 0)

Any particle colliding with it should stop moving in the relevant direction, but continue moving in the others - not bounce off.

I have one particle at pos that in a single timestep wants to go to newpos (it's being pushed both downward and eastward):

pos = (-0.068037, 0.000000, -58.516845)
newpos = (0.014446, 0.000000, -58.555490)

Clearly, on the X axis there is a collision. My ray collider detects it and pops back the point where the ray intersects the AABB:

intersection = (0.000000, 0.000000, -58.548722)

Now, if I just set the position to that point, at the next time step there will be a collision because the position will be exactly on the border of the AABB.

This makes every particle "stick" to whatever box they collide with. In the previous example, I'd like to have the particle slide down the AABB wall according to its current velocity.

How can I do that?


1 Answer 1


Ok, I think I've solved (although I still don't understand completely why - so I'm not sure it will work in every case).

I'll post here the (Java) solution in case somebody else has this problem. Note I only call this if I already know there is a collision between the to point and the b box.

It should work anyway but do your tests in case you use it.

The initial code was taken from Toxiclibs and adapted to my min-max based AABBs, and merges together a ray intersection with a purely position-based collision response.

public static void clampPointOutsideBox(final Vect3D from, final Vect3D to, final Box b)
    ImmutableVect3D normal;

    final Vect3D min = b.getMinPoint();
    final Vect3D max = b.getMaxPoint();

    final Vect3D direction = Vect3D.sub(to, from).normalised();
    final Vect3D invDir = Vect3D.reciprocal(direction);

    final boolean signDirX = invDir.x < 0;
    final boolean signDirY = invDir.y < 0;
    final boolean signDirZ = invDir.z < 0;

    Vect3D bbox = signDirX ? max : min;
    final double xmindist = bbox.x - from.x;
    double tmin = xmindist * invDir.x;

    normal = signDirX ? ImmutableVect3D.xaxis : ImmutableVect3D.xaxisinv;

    bbox = signDirX ? min : max;
    double tmax = (bbox.x - from.x) * invDir.x;

    bbox = signDirY ? max : min;
    final double ymindist = bbox.y - from.y;
    final double tymin = ymindist * invDir.y;

    bbox = signDirY ? min : max;
    final double tymax = (bbox.y - from.y) * invDir.y;

    if ((tmin > tymax) || (tymin > tmax))

    // take the maximum of the t(x)min and tymin,
    // and take the correct normal now to save later
    // computations
    if (tymin > tmin)
        tmin = tymin;

        normal = signDirY ? ImmutableVect3D.yaxis : ImmutableVect3D.yaxisinv;

    // take the minimum of t(x)max and tymax,
    // we don't need the normal here
    tmax = Math.min(tymax, tmax);

    bbox = signDirZ ? max : min;
    final double zmindist = bbox.z - from.z;
    final double tzmin = zmindist * invDir.z;

    bbox = signDirZ ? min : max;
    final double tzmax = (bbox.z - from.z) * invDir.z;

    if ((tmin > tzmax) || (tzmin > tmax))

    // take the maximum of (txmin,tymin) and tzmin,
    // and take the correct normal now to save later
    // computations
    if (tzmin > tmin)
        tmin = tzmin;

        normal = signDirZ ? ImmutableVect3D.zaxis : ImmutableVect3D.zaxisinv;

    // take the minimum of (txmax,tymax) and tzmax,
    // we don't need the normal here
    tmax = Math.min(tzmax, tmax);

    final Vect3D isec = Vect3D.add(from, Vect3D.mul(direction, tmin));

    double scale = 0.01;
    double restitution = 1.0;
    isec.add(new Vect3D(normal).mul(scale));

You must log in to answer this question.

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