重心坐标并不总是有效(3d)



我有一个由 12 个以原点为中心的三角形组成的 3d 盒子。我从原点向随机方向发射一条射线,目标是得到与射线相交的面。 我通过搜索所有射线/平面交点,然后使用重心坐标(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 
) 

这对我来说都是新的,任何帮助都会很棒!

此代码

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;
}

上面的代码假设最终你将拥有比 12 个三角形单位立方体更复杂的网格。如果您只需要单位立方体,请找到随机向量的最长绝对维度,该坐标的这个 + 符号将告诉您它将与 6 个立方体平面中的哪一个相交。如果没有最长的维度,例如您的光线方向是 [1,1,0],则光线穿过立方体的边缘或顶点。否则,测试其他 2 个坐标以找到它与 2 个三角形中的哪一个相交。

最新更新