Diffuse Shading in OpenGL Using Qt

Posted on Posted in OpenGL Tutorials, Qt Tutorials, Tutorials

This one is taken from one of my favourite books (OpenGL 4.0 Shading Language Cookbook) and the relevant chapter’s title for this tutorial in the book is called “Implementing diffuse, per-vertex shading with a single point light source”. Of course it’s modified to use OpenGL ES in Qt which is more cross-platform and creates less issues with building and running on different operating systems (including Android and iOS)





First of all let’s go through how diffuse shading is described in the book:

diffuse formula

Simply put, n is the Normal Vector, s is the Direction from the Surface to the Light Source, Ld is the Light Source Intensity and Kd is the Diffuse Reflectivity. Given these we have L= Ld * Kd * (s . n) for deciding the colour and its intensity in the fragment shader.





Now let’s go through some code. First let’s go through Vertex and Fragment shaders. Here’s the vertex shader code:

attribute vec3 vertexPosition;
attribute vec3 vertexNormal;

attribute vec2 vertexUV_a;
varying vec2 vertexUV;

varying vec3 lightIntensity;

uniform vec3 lightPosition;
uniform vec3 lightKd;
uniform vec3 lightLd;

uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelViewProjMatrix;

void main()
{
vertexUV = vertexUV_a;

// Diffuse
vec3 tnorm = normalize(normalMatrix * vertexNormal);
vec4 eyeCoords = modelViewMatrix * vec4(vertexPosition, 1.0);
vec3 s = normalize(vec3( vec4(lightPosition, 1.0) – eyeCoords));
lightIntensity = lightLd * lightKd * max( dot(s, tnorm), 0.0);
gl_Position = modelViewProjMatrix * vec4(vertexPosition, 1.0);
}

The first line is related to texturing, it just passes UV coordinates on to fragment shader. If you’re not familiar with the model-view-projection matrix I suggest you go through this tutorial carefully.

Here’s the Fragment shader code:

varying vec3 lightIntensity;
varying vec2 vertexUV;

uniform bool renderTexture;

uniform sampler2D texture;

void main()
{
vec4 texCol = texture2D(texture, vertexUV);
gl_FragColor = renderTexture ? vec4(lightIntensity, 1.0) * texCol : vec4(lightIntensity, 1.0);
}

Fragment shader is quite simple as seen here. If you’re not concerned about texturing the you’d simply have gl_FragColor = vec4(lightIntensity, 1.0) which only means using lightIntensity variable that was calculated in vertex shader.





Now let’s go through C++/Qt code. You can download the whole source code (plus Blender’s infamous monkey Suzanne in OBJ format) at the end of this post. One of the most important parts of the Qt project I’ve shared in this post is the OBJ Reader class which allows reading an OBJ file. It’s described in this post:

http://amin-ahmadi.com/2017/01/04/how-to-read-wavefront-obj-files-using-cqt/

Also here’s an screenshot of the code built and running in Mac OS X. (You can easily build and run in Windows too.)

qt diffuse shading





You can download the complete Qt Project source code from this link:

Download
Source Code ZIP

And here’s OBJ file that is used for rendering the monkey seen in the screenshot:

Download
Monkey OBJ File





Leave a Reply

Your email address will not be published. Required fields are marked *