6
$\begingroup$

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: enter image description here

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.

$\endgroup$
4
  • 2
    $\begingroup$ Do you have a reference picture of the image you expect to get? It could be easier to first replicate an exiting image and compare your result. $\endgroup$ Commented Jan 6, 2017 at 5:47
  • 1
    $\begingroup$ @JulienGuertault thank you so much for the suggestion! That was brilliant and I wish I had thought of it earlier. That would've helped with a lot of hair pulling. See my edited post. T $\endgroup$ Commented Jan 6, 2017 at 6:32
  • 1
    $\begingroup$ I've edited out the "one more thing" section now that you've posted it as a separate question. Notice that the separate question now appears in the "Linked" section on the right hand side of this page, because that question contains a link to this question. $\endgroup$ Commented Jan 7, 2017 at 12:20
  • $\begingroup$ In case it's helpful, here's a good short read about path tracing basics with some simple c++ source code accompany it: blog.demofox.org/2016/09/21/… $\endgroup$
    – Alan Wolfe
    Commented Jan 7, 2017 at 18:30

1 Answer 1

4
$\begingroup$

As suggested in the comments, I created an exact scene in Blender using the same .obj. After adding a mix shader node and setting one side to diffuse and the other to a perfect mirror, you can see that the results are almost identical. This would indicate that my implementation is correct.

Here is a side by side comparison. Mine is on the left, Blender's is on the right:

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.