捕捉到 y 轴 Unity 中存储的相对旋转

Snapping to a stored relative rotation in y axis Unity

这适用于在 Unity 中开发的 Microsoft HoloLens 应用程序。

我正在开发一项功能,"saves" 用户可以轻松返回的视点。我这样做是通过将场景中对象的相对 position/orientation 存储到主相机,然后通过语音命令将对象恢复到它们之前的相对 position/orientation。

我的位置恢复工作正常,我只需要恢复偏航轴 (y) 的方向,以便用户被迫面向正确的方向。

我尝试使用此解决方案将场景对象(在本例中称为 "terrainContainer")的 relative y 方向恢复到主相机:

//this is the stored relative orientation in y
float deltaYaw = Camera.main.transform.rotation.eulerAngles.y - terrainContainer.transform.rotation.eulerAngles.y; 

//this function adjusts the orientation of the terrainContainer to match previous relative orientation that was stored
public void SwitchRelativeOrientation(float deltaYaw, GameObject terrainContainer){
     float curDeltaYaw = Camera.main.transform.rotation.eulerAngles.y - terrainContainer.transform.rotation.eulerAngles.y;
     float diffDeltas = curDeltaYaw - deltaYaw;
     float setYaw = terrainContainer.transform.rotation.eulerAngles.y + diffDeltas;
     setYaw = Utils.MathUtils.Normalise(setYaw, 0, 360); //normalises the value recovered to a range from [0,360]

     //adjusting terrainContainer rotation
     terrainContainer.transform.rotation = Quaternion.Euler(terrainContainer.transform.rotation.x, setYaw, terrainContainer.transform.rotation.z);
}

当我执行以下操作时此实现有效:

当我执行以下操作时,此实施 失败

发生故障时,方向偏离了地形旋转的程度。所以如果地形被用户逆时针旋转了 20 度,地形应该是 50 度,那么地形最终是 70 度。

我不明白为什么会这样。我在位置变化之前进行轮换。如果您能提供任何帮助,我将不胜感激!

编辑: 正如下面评论中提到的,我采用了一种略有不同的方法来解决这个最终有效的问题:

//this is the stored relative orientation in y
float deltaYaw = viewpoint.transform.localRotation.eulerAngles.y

//this function adjusts the orientation of the terrainContainer to match previous relative orientation that was stored
public void SwitchRelativeOrientation(float deltaYaw, GameObject terrainContainer){
     Quaternion toQuat = Camera.main.transform.localRotation;
    //my implementation is flat on the xz plane
     toQuat.eulerAngles = new Vector3(0, toQuater.eulerAngles.y, 0);
    //orient terrain to same as camera
    terrainContainer.transform.rotation = toQuat;
    //now add the previous difference in rotation to the terrain
    terrainContainer.transform.rotation = Quaternion.Euler(terrainContainer.transform.rotation.eulerAngles.x, terrainContainer.transform.rotation.eulerAngles.x + deltaYaw, terrainContainer.transform.rotation.eulerAngles.z);
}

但我还可以看到另一个问题

terrainContainer.transform.rotation = Quaternion.Euler(terrainContainer.transform.rotation.x, setYaw, terrainContainer.transform.rotation.z);

Rotation 是一个四元数,本质上是一个 Vector4,您可以通过 rot.x、rot.y、rot.z、rot.w 来寻址它的成员,但是那些是与构成四元数的欧拉角不同。改用 yhid:

    terrainContainer.transform.rotation = Quaternion.Euler(terrainContainer.transform.eulerAngles.x, setYaw, terrainContainer.eulerAngles.z);

也可以通过

setYaw = Utils.MathUtils.Normalise(setYaw, 0, 360);

如果您的 setYaw 大于 360(在某些情况下很可能是这样),那么您正在截断信息。 你可以简单地删除这条线,因为 unity 在大于 360 的角度下工作得很好,或者如果你真的需要截断该值,你可以做

setYaw = setYaw % 360; //modulo division

正如下面评论中提到的,我采用了一种稍微不同的方法来解决这个最终有效的问题:

//this is the stored relative orientation in y
float deltaYaw = viewpoint.transform.localRotation.eulerAngles.y

//this function adjusts the orientation of the terrainContainer to match previous relative orientation that was stored
public void SwitchRelativeOrientation(float deltaYaw, GameObject terrainContainer){
     Quaternion toQuat = Camera.main.transform.localRotation;
    //my implementation is flat on the xz plane
     toQuat.eulerAngles = new Vector3(0, toQuater.eulerAngles.y, 0);
    //orient terrain to same as camera
    terrainContainer.transform.rotation = toQuat;
    //now add the previous difference in rotation to the terrain
    terrainContainer.transform.rotation = Quaternion.Euler(terrainContainer.transform.rotation.eulerAngles.x, terrainContainer.transform.rotation.eulerAngles.x + deltaYaw, terrainContainer.transform.rotation.eulerAngles.z);
}