在Unity中实现Oculus Rift手柄位置的镜像,以实现双侧运动

4

目前我正在尝试编写一个脚本,将一个手柄的移动效果复制到另一个手柄上,以便只有一只手臂能使用的用户也能进行双边运动。如何将一个手柄的位置镜像到另一个手柄上,使两个手臂能够协调运动?

镜像y轴和z轴很容易,因为它们同时移动并且旋转很容易镜像。但是,我无法镜像x轴运动。我希望当一个手掌向外移动时,另一个手掌也会做同样的动作,并且两个手臂一起向内移动。你有什么办法可以实现这一点吗? 我附上了我的当前脚本。我还使用OVRCemeraRig脚本中的简单布尔逻辑禁用了非镜像控制器的位置跟踪,以防止运动停滞。 需要使用OVRCemeraRig,因为使用final IK

我尝试过计算工作手臂的x位置与另一只手臂的x位置之间的差值,然后将该差值加到另一只手臂上,但没有成功。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class VRMirror : MonoBehaviour
{
    public bool mirrorLeft;
    public bool mirrorRight;
    public GameObject leftHand; //left hand anchor in OVRCameraRig
    public GameObject rightHand; //right hand anchor from OVRCameraRig
    void Start()
    {

    }
    void FixedUpdate()
    {
        Transform left = leftHand.GetComponent<Transform>();
        Transform right = rightHand.GetComponent<Transform>();
        if (mirrorLeft)
        {
            Vector3 leftPos = left.position;
            Quaternion leftRot = left.rotation;
            leftRot.y = -leftRot.y;
            right.position = leftPos;
            right.rotation = leftRot;
        }
        else if (mirrorRight)
        {
            Vector3 rightPos = right.position;
            Quaternion rightRot = right.rotation;

            rightRot.y = -rightRot.y;
            left.position = rightPos;
            left.rotation = rightRot;

        }
    }
}
2个回答

1
为了保证稳健性,让我们假设您玩家的身体旋转不一定总是指向(1,0,0)世界方向。相反,我们可以获取到玩家的变换playerTransform(确保使用检查器或在Start中分配它),然后使用它来进行计算。
要计算相对向量的双边对称位置,可以计算relativeVec - 2f * playerTransform.right * Vector3.Dot(relativeVec, playerTransform.right)。为什么这样做有效的解释在注释中。
对于位置,我们可以将源手的绝对位置转换为相对于玩家位置的相对位置,然后找到目标手的相对位置,然后将其转换回绝对位置。
对于旋转,确定源手的上方和前方,然后反射它们以确定目标手的上方和前方。使用Quaternion.SetLookRotation将向量转换为目标手的旋转。
我们可以使用相同的代码用于相对位置和方向向量,所以一旦掌握了数学知识,实际上并不需要太多的代码。而且,由于Transform是一个类,我们可以编写一个方法来执行反射过程,然后将我们想要作为源和目标的转换传递给它。
public class VRMirror : MonoBehaviour
{
    public bool mirrorLeft;
    public bool mirrorRight;
    public GameObject leftHand; //left hand anchor in OVRCameraRig
    public GameObject rightHand; //right hand anchor from OVRCameraRig

    public Transform playerTransform;

    void Start()
    {

    }
    void FixedUpdate()
    {

        Transform left = leftHand.GetComponent<Transform>();
        Transform right = rightHand.GetComponent<Transform>();
        if (mirrorLeft)
        {
            MirrorFromTo(left, right);
        }
        else if (mirrorRight)
        {
            MirrorFromTo(right, left);
        }
    }

    void MirrorFromTo(Transform sourceTransform, Transform destTransform)
    {
        // Determine dest position
        Vector3 playerToSourceHand = sourceTransform.position - playerTransform.position;
        Vector3 playerToDestHand = ReflectRelativeVector(playerToSourceHand);
        destTransform.position = playerTransform.position + playerToDestHand ;

        // Determine dest rotation
        Vector3 forwardVec = ReflectRelativeVector(sourceTransform.forward);
        Vector3 upVec = ReflectRelativeVector(sourceTransform.up);
        destTransform.rotation = Quaternion.LookRotation(forwardVec,upVec);
    }

    Vector3 ReflectRelativeVector(Vector3 relativeVec) 
    {
       // relativeVec
       //     Take the relative vector....
       // + Vector3.Dot(relativeVec, playerTransform.right)
       //     and for how far along the player's right direction it is 
       //     away from the player (may be negative),
       // * playerTransform.right
       //     move it that distance along the player's right...
       // * -2f
       //    negative two times (i.e., along the left direction 2x)

       return relativeVec 
           + Vector3.Dot(relativeVec, playerTransform.right)
               * playerTransform.right 
               * -2f;
    }
}

1
你在playerTransform中使用了什么?我正在使用玩家模型,它似乎可以工作。除了手腕的旋转。当我扭转一个手腕时,另一个手腕也会扭转。目前只有一个手腕会随着你的代码移动。使用我的代码,我能够让手腕镜像,除了旋前和旋后。那些是相反的。 - Afroca
1
我完全复制粘贴了您的代码。您的代码问题在于其中根本没有手腕旋转。您正在使用Vector3来执行旋转,但实际上应该使用四元数(Quaternion),我不确定这是否可能是问题所在。我回答了这个问题,并进行了一些微小的修改,现在它已经完美地运行了。 - Afroca
1
@Afroca 噢,其实我知道问题出在哪里了...我太傻了。使用 SetLookRotation 修改的是旋转的副本。我会将代码改为 destTransform.rotation = Quaternion.LookRotation(forwardVec,upVec);,假设你的左手本地轴像这样,而你的右手只有中指向 -x - Ruzihm
1
所以我刚刚遇到了一个错误。如果玩家转头,被镜像的手臂会随着头部移动。目前我正在使用整个玩家模型作为playerTransform。我应该使用其他东西吗?我将在原帖中编辑一个我的Unity截图。 - Afroca
1
实际上不要编辑你的答案。我在我的回答中留下了解释,但是我将你的答案作为正确答案。 - Afroca
显示剩余3条评论

1
我对@Ruzihm的内容进行了一些修改。非常感谢你的帮助。在我下面示例的代码中,一切都完美运行,但我建议使用@Ruzihm的答案,因为他处理旋转的方式更好。如果玩家模型静止不动,而且你没有全身转动,那么这段代码可以工作。如果你需要转动,请在ReflectRelativeVector函数中使用playerTransform.right而不是Vector3.right,但是使用playerTransform.right会随着头部移动而移动手臂。
public class VRMirror : MonoBehaviour
{
    public bool mirrorLeft;
    public bool mirrorRight;
    public GameObject leftHand; //left hand anchor in OVRCameraRig
    public GameObject rightHand; //right hand anchor from OVRCameraRig

    public Transform playerTransform;  

    void Start()
    {

    }
    void FixedUpdate()
    {

        Transform left = leftHand.GetComponent<Transform>();
        Transform right = rightHand.GetComponent<Transform>();
        if (mirrorLeft)
        {
             MirrorFromTo(left, right);
        }
        else if (mirrorRight)
        {
            MirrorFromTo(right, left);

        }
    }

    void MirrorFromTo(Transform sourceTransform, Transform destTransform)
    {
        // Determine dest position
        Vector3 playerToSourceHand = sourceTransform.position - playerTransform.position;
        Vector3 playerToDestHand = ReflectRelativeVector(playerToSourceHand);
        destTransform.position = playerTransform.position + playerToDestHand;

        // Determine dest rotation
        Quaternion destRot = sourceTransform.rotation;

        destRot.y = -destRot.y;
        destRot.z = -destRot.z;
        destTransform.rotation = destRot;

    }

    Vector3 ReflectRelativeVector(Vector3 relativeVec)
    {
        // relativeVec
        //     Take the relative vector....
        // + Vector3.Dot(relativeVec, playerTransform.right)
        //     and for how far along the player's right direction it is 
        //     away from the player (may be negative),
        // * playerTransform.right
        //     move it that distance along the player's right...
        // * -2f
        //    negative two times (i.e., along the left direction 2x)

        return relativeVec
        + Vector3.Dot(relativeVec, Vector3.right)
            * Vector3.right
            * -2f;
    }
}

这是编辑器的屏幕截图:

在此输入图片描述


1
我认为这是我第一次在Stack Overflow上看到有人修改四元数的组件并成功获得他们想要的结果。令人印象深刻! - Ruzihm
1
@Ruzihm 从逻辑上讲,我正在做你在旋转方面所做的事情。不过我对Unity还很陌生。再次感谢你的帮助!将来我一定会尝试联系你寻求帮助! - Afroca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接