OpenGL with QtWidgets: Light color

Keywords: Qt Fragment github git

(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

103 original articles were published. 27 were praised. 130,000 visits+
Private letter follow

Posted by luke101 on Tue, 04 Feb 2020 16:36:27 -0800