6

Alright so I've been trying for quite some time too Raycast in libgdx for 3d collision detection based on where im looking.. But I've drawn a blank and doesn't seem to be any documentation anywhere. Would someone be kind enough to send me in the right direction?

2 Answers2

9

It is actually really easy with libgdx to achieve what you are trying to do. The following is what I'm using to do a ray test and find the closest collision object that my ray would hit. Let's assume it is located in a class called BulletUtil.

private static final Vector3 rayFrom = new Vector3();
private static final Vector3 rayTo = new Vector3();
private static final ClosestRayResultCallback callback = new ClosestRayResultCallback(rayFrom, rayTo);

public static btCollisionObject rayTest(btCollisionWorld collisionWorld, Ray ray) {
    rayFrom.set(ray.origin);
    // 50 meters max from the origin
    rayTo.set(ray.direction).scl(50f).add(rayFrom);

    // we reuse the ClosestRayResultCallback, thus we need to reset its
    // values
    callback.setCollisionObject(null);
    callback.setClosestHitFraction(1f);
    callback.getRayFromWorld().setValue(rayFrom.x, rayFrom.y, rayFrom.z);
    callback.getRayToWorld().setValue(rayTo.x, rayTo.y, rayTo.z);

    collisionWorld.rayTest(rayFrom, rayTo, callback);

    if (callback.hasHit()) {
        return callback.getCollisionObject();
    }

    return null;
}

Now what else you need is an InputProcessor that reacts on the click events.

public class BulletInputProcessor extends InputAdapter {

    private Viewport pickingViewport;
    private btCollisionWorld collisionWorld;

    // a constructor which takes a Viewport and the collision world and stores them
    public BulletInputProcessor(...) { ... }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        if (button == Input.Buttons.LEFT) {
            Ray pickRay = pickingViewport.getPickRay(screenX, screenY);

            btCollisionObject body = BulletUtil.rayTest(collisionWorld, pickRay);
            if (body != null) {
                // do whatever you want with this body now
                return true;
            }
        }

        return false;
    }
}

The Viewport is responsible to create the picking Ray. You should use the viewport here which manages the PerspectiveCamera that you use to render the world. Don't forget to register the input processor via Gdx.input.setInputProcessor(new BulletInputProcessor(collisionWorld, viewport)).

noone
  • 19,520
  • 5
  • 61
  • 76
  • Okay so i think i understand what your saying but im heading to bed so won't get to test it till tomorrow *Btw thanks for the fast response!* –  Jul 28 '14 at 05:53
  • Okay so it seems I have seriously failed somewhere 0.0 No matter what I do it doesn't register it colliding with any of the other collision objects –  Jul 28 '14 at 08:42
  • Currently have this problem (just posted hours ago [http://stackoverflow.com/questions/27790457/libgdx-melee-attack-collision-detection). How do you find the 'ray' where a ModelInstance is pointing to? – hadez30 Jan 06 '15 at 07:34
1

@noone In your code, there are two lines which didn't work our for me. May be deprecated?

callback.getRayFromWorld().setValue(rayFrom.x, rayFrom.y, rayFrom.z);
callback.getRayToWorld().setValue(rayTo.x, rayTo.y, rayTo.z);

I have changed them to

  Vector3 rayFromWorld = new Vector3();
  rayFromWorld.set(rayFrom.x, rayFrom.y, rayFrom.z);
  Vector3 rayToWorld   = new Vector3();
  rayToWorld.set(rayTo.x, rayTo.y, rayTo.z);

which made the whole function work like a charm.

Another thing I found out was, that you have to activate the body (which is returned by this function) in order to apply forces on it. Mostly rigid bodys are set to sleep after a certain interval of time and a ClosestRayResultCallback does not wake them up.

btCollisionObject target = CollisionUtils.rayTest(dynamicsWorld, ray);
//test for collisionflags and stuff here
//and if your target is instance of btRigidBody
btRigidBody body = (btRigidBody)target;
body.activate();
body.applyCentralForce(ray.direction.scl(50000));
Jankapunkt
  • 8,128
  • 4
  • 30
  • 59