【问题标题】:Parent rotation for specific child position and rotation特定子位置和旋转的父旋转
【发布时间】:2020-09-18 02:20:59
【问题描述】:

我有一个字符只能在Y轴上转动,所以基本上左右,如果up是Vector3.up。角色有一个孩子,这是手榴弹产生的位置(他的右手),现在我试图弄清楚如何为父母计算正确的旋转,以便孩子准确地看着目标,但只能“水平”。父级的 x 和 z 旋转必须为 0。有没有办法做到这一点?如果孩子只在“水平面”上看正确的方向,而不是向上或向下看以完美地面对目标,这很好。

这个答案几乎是我想要的:http://answers.unity.com/comments/1339850/view.html

唯一的问题是产生的旋转是所有三个轴的混合,而不仅仅是一个 y 旋转。

【问题讨论】:

    标签: c# unity3d quaternions


    【解决方案1】:

    我会使用三角函数来解决这个问题。 cmets中的解释:

    Vector3 rotAxis = Vector3.up;
    
    // flatten child pos, target pos, char pos, and child forward.
    Vector3 flatChildPos = Vector3.ProjectOnPlane(childTransform.position, rotAxis);
    Vector3 flatTargetPos = Vector3.ProjectOnPlane(targetTransform.position, rotAxis);
    Vector3 flatCharPos = Vector3.ProjectOnPlane(charTransform.position, rotAxis);
    Vector3 flatChildForward = Vector3.ProjectOnPlane(childTransform.forward, rotAxis);
    
    Vector3 flatCharToTarget = flatTargetPos-flatCharPos;
    Vector3 flatChildToChar = flatCharPos-flatChildPos;
    
    // Find the angle going from the direction of child to parent to the child's forward
    // The sign will come in handy later
    float childAngle = Vector3.SignedAngle(flatChildToChar, flatChildForward,
            rotAxis);
    float absChildAngle = Mathf.Abs(childAngle);
    
    // Find the distance between child and character:
    float childDist = flatChildToChar.magnitude;
    
    // Find the distance between character and target:
    float targetDist = flatCharToTarget.magnitude;
    
    // Consider the triangle made by character position, position of target, and
    // desired child position. Use sin rule to find angle of target's corner
    float targetAngle = Mathf.Rad2Deg * Mathf.Asin(
            Mathf.Sin(absChildAngle * Mathf.Deg2Rad)
            * childDist/targetDist);
    
    // determine angle in parent's corner:
    float desiredParentAngle = 180f - absChildAngle - targetAngle;
    
    // Determine sign of angle at character from target to child. 
    // It's the same as the sign of angle at child from char to target.
    float sign = Mathf.Sign(childAngle);
    
    // Consider the triangle made by character position, position of target, and 
    // current child position. Determine the current signed angle in character corner.
    float currentParentAngle = Vector3.SignedAngle(flatCharToTarget, -flatChildToChar, 
            rotAxis);
    
    // Calculate the diff in angle needed to make the current triangle the desired one.
    float diffAngle = desiredParentAngle * sign - currentParentAngle;
    
    // Apply the diff in world space
    Quaternion newRot = Quaternion.AngleAxis(diffAngle, rotAxis) * charTransform.rotation;
    

    有趣的是,在某些情况下可能有两种可能的轮换。确定何时是这种情况以及第二次轮换留给读者的练习。提示:targetAngledesiredParentAngle 有时也有多个有效值;)

    【讨论】:

    • @Lyxodius 啊,我忘了在度数和弧度之间进行转换。现在应该可以了!!!
    • 哇,这真的有效!我完全惊呆了!我已经为此工作了两天,终于成功了!非常感谢!
    【解决方案2】:

    Afaik 你只需要反转孩子的localEulerAngles.y

    localEulerAngles 是子代相对于其父代的欧拉角偏移旋转。因此,仅采用 y 组件已经告诉您子代与其父代的偏移量。

    所以我想为了相应地旋转父级,你会这样做,例如

    // as usual get the direction from child to target
    var targetDirection = targetObject.transform.position - childObject.transform.position;
    
    // flatten the direction by erasing any difference in the Y-axis
    var targetDirectionFlat = Vector3.Scale(new Vector3(1,0,1), targetDirection).normalized;
    
    // get the Y angle offset between parent and child 
    var offset = -childObject.transform.localEulerAngles.y;
    
    // rotate the parent to face the flattened direction minus the offset
    // both are rotations around the Y axis only
    parent.transform.rotation = Quaternion.LookDirection(targetDirectionFlat) * Quaternion.Euler(Vector3.up * offset);
    

    注意:在智能手机上输入,但我希望 ides 清楚

    【讨论】:

    • 感谢您的回答!它似乎几乎可以工作,但由于某种原因,存在相当大的准确性错误。 imgur.com/QYlGxk8 最上面一行是 child.forward,最下面一行是 parent.forward。 child.forward 应该正好穿过图片上目标的中心。
    • @derHugo 我认为你犯了我第一次尝试时犯的同样错误,因为我没有考虑到孩子的本地位置是非零的。您需要根据父母的旋转来考虑孩子的世界位置变化。请参阅我的答案,了解我如何使用 trig 解决该问题 :)
    • @Ruzihm 是的,实际上这不是一个错误 ^^ 我现在从评论中看到 OP 想要它,但因为他说来自 URL 的那个几乎是目标,除了他想忽略Y 的差异我给出的答案更多基于假设在这个用例中只有轮换很重要^^我现在看到假设是错误的:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多