重心坐标并不总是有效 (3d)
Barycentric coordinates doesn't always work(3d)
我有一个由 12 个以原点为中心的三角形组成的 3d 盒子。我从原点向随机方向发射一条射线,目标是获得与射线相交的面。
我通过搜索所有 ray/plane 交点,然后用重心坐标 (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 个三角形中的哪个相交。
我有一个由 12 个以原点为中心的三角形组成的 3d 盒子。我从原点向随机方向发射一条射线,目标是获得与射线相交的面。 我通过搜索所有 ray/plane 交点,然后用重心坐标 (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 个三角形中的哪个相交。