我正在使用反射实现递归光线跟踪器。光线追踪器目前正在反射阴影区域,我不知道为什么。当反射代码被注释掉时,光线跟踪器的阴影方面按预期工作,所以我不认为这是问题。
Vec Camera::shade(Vec accumulator,
Ray ray,
vector<Surface*>surfaces,
vector<Light*>lights,
int recursion_depth) {
if (recursion_depth == 0) return Vec(0,0,0);
double closestIntersection = numeric_limits<double>::max();
Surface* cs;
for(unsigned int i=0; i < surfaces.size(); i++){
Surface* s = surfaces[i];
double intersection = s->intersection(ray);
if (intersection > EPSILON && intersection < closestIntersection) {
closestIntersection = intersection;
cs = s;
}
}
if (closestIntersection < numeric_limits<double>::max()) {
Point intersectionPoint = ray.origin + ray.dir*closestIntersection;
Vec intersectionNormal = cs->calculateIntersectionNormal(intersectionPoint);
Material materialToUse = cs->material;
for (unsigned int j=0; j<lights.size(); j++) {
Light* light = lights[j];
Vec dirToLight = (light->origin - intersectionPoint).norm();
Vec dirToCamera = (this->eye - intersectionPoint).norm();
bool visible = true;
for (unsigned int k=0; k<surfaces.size(); k++) {
Surface* s = surfaces[k];
double t = s->intersection(Ray(intersectionPoint, dirToLight));
if (t > EPSILON && t < closestIntersection) {
visible = false;
break;
}
}
if (visible) {
accumulator = accumulator + this->color(dirToLight, intersectionNormal,
intersectionPoint, dirToCamera, light, materialToUse);
}
}
//Reflective ray
//Vec r = d − 2(d · n)n
if (materialToUse.isReflective()) {
Vec d = ray.dir;
Vec r_v = d-intersectionNormal*2*intersectionNormal.dot(d);
Ray r(intersectionPoint+intersectionNormal*EPSILON, r_v);
//km is the ideal specular component of the material, and mult is component-wise multiplication
return this->shade(accumulator, r, surfaces, lights, recursion_depth--).mult(materialToUse.km);
}
else
return accumulator;
}
else
return accumulator;
}
Vec Camera::color(Vec dirToLight,
Vec intersectionNormal,
Point intersectionPoint,
Vec dirToCamera,
Light* light,
Material material) {
//kd I max(0, n · l) + ks I max(0, n · h)p
Vec I(light->r, light->g, light->b);
double dist = (intersectionPoint-light->origin).magnitude();
I = I/(dist*dist);
Vec h = (dirToLight + dirToCamera)/((dirToLight + dirToCamera).magnitude());
Vec kd = material.kd;
Vec ks = material.ks;
Vec diffuse = kd*I*fmax(0.0, intersectionNormal.dot(dirToLight));
Vec specular = ks*I*pow(fmax(0.0, intersectionNormal.dot(h)), material.r);
return diffuse+specular;
}
我提供了输出和预期输出。照明看起来有点不同b / c我最初是一个.exr文件,另一个是.png,但我在输出中绘制了箭头,表面应该反射阴影,但事实并非如此。
答案 0 :(得分:1)
要检查的几件事情:
内部for
循环中的可见性检查可能会返回误报(即,它计算的所有surfaces[k]
都不会比您的交叉点更接近lights[j]
,一些j
)。这会导致它错误地将light[j]
的贡献添加到您的accumulator
。这会导致阴影丢失,但它应该发生在任何地方,包括你的顶级递归级别,而你只看到反射中缺少阴影。
color()
方法中可能存在错误,该错误会返回一些错误的值,然后递增到accumulator
。虽然没有看到该代码,但很难确定。
您在recursion_depth
检查中使用materialToUse.IsReflective()
上的postfix减量。您能否验证recursion_depth
的递减值是否实际传递给shade()
方法调用? (如果没有,请尝试更改前缀减量)。
return this->shade(... recursion_depth--)...
编辑:您还可以验证recursion_depth
只是shade()
方法的参数,即任何地方都没有全局/静态recursion_depth
。假设没有(并且不应该),您可以将上面的调用更改为
return this->shade(... recursion_depth - 1)...
编辑2:还有其他几件事要看:
在color()
中,我不明白为什么要在计算中包含相机的方向。每个像素的除第一个之外的交叉点的颜色应该与相机的位置无关。但我怀疑这是导致这个问题的原因。
验证return this->shade(accumulator, r, surfaces, lights, recursion_depth--).mult(materialToUse.km);
使用该矩阵乘法做正确的事情。为什么要乘以materialToUse.km
?
验证materialToUse.km
每个曲面是否恒定(即它不会改变曲面的几何形状,迭代深度或其他任何内容)。
将语句return this->shade(accumulator, r, surfaces, lights, recursion_depth--).mult(materialToUse.km);
分解为其组件对象,以便在调试器中看到中间结果:
Vec reflectedColor = this->shade(accumulator, r, surfaces, lights, recursion_depth - 1);
Vec multipliedColor = reflectedColor.mult(materialToUse.km);
return multipliedColor;
确定一个有问题的像素的图像(x,y)坐标。设置在渲染该像素时触发的条件断点,然后逐步执行shade()
方法。假设您选择示例图像中右下箭头指向的像素,您应该看到一个递归shade()
。单步执行第一次递归,你会看到你的代码错误地添加了地板上的光线贡献,当它应该在阴影中时。
答案 1 :(得分:1)
回答我自己的问题:我没有检查t
是否应该小于从交叉路口到灯光位置的距离。
而不是:
if (t > EPSILON && t < closestIntersection) {
visible = false;
break;
}
它应该是:
if (t > EPSILON && t < max_t) {
visible = false;
break;
}
其中max_t
是
double max_t = dirToLight.magnitude();
在dirToLight
规范化之前