Hi everyone,
I've tried to update my ray tracer to handle Monte Carlo path tracing rather than standard ray tracing, and I have got it working but I'd like to check my algorithm over as I'm unsure about a few things. Here's what I'm doing:
Base rendering routine: For each pixel (loop through y, x) and for each sample (loop through sample number, e.g. 100 rays/pixel) shoot a ray through a random point in the pixel, add the results and then divide by the number of samples.
My trace function does the following:
- For each initial pixel ray, assign an attenuation vector with the value (1, 1, 1) which will be decreased as the ray propagates
- If there's no intersection, return a background colour
- If the intersected shape has an emissive colour, return that colour with 100% probability
- Define the following:
float kd = shape->material.diffuseColour.sum(), ks = shape->material.specularColour.sum(), kt = shape->material.transmitColour.sum();
...where '.sum()' adds together all the components of the vector
- Choose whether to spawn a diffuse, specular or transmitted ray like this:
diffuseAttenuation = attenuation*shape->material.diffuseColour; //Per-component multiplication
diffuseProbability = kd/(kd + ks + kt);
if (diffuseAttenuation.findmax() > cutoff && random(0, 1) < diffuseProbability) //'.findmax()' returns largest component of vector
{
- find a random (cosine weighted) direction
- spawn a recursive ray in this direction (its attenuation vector is now equal to diffuseAttenuation)
- multiply it by the current diffuse colour and return.
}
else
{
specularAttenuation = attenuation*shape->material.specularColour;
specularProbability = ks/(ks + kt);
if (specularAttenuation.findmax() > cutoff && random(0, 1) < specularProbability)
{
- spawn a recursive ray in a perfectly reflected direction (its attenuation vector is now equal to specularAttenuation)
- multiply it by the specular colour and return
}
else
{
transmitAttenuation = attenuation*shape->material.transmitColour;
if (transmitAttenuation.findmax() > cutoff)
{
- spawn a recursive ray in a perfectly refracted direction (its attenuation vector is now equal to transmitAttenuation)
- multiply it by the transmission colour and return
}
}
}
...OK, so here's what I want to ask about:
- I've seen some sites/papers say that I should divide each ray by its probability, e.g. the colour returned by a diffuse ray should be divided by diffuseProbability, etc... - should I be doing this?
- Are there any things you can see wrong with my algorithm? I don;t have any books on this so I'm just going based on what I can lift from papers and various PDFs from unviersities, none of which seem to tell the full story.
Thanks!
p.s. here's a picture it rendered which took about 45 minutes at 500 samples per pixel. Is this the kind of speed that I should be expecting with this type of path tracing?
http://i.imgur.com/hdVfmXh.png
:)