【问题标题】:SceneKit camera, how to compensate for euler rules (orientation) changesSceneKit 相机,如何补偿欧拉规则(方向)变化
【发布时间】:2023-03-03 13:03:01
【问题描述】:

也许这更像是一道数学题,但我希望有人能帮助我了解如何补偿相机方向的变化。

我想做的是能够使用类似游戏的控件在场景中移动我的相机。我设置了 W S A D 键来分别向前、向后、向左和向右移动相机。我通过更改相机节点的位置向量的值来做到这一点。我还有右左上和下箭头键映射到转动和倾斜相机。我通过调整相机节点的欧拉规则(俯仰和偏航)来做到这一点。

在我用左右箭头转动相机之前,一切正常。在此之后按 W 将相机移动到它在我对其应用偏航之前所面对的方向。这种行为对我来说很有意义,但我无法弄清楚我需要对位置矢量调整做什么来补偿我应用的偏航。

我是否需要以某种方式将我的位置向量乘以新的变换?或者更好的是还有其他一些属性,比如我可以更改的枢轴,以便我可以保持我的位置代码相同?

感谢您的任何指点。


这里更新的是我目前正在使用的代码:

public func displayTimerDidFire(timer: MyCustomDisplayTimer!) {
    if timer === cameraMoveTimer {

        var cameraTransform = cameraNode.transform
        var x = CGFloat(0.0)
        var y = CGFloat(0.0)
        var z = CGFloat(0.0)

        var step : CGFloat = 10.0

        if moveUpKeyDown {
            y += step
        }
        if moveDownKeyDown {
            y -= step
        }
        if moveLeftKeyDown {
            x -= step
        }
        if moveRightKeyDown {
            x += step
        }
        if moveForwardKeyDown {
            z -= step
        }
        if moveBackwardKeyDown {
            z += step
        }

        cameraTransform = SCNMatrix4Translate(cameraTransform, x, y, z)
        cameraNode.transform = cameraTransform
    }
    else if timer === cameraTiltTimer {
        var angles = cameraNode.eulerAngles
        var stepAngle : CGFloat = CGFloat(M_PI_2 / 90.0)

        if turnLeftKeyDown {
            angles.y += stepAngle
        }
        if turnRightKeyDown {
            angles.y -= stepAngle
        }
        if tiltForwardKeyDown {
            angles.x -= stepAngle
        }
        if tiltBackwardKeyDown {
            angles.x += stepAngle
        }

        cameraNode.eulerAngles = angles
    }
}

我有两个计时器,一个更新相机位置,另一个更新其方向。

我坚持的部分是我知道我的新变换(旧位置加上从 A S D W 的移动增量),我知道相机的旋转,但我不知道如何将这两者结合到我真正的新转换。 Transform 是 SCNMatrix4,rotation 是 SCNVector4。


更新 2

这是代码的修改版本。我改为使用转换。但是,我仍然找不到正确的操作来解释旋转。

public func displayTimerDidFire(timer: MyDisplayTimer!) {
    var cameraTransform = cameraNode.transform
    var x = CGFloat(0.0)
    var y = CGFloat(0.0)
    var z = CGFloat(0.0)

    var step : CGFloat = 10.0

    if moveUpKeyDown {
        y += step
    }
    if moveDownKeyDown {
        y -= step
    }
    if moveLeftKeyDown {
        x -= step
    }
    if moveRightKeyDown {
        x += step
    }
    if moveForwardKeyDown {
        z -= step
    }
    if moveBackwardKeyDown {
        z += step
    }

    cameraTransform = SCNMatrix4Translate(cameraTransform, x, y, z)
    // Do something with the transform to compensate for rotation..
    // ???

    cameraNode.transform = cameraTransform

    var angles = cameraNode.eulerAngles
    var stepAngle : CGFloat = CGFloat(M_PI_2 / 90.0)

    if turnLeftKeyDown {
        angles.y += stepAngle
    }
    if turnRightKeyDown {
        angles.y -= stepAngle
    }
    if tiltForwardKeyDown {
        angles.x -= stepAngle
    }
    if tiltBackwardKeyDown {
        angles.x += stepAngle
    }

    cameraNode.eulerAngles = angles
   // printNode(cameraNode)
}

上次更新

感谢您的建议。这是对我有用的实现

我需要这个 objc 助手,因为其中一些函数在 Swift 中似乎不可用:

@implementation MySceneKitUtils
+ (SCNVector3)position:(SCNVector3)position multipliedByRotation:(SCNVector4)rotation
{
    if (rotation.w == 0) {
        return position;
    }
    GLKVector3 gPosition = SCNVector3ToGLKVector3(position);
    GLKMatrix4 gRotation = GLKMatrix4MakeRotation(rotation.w, rotation.x, rotation.y, rotation.z);
    GLKVector3 r = GLKMatrix4MultiplyVector3(gRotation, gPosition);
    return SCNVector3FromGLKVector3(r);
}
@end

以及实现

public func displayTimerDidFire(timer: MyDisplayTimer!) {
    var x = CGFloat(0.0)
    var y = CGFloat(0.0)
    var z = CGFloat(0.0)

    var step : CGFloat = 10.0

    if moveUpKeyDown {
        y += step
    }
    if moveDownKeyDown {
        y -= step
    }
    if moveLeftKeyDown {
        x -= step
    }
    if moveRightKeyDown {
        x += step
    }
    if moveForwardKeyDown {
        z -= step
    }
    if moveBackwardKeyDown {
        z += step
    }

    var cameraTransform = cameraNode.transform
    var rotation = cameraNode.rotation
    var rotatedPosition = MySceneKitUtils.position(SCNVector3Make(x, y, z), multipliedByRotation: cameraNode.rotation)
    cameraTransform = SCNMatrix4Translate(cameraTransform, rotatedPosition.x, rotatedPosition.y, rotatedPosition.z)

    cameraNode.transform = cameraTransform

    // The rotation

    cameraTransform = cameraNode.transform
    var stepAngle = CGFloat(0.05)
    if turnLeftKeyDown {
        cameraTransform = SCNMatrix4Rotate(cameraTransform, stepAngle, 0.0, 1.0, 0.0);
    }
    if turnRightKeyDown {
        cameraTransform = SCNMatrix4Rotate(cameraTransform, -stepAngle, 0.0, 1.0, 0.0);
    }
    if tiltForwardKeyDown {
        cameraTransform = SCNMatrix4Rotate(cameraTransform, stepAngle, 1.0, 0.0, 0.0);
    }
    if tiltBackwardKeyDown {
        cameraTransform = SCNMatrix4Rotate(cameraTransform, -stepAngle, 1.0, 0.0, 0.0);
    }

    cameraNode.transform = cameraTransform
}

【问题讨论】:

  • 发布您的代码,听起来像是一个简单的错误,因为您将转换从输入应用到相机
  • 更新了代码示例。谢谢。

标签: ios macos camera scenekit


【解决方案1】:

如果 t 是您从 WSAD 键计算的翻译,那么您不应该简单地添加它 (node.position += t),而是首先应用旋转然后添加它:node.position += node.rotation * t

【讨论】:

  • 谢谢@mnuages。我认为这是我在概念上试图做的,但我不确定如何实现它。你如何将节点的位置乘以它的旋转?位置是 SCNVector3,旋转是 SCNVector4。我在 SceneKit 或 GLKit 中看不到任何东西可以做到这一点。谢谢。
  • 嗯,我也尝试过使用节点的变换(SCNMatrix4)和旋转(SCNVector4)。但同样我看不到任何方法可以使用这两个来生成一个新的 SCNMatrix4 我可以应用到我的转换属性。
  • 你可以使用GLKMatrix4MakeRotation从节点的rotation创建一个旋转矩阵(注意GLKMatrix4MakeRotation需要angle,x,y,zrotationx,y,z,angle),然后使用GLKMatrix4MultiplyVector3将您的翻译乘以旋转矩阵
  • 嗨@mnuages,很抱歉在这里添加一个帖子,我有同样的问题,但我有一些麻烦,我在这里发布了一个问题:stackoverflow.com/questions/32167131/…。你能看看?谢谢
【解决方案2】:

我的答案是对上述答案的补充。我已将其用于双指缩放。

            //Creating unit vector
            let unitVector = GLKVector4Make(0, 0, -1, 1)
            //converting tranform matrix
            let glktranform =  SCNMatrix4ToGLKMatrix4(cameraNode.transform)
            //multiply unit vector with transform matrix
            let rotatedMatrix = GLKMatrix4MultiplyVector4(glktranform, unitVector)

            //scale it with translation you compute from the WSAD key

            let finalScaledVector = GLKVector4MultiplyScalar(rotatedMatrix, translation)

            cameraNode.position.x = finalScaledVector.x
            cameraNode.position.y = finalScaledVector.y
            cameraNode.position.z = finalScaledVector.z

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2011-07-04
    • 1970-01-01
    • 2017-12-24
    • 2012-10-10
    • 1970-01-01
    • 2016-02-09
    • 2014-07-03
    • 2010-12-06
    • 1970-01-01
    相关资源
    最近更新 更多