C++ 重心坐标不';t总是工作(3d)

C++ 重心坐标不';t总是工作(3d),c++,linear-algebra,C++,Linear Algebra,我有一个由12个三角形组成的三维长方体,以原点为中心。我从原点向随机方向发射光线,目标是得到与光线相交的面。 我通过搜索所有光线/平面交点,然后用重心坐标(u、v、w)确定其上的面(如果有)。 这只在一半的时间内正常工作,通常会产生意外的结果: float triangleAREA(vec3 a, vec3 b, vec3 c) { return(length(cross(b-a, c-a)) / 2); } int isINtriangle(vec3 a, vec3 b, vec3 c

我有一个由12个三角形组成的三维长方体,以原点为中心。我从原点向随机方向发射光线,目标是得到与光线相交的面。 我通过搜索所有光线/平面交点,然后用重心坐标(u、v、w)确定其上的面(如果有)。 这只在一半的时间内正常工作,通常会产生意外的结果:

float triangleAREA(vec3 a, vec3 b, vec3 c)
{
    return(length(cross(b-a, c-a)) / 2);
}
int isINtriangle(vec3 a, vec3 b, vec3 c, vec3 p)
{
    float total_area = triangleAREA(a, b, c);
    float u = triangleAREA(a, b, p);
    float v = triangleAREA(a, c, p);
    float w = triangleAREA(c, b, p);

    if (u + v + w != total_area)
        return Ray::_NOintersection;
    else
    {
        if (u == 0 || v == 0 || w == 0)
            return Ray::_Onedge_OnVertex;
        else
            return Ray::_INtriangle;
    }
}
这就是我检查交点是否与光线方向相同的方法:

vec3 a = normalize(ray_direction); vec3 b = normalize(intersect);
if (
    a.x > b.x - 1 && a.x < b.x + 1 &&
    a.z > b.z - 1 && a.z < b.z + 1 &&
    a.y > b.y - 1 && a.y < b.y + 1 
) 
vec3 a=规格化(光线方向);vec3 b=规格化(相交);
如果(
a、 x>b.x-1&&a.xb.z-1&&a.zb.y-1&&a.y
这对我来说都是新鲜事,任何帮助都会很棒

此代码

if (u + v + w != total_area)
对于浮动来说是不可靠的。浮点数的工作方式与整数不同,对精确相等性的测试几乎没有任何意义

你应该做一些完全不同的事情。这里有一个方法。该代码未经测试,但在概念上它应该可以工作,我做过很多类似的事情

#include <assert.h>

// 0 when [0,p] ray goes through [0,t1,t2] plane.
// Otherwise, the sign tells relative orientation of the ray and the plane.
inline float crossDot( vec3 t1, vec3 t2, vec3 p )
{
    // Depending on winding order of triangles, and coordinate system (right versus left handed),
    // you may need to flip the cross() arguments
    return dot( cross( t1, t2 ), p );
}

// The triangle is [a, b, c], the points must have consistent winding,
// i.e. when viewed from [0,0,0] the order must be either clockwise or counterclockwise,
// for all triangles of your mesh.
// p does not need to be normalized, length is ignored, only direction is used.
int testRayTriangle( vec3 a, vec3 b, vec3 c, vec3 p )
{
    // If this assert fails because zero, you have a zero-area triangle, or a triangle that goes through [0,0,0].
    // If this assert fails because negative, you need to flip cross() arguments, or fix winding order in the mesh.
    assert( crossDot( a, b, c ) > 0 );
    const float e1 = crossDot( a, b, p );
    const float e2 = crossDot( b, c, p );
    const float e3 = crossDot( c, a, p );
    if( e1 < 0 || e2 < 0 || e3 < 0 )
        return Ray::_NOintersection;    // The ray points outwards in relation to some side plane
    if( e1 > 0 && e2 > 0 && e3 > 0 )
        return Ray::_INtriangle;    // The ray points inwards in relation to all 3 side planes
    // The ray goes through a side plane
    return Ray::_Onedge_OnVertex;
}
#包括
//当[0,p]射线穿过[0,t1,t2]平面时为0。
//否则,该符号表示光线和平面的相对方向。
内联浮点交叉点(vec3 t1、vec3 t2、vec3 p)
{
//根据三角形的缠绕顺序和坐标系(右手和左手),
//您可能需要翻转cross()参数
返回点(交叉点(t1,t2),p);
}
//三角形是[a,b,c],各点必须有一致的绕组,
//即,从[0,0,0]观察时,顺序必须为顺时针或逆时针,
//用于网格的所有三角形。
//p不需要规格化,长度被忽略,只使用方向。
int testRayTriangle(向量3 a、向量3 b、向量3 c、向量3 p)
{
//如果此断言因零而失败,则表示有一个面积为零的三角形,或一个穿过[0,0,0]的三角形。
//如果此断言因负值而失败,则需要翻转cross()参数,或修复网格中的缠绕顺序。
断言(交叉点(a,b,c)>0);
常数浮点e1=交叉点(a、b、p);
常数浮点e2=交叉点(b,c,p);
常数浮点e3=交叉点(c,a,p);
如果(e1<0 | | e2<0 | | e3<0)
返回光线::\u NOintersection;//光线相对于某个侧面指向外部
如果(e1>0&&e2>0&&e3>0)
返回光线::_INtriangle;//光线相对于所有3个侧面向内指向
//光线穿过一个侧面
返回光线::_Onedge_OnVertex;
}
上面的代码假设最终你会有比你的12个三角形单位立方体更复杂的网格。如果你只需要单位立方体,找到你的随机向量的最长绝对维数,这个坐标的+符号将告诉你它将与6个立方体平面中的哪一个相交。如果没有最长维度,例如光线方向为[1,1,0],则光线穿过立方体的边或顶点。否则,测试另外两个坐标,找出它与两个三角形中的哪一个相交