Wednesday, May 20, 2009

Noise and displacement

...some hard work, but displacement mapping is finally working !

Not quite mapping, as the displacement is not based on texture maps but rather on a procedural shader using Perlin noise.

Here is the first image with a shader using noise to produce colors..

..this was a bit puzzling to implement because Perlin noise usually returns a scalar.. but RenderMan shader language implements noise functions that return vectors and colors as well.
I did a quick search into AQSIS source code (I don't normally do that) and found out that one just has to call noise N times for N elements.. with slightly off input values !
Like for AQSIS, I did pick some prime numbers to use as offsets.

Next I found a fairly simple displacement shader, convert it to RibRender Asm (.rrasm) and went on to implement displacement in the shader VM as well.
To get to this simple (but beautiful to me now !) test I faced two major problems..

The first problem was that the shading asm was lacking, and so was the handling of variables. I did a few changes to the asm syntax and some major changes to the handling of symbols.. much work went on to improve debugging and prevent problems, with better type checking and lots of asserts 8)

The second problem, which is only partially solved, is the calculation of normals after displacement.
Normals are first calculated using whatever analytical formula of the high level primitive in question.
The displacement shader will then change the position value 'P' and most likely will call the "calculatenormal" function that will re-calculate a new normal based on the new modified position (see some displacement examplesand explanation here).
The problem for the renderer is that shading happens one grid at the time. To calculate a new normal, neighboring position samples are necesary.. but a grid is only a subset of the original primitive and the edges of the grid don't have all of neighboring samples to estimante the slope accurately..
So, if one calculates the slope between vertices by looking to the rightmost and bottom samples, this will fail for the rightmost column and bottommost row of the grid !
For now I just copy the differences from the coulmn and row before the last.. but I expect to notice artifacts at some point.

There are some other artifacts, especially at the center of the displaced sphere.. this is probably because there aren't enough samples to cover the area.
Looking at the colored grids debug image, it's clear that the grids at the center of the image get really thin and I guess I'm not copying too well with that.
Better sampling estimation is definitely needed.. as well as actual final micropolygon sampling without which there isn't any antialiasing (I could hack something by just accumulating points.. but we'll see !).

Time to sleep !!


  1. hhmm, something doesnt look right. why the sharp edges between 'dimples'?

    with perlin noise i would've expected a smooth surface.

  2. Perlin noise i only used as a base ( noise() function in RM shading language).
    In the specifi image I use a shader taken from this site -> ..called "turb". ..and of course adapted it to my sort-of-asm here (tabs display is messed up, should be 4..)