白泽图

  • 文章
    • Unity渲染
    • Unity项目开发
    • 工具
    • 数学
    • 算法
    • 网站搭建
    • 网络&操作系统
蒋程个人博客
互联网技术经验总结&分享
  1. 首页
  2. Unity项目开发
  3. 正文

将点从A方向旋转到B方向(解决两方向平行相反的问题)

2025-08-27 13点热度 0人点赞 0条评论
Quaternion rotation = Quaternion.FromToRotation(dirA, dirB);
return rotation * originalPoint;

通常使用上面方式来将一个点从方向A移动到方向B,但是如果方向A和方向B平行相反时(比如(0,0,1)->(0,0,-1))上面的计算会有问题,此时我们需要指定旋转轴,然后旋转180度,比如

Quaternion rotation = Quaternion.AngleAxis(180f, Vector3.up);
return rotation * originalPoint;

但是如果两点不在z轴平面,比如(1,1,1)->(-1,-1,-1),此时需要动态计算出旋转轴,可以使用如下代码

using UnityEngine;

public class ParallelRotationCalculator : MonoBehaviour
{
    public Vector3 startDirection = new Vector3(1, 1, 1);
    public Vector3 targetDirection = new Vector3(-1, -1, -1);
    public Vector3 originalPoint = Vector3.zero; // 原始点位置

    // 动态计算旋转轴(当两个向量平行相反时)
    private Vector3 CalculatePerpendicularAxis(Vector3 dir)
    {
        //使用正交化方法生成垂直向量
        dir.Normalize();
        // 选择与dir方向分量差异最大的轴,避免平行
        Vector3 candidateAxis = Mathf.Abs(dir.x) < 0.7f ? Vector3.right :
                              Mathf.Abs(dir.y) < 0.7f ? Vector3.up : Vector3.forward;
        Vector3 axis = Vector3.Cross(dir, candidateAxis).normalized;

        // 二次验证:若叉积模长接近0,换另一轴
        if (axis.sqrMagnitude < 0.001f)
        {
            candidateAxis = candidateAxis == Vector3.right ? Vector3.up : Vector3.right;
            axis = Vector3.Cross(dir, candidateAxis).normalized;
        }
        return axis;
    }

    // 计算旋转后的点位置
    public Vector3 CalculateRotatedPoint()
    {
        Vector3 dirA = startDirection.normalized;
        Vector3 dirB = targetDirection.normalized;

        //通过点积检测:若 Vector3.Dot(A, B) ≈ -1(考虑浮点误差),则两向量平行反向
        if (Vector3.Dot(dirA, dirB) < -0.999f) // 平行反向
        {
            Vector3 axis = CalculatePerpendicularAxis(dirA);
            Quaternion rotation = Quaternion.AngleAxis(180f, axis);
            return rotation * originalPoint;
        }
        else // 非平行方向
        {
            Quaternion rotation = Quaternion.FromToRotation(dirA, dirB);
            return rotation * originalPoint;
        }
    }

    // 可视化调试
    void OnDrawGizmos()
    {
        Vector3 rotatedPoint = CalculateRotatedPoint();
        Gizmos.color = Color.green;
        Gizmos.DrawSphere(originalPoint, 0.1f);      // 原始点
        Gizmos.color = Color.red;
        Gizmos.DrawSphere(rotatedPoint, 0.1f);       // 旋转后的点
        Gizmos.DrawLine(originalPoint, rotatedPoint); // 连线

        // 绘制旋转轴(仅平行反向时)
        if (Vector3.Dot(startDirection.normalized, targetDirection.normalized) < -0.999f)
        {
            Vector3 axis = CalculatePerpendicularAxis(startDirection);
            Gizmos.color = Color.blue;
            Gizmos.DrawLine(originalPoint - axis * 2, originalPoint + axis * 2);
        }
    }
}

效果图如下

标签: 暂无
最后更新:2025-08-27

蒋程

这个人很懒,什么都没留下

点赞
< 上一篇

文章评论

您需要 登录 之后才可以评论

COPYRIGHT © 2023 白泽图. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

登录
注册|忘记密码?