【发布时间】:2016-01-08 08:30:43
【问题描述】:
我正在尝试用 C++ 编写光线追踪器,但目前的结果并不如我所愿,所以我猜照明方程中存在错误。 这是我到目前为止所得到的:
Picture of my result. In the upper line what I've got, in the bottom line what I would like to get
我正在使用 Blinn(-Phong) 模型并假设所有灯光都是点灯。这是我的代码:
vec3f raytrace_ray(Scene* scene, ray3f ray) {
// get scene intersection
auto intersection = intersect_surfaces(scene, ray);
// if not hit, return background
if (!intersection.hit) {
return scene->background;
}
// accumulate color starting with ambient
vec3f c = zero3f;
c += scene->ambient*intersection.mat->kd;
//Add emission
c += intersection.mat->ke;
// foreach light
for (Light* light : scene->lights) {
// compute light response
auto lightRadiance = light->intensity / distSqr(light->frame.o, intersection.pos);
if(lightRadiance == zero3f) continue;
// compute light direction
auto l = normalize(light->frame.o - intersection.pos);
auto v = normalize(intersection.pos - ray.e);
auto h = normalize(l+v); //bisector
auto n = intersection.mat->n;
auto normal = intersection.norm;
// compute the material response (brdf*cos)
auto brdf = intersection.mat->ks*pow(max(0.0f, dot(normal,h)), intersection.mat->n);
// check for shadows and accumulate if needed
auto shadowRay = ray3f(intersection.pos, l, 0.001f, length(light->frame.o - intersection.pos));
float visibleTerm;
auto shadowIntersect = intersect_surfaces(scene, shadowRay);
if (shadowIntersect.hit) {
visibleTerm = 0;
}
else {
visibleTerm = 1;
}
//Accumulate
c += lightRadiance*visibleTerm*(intersection.mat->kd + brdf)*abs(dot(normal, l));
}
// if the material has reflections
// create the reflection ray
// accumulate the reflected light (recursive call) scaled by the material reflection
// return the accumulated color∫
return c;
}
现在我的问题是:
- 等式哪里错了?
- 从上次编辑中,我还添加了阴影,方法是创建一条射线(射线构造函数的最后两个参数是 tmin 和 tmax)并检查它是否击中了某些东西。如果是,我将 visibileTerm 设置为零(我还更新了屏幕截图)。我不确定这是否正确。
-
如何进一步添加反射和折射?我知道我必须递归调用该函数,但首先我必须计算什么以及以哪种方式?我尝试使用此代码在灯光的 for 循环中进行反射,但在某些测试无限递归中它不起作用:
ray3f reflectionRay = ray3f(intersection.pos, -l + 2 * dot(l, normal)*normal); c += intersection.mat->kr*raytrace_ray(scene, reflectionRay); -
从图二测试来看,路口也有问题,但不知道在哪里。我也尝试以这种方式用逆来改变正常计算:
auto normal = transform_normal_inverse(scene->camera->frame, surface->frame.z);但是我只得到了飞机的另一个倾斜度,而没有解决第二次测试。这是我的交集代码(我只使用了四边形和球体):
intersection3f intersect_surfaces(Scene* scene, ray3f ray) { auto intersection = intersection3f(); float currentDistance = INFINITY; float t; // foreach surface for (Surface* surface : scene->surfaces) { // if it is a quad if (surface->isquad) { /// compute ray intersection (and ray parameter), continue if not hit auto normal = transform_normal(scene->camera->frame, surface->frame.z); if (dot(ray.d, normal) == 0) { continue; } t = dot(surface->frame.o - ray.e, normal)/dot(ray.d,normal); // check if computed param is within ray.tmin and ray.tmax if (t < ray.tmin or t > ray.tmax) continue; // check if this is the closest intersection, continue if not auto p = ray.eval(t);//Intersection point if (dist(ray.e, p) >= currentDistance) { continue; } currentDistance = dist(ray.e, p); // if hit, set intersection record values intersection.ray_t = t; intersection.pos = p; intersection.norm = normalize(ray.e - p); intersection.mat = surface->mat; intersection.hit = true; } // if it is a sphere else { // compute ray intersection (and ray parameter), continue if not hit auto a = lengthSqr(ray.d); auto b = 2 * dot(ray.d, ray.e - surface->frame.o); auto c = lengthSqr(ray.e - surface->frame.o) - surface->radius*surface->radius; auto det = b*b - 4 * a*c; if (det < 0) { continue; } float t1 = (-b - sqrt(det)) / (2 * a); float t2 = (-b + sqrt(det)) / (2 * a); // check if computed param is within ray.tmin and ray.tmax if (t1 >= ray.tmin && t1 <= ray.tmax) t = t1; else if (t2 >= ray.tmin && t2 <= ray.tmax) t = t2; else continue; auto p = ray.eval(t); //Intersection point // check if this is the closest intersection, continue if not if (dist(ray.e, p) > currentDistance) { continue; } currentDistance = dist(ray.e, p); // if hit, set intersection record values intersection.ray_t = t; intersection.pos = p; intersection.norm = normalize(ray.e - p); intersection.mat = surface->mat; intersection.hit = true; intersection.ray_t = 2; } } return intersection; }
提前致谢。
【问题讨论】:
-
发布渲染外观的屏幕截图。对于 2.:您已经编写了一个光线投射器。光线追踪器在击中某物后会反弹多次以获得更准确的照明。
-
@Joonazan :我在帖子中添加了一些截图。关于第二个项目符号:我知道我必须以某种方式递归调用该函数,但是以哪种方式?此外,现在我很确定 Quad 路口也有错误,但我不知道在哪里。即使是这里的一些建议也会受到赞赏。
-
@Joonazan :我也尝试添加阴影,并相应更新了屏幕截图,但不确定是否正确。
标签: c++ graphics 3d raytracing lighting