《Qt-OpenGL系列编程》课程学习记录(12):光照纹理贴图
·
总结一下上一节的内容:物体呈现的颜色与以下因素有关:
- 物体的材质
- 环境光
- 物体对光源照射的光的漫反射
- 物体对光源照射的光的镜面反射
- 光源照射的光的颜色
- 照射的角度
现实中的物体多半不是由单一的材料组成的,所以物体的材质是复杂的。
下面使用两张图片作为纹理,根据纹理坐标从图片获取像素代替材质的值来参与计算观察效果。

从左边的图获取像素参与计算环境光和漫反射。
从右边的图获取像素参与计算镜面反射。
从图片看中间的材料是木材,四周的是金属材料。右边的图中间是黑色就认为木材对镜面反射没有反应。
被照射物体的材质:
struct Material
{
sampler2D diffuse;//漫反射纹理
sampler2D specular;//镜面反射纹理
float shininess;//反光度
};
uniform Material material;//被照射物体材质
移除了环境光材质颜色向量,因为环境光颜色在几乎所有情况下都等于漫反射颜色。
被照射物体的顶点着色器:
#version 450 core
layout (location = 0) in vec3 aPos;//顶点坐标
layout (location = 1) in vec3 aNormal;//法线数据
layout (location = 2) in vec2 aTexCoords;//纹理坐标
out vec3 Normal;
out vec3 FragPos;
out vec2 TexCoords;
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);
TexCoords = aTexCoords;
}
被照射物体的片段着色器:
#version 450 core
out vec4 FragColor;
in vec3 Normal;//法向量
in vec3 FragPos;//顶点
struct Material
{
sampler2D diffuse;//漫反射纹理
sampler2D specular;//镜面反射纹理
float shininess;//反光度
};
uniform Material material;//被照射物体材质
in vec2 TexCoords;//纹理坐标
struct Light //光照强度分量
{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
uniform vec3 lightPos;//光源位置
uniform vec3 viewPos;//摄像机/眼睛位置
void main()
{
//texture()从纹理中根据对应的纹理坐标取出对应的颜色值
vec3 diffuseTexColor=vec3(texture(material.diffuse,TexCoords));
vec3 specularTexColor=vec3(texture(material.specular,TexCoords));
// 环境光
vec3 ambient = diffuseTexColor * light.ambient;//环境光(物体反射的光源的颜色)
// 漫反射
vec3 norm = normalize(Normal);//法向量归一化
vec3 lightDir = normalize(lightPos - FragPos);//顶点到光源的向量
float diff = max(dot(norm, lightDir), 0.0);//法向量 与 顶点到光源的向量 进行点乘
vec3 diffuse = diff * diffuseTexColor * light.diffuse;//漫反射光
// 镜面反射
float specularStrength = 0.5;//镜面反射系数
vec3 viewDir = normalize(viewPos - FragPos);//摄像机位置 - 顶点位置
vec3 reflectDir = reflect(-lightDir, norm);//光的折射向量
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);//摄像机 与 反射向量 的点乘
vec3 specular = specularTexColor * spec * light.specular;
vec3 result = ambient + diffuse + specular;
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.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
static QVector3D lightColor(1.0f, 1.0f, 1.0f);
//static 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(40);
}
Widget::~Widget()
{
makeCurrent();
glDeleteBuffers(1,&VBO);
glDeleteVertexArrays(1,&VAO);
glDeleteVertexArrays(1,&lightVAO);
delete diffuseTex;
delete specularTex;
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, 8 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
}
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
{
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * 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("material.shininess", 32.0f);
shaderProgram.setUniformValue("lightPos",lightPos);
shaderProgram.setUniformValue("viewPos",viewPos);
diffuseTex = new QOpenGLTexture(QImage(":/container2.png").mirrored());
specularTex = new QOpenGLTexture(QImage(":/container2_specular.png").mirrored());
shaderProgram.bind();
shaderProgram.setUniformValue("material.diffuse", 0);
shaderProgram.setUniformValue("material.specular", 1);
}
{
lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/light.vert");
lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/light.frag");
if(!lightShaderProgram.link())
qDebug()<<"着色器程序2编译错误信息:"<<lightShaderProgram.log();
lightShaderProgram.bind();
}
}
void Widget::paintGL()
{
static int rorateAngle = 0;
++rorateAngle;
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, 1, 2), //眼睛的位置
QVector3D(0, 0, 0), //眼睛看的位置
QVector3D(0, 1, 0)); //此参数表示方向,相对于眼睛向上的方向。
//模型矩阵
QMatrix4x4 model;
model.setToIdentity();
model.rotate(rorateAngle, 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);
shaderProgram.setUniformValue("light.ambient", 0.4f, 0.4f, 0.4f);
shaderProgram.setUniformValue("light.diffuse", 0.9f, 0.9f, 0.9f);
shaderProgram.setUniformValue("light.specular", 1.0f, 1.0f, 1.0f);
shaderProgram.setUniformValue("material.shininess", 64.0f);
diffuseTex->bind(0);
specularTex->bind(1);
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, 4.0f, 0.0f);
model.scale(0.2f);
lightShaderProgram.bind();
lightShaderProgram.setUniformValue("projection", projection);
lightShaderProgram.setUniformValue("view", view);
lightShaderProgram.setUniformValue("model", model);
lightShaderProgram.setUniformValue("lightColor",lightColor);
glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES,0,36);
}
}

更多推荐
所有评论(0)