RayCasting in Libgdx 3d

社会主义新天地 提交于 2019-11-29 15:20:13

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 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));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!