(This is a study note for LearnOpenGL, translated in Chinese for the tutorial) https://learnopengl-cn.github.io/)
0. Preface
Previously, I learned the introductory chapter of LearnOpenGL, and this article started learning about the colors of light (Lighting).
1. How to implement
Color can be digitized by three components, red, green and blue, which are often abbreviated as RGB.In real life, we see that the color of an object is not the color it really has, but the Reflected color it reflects.In other words, colors that cannot be absorbed by an object (Absorb) (rejected colors) are the colors of the object that we can perceive.
When we create a light source in OpenGL, we give the light source a color (such as white).When we multiply the color of a light source by the color value of an object, we get the color that the object reflects (that is, the color we perceive).
gl_FragColor = vec4(lightColor * objectColor, 1.0);
The next step is to draw two boxes, a lamp and an object in the scene using the previous Camera+ shader.If the light source vector of the object is changed to cyan vec3(0,1,1), the reflected color changes accordingly.
2. Implementation Code
(Project git link: https://github.com/gongjianbo/OpenGLwithQtWidgets.git)
My GLColors class implementation effect (MyCamera is a ported tutorial custom class, and the code is also in the git project):
GLColors class code:
#ifndef GLCOLORS_H #define GLCOLORS_H #include <QOpenGLWidget> #include <QOpenGLFunctions_3_3_Core> #include <QOpenGLShaderProgram> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include <QKeyEvent> #include <QMouseEvent> #include <QWheelEvent> #include <QTimerEvent> #include "MyCamera.h" //Illumination color class GLColors : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core { Q_OBJECT public: explicit GLColors(QWidget *parent = nullptr); ~GLColors(); protected: //Set OpenGL resources and status.Called once before the first call to resizeGL or paintGL void initializeGL() override; //Render OpenGL scenes, used whenever a widget needs to be updated void paintGL() override; //Set OpenGL viewport, projection, etc., to be called whenever size changes void resizeGL(int width, int height) override; //Mouse action, overload event handling for Qt void keyPressEvent(QKeyEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; private: void initShader(); private: //Shader Program QOpenGLShaderProgram _lightingShader,_lampShader; //Vertex array object QOpenGLVertexArrayObject _lightingVao,_lampVao; //vertex buffer QOpenGLBuffer _vbo; //camera of view MyCamera _camera; }; #endif // GLCOLORS_H
#include "GLColors.h" #include <QObject> GLColors::GLColors(QWidget *parent) : QOpenGLWidget(parent) { setFocusPolicy(Qt::ClickFocus); //Widget has no focus by default } GLColors::~GLColors() { //By making the corresponding context the current context and binding the frame buffer object in that context, //Ready to render OpenGL content for this widget.paintGL() is called automatically before it is called. makeCurrent(); _vbo.destroy(); _lightingVao.destroy(); _lampVao.destroy(); //Release context.In most cases, you do not need to call this function. //Because the widget will ensure that the context is properly bound and released when paintGL() is called. doneCurrent(); } void GLColors::initializeGL() { //Initialize OpenGL function resolution for the current context initializeOpenGLFunctions(); initShader(); //VAO,VBO float vertices[] = { -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, }; _vbo=QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); _vbo.create(); //light vao _lightingVao.create(); _lightingVao.bind(); _vbo.bind(); _vbo.allocate(vertices,sizeof(vertices)); //setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0) int attr = -1; attr = _lightingShader.attributeLocation("aPos"); //setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0) _lightingShader.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3); _lightingShader.enableAttributeArray(attr); _vbo.release(); _lightingVao.release(); //lamp vao _lampVao.create(); _lampVao.bind(); _vbo.bind(); attr = _lampShader.attributeLocation("aPos"); //setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0) _lampShader.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3); _lampShader.enableAttributeArray(attr); _vbo.release(); _lampVao.release(); } void GLColors::paintGL() { glClearColor(0.1f, 0.1f, 0.1f, 1.0f); //Clear Depth Buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Z-buffer, Depth Buffer. glEnable(GL_DEPTH_TEST); //draw lighting _lightingShader.bind(); _lightingShader.setUniformValue("objectColor",QVector3D(1.0f,0.5f,0.31f)); _lightingShader.setUniformValue("lightColor",QVector3D(1.0f,1.0f,1.0f)); QMatrix4x4 view=_camera.getViewMatrix(); //Observation Matrix //QMatrix4x4 view; //view.translate(QVector3D(0.0f, 0.0f, -10.0f)); //qDebug()<<"view"<<view; _lightingShader.setUniformValue("view", view); QMatrix4x4 projection; //perspective projection projection.perspective(_camera.getZoom(), 1.0f * width() / height(), 0.1f, 100.0f); _lightingShader.setUniformValue("projection", projection); QMatrix4x4 model;//Model Matrix model.rotate(45,QVector3D(1.0f,1.0f,0.0f)); _lightingShader.setUniformValue("model", model); _lightingVao.bind(); glDrawArrays(GL_TRIANGLES, 0, 36); _lightingVao.release(); _lightingShader.release(); //draw lamp _lampShader.bind(); _lampShader.setUniformValue("view", view); _lampShader.setUniformValue("projection", projection); model=QMatrix4x4(); model.translate(QVector3D(1.2f, 1.0f, 2.0f)); model.scale(0.2f); _lampShader.setUniformValue("model", model); _lampVao.bind(); glDrawArrays(GL_TRIANGLES, 0, 36); _lampVao.release(); _lampShader.release(); } void GLColors::resizeGL(int width, int height) { glViewport(0, 0, width, height); } void GLColors::keyPressEvent(QKeyEvent *event) { _camera.keyPress(event->key()); update(); QOpenGLWidget::keyPressEvent(event); } void GLColors::mousePressEvent(QMouseEvent *event) { _camera.mousePress(event->pos()); update(); QOpenGLWidget::mousePressEvent(event); } void GLColors::mouseReleaseEvent(QMouseEvent *event) { _camera.mouseRelease(event->pos()); update(); QOpenGLWidget::mouseReleaseEvent(event); } void GLColors::mouseMoveEvent(QMouseEvent *event) { _camera.mouseMove(event->pos()); update(); QOpenGLWidget::mouseMoveEvent(event); } void GLColors::wheelEvent(QWheelEvent *event) { _camera.mouseWheel(event->delta()); update(); QOpenGLWidget::wheelEvent(event); } void GLColors::initShader() { //lingting shader //in input, out output, uniform sent from cpu to gpu const char *lighting_vertex=R"(#version 330 core layout (location = 0) in vec3 aPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); })"; const char *lighting_fragment=R"(#version 330 core uniform vec3 objectColor; uniform vec3 lightColor; void main() { gl_FragColor = vec4(lightColor * objectColor, 1.0); })"; //Compile source as a shader of the specified type and add it to this shader program if(!_lightingShader.addCacheableShaderFromSourceCode( QOpenGLShader::Vertex,lighting_vertex)){ qDebug()<<"compiler vertex error"<<_lightingShader.log(); } if(!_lightingShader.addCacheableShaderFromSourceCode( QOpenGLShader::Fragment,lighting_fragment)){ qDebug()<<"compiler fragment error"<<_lightingShader.log(); } //Use addShader() to link shaders added to the program together. if(!_lightingShader.link()){ qDebug()<<"link shaderprogram error"<<_lightingShader.log(); } //lamp shader const char *lamp_vertex=R"(#version 330 core layout (location = 0) in vec3 aPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); })"; const char *lamp_fragment=R"(#version 330 core void main() { gl_FragColor = vec4(1.0); })"; // set alle 4 vector values to 1.0 if(!_lampShader.addCacheableShaderFromSourceCode( QOpenGLShader::Vertex,lamp_vertex)){ qDebug()<<"compiler vertex error"<<_lampShader.log(); } if(!_lampShader.addCacheableShaderFromSourceCode( QOpenGLShader::Fragment,lamp_fragment)){ qDebug()<<"compiler fragment error"<<_lampShader.log(); } if(!_lampShader.link()){ qDebug()<<"link shaderprogram error"<<_lampShader.log(); } }
3. Reference
LearnOpenGL: https://learnopengl-cn.github.io/02%20Lighting/01%20Colors/
Blog (Qt+OpenGL): https://www.jianshu.com/p/e7e9097d2748
Blog (Qt+OpenGL): https://blog.csdn.net/z136411501/article/details/80111754