您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 4浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

OpenGL with QtWidgets:光照颜色

龚建波 发布时间:2020-02-04 23:48:07 ,浏览量:4

(本文是LearnOpenGL的学习笔记, 教程中文翻译地址https://learnopengl-cn.github.io/(备用地址https://learnopengl-cn.readthedocs.io/zh/latest/),写于 2020-2-4 ,并在 2021-9-7 进行了更新)

0.前言

前面学习了LearnOpenGL的入门章节,本文开始学习光照 (Lighting) 的颜色 (Colors)。

1.如何实现

颜色可以数字化的由红色(Red)、绿色(Green)和蓝色(Blue)三个分量组成,它们通常被缩写为RGB。我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色。换句话说,那些不能被物体所吸收(Absorb)的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色。

当我们在OpenGL中创建一个光源时,我们给光源一个颜色(如白色)。当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)。

gl_FragColor = vec4(lightColor * objectColor, 1.0);

接下来就是利用之前学的顶点的知识在场景中绘制了两个盒子,一个光源(lamp),一个反射光照颜色的物体(lighting)。如果把物体的光照向量改为青色 vec3(0,1,1) ,那么反射的颜色也相应地改变了。

2.实现代码

(项目git链接:https://github.com/gongjianbo/OpenGLwithQtWidgets.git)

我的GLColors类实现效果:

GLColors类代码:

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//光照颜色
//QOpenGLWidget窗口上下文
//QOpenGLFunctions访问OpenGL接口,可以不继承作为成员变量使用
class GLColors
        : public QOpenGLWidget
        , protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    explicit GLColors(QWidget *parent = nullptr);
    ~GLColors();

protected:
    //【】继承QOpenGLWidget后重写这三个虚函数
    //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    void initializeGL() override;
    //渲染OpenGL场景,每当需要更新小部件时使用
    void paintGL() override;
    //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    void resizeGL(int width, int height) override;

    //鼠标操作,重载Qt的事件处理
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;

private:
    void initShader();

private:
    //着色器程序
    QOpenGLShaderProgram lightingShader,lampShader;
    //顶点数组对象
    QOpenGLVertexArrayObject lightingVao,lampVao;
    //顶点缓冲
    QOpenGLBuffer vbo;

    //
    QVector3D rotationAxis;
    QQuaternion rotationQuat;
    //透视投影的fovy参数,视野范围
    float projectionFovy{ 45.0f };

    //鼠标位置
    QPoint mousePos;
};

#include "GLColors.h"
#include 
#include 
#include 

GLColors::GLColors(QWidget *parent)
    : QOpenGLWidget(parent)
{

}

GLColors::~GLColors()
{
    //initializeGL在显示时才调用,释放未初始化的会异常
    if(!isValid())
        return;
    //QOpenGLWidget
    //三个虚函数不需要makeCurrent,对应的操作已由框架完成
    //但是释放时需要设置当前上下文
    makeCurrent();
    vbo.destroy();
    lightingVao.destroy();
    lampVao.destroy();
    doneCurrent();
}

void GLColors::initializeGL()
{
    //为当前上下文初始化OpenGL函数解析
    initializeOpenGLFunctions();
    initShader();

    //方块的顶点
    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)
    lightingShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3);
    lightingShader.enableAttributeArray(0);
    vbo.release();
    lightingVao.release();

    //lamp vao
    lampVao.create();
    lampVao.bind();
    vbo.bind();
    //setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0)
    lampShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3);
    lampShader.enableAttributeArray(0);
    vbo.release();
    lampVao.release();
}

void GLColors::paintGL()
{
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    //清除深度缓冲
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Z缓冲(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; //观察矩阵
    float radius = 20.0f;
    view.translate(0.0f, 0.0f, -radius);
    view.rotate(rotationQuat);
    lightingShader.setUniformValue("view", view);
    QMatrix4x4 projection; //透视投影
    projection.perspective(projectionFovy, 1.0f * width() / height(), 0.1f, 100.0f);
    lightingShader.setUniformValue("projection", projection);
    QMatrix4x4 model;//模型矩阵
    model.rotate(30, 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.0f, 1.0f, 0.0f));
    model.rotate(30, QVector3D(1.0f, 1.0f, 0.0f));
    //model.translate(QVector3D(1.2f, 1.0f, 2.0f));
    model.scale(0.3f);
    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::mousePressEvent(QMouseEvent *event)
{
    event->accept();
    mousePos = event->pos();
}

void GLColors::mouseReleaseEvent(QMouseEvent *event)
{
    event->accept();
}

void GLColors::mouseMoveEvent(QMouseEvent *event)
{
    event->accept();
    //参照示例cube
    QVector2D diff = QVector2D(event->pos()) - QVector2D(mousePos);
    mousePos = event->pos();
    QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
    rotationAxis = (rotationAxis + n).normalized();
    //不能对换乘的顺序
    rotationQuat = QQuaternion::fromAxisAndAngle(rotationAxis, 2.0f) * rotationQuat;

    update();
}

void GLColors::wheelEvent(QWheelEvent *event)
{
    event->accept();
    //fovy越小,模型看起来越大
    if(event->delta() < 0){
        //鼠标向下滑动为-,这里作为zoom out
        projectionFovy += 0.5f;
        if(projectionFovy > 90)
            projectionFovy = 90;
    }else{
        //鼠标向上滑动为+,这里作为zoom in
        projectionFovy -= 0.5f;
        if(projectionFovy < 1)
            projectionFovy = 1;
    }
    update();
}

void GLColors::initShader()
{
    //lingting shader
    //in输入,out输出,uniform从cpu向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;
out vec4 FragColor;

void main()
{
FragColor = vec4(lightColor * objectColor, 1.0);
})";

    //将source编译为指定类型的着色器,并添加到此着色器程序
    if(!lightingShader.addCacheableShaderFromSourceCode(
                QOpenGLShader::Vertex,lighting_vertex)){
        qDebug()            
关注
打赏
1655829268
查看更多评论
0.3455s