SceneKit摄像头,如何补偿欧拉规则(方向)的变化 [英] SceneKit camera, how to compensate for euler rules (orientation) changes

查看:1720
本文介绍了SceneKit摄像头,如何补偿欧拉规则(方向)的变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我会喜欢做的是能够使用游戏般的控制来移动我的相机在场景周围。我有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
}
如果moveDownKeyDown {
y - = step
}
如果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)

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

cameraNode.eulerAngles = angles
}
}

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



我坚持的部分是我知道我的新变换(旧位置加上从ASDW的移动增量),我知道相机的旋转,但我不知道如何将这两个组合成我真正的新变换。 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)
//使用变换执行某些操作以补偿旋转。
// ???

cameraNode.transform = cameraTransform

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

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

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






最近更新



感谢您的建议。下面是为我工作的实现



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

  @implementation MySceneKitUtils 
+(SCNVector3)position:(SCNVector3)position multiplierByRotation:(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 b $ b var z = CGFloat(0.0)

var step:CGFloat = 10.0

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

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

cameraNode.transform = cameraTransform

//旋转

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
}


解决方案

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

Maybe this is more of a math question, but I am hoping somebody can help me understand how I would compensate for changes to my camera's orientation.

What I would like to do is to be able to move my camera around the scene using game-like controls. I have W S A D keys set up to move the camera forward, backward, left and right respectively. I do this by changing the values of the camera node's position vector. I also have the right left up and down arrow keys mapped to turning and tilting the camera. I do this by adjusting the camera node's euler rules (pitch and yaw).

Things work well until I turn the camera with the right and left arrows. Pressing W after this moves the camera in the direction it was facing before I applied yaw to it. The behavior makes sense to me, but I cannot figure out what I need to do to my position-vector tweaking to compensate for the yaw I've applied.

Do I need to multiply my position vector somehow by new transform? Or better yet is there some other property like the pivot that I can change, so that I can keep my position code the same?

Thanks for any pointers.


Update here is the code I'm working with so far:

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

I have two timers, one that updates the cameras position, and the other that updates its orientation.

The part I'm stuck on is that I know my new transform (old position plus the move increment from A S D W), and I know the camera's rotation, but I don't know how to combine those two into my true new transform. Transform is a SCNMatrix4, and rotation is a SCNVector4.


Update 2

Here is a reworked version of the code. I switched to working with the transform instead. I still cannot find the right manipulation to account for the rotation however.

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)
}


Last Update

Thanks for the suggestions. Here is the implementation that is working for me

I needed this objc helper, as some of these functions to not seem to be available in 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

And the implementation

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
}

解决方案

if t is the translation you compute from the WSAD keys, then you should not simply add it (node.position += t) but first apply a rotation and then add it : node.position += node.rotation * t

这篇关于SceneKit摄像头,如何补偿欧拉规则(方向)的变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆