Raytracer and Rasteriser
I wrote a raytracer and a rasteriser as part of my university course. The raytracer supported features such as indirect lighting, reflection, refraction, and a photon mapper capable of simulating the final positions of 60,000,000 photons in a few minutes (and quite a few GBs of RAM).
Raytracer #
Features #
- Direct, specular, and ambient lighting.
- Soft shadows.
- Reflection.
- Refraction with Snell’s law, Fresnel’s law,
- Total Internal Reflection, and Beer’s law.
- Material roughness and rough reflections.
- Anti-aliasing.
- Obj 3D model importer.
- Ability to switch to and from rasteriser using F1 key. Other F keys can be used to enable/disable certain features, see README.
- OpenMP support
- Undersampling - render at a lower resolution than the window.
Direct Illumination, Shadows, and Reflection #
Once anti-aliasing is implemented, the triangle normal need only be randomised for each sample, in order to acquire roughness. For each sample, the rotation of the triangle normal - for the triangle which the ray intersects with - is given a random offset. The magnitude of this random offset is dictated by the roughness attribute of the triangle. This gives a rough, blurred, look to rough mirrors. It also makes specularity look more realistic.
Reflections can be implemented simply by firing another ray from the intersection position in the right direction, and using the colour it returns as the pixel colour. This colour is then blended with the diffuse color depending on material properties. You get rough mirrors for free by having roughness.
Refraction #
Refraction is achieved by firing rays through the material, accounting for the difference in refractive index. The amount of light which is refracted vs diffused depends on the transparency of the material.
If a ray hits a transparent triangle on the opposite side to the normal, then the
refractive index is 1/R
, where R is the index of the material. Otherwise it’s just
R
.
Fresnel’s Law determines how much of a ray is reflected when it hits a change in refractive index. Above a certain angle - the critical angle - the rays totally reflect, causing Total Internal Reflection.
Beer’s Law describes a property of semi-transparent materials where colour is absorbed from light per length it passes through the material. The application of Beer’s law gives a jelly-like effect.
refractedColor = incomingColor * exp(-absorbedColor * lengthInMaterial)
Photon Mapper #
Millions of photons are simulated after being emitted from the light, and then their final positions are recorded. The record of all the final positions is called a photon map. I used an OctTree (like a quad tree, but 2x2x2 rather than 2x2) to enable efficient querying of photon positions.
Hitting any surface will result in a certain percentage of the photon’s color being reflected, which results in indirect lighting. Photons will keep bouncing until their color is low enough to be negligible in which case they’ll stop. The percentage of color which isn’t reflected will be stored in the photon map as a final photon position (ie: diffuse) or sent split into colors and refracted if the triangle is transparent.
Warning: the default settings for the photon map require 4GB of free RAM. Reduce the photon count in drawRaytracer() if you don’t have that available.
Rasteriser #
Features #
- Direct and ambient lighting.
- Perspective Correct Interpolation.
- “Real Time” Shadow Mapping.
- Obj 3D model importer.
- Ability to switch to and from rasteriser using F1 key. Other F keys can be used to enable/disable certain features, see README.
- Undersampling - render at a lower resolution than the window.
Comments