Edd Biddulph

Twitter | CV


March 2010

Heightmap-Based Graphical Editing

Originally intended as a level design tool for a 2D platform game, this is an editor which allows the user to create, move, rotate, and scale textured rectangles called patches. Each patch has an alpha component to facilitate composition, and a height field. The height fields are blended and masked to create geometry without a specific boundary representation. After composition, the resulting rendered height field in display is used to derive surface normals per-pixel and so can be used with dynamic lighting. A screenspace ambient occlusion effect is also applied. It uses fragment shaders and dependent texture fetch. To reduce banding and aliasing, each height field lookup is blurred by averaging the surrounding texels. This project utilizes OpenGL and is the first project in which I used the 'exotic' blending operators SUB, MIN, and MAX to simulate what is really an emulation of depth-comparison for hidden surface removal. However, this program does not require writable depth value per fragment and allows different operators to be used. For example, a sum operator can be used to add elevation to simulate the packing of a material (such as mud) onto another shape. This would certainly not be possible with the regular accelerated depth buffer, and is transparent to the gradient-extracting shading stage. Although the problem is now alleviated, I originally did have trouble with banding and aliasing artefacts in the resulting image. To resolve this, I first tried using a higher-order filter when interpolating the height values for extracting gradients as suggested by Inigo Quilez on his website (see link below). However this did not fully solve the problem and noticeably decreased fragment throughput. Furthermore, these additional operations occurred in the patch application shaders which meant that when many patches were visible onscreen at once, the performance penalty would be considerably great. I resolved to fix both issues at once by sticking to the hardware-accelerated texture filtering when extracting gradients (via forward differences) and applying a percentage-closer filter to the entire image after all patches had been applied. This meant that the cost of filtering was constant across all frames and the texture access neighbourhood was regular (making it cache-friendly).

At this time, there is no way to save the creation to a file, but this is something I'd like to add in the future.


Use F1 to toggle between viewing and editing. You can still scroll around and drag elements in view mode, but you won't be able to see any of the markers which show you what is clickable. GPaint will be in editing mode when it first starts, but nothing will be displayed.

While in edit mode, hold Tab to show the control screen. Here you can select the heightmap mode of the patches you create, the colour, height, and radius of the lights you create, and the patch material. When you hover over a control, a line of text may appear at the bottom of the control screen to tell you some information about the control you are hovering over. For the colour sliders, this will be the colour channel and it's numerical value for example. You cannot make changes to any patches or light sources while the control screen is shown. Furthermore, you cannot bring up the control screen when you are in viewing mode.

GPaint starts in edit mode, with no patches or light sources. Hold Alt and press LMB to create a light source. You will see red X markers appear which indicate things that you can drag around by clicking and holding LMB. To delete something, hold D and click on it's centre marker with LMB. To scroll around the scene, hold Ctrl and drag with the left mouse button. To create a patch, hold Shift and click LMB. Patches have markers at their corners which allow you to scale and rotate them. To move a patch without scaling or rotating it, drag it by it's centre marker. You will be shown the outer edges of the patches in edit mode, but in viewing mode these will not be visible. There are 4 heightmap application styles available: ADD, SUB, MIN, and MAX. These indicate which operation will be used when applying the height texture of the patch. MAX is the default and has the same effect as hidden-surface removal. ADD will behave as if you are layering the patches on top of each other, like layers of mud. SUB will behave as if you are cutting away at the scene, and patches created with this style selected will create holes in their shape. MIN is a bit less intuitive than the others - it is easiest to think of it as an intersection or a 'height limiter'.

The sequence of images below shows subtractive patches being used to cut away the geometry formed by some previously-created additive patches.

Download (13/Aug/2011) - Includes source and Windows 32-bit executable. Source code is licensed under the zlib license.

http://www.iquilezles.org/www/articles/texture/texture.htm - Higher-order filter which I tried out before finding that it was too costly for this particular usage.