Back to posts.

I remember that before I started with OpenGL or graphics programming I saw all these nice colorful images without actually knowing that it were normal maps I was looking at. Also when writing shaders I didn't really know common ways to check if the results of my shading calculations were actually correct. Sometimes your lighting might look correct but then at some point you might realize that you were actually mixing different spaces or that you made some other silly mistake. Therefore I present here some snippets which might be usefull for someone starting with writing their own shaders. If you have comments or suggestions on ways to debug your shaders please drop me a mail.

One of the most important things you need to consider is that your normals are correct. This means that they need to be normalized and that they must be converted into the space in which you are doing your lighting calculations. Note, when doing light calculations always make sure that you are in the same space with all your vectors. Also normalize the vectors which are meant to be used as "direction" vectors.

I find it convenient to work in view space and therefore convert the normals to this space using a normal matrix. As normal matrix I simply use the upper 3x3 matrix of the modelview-matrix. The modelview-matrix is: `model_matrix * view_matrix`; and basically allows you to move into view space. You can only use the upper 3x3 matrix if your model matrix is a rigid body transformation. A rigid transformation of a vector space preserves distances between every pair of points. You'll sometimes see somethine like:

`mat3 normal_matrix = transpose(inverse(mat3(modelview_matrix)))`

For rigid body transformations the transpose would cancel out the transpose again. When you have uniform scaling or rotation you don't need to use the above `transpose` and `inverse` but you can directly use the upper 3x3 of the modelview-matrix.

The image below shows an example of normals that are not converted into model-view space. You can clearly see that the normals change which would mean the light attenuation will change as well. When you see that your normals are changing from pinkish to greenish you know that the normals are not in model-view space.

Normals not multiplied by normal matrix or `mat3(modelviewmatrix)`

The shader code which created the above version (simplyfied to only the important parts)

```// VERTEX SHADER
// --------------------------------------
#version 150
uniform mat4 u_pm;   // projection matrix
uniform mat4 u_vm;   // view matrix
uniform mat4 u_mm;   // model matrix
in vec4 a_pos;       // vertex position in
in vec3 a_norm;      // normal in
out vec3 v_norm;     // normal out
out mat4 v_mv;       // modelview matrix out
out vec3 v_pos;      // vertex position out

void main() {
gl_Position = u_pm * u_vm * u_mm * a_pos;
v_mv = u_vm * u_mm;
v_norm = a_norm;
v_pos = vec3(v_mv * a_pos);  // our position in eye coords
}

// --------------------------------------
#version 150
uniform mat4 u_vm;
out vec4 fragcolor;
in vec3 v_norm;
in vec3 v_pos;
in mat4 v_mv;

void main() {
fragcolor.rgb = 0.5 + 0.5 * v_norm;   // note that we are directly using the normals as colors and don't convert it to eye coords
}```

When you multiply your normals using the upper 3x3 matrix of your model-view matrix all colors should look blueish/purpleish and not green/reddish, as in the image below. Note that you can only use the upper 3x3 matrix of your model-view matrix when it contains uniform transformations. When you have non-uniform transformations you should provide a separate normal matrix and use that instead.

The fragment shader, which does correctly multiply the normals by the view matrix that created the above image looks something like below. Note, this is the correct version as we want all our calculations done in the same space. For the vertex shader see the previous snippet.

```// FRAGMENT SHADER
#version 150
#define USE_HALF_VECTOR 1
uniform mat4 u_vm;
out vec4 fragcolor;
in vec3 v_norm; // in object coords
in vec3 v_pos;  // in eye coords
in mat4 v_mv;   // model-view-matrix

void main() {
vec3 spec = vec3(0.0);
vec3 n = normalize(mat3(v_mv) * v_norm); // here we transform our normal to eye space
fragcolor.rgb = 0.5 + 0.5 * n;
}```

Here are a couple of other images which may help you to debug your shaders. So first, check your normals and if your are converting them into the same space as where you're doing the lighting calculations. Above I convert everything into eye space (also called view space, camera space by others).

### Debugging

First you can draw your normals like `fragcolor.rgb = 0.5 + 0.5 * n` and check if the colors stay a bit purple/blueish and don't turn red/greenish. If they stay nice blue/purple everything is fine, else not.

Secondly you can use a `vec3(1.0)` as you light direction vector. If you're normals are incorrect you will get black spots in your result, like the image below. Compare with the next image below two where the normals are correctly converted to the same space (eye).

When you correctly moved the normals to the same space then you'll see something like below. Notice how the light also brightens the back side of the monkey? This is correct because we do not move the position of the light which is shining onto the monkey.

Another image with specular and diffuse lighting where we do not convert the normals to eye space. Again notice how the back of the monkey's head is not lit up by the light.

The correct version, where we use specular and diffuse shading:

```#version 150
uniform mat4 u_pm;
uniform mat4 u_vm;
uniform mat4 u_mm;
in vec4 a_pos;
in vec3 a_norm;
out vec3 v_norm;
out mat4 v_mv;
out vec3 v_pos;

void main() {
gl_Position = u_pm * u_vm * u_mm * a_pos;
v_mv = u_vm * u_mm;
v_norm = a_norm;
v_pos = vec3(v_mv * a_pos);
}```

```#version 150
#define USE_HALF_VECTOR 1

uniform mat4 u_vm;

out vec4 fragcolor;
in vec3 v_norm;
in vec3 v_pos;
in mat4 v_mv;

void main() {

vec3 spec = vec3(0.0);
vec3 n = normalize(mat3(v_mv) * v_norm); // modelview matrix to move the normal into eye space

// diffuse
vec3 s = vec3(1.0, 1.0, 1.0);
float sdn = max(dot(n, s), 0.0);

#if USE_HALF_VECTOR
vec3 v = normalize(-v_pos);
vec3 h = normalize(v + s);
if(sdn > 0.0) {
spec = pow(max(dot(h,n), 0.0), 13.0) * vec3(1.0, 0.0, 1.0) * 5;
}
#else
vec3 v = normalize(-v_pos);
vec3 r = reflect(-s, n);
if(sdn > 0.0) {
spec = pow(max(dot(r, v), 0.0), 3.0) * vec3(1.0, 0.0, 1.0);
}
#endif

fragcolor.a = 1.0;
fragcolor.rgb = vec3(0.0, 0.2, 0.6) * sdn + 0.4 * spec;
}```
• NAT Types This is so exciting, in this article I dive into some of the different ways a NAT device translates addresses which is important for peer-to-peer connections.
• Building Cabinets In this post I dive into the design and construction of a cabinet with an interact LED strip. I also explain how I dynamically change the colors of the LEDs over TCP/UDP.
• Compiling GStreamer from source on Windows How to compile GStreamer on Windows from Source using Visual Studio 2019 and the meson build system.
• Debugging CMake Issues In this post I explain a process you can follow to debug issues with CMake by focusing on a specific target and making the output verbose.
• Dual Boot Arch Linux and Windows 10 How to install Arch Linux and Windows 10 Pro as dual boot. A step by step tutorial how to create bootable installers, partition and setup a dual boot menu.
• Mindset Updated Edition, Carol S. Dweck (Book Notes) Paragraphs I marked from the book "Mindset" from Carol S. Dweck.
• How to setup a self-hosted Unifi NVR with Arch Linux A step by step HOW-TO that explain show to setup a Unifi Video Controller with an NFS share with Arch Linux.
• Blender 2.8 How to use Transparent Textures Follow this node setup when you want to use an image with transparency as a "sticker".
• Compiling FFmpeg with X264 on Windows 10 using MSVC A couple of steps to compile FFmpeg on Windows using MSVC.
• Blender 2.8 OpenGL Buffer Exporter The following Blender script creates a [name].h and [name].cpp for the selected object and stores the positions, normals and UVs.
• Blender 2.8 Baking lightmaps Light maps are a cheap way to add a lot of realism to you static scenes and have been used forever.
• Blender 2.8 Tips and Tricks Use Environment Map only for reflections; create a floor plane for a Product Render, diffuse texture for roughness and more!
• Setting up a Bluetooth Headset on Arch Linux Learn how to setup a Sennheiser PXC 550 Bluetooth headset on Arch Linux.
• Compiling x264 on Windows with MSVC Compile the excellent x264 source on Windows using MSYS2 and MSVC.
• C/C++ Snippets Is a number divisible by four?
• Reading Chunks from a Buffer Some thoughts on reading bytes from a file; handy for reading NALs.
• Handy Bash Commands Bash scripts: removing white space, lowercase filenames, backup using tar, etc.
• Building a zero copy parser Simple solution to parse data in a pretty performant way. Used this for a RTSP protocol parser.
• Kalman Filter A very simple yet powerful filter which works great when you have to smooth noisy data. Used for the Nike Rise 2.0 project.
• Saving pixel data using libpng Do you have raw RGBA data that you want to save? Use this snippet to save it into a PNG file.
• Compile Apache, PHP and MySQL on Mac 10.10 Setup you own PHP, MySQL and Apache and with virtual document roots.
• Fast Pixel Transfers with Pixel Buffer Objects Using Pixel Buffer Objects (PBO) for fast asynchronous data transfers and OpenGL.
• High Resolution Timer function in C/C++ Wait...... wait.. fast high resolution timer funtions (Windows, Linux, Mac)
• Rendering text with Pango, Cairo and Freetype My never ending obsession with font rendering. A complex beast to do well. Use Pango and FreeType for the heavy lifting.
• Fast OpenGL blur shader Make things look blurry ... and fast using this OpenGL blur shader.
• Spherical Environment Mapping with OpenGL An old trick to get great lighting effects using Environment Maps and OpenGL.
• Using OpenSSL with memory BIOs OpenSSL is a great library with lots of abstractions. In this post I discuss how to break some of these abstractions and use your own memory buffers.
• Attributeless Vertex Shader with OpenGL A simple way to render a fullscreen quad without a vertex buffer with OpenGL.
• Circular Image Selector Some thoughts on a different way to select images from a huge collection in a compact UI.
• Decoding H264 and YUV420P playback Using libav to demux and playback with OpenGL.
• Fast Fourier Transform Analyse your audio using the Fastest Fourier Transform in the West.
• OpenGL Rim Shader Pretty glowy edges using a GLSL rim shader.
• Rendering The Depth Buffer Render the non-linear OpenGL Depth Buffer.
• Delaunay Triangulation Do you need to triangulate some shape: use the “Triangle” library.
• RapidXML RapidXML is a versatile and fast XML parser with a simple API. Check out these examples.
• Git Snippets Some simple GIT snippets; added here to remind myself.
• Basic Shading With OpenGL A couple of basic GLSL shaders with explanation.
• Open Source Libraries For Creative Coding Collection of great open source libraries for you creative programming projects.
• Bouncing particle effect Snippet that can be used to create a bouncy particle effect; basic, effective, simple but nice.
• OpenGL Instanced Rendering Want to render thousands and thousands of objects? Use OpenGL instanced rendering. The solution...the only solution.
• Mapping a texture on a disc Ever heard about projective interpolation related to texture mapping? Learn about this intertesting issue with OpenGL and texture mapping.
• Download HTML page using CURL When you want a quick solution to perform a HTTP(S) request CURL is always a quick an simple solution. Check out this example code.
• Height Field Simulation on GPU Although not a Navier-Stokes implementation ... still a very nice and enjoyable effect.
• OpenCV Optical Flow: when doing anything with tracking you've probably heard of it. See this simple example code using OpenCV and OpenGL.
• Some notes on OpenGL FBOs and Depth Testing, using different Attachment Points, a YUV420p shader, ...
• Math Meaning of the Dot Product in 3D graphics, calculating a perpendicular vector using Sam Hocevar's solution, orientation matrix and more.
• Gists to remember Some gists that I want to remember, often use, etc...
• Reverse SSH Do you want to login, into a remote PC but the remote PC is behind a firewall? Then use this simple reverse SSH trick which doesn't require changing your firewall rules.
• Working Set Having issues with your compiler? Or during linking? Check these common issues and their solutions. I also list several tools that you can use to get a some useful info.
• Consumer + Producer model with libuv Example of a common Multi Threaded Consumer/Producer Model using LibUV.
• Parsing binary data Learn about the basic of a binary protocol and how to create one easily yourself.
• C++ file operation snippets Reading a file into a string, vector, checking the file size, change to a position, etc. A collection of C++ file operation snippets.
• Importance of blur with image gradients Do you want to experiment with OpenGL and aligning Brush Strokes along Image Gradients? Then check out this post about the importance of blurring.
• Real-time oil painting with openGL Code snippet for fake "oil painting" effect with OpenGL using instanced rendering.
• x264 encoder Basic example on how to use libx264 to encode image data using libav
• Generative helix with openGL Screenshots of a project I worked on with that generates a DNA helix.
• Mini test with vector field Screenshots while experimenting with a vector field; nothing much to see here.
• Protractor gesture recognizer Testing the amazing One Dollar \$1 gesture recognizer. The simplest and very good gesture recognizer.
• Hair simulation Example code that implements the "Fast Simulation of Inextensible Hair and Fur" paper from M. Müller, T.Y. Kim and N.Chentanez.
• Some glitch screenshots Glitch screenshots.
• Working on video installation Screenshots of some experiments of a video installation.
• Generative meshes I enjoy creating physics based simulations and render them on high res. Here are some experiments I did a time ago.
• Converting video/audio using avconv Examples that show you how to use avconv to manipulate video and audio files.
• Auto start terminal app on mac Automatically start you application whe Mac boots and make sure that it restarts your app when it exists. Handy for interactive installations.
• Export blender object to simple file format Export the selected object in Blender into a .h and .cpp file that prepresents the buffer.