我正在尝试使用 opengl 4.3 中的计算着色器编写实时光线追踪器。我知道这是一个相当受欢迎的问题。 我已经检查了这个和这个,但是那里提供的架构与我的用例并不真正对应。
我只是试图将P. Shirley的书中提供的ray_color
函数转换为非递归函数。
上述ray_color
功能:
color ray_color(const ray& r, const hittable& world, int depth) {
hit_record rec;
// If we've exceeded the ray bounce limit, no more light is gathered.
if (depth <= 0)
return color(0,0,0);
if (world.hit(r, 0.001, infinity, rec)) {
point3 target = rec.p + rec.normal + random_unit_vector();
return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1);
}
vec3 unit_direction = unit_vector(r.direction());
auto t = 0.5*(unit_direction.y() + 1.0);
return (1.0-t)*color(1.0, 1.0, 1.0) + t*color(0.5, 0.7, 1.0);
}
这是我的尝试:
vec3 no_hit_color(in Ray r) {
vec3 dir = normalize(r.direction);
float temp = 0.5 * (dir.y + 1.0);
vec3 cval = vec3(1.0 - temp) + temp * vec3(0.5, 0.7, 1.0);
return cval;
}
vec3 ray_color(in Ray r, in Scene scene, int depth) {
//
Ray r_in;
r_in.origin = r.origin;
r_in.direction = r.direction;
vec3 bcolor = vec3(1);
while (true) {
Ray r_out;
if (depth <= 0) {
//
return vec3(0);
}
HitRecord rec;
if (hit_scene(scene, r_in, 0.001, INFINITY, rec)) {
vec3 target = rec.point + random_in_hemisphere(rec.normal);
r_in = makeRay(rec.point, target - rec.point);
depth--;
bcolor *= 0.5;
} else {
bcolor *= no_hit_color(r_in);
return bcolor;
}
}
}
如果我使用深度的静态值,例如#define MAX_DEPTH
,我认为我可以通过制作自己的堆栈来实现算法,但我想将深度保留为动态变量,用户可以让用户根据他们的计算能力进行调整。 所以我想在可能的情况下使用 while 来实现它。 我的版本在球体底部附近生成一个黑色切片,与参考图片不对应。
更新 1:
我有点相信上面的实现是正确的,但我从中生成光线的相机位置是有问题的。
我已经确认实现确实是正确的。下面是一个 glsl 版本和 c++ 版本供将来参考。 它应该为你以后实现更复杂的东西提供一个方向。
// glsl version
vec3 ray_color(in Ray r, in Scene scene, int depth) {
//
Ray r_in;
r_in.origin = r.origin;
r_in.direction = r.direction;
vec3 bcolor = vec3(1);
while (true) {
if (depth <= 0) {
//
return vec3(0);
// return bcolor;
}
HitRecord rec;
if (hit_scene(scene, r_in, 0.001, INFINITY, rec)) {
vec3 target = rec.point + random_in_hemisphere(rec.normal);
r_in = makeRay(rec.point, target - rec.point);
depth--;
bcolor *= 0.5;
} else {
vec3 dir = normalize(r_in.direction);
float temp = 0.5 * (dir.y + 1.0);
bcolor *= vec3(1.0 - temp) + temp * vec3(0.5, 0.7, 1.0);
return bcolor;
}
}
}
// cpp version
color ray_color2(const Ray &r, const HittableList &scene, int depth) {
Ray r_in = Ray(r.origin, r.direction);
color rcolor = color(1);
while (true) {
HitRecord record;
if (depth <= 0) {
// final case
return color(0);
}
if (scene.hit(r_in, 0.001, INF, record)) {
// recursive case
point3 target = record.point + random_in_hemisphere(record.normal);
r_in = Ray(record.point, target - record.point);
depth--;
rcolor *= 0.5;
} else {
vec3 direction = to_unit(r_in.direction);
double temp = 0.5 * (direction.y + 1.0);
rcolor *= (1.0 - temp) * color(1.0) + temp * color(0.5, 0.7, 1.0);
return rcolor;
}
}
}
基本上,只要可以使用线性算子对光线的贡献进行建模,就应该可以使用while
循环来实现该功能。请注意,该函数不使用调用堆栈,因此它可以在光线的最大反弹率或最大深度(无论您喜欢哪个(是动态的情况下使用。