【问题标题】:How can I calculate the rotation when using a quaternion camera?使用四元数相机时如何计算旋转?
【发布时间】:2012-02-01 06:12:59
【问题描述】:

给定一个四元数相机,当玩家可以在不同的表面法线(墙壁)上行走时,我如何计算它的旋转。

我正在开发一款允许玩家在 3D 空间中在天花板和墙壁上行走的游戏。我选择使用四元数相机系统来避免 Gimbal Lock。给定一组 up(0,1,0)、right(1,0,0) 和 forward(0,0,1) 向量,我构造了一个四元数。玩家围绕向上的矢量旋转来获得航向,围绕着向右的矢量旋转来获得俯仰。

在不改变重力矢量的情况下,相机可以正常工作,并允许玩家在环境中移动,就好像它是标准的 FPS 游戏一样。

为简单起见,假设玩家可以按下一个键,该键从最近的与当前法线不同的碰撞表面抓取法线,并将其分配为新的重力向量。

不幸的是,我遇到了脑残,无法弄清楚如何从这个新的重力向量中正确获取新的上、右和前向量,并将它们应用于当前的旋转四元数,或者即使那是解决问题的正确方法。如果有帮助,我的相机的移动和旋转代码如下。

Field forwardVector:TVector = TVector.Create(0,0,1)
Field rightVector:TVector = TVector.Create(1,0,0)
Field upVector:TVector = TVector.Create(0,1,0)

Field pos:TVector = New TVector
Field headingQuaternion:TQuaternion = TQuaternion.Create()
Field pitchQuaternion:TQuaternion = TQuaternion.Create()
Field combinedRotation:TQuaternion = TQuaternion.Create()
Field gravityVector:TVector = TVector.Create(0,1,0)

'---------
'ChangeGravityVector
'---------
Method ChangeGravityVector( newGravityVector:TVector )

    gravityVector = newGravityVector

End Method

'---------
'MoveForward
'---------
Method MoveForward( moveAmount:Float, noGravity:Byte = False )

    Local vecRot:TVector

    If( noGravity = True )

        headingQuaternion.MultiplyByVector( forwardVector )
        vecRot = combinedRotation.MultiplyByVector( forwardVector )

    Else

        vecRot = headingQuaternion.MultiplyByVector( forwardVector )

    EndIf

    vecRot.ScaleVector( moveAmount )
    pos.AddVector( vecRot )

End Method

'---------
'MoveUp
'---------
Method MoveUp( moveAmount:Float, noGravity:Byte = False  )

    Local vecRot:TVector

    If( noGravity = True )

        headingQuaternion.MultiplyByVector( gravityVector )
        vecRot = combinedRotation.MultiplyByVector( gravityVector )

    Else

        vecRot = headingQuaternion.MultiplyByVector( gravityVector )

    EndIf

    vecRot.ScaleVector( moveAmount )
    pos.AddVector( vecRot )

End Method

'---------
'MoveRight
'---------
Method MoveRight( moveAmount:Float, noGravity:Byte = False  )

    Local vecRot:TVector

    If( noGravity = True )

        headingQuaternion.MultiplyByVector( rightVector )
        vecRot = combinedRotation.MultiplyByVector( rightVector )

    Else

        vecRot = headingQuaternion.MultiplyByVector( rightVector )

    EndIf

    vecRot.ScaleVector( moveAmount )
    pos.AddVector( vecRot )

End Method

'---------
'RotateX
'---------
Method RotateX( rotateAmount:Float )

    Local xRotQuat:TQuaternion = TQuaternion.Create()
    xRotQuat.ConvertFromAxisAngle( rightVector, rotateAmount )
    pitchQuaternion = pitchQuaternion.MultiplyByQuaternion( xRotQuat )

End Method

'---------
'RotateY
'---------
Method RotateY( rotateAmount:Float )

    Local yRotQuat:TQuaternion = TQuaternion.Create()
    yRotQuat.ConvertFromAxisAngle( gravityVector, rotateAmount )
    headingQuaternion = yRotQuat.MultiplyByQuaternion( headingQuaternion )

End Method

'---------
'GetCameraMatrix
'---------
Method GetCameraMatrix:TMatrix4x4()

    combinedRotation = headingQuaternion.MultiplyByQuaternion( pitchQuaternion )
    Return combinedRotation.GetMatrix()

End Method

【问题讨论】:

    标签: camera rotation quaternions


    【解决方案1】:

    好的,所以我找到了一个行之有效的解决方案,结果证明,我想错了。唯一需要改变的向量是上向量,其他两个向量,前向和右向,应该保持不变。以下代码将当前四元数与新的向上向量对齐。诀窍是你使用当前向上向量和新向上向量之间的点积的平方以及这两者之间的交叉向量来创建一个新的四元数。然后,您将其乘以您当前的航向和两者之间的 slerp。记得在之后设置新的向上向量。您可以在 slerp 中使用任何您想要的值来使其更平滑,1.0 会立即进行过渡。

            Local newQuat:TQuaternion = New TQuaternion
            Local cross:TVector = upVector.GetCrossProduct( newGravityVector )
            Local dot:Float = upVector.GetDotProduct( newGravityVector )
            Local dotSquare:Float = Sqr( ( 1.0 + dot ) * 2.0 )
            Local scale:Float = 1.0/dotSquare
            newQuat.x = cross.x*scale
            newQuat.y = cross.y*scale
            newQuat.z = cross.z*scale
            newQuat.w = dotSquare*0.5
    
            newQuat = newQuat.MultiplyByQuaternion( headingQuaternion )
    
            headingQuaternion = headingQuaternion.Slerp( headingQuaternion, newQuat, 1.0 )
    
            gravityVector = newGravityVector
            upVector = newGravityVector
    

    【讨论】:

      猜你喜欢
      • 2016-02-24
      • 2012-07-24
      • 2012-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-09
      • 1970-01-01
      相关资源
      最近更新 更多