Although the 3Delight/blender addon is mostly abandoned due to lack of time to keep it maintained, I want to at least bring it up to date with the latest 3Delight release, which has had a lot of good updates in the pathtracing/physically based rendering department.
3Delight’s approach to the problem has been to extend some of the commonly used shadeops, seemingly with the intention of making it simple to convert over old shaders, or create simple shaders from scratch. It definitely has advantages in terms of the amount of work required to get something set up, but imo it’s also a bit messy and confusing how it all fits together, especially if you’re familiar with a more common and organised physically based shading infrastructure as in pbrt.
I’d actually already made my own physically based shading setup about a year ago, fully implemented in RSL and based on pbrt (with path tracing, several types of lights and materials, multiple importance sampling, importance sampling of environment maps, …), the main drawback being that it was relatively slow. I’m hoping that the new features in v11 can help here.
So far, with the help of Paolo Berto, I think I’ve got a few things figured out. The main shadeops to be concerned with are:
This is similar to f() in pbrt, it evaluates the value of a bsdf along a given direction.
Using the similar “distribution” parameters as in bsdf(), this is similar to sample_f() in pbrt, sampling the bsdf to generate outgoing vectors. The big difference here though is that trace() does much more than just sampling the bsdf, it also traces rays, performs multiple importance sampling, and returns pre-integrated results in the form of an RGB colour.
trace() is concerned with incoming light from scene geometry, including physical lights that can be intersected, that can generate a valid pdf and therefore can be used with MIS. This means that lights with delta distributions (eg. point lights, distant lights) are ignored and have to be handled separately. But for area lights and an implicit environment light, trace() can work well.
To take advantage of this, you need to define ‘proper’ area lights in the RIB, using AreaLightSource and giving them some geometry. Then when using trace()’s new “samplearealights: 1″ parameter, trace() will presumably then a) sample the light sources explicitly, generating ray directions and pdfs and also b) consider those area light shapes for intersection when sampling the bsdf and generating rays from that.
At the moment I assume that it does something similar for the environment, if you assign an environment map in the trace() call – that it will (importance?) sample the environment hemisphere and perform MIS with that too.
So what about other lights than area lights? Well, other lighting effects that are generated in shader code don’t give enough information to the renderer to be effectively sampled explicitly in the trace() framework, and neither can lights representing a delta distribution. You can still sample them yourself though, just with an oldschool light loop – i.e. for each light, retrieve Cl and L from the light, multiply by the bsdf() value, compute visibility, and accumulate with your existing colour from trace().
Next: Putting it all together …