I apologize if my methods seem way off because this is my first time trying to build a path tracer and I'm struggling quite a bit. Currently, I am trying to mimic the "mix shader" node in Blender 3D that combines two different shaders. I would like to add this functionality to my path tracer because it would allow me to make a plastic-like material. Reading through a few explanations, it seems it takes a probabilistic approach to picking one or the other when a ray hits the surface.
Here is a rendering of an object with a 50/50 mix of ideal reflection and ideal diffuse at 80 samples per pixel:
Something is just off about it. Especially those weird underside highlights on the leg extending farthest to the left. I have a strong feeling I'm implementing it wrong.
Here is a pseudo implementation of the path tracing part. It uses explicit light sampling. Based off of smallpt path tracer.
rayColor(ray r, depth, int E=1)
{
if(r doesn't hit triangle)
return 0
if(r hit is a light)
{
if(E)
return light_emission
else
return 0
}
vector x = r.origin + r.direction*t // x is point where r hit tri
vector n = normal where ray hit triangle
n.normalize()
vector nl = n.dot(r.d) < 0 ? n : n*(-1) // properly orient normal
if(++depth > 5) return 0 // max bounces
float triangle_area = area of emitting triangle
vector x_light_random = random point on emitting triangle
vector light_normal = normal of emitting triangle
vector d = x_light_random = x_converted;
if(light_normal.dot(d) > 0) light_normal *= -1; // make it emit
// both sides
object_normal.normalize();
light_normal.normalize();
BRDF = 1/PI // perfect diffuse
light_emitted = 1 // emission of 1
vector light_out = 0
if(ray starting at x towards d hits light (i.e. not in shadow))
{
light_out = BRDF*light_emitted*(object_normal.dot(d))*
(-1*light_normal.dot(d)*triangle_area)/
(d.length*d.length*d.length*d.length)
}
vector direct_light = color_of_object_triangle*light_out;
//----SPECULAR-----
vector d2 = r.dir-n*2*n.dot(r.dir); // ideal reflection
vector light_color = 1 // white since dialectics don't change spec
vector specular = light_color*rayColor(createRay(x, d2),depth)
float P = 0.5; // 50/50 chance of mirror/diffuse
if(erand(Xi) < P)
return direct_light/P
else
return spec/(1-P)
Thank you to anyone who can offer me some direction! Again, sorry if this is really convoluted. I've made it so far and I'm about to give up, but I feel like I'm reaaaally close.