• Bernhard Rainer

  • Michael Kammer

    TU Wien Rendering Course
  • Lukas Geyer

  • Manuel Kröter

    TU Wien Rendering Course
  • Silvana Podaras

  • Christian Kössler

    TU Wien Rendering Course
  • Michael Probst

    TU Wien Rendering Course
  • Florian Spechtenhauser

    TU Wien Rendering Course
  • Jean-Baptiste Kaiser

    TU Wien Rendering Course
  • Michael Rebec

  • Stefan Doppelbauer

  • Smallpaint - A Global Illumination Renderer
  • Bernhard Langer

    TU Wien Rendering Course
  • Peter Vorlaufer


Smallpaint is a renderer program implementing the classic Monte Carlo path tracing global illumination algorithm. Looking at the images above, you may not see what you would expect from a such a ray tracer: it has an interesting look which resembles the viewer of a painting. Please meet smallpaint.


  • implementation in ~250 effective lines of code,
  • multi-threaded rendering thanks to the OpenMP library,
  • some c++11 wizardry (ty CsL!),
  • quasi-monte carlo sampling using low-discrepancy Halton series,
  • cosine importance sampling,
  • faster convergence through next event estimation (currently removed),
  • soft shadows, antialiasing by integrating over the screen pixels (path tracing),
  • refractions, color bleeding, caustics,
  • can be compiled into a binary with less than 4096 bytes (an image of the full binary),
  • …and most importantly: a great painterly look. Hence, it is called smallpaint,
  • (new) algorithms implemented as of early 2017: path tracing, volumetric path tracing, primary sample space metropolis light transport, progressive photon mapping, virtual ray lights, 1D multiple importance sampling.

The entirety of our Rendering course describing these techniques is now available here.

License: The source code is under the permissive MIT license. Feel free to reuse the materials and hack away at the code! If you built something on top of this, please drop me a message – I’d love to see where others take these ideas and will leave links to the best ones here.

Knobs and switches

  • adjust the params[“spp”] to acquire a clearer or grainier picture of your choice,
  • pick a refraction index for the glass sphere with params[“refr_index”],
  • tinkering around with the rest of the code is completely up to you!

What’s causing this?

The cause of the painterly look is actually a bug – there’s an incorrect usage of the Halton-series with correlating dimensions, and the errors are spread throughout the screen with an equally wrong sampling function. one would wish that every bug could look just as beautiful as this one.

Important note

If you take a closer look at the source code, you may notice that smallpaint doesn’t do any kind of tone mapping – it directly writes the measured contributions into the image file. Also, there are some magic constants used as scaling factors here and there.

When doing ray tracing, the goal is to compute the radiance returning to the eye along rays of light through each pixel of an image. As a last step, we map these values to – for example – RGB values for visualization. Trying to measure RGB intensities directly does not make any sense, and is also scientifically unacceptable. The reason for omitting this from smallpaint is solely to save a few lines of code. Your computer graphics professor would probably throw lightning bolts at you for this.

Download smallpaint

Code (with GUI)

Code (old, no GUI)

Code walkthrough lecture

Community contributions

2023. 01. 07. Lucas Franca added a Rust implementation. Thank you!


If you made use of this work in your research work, please consider adding the following citation.

Author = {K'{a}roly Zsolnai-Feh'{e}r},
Year = {2018},
Note = {https://users.cg.tuwien.ac.at/zsolnai/gfx/smallpaint/},
Title = {Smallpaint: A Global Illumination Renderer}

Changelog for smallpaint

2010.11.11 changelog:

  • the usage of rand() instead of rand_r() caused performance issues on linux systems. 

2013.03.08 changelog:

  • the solution to the sampling problem is added as commented code,
  • the fixed version of the path tracer is added to the package,
  • slight code cleanup. 

2013.05.11 changelog: 

  • Christian Hafner adds Schlick’s approximation to the Fresnel equation. It is included in the fixed version of the code. Thank you! 

2013.05.18 changelog:

  • Christian Machacek adds Russian Roulette path termination and other code improvements. It is included in the fixed version of the code. Thank you! 

2013.07.12 changelog:

  • Christian Machacek adds a pbrt-inspired BVH implementation and lots of various other fixes. Thank you! 

2013.07.15 changelog:

  • Jean-Baptiste Kaiser adds a neat implementation of Kelemen et. al’s Primary Sample Space Metropolis Light Transport (PSSMLT) algorithm. Good job, thank you!

2015.01.16 changelog:

  • Georg Sperl adds a volumetric path tracing variant which is now included in the code archive. Thank you!

2015.05.01 changelog:

2015.05.26 changelog:

  • I added an implementation of multiple importance sampling for two Monte Carlo estimators in 1D. Kind thanks for Jaroslav Křivánek for pushing a fix as well!

2017.03.21 changelog:

  • Michael Oppitz added a full GUI around smallpaint and a progressive photon mapping implementation. Make sure to have a look at this, it’s super fun to use. Thank you!

2018.06.25 changelog:

  • Michael Oppitz added a virtual ray lights implementation. Thank you!

2020.02.26 changelog:

  • This work is now under the permissive MIT license. Go nuts!

Also, make sure to check out Adam Celarek‘s course project as well on path tracing, bidirectional path tracing and photon tracing.

Thanks to

  • László Szirmay-Kalos, my former computer graphics advisor,
  • Michael Wimmer, my current one,
  • Kevin Beason for the inspiring smallpt renderer,
  • Jochen Eisner for his remarks about rand_r() and lambda functions,
  • the ompf.org forum for all the good people addicted to ray tracing and global illumination,
  • my students who have been hard at work to improve smallpaint and to add lots of goodies!