I made a path tracer to have a reference for the realtime GI i'm working on, the image looks like this:
I had to add a division by Pi to the realtime stuff to make it match, which means i did it wrong for many years it seems
However, i wrote the path tracer just out of my head without making sure it is correct. (It is very simple, no light sampling - just random directions and hit the light by luck.)
So i'm unsure, and tried to make another reference render with Mitsuba (failed), and Blender:
Blender fails to handle flat shading it seems, so the edges are round by accident, but the image is surely too bright. I tried to disable all tone mapping / color management and use just gamma 2.2, but it's hard to trust the remaining color transform to mach mine.
Confusion became even larger, because the blender image looks more like my initial realtime result.
Maybe someone can recommend me another free path tracer that can handle simple lambert diffuse and emissive polygons,
or can you spot a bug / confirm my path tracer code?:
static vec Radiance (vec &pos, vec &norm, vec &albedo, const int bounce, const int maxBounces, const LinkMesh &mesh, const RaytraceMesh &tracer)
{
vec rndDir = RandomDirCosineWeighted(norm);
int hitIndex;
float t = tracer.TraceRay (hitIndex, pos, rndDir, 0, FLT_MAX);
if (hitIndex == -1) return vec(0,0,0);
pos += rndDir * t;
norm = mesh.mPolyNormals[hitIndex] * -1;
vec indirectAlbedo = mesh.mPolyColors[hitIndex];
float indirectEmission = mesh.mPolyEmission[hitIndex];
vec emit = indirectAlbedo * indirectEmission;
if (bounce < maxBounces)
emit += Radiance (pos, norm, indirectAlbedo, bounce+1, maxBounces, mesh, tracer);
emit = cmul(albedo, emit) / float(PI);
return emit;
}
My only confusion here is again the final division by PI. My thought here was: We project the hemisphere down to the unit circle which has area of PI, so one ray has a weight of 1/Pi. Is this correct?
I call the above recursive function with per pixel code like this, to be complete:
vec pos = origin + ray * t; // move to primary hit
vec norm = mesh.mPolyNormals[hitIndex] * -1; // next path direction
vec albedo = mesh.mPolyColors[hitIndex]; // material at hit
float emission = mesh.mPolyEmission[hitIndex];
vec color = Tools::Radiance (pos, norm, aldebo, 0, bounces, mesh, tracer); // path tracing
color += aldebo * emission; // add emission from primary hit
// accumulate pixel with this color sample...
My color transform is just gamma:
outColor = min(1, pow(accumulatedColor, 1/2.2f));
Thanks for help!
Edit: All renders use 10 bounces - made sure of that.
I made the Cornell Box scene without using any reference about material and geometry, so it can't be compared to other similar renders.