首页 文章

SceneKit相机,如何补偿euler规则(方向)的变化

提问于
浏览
3

也许这更像是一个数学问题,但我希望有人可以帮助我理解如何补偿相机方向的变化 .

我想做的是能够使用类似游戏的控件将我的相机移动到场景中 . 我有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,旋转是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
}

2 回答

  • 0

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

  • 3

    我的答案是上面的答案 . 我用它来进行缩放变焦 .

    //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
    

    希望这会有所帮助 .

相关问题