尝试计算点“ point”是否在三角形中时,我的代码有什么问题?

时间:2018-12-21 14:27:59

标签: c++ graphics glsl

有人可以看到我的代码有什么问题吗?

NET USE J: $appsource

以浆果为中心的坐标

float intersect(Ray ray, Triangle triangle) {
    float scalar = (0 - dot(triangle.normal, ray.origin)) / dot(triangle.normal, ray.dir);
    vec3 point = ray.origin + scalar * ray.dir;

使用Berrycentric坐标 计算tby 矩阵 tby = [A点] ==> tby = inverse(矩阵) [A点]

    vec3 A = vec3(1, 0, 0);
    vec3 B = vec3(0, 1, 0);
    vec3 C = vec3(0, 0, 1);

我到目前为止所创造的 TriangleStruct

    mat3 matrix = mat3(point, A - B, A - C);
    vec3 tby = transpose(matrix) * vec3(A - point);

    float t = tby.x;
    float beta = tby.y;
    float gamma = tby.z;
    if (beta + gamma < 1 && beta > 0 && gamma > 0 && t > 0)
        return scalar;
    return -1.0;
}

要点

    struct Triangle
    {
     vec3 p1;
     vec3 p2;
     vec3 p3;
     vec3 normal;
     Material material;
    };

三角形

    vec3 p1 = vec3(-0.3,0.2,0.5);
    vec3 p2 = vec3(0.3,0.2,0.5);
    vec3 p3 = vec3(0.15,0.0,0.0);
    vec3 p4 = vec3(0.15,0.2,0.5);

三角形1

    {

三角形2

    scene.triangles[0].p1 = p1;
    scene.triangles[0].p2 = p4;
    scene.triangles[0].p3 = p3;
    scene.triangles[0].normal = normalize(cross((p4-p1), (p3-p1)));

三角形3

    scene.triangles[1].p1 = p3;
    scene.triangles[1].p2 = p2;
    scene.triangles[1].p3 = p1;
    scene.triangles[1].normal = normalize(cross((p2-p3), (p1-p3)));

...

    scene.triangles[2].p1 =p3;
    scene.triangles[2].p2 = p4;
    scene.triangles[2].p3 = p2;
    scene.triangles[2].normal = normalize(cross((p4-p3), (p2-p3)));

2 个答案:

答案 0 :(得分:1)

根据我的理解,您尝试检查ray是否通过triangle。 我看到的第一个错误是point

vec3 point = ray.origin + scalar * ray.dir;

具有无意义的定义。您可以计算ray与平行于穿过原点的triangle的平面的交点。除非出于某种神奇的原因,该平面与triangle的平面重合,否则所有与此point一起进行的计算都没有任何意义。

要解决此问题,您需要像这样定义scalar

float scalar = dot(triangle.normal,triangle.x) - dot(triangle.normal,ray.origin); 
scalar /= dot(triangle.normal,ray.dir);

其中triangle.xtriangle的任意点。

解决此问题后,可以讨论代码的其他部分是否有意义。

还请提供有关代码细节(即实施的相关部分)的更多信息。


现在介绍如何检查射线是否与三角形相交。 将射线与三角形的平面相交然后在二维设置中检查点是否在三角形内部的方法在稳定性方面不是很好。所以避免它。

一种更简单直接的方法是计算差异向量:

vec3 dvec1 = tringle.p1 - ray.origin;
vec3 dvec2 = tringle.p2 - ray.origin;
vec3 dvec3 = tringle.p3 - ray.origin;

,然后检查ray.dir是否可以表示为具有正系数的dvec1dvec2dvec3的线性和。这可以通过计算矩阵mat3(dvec1,dvec2,dvec3)的逆并将其乘以ray.dir来实现(通过这种方式,您可以获得表示ray.dir的{​​{1}}线性和的系数。 ,dvec1dvec2)。

但是,由于除法,矩阵方法并非完全稳定。可以通过实现逻辑上等效的代码而无需进行除法来进一步改进。

dvec3

在第一个vec3 dvec12 = cross_product(dvec1, dvec2); if(dot(dvec12,dvec3)*dot(dvec12,ray.dir) < 0.) return false; vec3 dvec23 = cross_product(dvec2, dvec3); if(dot(dvec23,dvec1)*dot(dvec23,ray.dir) < 0.) return false; vec3 dvec31 = cross_product(dvec3, dvec1); if(dot(dvec31,dvec2)*dot(dvec31,ray.dir) < 0.) return false; return true; 中,我们检查if相对于ray.dir所在的平面是否与dvec3在同一半平面上。如果不是,那么{dvec1,dvec2}不会与三角形相交。

然后我们对其他向量重复此检查。

答案 1 :(得分:1)

我建议像这样重写您的代码:

bool PointInOrOn( vec3 P1, vec3 P2, vec3 A, vec3 B )
{
    vec3 CP1 = cross( B - A, P1 - A )
    vec3 CP2 = cross( B - A, P2 - A )
    return step(0.0, dot( CP1, CP2 ));
}

float intersect(Ray ray, Triangle triangle)
{
    vec3 D = normalize(ray.dir);         // skip normalize, if ray.dir is normalized
    vec3 N = normalize(triangle.normal); // skip normalize, if triangle.normal is normalized

    float d = dot(triangle.p1 - ray.origin, N) / dot(D, N)
    vec3  X = ray.origin + D * d;

    float isIn = PointInOrOn( X, triangle.p1, triangle.p2, triangle.p3 ) *
                 PointInOrOn( X, triangle.p2, triangle.p3, triangle.p1 ) *
                 PointInOrOn( X, triangle.p3, triangle.p1, triangle.p2 );

    if ( isIn > 0.01 )
        return d;
    return -1.0;
}

请参阅以下说明。


射线与三角形图元的交点

射线由点R0和归一化方向D定义。
平面由具有三个点PAPBPC的三角形定义。

平面的法向矢量可以通过三角形的两条腿的叉积来计算:

N  =  normalize( cross(PC-PA, PB-PA)

n与平面的法线距离R0为:

n  =  | R0 - PA | * cos(alpha)  =  dot(PA - R0, N)

由此得出,交点d与射线R0的原点的距离X为:

d  =  n / cos(beta)  =  n / dot(D, N)

交点X为:

X  =  R0 + D * d  =  R0 + D * dot(PA - R0, N) / dot(D, N)

要找出一个点是否在三角形内,是否必须测试从角点到相交点的线是否在连接到该角点的腿之间。三角形由点ABC定义,要测试的点为P

bool PointInOrOn( P1, P2, A, B )
{
    CP1 = cross( B - A, P1 - A )
    CP2 = cross( B - A, P2 - A )
    return dot( CP1, CP2 ) >= 0
}

bool PointInOrOnTriangle( P, A, B, C )
{
    return PointInOrOn( P, A, B, C ) &&
           PointInOrOn( P, B, C, A ) &&
           PointInOrOn( P, C, A, B )
}