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:
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.)
You can download the complete Qt Project source code from this link:
And here’s OBJ file that is used for rendering the monkey seen in the screenshot:
Hello,
First thanks for sharing a well made and stable source code.
In my case what happens is that some .obj only show a triangle yes and a no. I only see half of the triangles
thanks
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.
How to read MTL file, and put the texture to the model?
You might be able to do that with the QML SceneLoader and more recent versions of Qt.
Here’s an example:
http://amin-ahmadi.com/2018/01/28/viewing-3d-models-using-qt/
Although to load and use MTL files you might need to put in a bit of effort yourself.
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?
I see. Here is a link to all OpenGL related posts that I have written:
http://amin-ahmadi.com/tag/opengl
I hope there’s something you can use. Otherwise you have to try Google, and you can also look for OpenGL only posts since you can adapt the same thing to Qt anyway.
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?
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.
Sure, it works fine in Debug mode, and most other QT works fine too.
Hmmm, that is strange. Can you try installing Qt 5.9.4 and try again? I noticed you are using 5.9.0 and there has been 4 patches for that version, maybe there was something wrong with the version you are using, just a wild guess 😉 Here’s a link for you:
https://download.qt.io/official_releases/qt/5.9/5.9.4/
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.
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.
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.
Are you able to run any Qt OpenGL projects at all?
Try some of the official Qt examples first.
This crashes in release mode for me.
Thanks though, helped me understand the QT/Open Link
What’s the issue exactly?