Libgdx: Moving a rotated perspective camera

2020-07-24 05:06发布

问题:

I am developing an android app which visualize the map of an environment and currently i am using libgdx to draw the map, also like any map application the user should be capable of zoom, rotate and moving the map,

I have developed a GestureHandler class which implements GestureListener interface and interacts with a PerspectiveCamera(since i will use 3d components in the future):

@Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
    float tempX = (mapView.getCamera().position.x - deltaX * 0.5f);
    float tempY = (mapView.getCamera().position.y + deltaY * 0.5f);

    mapView.getCamera().position.set(
            MathUtils.lerp(mapView.getCamera().position.x, tempX, mapView.getCamera().fieldOfView / 100),
            MathUtils.lerp(mapView.getCamera().position.y, tempY, mapView.getCamera().fieldOfView / 100),
            mapView.getCamera().position.z);
    mapView.getCamera().update();
    return false;
}


float initialDistance = 0;
float initialAngle = 0;
float distance = 0;

private void zoom(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2)
{
    initialDistance = initialPointer1.dst(initialPointer2);
    float iDeltaX = initialPointer2.x - initialPointer1.x;
    float iDeltaY = initialPointer2.y - initialPointer1.y;
    initialAngle = (float)Math.atan2((double)iDeltaY,(double)iDeltaX) * MathUtils.radiansToDegrees;
    if(initialAngle < 0)
        initialAngle = 360 - (-initialAngle);


    distance = initialPointer1.dst(pointer2);
    float deltaX = pointer2.x - initialPointer1.x;
    float deltaY = pointer2.y - initialPointer1.y;
    newAngle = (float)Math.atan2((double)deltaY,(double)deltaX) * MathUtils.radiansToDegrees;
    if(newAngle < 0)
        newAngle = 360 - (-newAngle);

    //Log.e("test", distance + " " + initialDistance);
    //Log.e("test", newAngle + " " + initialAngle);
    float ratio = initialDistance/distance;
    mapView.getCamera().fieldOfView = MathUtils.clamp(initialZoomScale * ratio, 1f, 100.0f);
    Log.e("zoom", String.valueOf(mapView.getCamera().fieldOfView));
    mapView.getCamera().update();
}


@Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {

    zoom(initialPointer1, initialPointer2, pointer1, pointer2);

    float delta1X = pointer2.x - pointer1.x;
    float delta1Y = pointer2.y - pointer1.y;
    newAngle = (float)Math.atan2((double)delta1Y,(double)delta1X) * MathUtils.radiansToDegrees;
    if(newAngle < 0)
        newAngle = 360 - (-newAngle);

    System.out.println("new "+newAngle);

    if(newAngle - currentAngle >= 0.01000f)
    {
        System.out.println("Increasing");
        mapView.getCamera().rotate(0.5f,0,0,1);

    }
    else if(newAngle - currentAngle <= -0.010000f) {
        System.out.println("DEcreasing");

        mapView.getCamera().rotate(-0.5f,0,0,1);
    }
    if(Math.abs(newAngle - currentAngle) >= 0.01000f)
    {
        currentAngle = newAngle;
    }
    return true;
}

Everything is fine until as far as i don't rotate the camera, just like this unsolved similar question after rotating the camera, movements will be affected by applied rotation.Any help specially sample codes?

Edit:

After lots of efforts i finally solved it, As Tenfour04 said in his answer i had to use two separate matrices for transformation and rotations, and finally set the result of their multiplication to view matrix of camera using:

camera.view.set(position).mul(orientation);

Also the most important thing is to set the Transformation Matrix of my batch to camera.view:

batch.setTransformationMatrix(camera.view)

回答1:

Instead of applying the gestures directly to the camera, apply them to a pair of Matrix4's that you use to store the orientation and position separately. Then in the render method, multiply the two matrices and apply them to your camera's view.

In the render() method:

camera.view.set(orientation).mul(position); //Might need to swap orientation/position--don't remember. 
camera.update();

Your zoom method is fine because field of view affects the camera's projection matrix rather than its view matrix.