Qt实现OpenGL光照,环境光,漫反射,镜面高光⑧

本帖将参考LearnOpenGL这一经典教程,使用Qt的原生环境完成教程中所提的所有流程,并尽量和原教程保持一致,如有错误,欢迎评论!

为了方便大家参考,我将项目分享至了gitee,并实时进行更行:Qt实现OpenGL的经典教程: (gitee.com)

教程中文网站:LearnOpenGLCN 

教程原网站:LearnOpenGL

Qt版本:6.7

操作系统:Windows10

环境光和漫反射

基础代码请参考我的gitee或者上一篇专栏中的内容。我们在此基础上对代码进行修改。

我们分别设置灯对象和用于显示光照的物体对象的shader和vao:

private:
    QOpenGLShaderProgram *_shaderProgram;
    QOpenGLShaderProgram *_shaderProgram1;
    QOpenGLTexture *_texture;
    QOpenGLTexture *_texture1;
    QOpenGLVertexArrayObject *_vao;
    QOpenGLVertexArrayObject *_vao1;
    QOpenGLBuffer *_vbo;
    QOpenGLBuffer *_ebo;

在物体对象的顶点着色器中,我们将顶点的世界坐标位置和法线向量传给片段着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 FragPos;
out vec3 Normal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;

    gl_Position = projection * view * vec4(FragPos, 1.0);
}

在片段着色器中,我们依靠这两个向量实现环境光和漫反射:

  

uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    // diffuse
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

环境光比较简单,通过加和灯光颜色即可,漫反射对光线照射与法向量夹角进行计算,用其内积作为评估标准,光线照射越垂直,则内积越大,反之越小,以此来反应漫反射的强弱

镜面高光

镜面高光需要考虑到摄像机的位置,当观察者的视线正对着反射光线时,那么此时就有最大的镜面高光,所以需要计算反射光线和摄像机位置的内积:

#version 330 core
out vec4 FragColor;

in vec3 Normal;
in vec3 FragPos;

uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    // diffuse
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;

    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
}

为了避免负值的出现(当摄像机位置和反射光线的角度超过90度时),这里使用了一个max函数,同时使用幂函数来使反射出出现高光的效果。

PaintGL渲染

void MyOpenGLWidget::paintGL()
{
    //update();
    //由于继承了QOpenGLFunctions,可以直接使用OpenGL中的函数
    // render
    // ------
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓冲

    // bind Texture
    // glActiveTexture(GL_TEXTURE0);
    // _texture->bind();
    // glActiveTexture(GL_TEXTURE1);
    // _texture1->bind();

    //更新帧时间,由于定时器60fps,所以这里的_deltaTime为17上下
    _deltaTime = (QTime::currentTime().msecsSinceStartOfDay() - _lastMescCount) /1000.0f;
    _lastMescCount = QTime::currentTime().msecsSinceStartOfDay();

    _shaderProgram->bind();
    _shaderProgram->setUniformValue("objectColor", 1.0f, 0.5f, 0.31f);
    _shaderProgram->setUniformValue("lightColor", 1.0f, 1.0f, 1.0f);
    _shaderProgram->setUniformValue("lightPos", 1.2f, 1.0f, 2.0f);
    _shaderProgram->setUniformValue("viewPos", _cameraPos);
    QMatrix4x4 projection;
    QMatrix4x4 view;
    view.lookAt(_cameraPos, _cameraPos + _cameraFront, _cameraUp);
    projection.perspective(45.0f,
                           float(this->width())/float(this->height()),
                           0.1f,
                           100.0f);
    _shaderProgram->setUniformValue("view", view);
    _shaderProgram->setUniformValue("projection", projection);
    QMatrix4x4 model;
    _shaderProgram->setUniformValue("model", model);
    _vao->bind();
    glDrawArrays(GL_TRIANGLES, 0, 36);

    _shaderProgram1->bind();
    _shaderProgram1->setUniformValue("view", view);
    _shaderProgram1->setUniformValue("projection", projection);
    model.translate(1.2f, 1.0f, 2.0f);
    model.scale(0.2);
    _shaderProgram1->setUniformValue("model", model);
    _vao1->bind();
    glDrawArrays(GL_TRIANGLES, 0, 36);
}

调用两个shader和vao分别渲染灯和光照物体,点击运行,便得到了如下结果:

代码已经分享至gitee,详细请看文章开头。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值