求射线与三角形的交点,并附代码

1. 射线与平面求交

射线可以描述为:
p(t)=p0+t∗u→ p(t) = p_0 + t*\overrightarrow{u} p(t)=p0+tu
其中,p0是射线的起始点,u是射线的方向向量(需要单位化),t是参数,表示射线上任意一点到起点的距离。

计算射线与三角形平面的交点的数学公式可以分为两部分:首先找到射线与三角形所在平面的交点,然后判断该交点是否在三角形内部。以下是详细的步骤和公式:

平面可以描述为:
n→⋅(p−p0’)=0 \overrightarrow{n}\cdot(p-p_{0}^{’}) = 0 n(pp0)=0
其中,p 是平面上的任意一点,n 是平面的单位法向量,p0' 是平面上任意一点(可以是三角形的任意一个顶点)。

为了找到射线与平面的交点,我们需要将射线的方程代入平面的方程中,并解出参数 t:
n→⋅(p0+t∗u→−p0’)=0n→⋅p0+t(n→⋅u→)−n→⋅p0’=0t(n→⋅u→)=n→⋅p0−n→⋅p0’t=(n→⋅p0−n→⋅p0’)/(n→⋅u→) \overrightarrow{n}\cdot(p_0 + t*\overrightarrow{u}-p_{0}^{’})=0 \\ \overrightarrow{n}\cdot p_0+t(\overrightarrow{n} \cdot \overrightarrow{u}) - \overrightarrow{n}\cdot p_{0}^{’} = 0 \\ t(\overrightarrow{n} \cdot \overrightarrow{u}) = \overrightarrow{n}\cdot p_0 - \overrightarrow{n}\cdot p_{0}^{’} \\ t = (\overrightarrow{n}\cdot p_0 - \overrightarrow{n}\cdot p_{0}^{’}) / (\overrightarrow{n} \cdot \overrightarrow{u}) n(p0+tup0)=0np0+t(nu)np0=0t(nu)=np0np0t=(np0np0)/(nu)
如果 n · u ≠ 0(即射线的方向向量与平面的法向量不垂直),则可以求出 t 的值,进而求出交点 p(t)。

2. 判断交点是否在三角形内部

求出交点后,我们需要判断该交点是否在三角形内部。这可以通过重心坐标法来实现

啥是重心坐标:

在这里插入图片描述

如图,对于空间三角形P1、P2、P3内任一点P,必定唯一存在三个数w1、w2、w3,满足:
w1+w2+w3=1P=w1∗P1+w2∗P2+w3+P3 w_1+w_2+w_3 = 1 \\ P = w_1 * P_1 + w_2 * P_2 + w_3 + P_3 w1+w2+w3=1P=w1P1+w2P2+w3+P3
则(w1,w2,w3)就称为此三角形上P点的(归一化)重心坐标。

重心坐标求解

构建方程组,求解P点坐标
{w1+w2+w3=1Px=w1∗P1x+w2∗P2x+w3∗P3xPy=w1∗P1y+w2∗P2y+w3∗P3y={Px−P3x=w1∗(P1x−P3x)+w2∗(P2x−P3x)Py−P3y=w1∗(P1y−P3y)+w2∗(P2y−P3y)w3=1−w1−w2 \begin{cases} w_1 + w_2 + w_3 = 1 \\ P_x = w_1 * P_{1x} + w_2 * P_{2x} + w_3 * P_{3x} \\ P_y = w_1 * P_{1y} + w_2 * P_{2y} + w_3 * P_{3y} \end{cases} =\\ \begin{cases} P_x - P_{3x} = w_1 * (P_{1x} - P_{3x}) + w_2 * (P_{2x} - P_{3x}) \\ P_y - P_{3y} = w_1 * (P_{1y} - P_{3y}) + w_2 * (P_{2y} - P_{3y}) \\ w_3 = 1 - w_1 - w_2\\ \end{cases} w1+w2+w3=1Px=w1P1x+w2P2x+w3P3xPy=w1P1y+w2P2y+w3P3y=PxP3x=w1(P1xP3x)+w2(P2xP3x)PyP3y=w1(P1yP3y)+w2(P2yP3y)w3=1w1w2
设向量CAB,分别为C = P - P3A=P1-P3B=P2-P3
在这里插入图片描述
故方程组可写为如下表达式
{Cx=w1Ax+w2BxCy=w1Ay+w2Byw3=1−w1−w2={w1=CxBy−CyBxAxBy−AyBx=C→×B→A→×B→=(C→×B→)⋅(A→×B→)(A→×B→)⋅(A→×B→)w2=CxAy−CyAxAxBy−AyBx=C→×A→A→×B→=(C→×A→)⋅(A→×B→)(A→×B→)⋅(A→×B→)w3=1−w1−w2 \begin{cases} C_x = w_1 A_x + w_2 B_x \\ C_y = w_1 A_y + w_2 B_y \\ w_3 = 1 - w_1 - w_2 \end{cases} = \\ \begin{cases} w_1 = \frac{C_x B_y - C_yB_x}{A_x B_y - A_yB_x} = \frac{\overrightarrow{C}\times\overrightarrow{B}}{\overrightarrow{A}\times\overrightarrow{B}}= \frac{(\overrightarrow{C}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})} {(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\ w_2 = \frac{C_x A_y - C_yA_x}{A_x B_y - A_yB_x} =\frac{\overrightarrow{C}\times\overrightarrow{A}}{\overrightarrow{A}\times\overrightarrow{B}} =\frac{(\overrightarrow{C}\times\overrightarrow{A})\cdot(\overrightarrow{A}\times\overrightarrow{B})} {(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\ w_3 = 1 - w_1 - w_2 \end{cases} Cx=w1Ax+w2BxCy=w1Ay+w2Byw3=1w1w2=w1=AxByAyBxCxByCyBx=A×BC×B=(A×B)(A×B)(C×B)(A×B)w2=AxByAyBxCxAyCyAx=A×BC×A=(A×B)(A×B)(C×A)(A×B)w3=1w1w2
以下过程,要将叉乘转为点乘,在<<OpenGL编程指南(原书第9版)>>一书,关于transform feedback的例程中,着色器计算射线与三角形的交点时,用的点乘进行计算,遂进行分析推导,如下:

通过标量三重积公式:
a→⋅(b→×c→)=b→⋅(c→×a→)=c→⋅(a→×b→) \overrightarrow{a}\cdot(\overrightarrow{b}\times\overrightarrow{c}) =\overrightarrow{b}\cdot(\overrightarrow{c}\times\overrightarrow{a}) =\overrightarrow{c}\cdot(\overrightarrow{a}\times\overrightarrow{b}) a(b×c)=b(c×a)=c(a×b)
可得
w1=(C→×B→)⋅(A→×B→)(A→×B→)⋅(A→×B→)=A→⋅[(C→×B→)×B→](A→×B→)⋅(A→×B→)w2=(C→×A→)⋅(A→×B→)(A→×B→)⋅(A→×B→)=B→⋅[(C→×A→)×A→](A→×B→)⋅(A→×B→) w_1 = \frac{(\overrightarrow{C}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})} {(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})} = \frac{\overrightarrow{A} \cdot [(\overrightarrow{C}\times\overrightarrow{B})\times\overrightarrow{B}]}{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\ w_2 =\frac{(\overrightarrow{C}\times\overrightarrow{A})\cdot(\overrightarrow{A}\times\overrightarrow{B})} {(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})} = \frac{\overrightarrow{B} \cdot [(\overrightarrow{C}\times\overrightarrow{A})\times\overrightarrow{A}]}{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\ w1=(A×B)(A×B)(C×B)(A×B)=(A×B)(A×B)A[(C×B)×B]w2=(A×B)(A×B)(C×A)(A×B)=(A×B)(A×B)B[(C×A)×A]
通过向量三重积公式:
a→×(b→×c→)=(a→⋅c→)b→−(a→⋅b→)c→ \overrightarrow{a}\times(\overrightarrow{b}\times\overrightarrow{c}) =(\overrightarrow{a}\cdot\overrightarrow{c})\overrightarrow{b} - (\overrightarrow{a}\cdot\overrightarrow{b})\overrightarrow{c} a×(b×c)=(ac)b(ab)c
由此可得:
A→⋅[(C→×B→)×B→]=A→⋅((B→⋅B→)C→−(B→⋅C→)B→)=(B→⋅B→)(A→⋅C→)−(B→⋅C→)(A→⋅B→)B→⋅[(C→×A→)×A→]=B→⋅((A→⋅A→)C→−(A→⋅C→)A→)=(A→⋅A→)(B→⋅C→)−(A→⋅C→)(A→⋅B→) \overrightarrow{A} \cdot [(\overrightarrow{C}\times\overrightarrow{B})\times\overrightarrow{B}] = \overrightarrow{A} \cdot ((\overrightarrow{B}\cdot\overrightarrow{B})\overrightarrow{C} - (\overrightarrow{B}\cdot\overrightarrow{C})\overrightarrow{B}) =(\overrightarrow{B}\cdot\overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{C} ) - (\overrightarrow{B}\cdot\overrightarrow{C})(\overrightarrow{A} \cdot \overrightarrow{B}) \\ \overrightarrow{B} \cdot [(\overrightarrow{C}\times\overrightarrow{A})\times\overrightarrow{A}] = \overrightarrow{B} \cdot ((\overrightarrow{A}\cdot\overrightarrow{A})\overrightarrow{C} - (\overrightarrow{A}\cdot\overrightarrow{C})\overrightarrow{A}) = (\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{C}) - (\overrightarrow{A}\cdot\overrightarrow{C})(\overrightarrow{A}\cdot\overrightarrow{B}) A[(C×B)×B]=A((BB)C(BC)B)=(BB)(AC)(BC)(AB)B[(C×A)×A]=B((AA)C(AC)A)=(AA)(BC)(AC)(AB)
而根据拉格朗日恒等式:
(a→⋅b→)2+(a→×b→)⋅(a→×b→)=∥a→∥2∥b→∥2 (\overrightarrow{a} \cdot \overrightarrow{b})^2+(\overrightarrow{a}\times\overrightarrow{b})⋅(\overrightarrow{a}\times\overrightarrow{b})=\lVert\overrightarrow{a}\rVert^2\lVert\overrightarrow{b}\rVert^2 (ab)2+(a×b)(a×b)=a2b2
由此可得:
(A→×B→)⋅(A→×B→)=∥A→∥2∥B→∥2−(A→⋅B→)2 (\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B}) =\lVert\overrightarrow{A}\rVert^2\lVert\overrightarrow{B}\rVert^2 - (\overrightarrow{A} \cdot \overrightarrow{B})^2 (A×B)(A×B)=A2B2(AB)2

w1=(B→⋅B→)(A→⋅C→)−(B→⋅C→)(A→⋅B→)(A→⋅A→)(B→⋅B→)−(A→⋅B→)(A→⋅B→)w2=(A→⋅A→)(B→⋅C→)−(A→⋅C→)(A→⋅B→)(A→⋅A→)(B→⋅B→)−(A→⋅B→)(A→⋅B→) w_1 = \frac{(\overrightarrow{B}\cdot\overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{C} ) - (\overrightarrow{B}\cdot\overrightarrow{C})(\overrightarrow{A} \cdot \overrightarrow{B}) }{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{B}) - (\overrightarrow{A} \cdot \overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{B})}\\ w_2 =\frac{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{C}) - (\overrightarrow{A}\cdot\overrightarrow{C})(\overrightarrow{A}\cdot\overrightarrow{B})}{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{B}) - (\overrightarrow{A} \cdot \overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{B})} w1=(AA)(BB)(AB)(AB)(BB)(AC)(BC)(AB)w2=(AA)(BB)(AB)(AB)(AA)(BC)(AC)(AB)

着色器代码

原例程代码如下:

bool intersect(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, out vec3 point)
{
    vec3 u, v, n;
    vec3 w0, w;
    float r, a, b;

    u = (v1 - v0);
    v = (v2 - v0);
    n = cross(u, v);

    w0 = origin - v0;
    a = -dot(n, w0);
    b = dot(n, direction);

    r = a / b;
    if (r < 0.0 || r > 1.0)
        return false;

    point = origin + r * direction;

    float uu, uv, vv, wu, wv, D;

    uu = dot(u, u);
    uv = dot(u, v);
    vv = dot(v, v);
    w = point - v0;
    wu = dot(w, u);
    wv = dot(w, v);
    D = uv * uv - uu * vv;

    float s, t;

    s = (uv * wv - vv * wu) / D;
    if (s < 0.0 || s > 1.0)
        return false;

    t = (uv * wu - uu * wv) / D;
    if (t < 0.0 || (s + t) > 1.0)
        return false;

    return true;
}

为了更清楚的与上面对应,变量改为如下

bool intersect(vec3 P0, vec3 u, vec3 P1, vec3 P2, vec3 P3, out vec3 P)
{
    vec3 A, B, n;
    vec3 w0, w;
    float t, a, b;
	
    //三角形边向量,以及法向量
    A = (P1 - P3);
    B = (P2 - P3);
    n = cross(A, B);

    w0 = P0 - P3;
    a = -dot(n, w0);
    b = dot(n, u);
	
    //求参数t
    t = a / b;
    //t < 0.0,交点在射线起点之前
    //t > 1.0,交点在射线延伸方向之外
    if (t < 0.0 || t > 1.0)
        return false;
    
    //计算交点
    P = P0 + r * u;

    float AA, AB, BB, CA, CB, D;

    AA = dot(A, A);
    AB = dot(A, B);
    BB = dot(B, B);
    C = P - P3;
    CA = dot(C, A);
    CB = dot(C, B);
    D = AB * AB - AA * BB;

    float w1, w2;

    w1 = (AB * CB - BB * CA) / D;
    if (w1 < 0.0 || w1 > 1.0)
        return false;

    w2 = (AB * CA - AA * CB) / D;
    if (w2 < 0.0 || (w1 + w2) > 1.0)
        return false;

    return true;
}
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值