IAM目前正在写与三角形相交光线跟踪器。我已经导出的网格作为.RAW格式只是有每个顶点的坐标。而且我注意到一件事,当我将相机旋转它种显示闭塞网。
下面我后我的三角形相交功能在我的片段着色器
bool hitTriangle(vec3 orig,vec3 dir,vec3 a,vec3 b,vec3 c,out vec3 uvt,out vec3 triangleNormal){
float eps=1e-8;
vec3 ab=b-a;
vec3 ac=c-a;
triangleNormal = normalize(cross(ab,ac));
vec3 n=cross(dir,ac);
float det=dot(ab,n);
// if the determinant is negative the triangle is backfacing
// if the determinant is close to 0, the ray misses the triangl
if(det<=eps){ return false;}
vec3 ao=orig-a;
float u=dot(ao,n)/det;
if(u<0.0 || u>1.0){ return false;}
vec3 e=cross(ao,ab);
float v=dot(dir,e)/det;
if(v<0.0||u+v>1.0){ return false;}
float t= dot(ac,e)/det;
uvt = vec3(u,v,t);
return true;
}
它下面的hitScene函数在那里我经历的所有网和检查十字路口
bool hitScene(Ray R_, out vec3 hitPos, out vec3 normal, out Material material, Sphere lightSource){ // na thimithw na thesw to isShpere false stin trace synartisi
vec4 a = vec4(0.0), b = vec4(0.0), c = vec4(0.0);
float mindist = -1000.;
bool weHitSomething = false;
vec3 hitPos1 = vec3(0.),triangleNormal = vec3(0.,0.,0.), sphereNormal;
//here we chck all the mesh if we hit a triangle if the mesh and we keep the closest hitpoint
for (int i = 0; i < vertsCount; i += 3) {
a = texelFetch(uMeshData, ivec2(i, 0), 0);
b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));
vec3 uvt;
bool isHit = hitTriangle(R_.orig,R_.dir, a.xyz,b.xyz,c.xyz,uvt, triangleNormal);
if (isHit) {
vec3 intersect = R_.orig + R_.dir*uvt.z;
float z = intersect.z;
if (z>mindist) {
hitPos1 = intersect;
mindist = z;
weHitSomething = true;
material.type = METAL;
material.albedo = vec3(.0, .8, .8);
normal = triangleNormal;
hitPos = hitPos1;
}
}
}
return weHitSomething;
}
以下是穿过的痕迹循环跟踪功能
//Trace is the main function of the max bounces
vec3 Trace(out Ray ray, Sphere lightSource){
vec3 hitPos, normal;
bool isShpere;
Material material;
vec3 color = vec3(1.);
vec3 attenuation = vec3(1.);
vec3 light = vec3(1.,1.,1.), shadow = vec3(1.,1.,1.);
//this if for every ray to bounce 4 times.(hopefully)
for(int i=0; i< MAX_BOUNCES; i++){
// we check if we hit something
if(hitScene(ray, hitPos, normal, material, lightSource)){
//we calculate the new direction
vec3 direction = normalize(reflect(ray.dir, normal));
ray = Ray(hitPos, direction);
color *= material.albedo * attenuation*hitPos;
attenuation *= material.albedo;
}
else{
color = attenuation;
}
}
return color;
}
而IAM得到类似的东西后:正如你看到我正在思考,但我看到的立方体以及内部的球体。这是否意味着我无法通过光线 - 三角形相交测试?或最小距离不正确?
可能是什么问题的根源?
这不会解决你所有的问题,但它是答案的一部分。
在你的代码中有Barycentric coordinates的基本误解。重心坐标不在一个坐标,但它们是在范围3点的值[0,1]。想象一个重心坐标作为3点的权重,其重量的三角形的3个点。
重心的坐标的3台秤的总和为1:
b.x + b.x + b.z == 1
如果一个三角形由三个点A
,B
和C
,然后在三角形,这是由重心定义的坐标可以由下式来计算点X
定义:
X = A * b.x + B * b.y + C * b.z
这意味着交点distance
在hitScene
具有如下必须适应的计算:
vec3 intersect = a.xyz * uvt.x + b.xyz * uvt.y + c.xyz * uvt.z;
于光线的原点氏距离为是向量的长度形成起源于交叉点i的射线的方向。 一般来说,我会以某种方式计算该这样:
float z = dot(intersect - R_.orig, normalize(R_.dir));
此外,该算法计算重心坐标看起来很奇怪。我很肯定它必须uvt = vec3(t, u, v)
而非uvt = vec3(u, v, t);
。但是,这还需要进一步调查。
三角形和射线的交点可以被计算如下:
光线由点R0
和方向D
限定。
面被与三个点PA
,PB
和PC
三角形定义。
平面的法向矢量可通过2和腿部的三角形的叉积计算:
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)
运用你的代码,我建议使用下面的函数hitTriangle
:
true
如果射线相交的射线(dir
)的原点后的三角形在射线(orig
)的正方向原语。N
是由三角形限定的平面的法向矢量。uvt
是三角形的Barycentric coordinates。x
是在三角形的交点。dist
距离射线(orig
)的原点到交点x
的距离。注意,光线方向(dir
)必须归一化。输出值有如果函数返回true
只有一个意思。
bool hitTriangle(
vec3 orig, vec3 dir, vec3 a, vec3 b, vec3 c,
out vec3 uvt, out vec3 N, out vec3 x, out float dist) {
float eps=1e-8;
vec3 ab = b - a;
vec3 ac = c - a;
N = normalize(cross(ab, ac));
dist = dot(a - orig, N) / dot(dir, N);
x = orig + dir * dist;
vec3 ax = x - a;
float d00 = dot(ab, ab);
float d01 = dot(ab, ac);
float d11 = dot(ac, ac);
float d20 = dot(ax, ab);
float d21 = dot(ax, ac);
float denom = d00 * d11 - d01 * d01; // determinant
// if the determinant is negative the triangle is backfacing
// if the determinant is close to 0, the ray misses the triangl
if ( denom <= eps )
return false;
uvt.y = (d11 * d20 - d01 * d21) / denom;
if ( uvt.y < 0.0 || uvt.y > 1.0 )
return false;
uvt.z = (d00 * d21 - d01 * d20) / denom;
if ( uvt.z < 0.0 || uvt.z > 1.0 )
return false;
uvt.x = 1.0 - uvt.y - uvt.z;
if ( uvt.x < 0.0 || uvt.x > 1.0 )
return false;
return true;
}
在功能hitTriangle
使用命中测试(hitScene
)如下:
bool hitScene(Ray R_, out vec3 hitPos, out vec3 normal, out Material material, Sphere lightSource){ // na thimithw na thesw to isShpere false stin trace synartisi
vec4 a = vec4(0.0), b = vec4(0.0), c = vec4(0.0);
float mindist = 1000.;
bool weHitSomething = false;
vec3 hitPos1 = vec3(0.),triangleNormal = vec3(0.,0.,0.), sphereNormal;
vec3 ray_dir = normalize(R_.dir);
//here we chck all the mesh if we hit a triangle if the mesh and we keep the closest hitpoint
for (int i = 0; i < vertsCount; i += 3) {
a = texelFetch(uMeshData, ivec2(i, 0), 0);
b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));
vec3 uvt;
vec3 intersect;
float z;
bool isHit = hitTriangle(R_.orig, ray_dir, a.xyz, b.xyz, c.xyz, uvt, triangleNormal, intersect, z);
if (isHit)
{
if (z < mindist && z > 0.001)
{
hitPos1 = intersect;
mindist = z;
weHitSomething = true;
material.type = METAL;
material.albedo = vec3(.0, .8, .8);
normal = triangleNormal;
hitPos = hitPos1;
}
}
}
return weHitSomething;
}