A GLSL version of smallpt

smallpt is a bare minimum path tracer written under 100 lines of C++, featuring diffuse, and specular reflection, and refraction. Using the detailed explanation slides by David Cline, I experimented porting it to GLSL on Shadertoy.

This proved to be an interesting experiment that brought a few lessons.

You can see the shader and tweak it here. By default it uses 6 samples per pixel, and 3 bounces, which allows it to run smoothly on average hardware. I found 40 samples per pixel and 5 bounces to give nice results while maintaining interactive framerate.

Path tracing, 40 samples per pixel, 5 bounces

Path tracing, 40 samples per pixel, 5 bounces

Update: since GLSL Sandbox has a feature, reading from the previous frame buffer, that Shadertoy is missing at the moment, I thought it’d be interesting try it to have the image converging over time. A little hacking later, a minute or so worth of rendering got me this kind of result: Given the effort, I am really pleased by the result.

Path tracing, 40 samples per pixel, 5 bounces

Path tracing, unknown number of samples per pixel, 7 bounces

Ambient shadows in The Last of Us

Last month at SIGGRAPH, Michał Iwanicki of Naughty Dogs presented his talk “Lighting technology in The Last of Us”, in which he focused on the technique they used for ambient shadows. In short: light maps and analytic occlusion with ellipsoid approximations of objects. Clever!

The effect of quantization in gamma space and linear space

I mentioned already (here and here) that one problem with gamma correct rendering is how we lose prevision for small values, and may run out of it if we didn’t have enough of it. I wrote a quick shader to demonstrate this problem and see how severe it is depending on the number of bits.

Thanks to BeautyPi‘s fantastic tool, ShaderToy, I could put it on line. Here is the live demo with an absurdly low precision format (R5G6B5) so you cannot miss the banding; just press the play button. It displays colors with maximum and low precision, in linear space and gamma space. The lighter vertical line shows the 50% intensity position. You can see the shader and play with the values here.

Gamma correct and HDR rendering in a 32 bits buffer

Recently I am looking for the available options for doing gamma correct and/or HDR rendering in a 32 bits buffer. Gamma correct means you need higher precision for low values (this article by Benjamin Supnik demonstrates why). HDR means you may have values greater than 1, and since your range is getting wider, you want higher precision everywhere. The way to go recommended everywhere is to use 16 bits floats, like RGBA16, or even higher. But suppose you don’t want your buffer to get above 32 bits, what tools are available?

Note: the article has been reworked as I gathered more information. I thought organizing them was better than merely adding an update notice at the end.

RGBM

My first thought was to use standard RGBA8, store the maximum of the RGB channels in the alpha channel, and store the RGB vector divided by that scale. A back of the envelope test later, I was forgetting about it, convinced it wouldn’t go very far: since values are limited to the [0, 1] range, it would require to define the maximum value meant when alpha is 1. More importantly, interpolation would give incorrect results.

Or so I thought. It seems doing this is known as RGBM (M for shared multiplier) and while indeed the interpolation gives incorrect results, this article argues they are barely noticeable, and the other advantages outweigh it (see RGBD here after for an other worth reading article).

There are also variations of this approach, as shown on this online Unity demo. Here is the code.

RGBD

By searching on the web I first found this solution, consisting in storing the inverse of the scale in the alpha channel. Known as RGBD (D for shared divider), it doesn’t suffer from having to define a maximum value, and plotting the function seems to show an acceptable precision across the range. Unfortunately it doesn’t interpolate either.

This article gives a good comparison of RGBM and RGBD, and addresses the question of interpolation. Interestingly, it notes that while neither have correct interpolation, whether it may acceptable or not depends on the distribution of the colors.

RGBE

Then you have the RGBE (E for shared exponent): RGB and an exponent. Here is a shader implementation using an RGBA8 buffer. But then again, because of the exponent being stored in the alpha channel, interpolation is going to be an issue.

RGB9_E5

Further searching, I stumbled upon the OpenGL EXT_texture_shared_exponent extension, which defines a GL_RGB9_E5 texture format with three 9 bits components for the color channels, and an additional 5 bits exponent shared by the channels. This sounded nice: 9 bits of precision is already twice as many shades, and the exponent gives precision everywhere, as long as the channels values have the same order of magnitude. Because it is a standard format, I assume interpolation is going to be a non issue. Unfortunately as can be read on the OpenGL wiki, while this is a required texture format, it is not required for renderbuffers. In other words: chances are it’s not going to be implemented.

LogLUV

Since we really want a wide range of light intensity, a different approach is to use a different color space. Several people mentioned LogLUV, which I hear gives good results, at the expense of a high instruction cost for both packing and unpacking. Here is a detailed explanation.

R11G11B10

There is still the R11F_G11F_B10F format (DXGI_FORMAT_R11G11B10_FLOAT in DirectX) where R and G channels have a 6 bits mantissa and a 5 bits exponent, and B has a 5 bits mantissa and 5 bits exponent. Since floats have higher precision with low values, this seem very well suited to gamma correct rendering. And since this is a standard format, interpolation should be a non issue.

Conclusion

I haven’t tested in practice yet, but from these readings it seems to me the sensible solution would be to use a R11G11B10 float format when available. Otherwise (for example on mobile platforms) choose between RGBM and RGBD depending on the kind of image being rendered. Unless the format is standard, it seems interpolation is always going to be an issue, and the best you can do is mitigate by choosing the solution depending on your use case.

Did I miss something?

How to use light to make better demos?

This is the third day at Revision, and my contribution this year is the talk I gave yesterday. Unlike last year, this seminar is not technical at all but focused on the design aspect and, to some extent, how it relates to the technical one. The context is demomaking, but many ideas are still valid in other media.

There were some issues with the recording unfortunately, which means some elements are missing (you will notice some blanks at the beginning). In particular after 5mn, there is an important point which was completely cut out. The text was:

Throwing a new technique at whatever you’re doing is not going to make it any better. It’s only going to change what you can achieve. There are two sides of image creation: the technical one and the artistic one. Different techniques allow to do different things, and the more techniques you master, the better you understand what you can and cannot do with them, and how to do it. Technique becomes a tool that changes how you can express yourself.

Here are the slides with notes (~5MB), or a low quality version (~1MB).

For more demoscene related talks, here is the full list of seminars at Revision 2013.

FaceWorks demonstration at GTC

Geeks3D mentioned this keynote at the GPU Technology Conference, where NVIDIA’s CEO shows their technology called FaceWorks. After talking about the uncanny valley and avatar rendering uses, came the live demonstration, which seriously raises the bar in terms of face rendering and animation.

The quality is incredible, the gap from photo realism is getting very narrow, and some expressions are really convincing. The transitions and frozen expressions feel weird though, so I am wondering how it would look running freely for a moment, with all the rapid subtle moves we show even when staying idle. The avatar as a mean of communication is certainly very appealing. It would be interesting to see if when facing this rendering, we would react to the expressions displayed.

The demo itself starts after 8 minutes.