【问题标题】:Libgdx first person camera controllLibgdx 第一人称相机控制
【发布时间】:2014-03-16 13:33:19
【问题描述】:

我刚开始在 libgdx 中玩 3D arround。我已经知道如何画基本的Models,我试着用CameraController 来玩arround。现在我想创建一个FirstPersonCameraFirstPersonCameraController。我考虑过扩展PerspectiveCamera 并在其中添加MyMovingObject targetMyMovingObject 将持有一个x, y, z position,其中y 是一个常数值,因为我目前无法移动up/down。所以我的动作基本上是二维的。 MyMovingObject 还将存储 left/right rotation,这是其 moving direction/ xSpeed, zSpeed 所需的。但是Player 也应该能够上下查看,MyMovingObject 并不真正需要这种向上/向下旋转,因为它只会更改视图而不会更改其他属性。所以我不确定我是否走对了路。
我希望能够使用W,A,S,D 向前、向左、向右、向后移动,并使用鼠标向左向右旋转。我也想使用鼠标上下查看,就像在大多数First Person 游戏中一样。
我应该使用另一种方式,而不是通过扩展PerspectiveCamera 创建自己的相机吗? 还是这种方法很好,我只需要将上/下旋转存储在MyMovingObject 中,如果它仅用于视图?
还是使用W,A,S,D and mouse 控制摄像头并根据摄像头位置和旋转更新MyMovingObjects 位置会更好?
我希望你明白我的意思。解释起来似乎有点复杂(至少对我来说)。

编辑:我现在为我的 NPC 和玩家使用 Vector3 directionVector3 positionVector3 size。我通过以下方式计算速度:xSpeed = direction.x / (direction.x + direction.z) * speed; zSpeed 相同。通过这样做,我“过滤”了 y 值,我只得到 x 和 y 的百分比。唯一的问题是,当我直视xz0。我可以通过使用UpVecotr 来解决这个问题,当我进行“俯仰旋转”时它会旋转。但是我如何旋转他?我需要围绕侧向矢量旋转它。谢谢

编辑:旋转和移动现在可以工作(见我的回答),但我对“俯仰旋转”的限制有很大的问题。我正在使用:if (direction.y < 0.9 && angle > 1) doPitchRotation(); else if (direction.y > -0.9 && angle < 1) doPitchRotation(); 所以如果我向下旋转并且我仍然向下看至少 -0.9 y 它只是不执行旋转。但真正发生的是:我旋转到 - 0.9 然后它围绕 Y 轴旋转,在另一侧它向上旋转,即使我向下移动鼠标。你能解释一下为什么吗?为什么我向下看转身时Y轴会翻转?

编辑:现在可以使用了。似乎我的 upVector 有时会得到一些错误的值。对于陆基凸轮,您还可以使用 Y 轴和方向矢量的叉积。不需要 upVector。

【问题讨论】:

    标签: java camera libgdx


    【解决方案1】:

    我知道这个问题已经有了很好的答案。但是我对所选答案有一些问题。我只是想帮助正在寻找相同解决方案的人。 我注意到所选答案有一些奇怪的行为。我没有保持 Y 存在。这在 fps 上当然非常重要。所以这个并不完美,但我想把它放在这里。

    // put into the create() method.
    Gdx.input.setInputProcessor(new InputProcessor() {
            private int dragX, dragY;
            float rotateSpeed = 0.2f;
            // dont' forget to override other methods.
            @Override
            public boolean mouseMoved(int screenX, int screenY) {
                Vector3 direction = cam.direction.cpy();
    
                // rotating on the y axis
                float x = dragX -screenX;
                // change this Vector3.y with cam.up if you have a dynamic up.
                cam.rotate(Vector3.Y,x * rotateSpeed);
    
                // rotating on the x and z axis is different
                float y = (float) Math.sin( (double)(dragY -screenY)/180f);
                if (Math.abs(cam.direction.y + y * (rotateSpeed*5.0f))< 0.9) {
                    cam.direction.y +=  y * (rotateSpeed*5.0f) ;
                }
    
                cam.update();
                dragX = screenX;
                dragY = screenY;
                return true;
            }
    
        });
    

    注意:请勿使用任何相机控制器。
    注意2:这可能会派上用场:Gdx.input.setCursorCatched(true);

    编辑:我只是想分享我用来用wasd键改变相机位置的步行功能。当W 键按下时,forward 为真。并且当密钥向上时forward 为假。其他方向的原理相同。要检测上下键,请使用上述代码中的InputProcessor
    这会在二维空间(X-Z 轴)中产生运动。相机的方向不会改变运动的方向,因为我们正在消除 Y 轴。方向。
    现在必须即使相机指向天空(与地面成非 90 度角),方向矢量的长度也不固定为1.0f。所以不会有任何移动速度的损失。 为了测试这一点,我上下旋转了相机(前后移动了鼠标),方向向量的 x 和 z 值没有改变。所以当方向向量的 y 轴被消除后,我们就有了一个不受相机 Y 角度影响的二维方向向量。

    private void walking(float timeElapsed) {
            float speed = movementSpeed;
            if ((forward | back) & (right | left)) {
                speed /= Math.sqrt(2);
            }
            System.out.println(speed);
            if (forward) {
                Vector3 v = cam.direction.cpy();
                v.y = 0f;
                v.x *= speed * timeElapsed;
                v.z *= speed * timeElapsed;
                cam.translate(v);
                cam.update();
            }
            if (back) {
                Vector3 v = cam.direction.cpy();
                v.y = 0f;
                v.x = -v.x;
                v.z = -v.z;
                v.x *= speed * timeElapsed;
                v.z *= speed * timeElapsed;
                cam.translate(v);
                cam.update();
            }
            if (left) {
                Vector3 v = cam.direction.cpy();
                v.y = 0f;
                v.rotate(Vector3.Y, 90);
                v.x *= speed * timeElapsed;
                v.z *= speed * timeElapsed;
                cam.translate(v);
                cam.update();
            }
            if (right) {
                Vector3 v = cam.direction.cpy();
                v.y = 0f;
                v.rotate(Vector3.Y, -90);
                v.x *= speed * timeElapsed;
                v.z *= speed * timeElapsed;
                cam.translate(v);
                cam.update();
    
            }
        }
    

    【讨论】:

    • 感谢您的回答。但我想上轴不应该与 y 轴相同。想一想:你直视。这意味着,您的方向向量、向上向量和 y 轴都是相同的。当你向前推进时,你怎么知道该往哪里移动?因此,我在制作pitch-rotation 时也旋转了向上向量,并将 y 轴用于yaw-rotation。所以当我向上看时,向上矢量指向我身后,所以知道向前按时要移动到哪里。
    • 但是如果你直视呢? v.x 和 v.y 将是 0,不是吗?那你一点速度都没有吧?
    • @Springrbua 你好。我知道你不想要俯仰和偏航。经典射手没有这个(比如cs)。我尝试了选择的答案,但它出现了意想不到的音调和打哈欠。所以我写了这个。这种方法的唯一目的是它不会让音高、扭曲等。
    • @Springrbua 它不会让您向上看 90 度(仅 81 度)。你也不能直视。如果你走得太远,相机就会倒过来。
    • @Springrbua 如果你想俯仰,相机可以围绕方向矢量旋转。我没有对此进行测试。
    【解决方案2】:

    感谢分享this 链接。我发现它非常有用。 这是我关于旋转陆基相机的代码,它似乎可以正常工作。

    private int mouseX = 0;
    private int mouseY = 0;
    private float rotSpeed = 0.2f;
    
    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        int magX = Math.abs(mouseX - screenX);
        int magY = Math.abs(mouseY - screenY);
    
        if (mouseX > screenX) {
            cam.rotate(Vector3.Y, 1 * magX * rotSpeed);
            cam.update();
        }
    
        if (mouseX < screenX) {
            cam.rotate(Vector3.Y, -1 * magX * rotSpeed);
            cam.update();
        }
    
        if (mouseY < screenY) {
            if (cam.direction.y > -0.965)
                cam.rotate(cam.direction.cpy().crs(Vector3.Y), -1 * magY * rotSpeed);
            cam.update();
        }
    
        if (mouseY > screenY) {
    
            if (cam.direction.y < 0.965)
                cam.rotate(cam.direction.cpy().crs(Vector3.Y), 1 * magY * rotSpeed);
            cam.update();
        }
    
        mouseX = screenX;
        mouseY = screenY;
    
        return false;
    }
    

    这适用于陆基相机。如果要制作飞控相机,则必须围绕cam.direction.crs(cam.up) 进行俯仰旋转。我不会使用Vector3.cpy(),而是存储一个Vector3 help,它会获取这些临时值,因为Vector3.cpy() 创建了一个新的Vector3,并且这个操作在每个渲染循环中执行。 对于飞控相机,您还需要添加roll 旋转并围绕cam.up 向量进行yaw 旋转。

    【讨论】:

    • 不错的答案。只有 2 条建议:1) Vector3.cpy() 似乎创建了一个 new Vector3() 并为其赋予其他 Vecotr3 的值。每个渲染循环创建一个新对象并不是那么好。所以我会使用 Vector3 帮助,它获取临时值。 2)据我所知,对于陆基相机,您还可以围绕direction.crs(Vector3.Y)进行俯仰旋转。我应该编辑你的答案吗?到时候我会把它标记为已接受!
    【解决方案3】:

    This article 在我看来真的很有帮助。我找到了一个应该可行的解决方案,但我还没有尝试过。我的MovingObjects 都有Vector3 positionVector3 directionVector3 sizeVecotr3 upVectorPlayer 类扩展了这个 MovingObject 类并将MouseKeycontroll 添加到运动中。 在MovingObject 类中,我有以下方法:

    1. rotateYaw(float degrees):将Vector3 direction 围绕Y-Axis 旋转给定度数(libgdx 具有Vector3 的旋转功能)--> 简单
    2. rotatePitch(float degrees):将Vector3 direction 围绕direction.cross(Vector3.Y) 旋转,这是MovingObject 的旋转侧向量,按给定度数。 Pitch-Rotation 也必须旋转 upVector,因此您将 upVector 围绕同一轴旋转给定度数。明白了这点就很简单了。
    3. move(delta) 将您的MovingObjectx,z 方向移动:

      if (direction.y == 1) {
        // You are looking straight up, no x,z direction, move in the opposite
        // direction of upVector
        xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed);
        zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed);
        position.add(xSpeed * delta, 0, ySpeed * delta);
      } else if (direction.y == -1) {
        // You are looking straight down, no x,z direction, move in the direction of
        // upVector
        xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed;
        zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed;
        position.add(xSpeed * delta, 0, ySpeed * delta);
      } else {
        // You are not looking straight up or down, so you have x,z direction. Use
        // that.
        xSpeed = direction.x / (Math.abs(direction.x) + Math.abs(direction.z)) * speed;
        zSpeed = direction.z / (Math.abs(direction.x) + Math.abs(direction.z)) * speed;
        position.add(xSpeed * delta, 0, ySpeed * delta);
      }
      

    我直到现在才测试这个,但我认为它应该可以工作。请注意,在Pitch-rotation 中,您还应该将其限制为直上/直下。通过检查 x 和 z 的符号来做到这一点。如果在您执行Pitch-rotation 时它们发生了变化,您旋转了 90 度以上。 我还在等待其他答案,如果我错了,请纠正我!

    编辑:我测试过了。它是这样工作的,但有一些事情需要注意:

    1. direction.cross(upVector) 更改 direction 向量。因此,首先将这些数据存储在某个地方!使用后重置方向向量。
    2. 音高限制有一个问题:如果您控制符号变化,正如我所建议的那样,会发生以下情况:您直视,符号 x 和符号 z 为 0。您向下看,符号变化并且您的动作(限制)开始。因此,如果它不为零,请注意检查。 我仍然不知道如何进行音高限制,我编辑了我的问题来解释我的问题。
    3. 每当您更改某些内容时,请考虑规范化您的 directionupVector

    我认为这应该工作得很好。如果您有任何改进,请告诉我,我会在这里更新。如果您有其他解决方案,请添加答案!谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多