问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Unity中计算线和面交点的三维数学应用

创作时间:
作者:
@小白创作中心

Unity中计算线和面交点的三维数学应用

引用
CSDN
1.
https://m.blog.csdn.net/dxs1990/article/details/138125760

在Unity引擎中,计算线和面的交点是一个常见的三维数学问题。本文将介绍一种基于向量运算和相似三角形原理的计算方法,并提供具体的实现代码。

实现方法有多种,下面介绍一种简单的方法。利用一个点指向面上任意点的向量,到该面法线的投影长度相同的基本原理,结合相似三角形既可以求出交点。

原理

如下图:

GD组成的线段和ABC组成的三角形相交与E点,ABCDG的坐标已知求E点坐标。

首先用叉乘求出ABC面的法线N;(D点分别到ABC各点的向量在法线N上投影的模长是相同的,同样等于D点到E点的向量在N投影的模长)

分别用点乘的方法求出,DA到N的投影模长a和DG到N的投影模长b;

∵DE到N的投影模长同样等于a

∴由相似三角形可得

a/b = |DE|/|DG|

由次可得E点的坐标

实现代码

Vector3 GetIntersectPoint(Vector3 C1, Vector3 C2, Vector3 C3, Vector3 L1, Vector3 L2)
{
    //求面的法线
    Vector3 n0 = (C2 - C1).normalized;
    Vector3 n1 = (C2 - C3).normalized;
    Vector3 N = Vector3.Cross(n0,  n1);
    //线段的向量和到面上点的向量
    Vector3 line1 = L2 - L1;
    Vector3 line2 = C1 - L1;
    //与面法线点成比,得到线段点到面的模长
    float dis1 = Vector3.Dot(N, line1);
    float dis2 = Vector3.Dot(N, line2);
    float magnitude = (dis2 / dis1)*line1.magnitude;
    //用线段的单位向量乘模长求出交点
    Vector3 direction = line1.normalized * magnitude;
    return L1 + direction;
}

同样的方法也可以计算两条线段的交点

Vector3 GetIntersectPoint(Vector3 C1, Vector3 C2, Vector3 P1, Vector3 P2)
{
   // 分别求出两个线段的单位向量
    Vector3 L0=(C2 - C1).normalized;
    Vector3 L1=( P2 - P1).normalized;
   //俩次差乘建立 L0为一个坐标轴的的坐标系
    Vector3 H = Vector3.Cross(L0,  L1);
    Vector3 N = Vector3.Cross( L0, H);
    float dis1 = Vector3.Dot(N, L1);
    float dis2 = Vector3.Dot(N, (P1-C1));
  
    float magnitude = dis2 / dis1;
    return L1 * magnitude + P1;
 }

叉乘判断线段和面是否相交

//判断面和线段是否相相交
bool isCut(Vector3 C1, Vector3 C2, Vector3 L1, Vector3 L2)
{
    Vector3 V0 = squeeze( C2 - C1);
    Vector3 V1 = squeeze( L1 - C1);
    Vector3 V2 = squeeze( L2 - C1);
    Vector3 Cross1 = Vector3.Cross(V0, V1).normalized;
    Vector3 Cross2 = Vector3.Cross(V0, V2).normalized;
    float Dot = Vector3.Dot(Cross1, Cross2);
    if (Dot>0)
    {
        //同边不相交
        return false;
    }
    else
    {
        //同异边相交
        return true;
    }
}
//坐标平面化,去除y值
Vector3 squeeze(Vector3 vector)
{
    return new Vector3(vector.x, 0, vector.z);
}

判断两条线段是否相交

bool isCut(Vector3 C1, Vector3 C2, Vector3 L1, Vector3 L2)
{
    Vector3 V0 =C2 - C1;
    Vector3 V1 =L1 - C1;
    Vector3 V2 = L2 - C1;
    Vector3 Cross1 = Vector3.Cross(V0, V1).normalized;
    Vector3 Cross2 = Vector3.Cross(V0, V2).normalized;
    float Dot = Vector3.Dot(Cross1, Cross2);
      if (Dot>0)
    {
        //同边不相交
        return false;
    }
    else
    {
        //同异边相交
        return true;
    }
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号