Above on the left is my attempt and on the right is what I'm aiming for.As you can see my sphere with the specular brdf has a weird dark ring
In my radiance function I am recursing through the intersected objects with the next intersection from the ray that's being traced. I'm using russian roulette with a depth of 5 to avoid infinite recursion. After this I find a point of intersection Vec y
and calculate the normal there. After this I sample the brdf, which in this case is specular, to get the incoming direction vector, stored in i. Finally I call the function using a new ray with the point of intersection and -i.
I have a feeling the my error is with my normal vector n being sent to brdf.eval or brdf.sample. I am not sure if the normal is supposed to be the normal at the origin of the ray, r.o, or at the intersection point y. When I try changing it the specular sphere ends up completely black, or my diffuse brdf for the rest of the scene becomes incorrect.
Vec receivedRadiance(const Ray &r, int depth, bool flag) {
double t, p; // Distance to intersection/pdf
int id = 0; // id of intersected sphere
if (!intersect(r, t, id)) return Vec(); // if miss, return black
const Sphere &obj = spheres[id]; // the hit object
const BRDF &brdf = obj.brdf; // Surface BRDF at x
Vec rad = obj.e; // Emitted radiance
Vec o = (Vec() - r.d).normalize(); // The outgoing direction (= -r.d)
Vec x = r.o + r.d*t; // The intersection point
Vec n = (x - obj.p).normalize(); // The normal direction
if (n.dot(r.d) < 0) n = n*-1.0;
if (depth <= 5)
p = 1.0;
else
p = .9;
if (rng() < p)
{
Vec i, b;
brdf.sample(n, o, i, p);
b = brdf.eval(n, o, i);
Ray y = Ray(x, i * -1);
rad = rad + (receivedRadiance(y, depth + 1, true) * (PI)).mult(b) * (1 / p);
}
return rad;}
Here is my specular BRDF struct:
struct SpecularBRDF : public BRDF {
SpecularBRDF(Vec ks_) : ks(ks_) {}
Vec eval(const Vec &n, const Vec &o, const Vec &i) const {
Vec m;
mirroredDir(n, o, m);
if (abs(i.x - m.x) < 1e-5 && abs(i.y - m.y) < 1e-5 && abs(i.z - m.z) < 1e-5) //i == m
return ks * (1 / n.dot(i));
else
return Vec(0.0, 0.0, 0.0);
}
void sample(const Vec &n, const Vec &o, Vec &i, double &pdf) const {
mirroredDir(n, o, i);
pdf = 1.0;
}
Vec ks;}
And my mirrorDir function:
inline void mirroredDir(const Vec &n, const Vec &o, Vec &m){
m = n * 2.0 * (n.dot(o)) - o;}