Diffuse Shading in OpenGL Using Qt

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:

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



15 Replies to “Diffuse Shading in OpenGL Using Qt”

  1. Starting C:UsersmicDownloadsQtDiffuseOpenGLbuild-OBJ-Reader-Desktop_Qt_5_9_0_MSVC2015_64bit-ReleasereleaseOBJ-Reader.exe…
    QOpenGLShaderProgram::attributeLocation(vertexPosition): shader program is not linked
    QOpenGLShaderProgram::attributeLocation(vertexPosition): shader program is not linked
    QOpenGLShaderProgram::attributeLocation(vertexNormal): shader program is not linked
    QOpenGLShaderProgram::attributeLocation(vertexNormal): shader program is not linked
    QOpenGLShaderProgram::attributeLocation(vertexUV_a): shader program is not linked
    QOpenGLShaderProgram::attributeLocation(vertexUV_a): shader program is not linked
    QOpenGLShaderProgram::uniformLocation(renderTexture): shader program is not linked
    QOpenGLShaderProgram::uniformLocation(normalMatrix): shader program is not linked
    The program has unexpectedly finished.
    The process was ended forcefully.
    C:/Users/mic/Downloads/QtDiffuseOpenGL/build-OBJ-Reader-Desktop_Qt_5_9_0_MSVC2015_64bit-Release/release/OBJ-Reader.exe crashed.

  2. Is it possible to use “old” OpenGL with QT in the same manner? – I want to use interface designer, but at the same time have access to glBegin(GL_LINES) and these old effective functions that are good for changing data.

    1. QtOpenGL functionalities are just wrappers for the OpenGL itself. So you can definitely use whatever is supported by the underlying OpenGL version you are using. You must check to see if the underlying OpenGL verison supports any functions you want to use or not. However, and rather as a piece of advice, try to use the “New” (which itself is quite “Old”) version of OpenGL functions since they will provide better compatibility with more recent versions.

      1. Thanks a lot. We use ARM, the GPU only support OpenGL ES 2.0. But QT3D it base on OpenGL ES 3.0. We can not use it. Do you have some 2.0 exsample?

          1. Sorry, another question. I use Embedded platform, it only support opengl es 2.0. I want to play a video using opengl, I use glTexImage2D,but it is too slow. How should I optimize it?

          2. Can I assume that you have already tried conventional methods for playing videos and you weren’t happy with the results?!
            Such as QMediaPlayer?! Here’s a link: http://doc.qt.io/qt-5/qmediaplayer.html

            If that is the case, I would suggest to look for the bottlenecks first. Are you sure only the displaying part is causing the performance to drop? Because glTexImage2D would only affect that, and it should be quite performant in most cases. Maybe the part where you read video frames and decode them to textures is making it slow. I’m sorry but I can only guess using the provided info
            I hope this helps.

  3. Thanks very much. We tried this class in 5.8. But we found a strange things, this class can not run in emedded linux, we checked environment( in linux we use GStreamer to decode), sadly, we spent two weeks and get nothing. To be honest, we disappoint for QT compatibility. That’s why we use original OpenGL API. Yesterday, we found the problem as you said glTexImage2D can not use to show dynamic texture. EGLImage is the solution, qtmutilmedia class use it, it can access GPU Memory directly, but we still find some sample for EGLImage.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.