有人可以看到我的代码有什么问题吗?
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)));
答案 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.x
是triangle
的任意点。
解决此问题后,可以讨论代码的其他部分是否有意义。
还请提供有关代码细节(即实施的相关部分)的更多信息。
现在介绍如何检查射线是否与三角形相交。 将射线与三角形的平面相交然后在二维设置中检查点是否在三角形内部的方法在稳定性方面不是很好。所以避免它。
一种更简单直接的方法是计算差异向量:
vec3 dvec1 = tringle.p1 - ray.origin;
vec3 dvec2 = tringle.p2 - ray.origin;
vec3 dvec3 = tringle.p3 - ray.origin;
,然后检查ray.dir
是否可以表示为具有正系数的dvec1
,dvec2
和dvec3
的线性和。这可以通过计算矩阵mat3(dvec1,dvec2,dvec3)
的逆并将其乘以ray.dir
来实现(通过这种方式,您可以获得表示ray.dir
的{{1}}线性和的系数。 ,dvec1
和dvec2
)。
但是,由于除法,矩阵方法并非完全稳定。可以通过实现逻辑上等效的代码而无需进行除法来进一步改进。
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
定义。
平面由具有三个点PA
,PB
和PC
的三角形定义。
平面的法向矢量可以通过三角形的两条腿的叉积来计算:
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)
要找出一个点是否在三角形内,是否必须测试从角点到相交点的线是否在连接到该角点的腿之间。三角形由点A
,B
,C
定义,要测试的点为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 )
}