环境光(Ambient Lighting)
用于综合那些细微的不易于处理的“小光照”,将它们的影响合计为一个环境光照常量,因此物体在没有主光源的情况下也存在一些颜色。
漫反射光(Diffuse Lighting)
模拟物体对光源的漫反射。
物体的某一部分越是正对着(越接近90°)光源,就越亮;越是在侧面(越是解决0°)就越暗。
镜面光照(Specular Lighting)
模拟物体对光源的镜面反射。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。


在0~90度之间的位置的光照亮度在两者之间。
有一种数学计算能模拟这种情况,即向量的点乘:光线向量和像素点的法线向量做点乘运算。

只有眼睛在和入射角接近的角度才能看到反射光线(比如现实中看镜子里的物体时要移动位置)。

镜面反射光 = 反射光的向量R * 眼睛位置的向量E。
光源的着色器和上一篇一样:
- //顶点着色器light.vert
- #version 450 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.0);
- }
- //片段着色器 light.frag
- #version 450 core
- out vec4 FragColor;
- uniform vec3 lightColor;
- void main()
- {
- FragColor = vec4(lightColor, 1.0);
- }
被照射物体的着色器:
- //顶点着色器 shapes.vert
- #version 450 core
- layout (location = 0) in vec3 aPos;//顶点坐标
- layout (location = 1) in vec3 aNormal;//法线数据
-
- out vec3 Normal;
- out vec3 FragPos;
-
- uniform mat4 model;
- uniform mat4 view;
- uniform mat4 projection;
- void main()
- {
- Normal = mat3(transpose(inverse(model))) * aNormal;//法线矩阵的公式 处理后得到法向量
- FragPos = vec3(model * vec4(aPos,1.0));
- gl_Position = projection * view * model * vec4(aPos, 1.0);
- }
- //片段着色器 shapes.frag
- #version 450 core
- out vec4 FragColor;
-
- in vec3 Normal;//法向量
- in vec3 FragPos;//顶点
-
- uniform vec3 objectColor;
- uniform vec3 lightColor;
- uniform vec3 lightPos;//光源位置
- uniform vec3 viewPos;//摄像机/眼睛位置
-
- void main()
- {
- // 环境光
- float ambientStrength = 0.1;//环境光强度系数
- vec3 ambient = ambientStrength * lightColor;//环境光(物体反射的光源的颜色)
-
- // 漫反射
- vec3 norm = normalize(Normal);//法向量归一化
- vec3 lightDir = normalize(lightPos - FragPos);//顶点到光源的向量
- float diff = max(dot(norm, lightDir), 0.0);//法向量 与 顶点到光源的向量 进行点乘
- vec3 diffuse = diff * lightColor;//漫反射光
-
- // 镜面反射
- 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);
- }
- #include "widget.h"
- #include <QOpenGLShaderProgram>
- #include <QTimer>
- #include <QTime>
-
- static uint VBO, VAO, lightVAO;
-
- const float vertices[] = {
- //顶点坐标 法向量(每个面上的点法向量是相同的)
- -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
- -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-
- -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
- -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-
- -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
- -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
- -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
- -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
- 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
- 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
- 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
- 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-
- -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
- -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-
- -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
- };
-
-
- static const QVector3D lightColor(1.0f, 1.0f, 1.0f);
- //static const QVector3D lightColor(0.33f, 0.42f, 0.18f);
- static const QVector3D objectColor(1.0f, 0.5f, 0.31f);
- static const QVector3D lightPos(1.2f, 1.0f, 2.0f);//光源位置
- static const QVector3D viewPos(0.0,0.0,5.0);//摄像机/眼睛位置
-
- Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
- {
- auto timer = new QTimer(this);
- connect(timer,&QTimer::timeout,this,[this]{update();});
- timer->start(300);
- }
-
- Widget::~Widget()
- {
- makeCurrent();
- glDeleteBuffers(1,&VBO);
- glDeleteVertexArrays(1,&VAO);
- glDeleteVertexArrays(1,&lightVAO);
- doneCurrent();
- }
-
- void Widget::initializeGL()
- {
- initializeOpenGLFunctions();
-
- glGenVertexArrays(1, &VAO);
- glBindVertexArray(VAO);
-
- glGenBuffers(1, &VBO);
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-
- {
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
- glEnableVertexAttribArray(0);
-
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));
- glEnableVertexAttribArray(1);
- }
-
- glGenVertexArrays(1, &lightVAO);
- glBindVertexArray(lightVAO);
-
- {
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
- glEnableVertexAttribArray(0);
- }
-
- {
- shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
- shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
- if(!shaderProgram.link())
- qDebug()<<"着色器程序1编译错误信息:"<<shaderProgram.log();
- shaderProgram.bind();
- shaderProgram.setUniformValue("objectColor",objectColor);
- shaderProgram.setUniformValue("lightColor",lightColor);
- shaderProgram.setUniformValue("lightPos",lightPos);
- shaderProgram.setUniformValue("viewPos",viewPos);
-
- }
-
- {
- lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/light.vert");
- lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/light.frag");
- if(!lightShaderProgram.link())
- qDebug()<<"着色器程序2编译错误信息:"<<lightShaderProgram.log();
- lightShaderProgram.bind();
- lightShaderProgram.setUniformValue("lightColor",lightColor);
- }
- }
-
- void Widget::paintGL()
- {
- glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- //投影矩阵
- QMatrix4x4 projection;
- projection.perspective(60, //画面视野的角度 人眼在头部不动的情况下,视野大概为60°
- (float)width()/height(), //窗口比例
- 0.1f,100);//参数三和四表示距离摄像机多近个多远范围内的物体要被显示。超出这个范围的物体将无法被显示。
-
- //视图矩阵
- QMatrix4x4 view;
- view.setToIdentity();//对矩阵进行单位化,保证所有矩阵运算都会在一个单位矩阵上进行
- view.lookAt(QVector3D(2, 2, 2), //眼睛的位置
- QVector3D(0, 0, 0), //眼睛看的位置
- QVector3D(0, 1, 0)); //此参数表示方向,相对于眼睛向上的方向。
-
- //模型矩阵
- QMatrix4x4 model;
- model.setToIdentity();
- model.rotate(QTime::currentTime().msec(), 1.0f, 5.0f, 0.5f);//旋转 该矩阵将坐标绕矢量 (x, y, z) 旋转angle度
- model.scale(0.6f);//缩放
-
- {
- shaderProgram.bind();
- shaderProgram.setUniformValue("projection", projection);
- shaderProgram.setUniformValue("model", model);
- shaderProgram.setUniformValue("view", view);
-
- glBindVertexArray(VAO);
- glDrawArrays(GL_TRIANGLES,0,36);
- }
-
- {
- QVector3D lightPos(0.f, 1.0f, -2.0f);
-
- model.setToIdentity();
- model.translate(lightPos);
- model.rotate(1.0, 1.0f, 5.0f, 0.5f);
- model.scale(0.2f);
-
- lightShaderProgram.bind();
- lightShaderProgram.setUniformValue("projection", projection);
- lightShaderProgram.setUniformValue("view", view);
- lightShaderProgram.setUniformValue("model", model);
-
- glBindVertexArray(lightVAO);
- glDrawArrays(GL_TRIANGLES,0,36);
- }
- }
