现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是我们有限的计算能力所无法模拟的,冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。下面这张图展示了这些光照分量看起来的样子。
我们使用一个很小的常量(光照)颜色,添加到物体片段的最终颜色中,这样子的话即便场景中没有直接的光源也能看起来存在有一些发散的光。
把环境光照添加到场景里非常简单。我们用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色:
void main()
{
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
环境光照本身不能提供最有趣的结果,但是漫反射光照就能开始对物体产生显著的视觉影响了。漫反射光照使物体上与光线方向越接近的片段能从光源处获得更多的亮度。
上方有一个光源,它所发出的光线落在物体的一个片段上。我们需要测量这个光线是以什么角度接触到这个片段的。如果光线垂直于物体表面,这束光对物体的影响更亮。为了测量光线和片段的角度,我们使用一个叫做法向量的东西,它是垂直于片段表面的一个向量(这里以黄色箭头表示),这两个向量之间的角度很容易就能够通过点乘计算出来。
所以,计算漫反射光照需要以下几点:
以下是漫反射光照的计算。
光的方向向量lightDir是光源位置向量与片段位置向量之间的向量差。我们对norm和lightDir向量进行点乘,计算光源对当前片段实际的漫反射影响。结果值再乘以光的颜色,得到漫反射分量。两个向量之间的角度越大,漫反射分量就会越小;如果两个向量之间的角度大于90度,点乘的结果就会变成负数,这样会导致漫反射分量变为负数。为此,使用max函数返回两个参数之间较大的参数,从而保证漫反射分量不会变成负数。
//diffuse
vec3 norm = normalize(outNormal); //法向量标准化
vec3 lightDir = normalize(lightPos - FragPos);//光的方向向量是光源位置向量与片段位置向量之间的向量差
float diff = max(dot(norm, lightDir), 0.0);//点乘
vec3 diffuse = diff * lightColor;
片段着色器里的计算都是在世界空间坐标中进行的。所以,我们应该把法向量也转换为世界空间坐标 。如果模型矩阵执行了不等比缩放,顶点的改变会导致法向量不再垂直于表面了,这样光照就会被破坏。修复这个行为的诀窍是使用一个为法向量专门定制的模型矩阵。这个矩阵称之为法线矩阵。
使用以下方法:
outNormal = mat3(transpose(inverse(model))) * normal;
和漫反射光照一样,镜面光照也决定于光的方向向量和物体的法向量,但是它也决定于观察方向,例如玩家是从什么方向看向这个片段的。镜面光照决定于表面的反射特性。如果我们把物体表面设想为一面镜子,那么镜面光照最强的地方就是我们看到表面上反射光的地方。你可以在下图中看到效果:
我们通过根据法向量翻折入射光的方向来计算反射向量(R)。然后我们计算反射向量与观察方向的角度差,它们之间夹角越小,镜面光的作用就越大。由此产生的效果就是,我们看向在入射光在表面的反射方向时,会看到一点高光。
//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);
#include "myopenglwidget.h"
#include
#include
#include
#include
#include
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
};
GLuint indices[] = {
0, 1, 3,
1, 2, 3
};
GLuint VBO, VAO,EBO,lightVAO;
GLuint shaderProgram;
QVector3D lightPos(1.2f,1.0f,2.0f);
QVector3D lightColor(1.0f,1.0f,1.0f);
QVector3D objectColor(1.0f,0.5f,0.31f);
QTimer *timer;
QTime gtime;
QVector cubePositions = {
QVector3D( 0.0f, 0.0f, 0.0f),
QVector3D( 2.0f, 5.0f, -15.0f),
QVector3D(-1.5f, -2.2f, -2.5f),
QVector3D(-3.8f, -2.0f, -12.3f),
QVector3D( 2.4f, -0.4f, -3.5f),
QVector3D(-1.7f, 3.0f, -7.5f),
QVector3D( 1.3f, -2.0f, -2.5f),
QVector3D( 1.5f, 2.0f, -2.5f),
QVector3D( 1.5f, 0.2f, -1.5f),
QVector3D(-1.3f, 1.0f, -1.5f)
};
float fov = 45.0f;
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
cameraPos = QVector3D( 0.0f, 0.0f, 5.0f);//摄像机位置
cameraTarget = QVector3D( 0.0f, 0.0f, 0.0f);//摄像机看到的位置
cameraDirection = QVector3D(cameraPos - cameraTarget);//摄像机的方向
cameraDirection.normalize();
up = QVector3D(0.0f, 1.0f, 0.0f);
cameraRight = QVector3D::crossProduct(up,cameraDirection);//两个向量叉乘的结果会同时垂直于两向量,因此我们会得到指向x轴正方向的那个向量
cameraRight.normalize();
cameraUp = QVector3D::crossProduct(cameraDirection,cameraRight);
cameraFront = QVector3D( 0.0f, 0.0f, -1.0f);
timer = new QTimer();
timer->start(50);
gtime.start();
connect(timer,&QTimer::timeout,[=]{
update();
});
setFocusPolicy(Qt::StrongFocus);
//setMouseTracking(true);
}
void MyOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
m_program->link();
qDebug()<log();
m_lightProgram = new QOpenGLShaderProgram();
m_lightProgram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/light.vert");
m_lightProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/light.frag");
m_lightProgram->link();
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);//绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把顶点数据复制到缓冲的内存中GL_STATIC_DRAW :数据不会或几乎不会改变。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glGenVertexArrays(1, &lightVAO);
glGenBuffers(1, &VBO);
glBindVertexArray(lightVAO);//绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把顶点数据复制到缓冲的内存中GL_STATIC_DRAW :数据不会或几乎不会改变。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);//解绑VAO
m_program->bind();
m_program->setUniformValue("objColor",objectColor);
m_program->setUniformValue("lightColor",lightColor);
m_program->setUniformValue("lightPos",lightPos);
m_program->setUniformValue("viewPos",cameraPos);
m_lightProgram->bind();
m_lightProgram->setUniformValue("lightColor",lightColor);
}
void MyOpenGLWidget::paintGL()
{
glClearColor(0.2f,0.3f,0.3f,1.0f);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 model;
QMatrix4x4 view;
float time = gtime.elapsed()/50.0;
//int time = QTime::currentTime().msec();
QMatrix4x4 projection;
projection.perspective(fov,(float)( width())/(height()),0.1,100);
view.lookAt(cameraPos,cameraPos + cameraFront,up);
m_program->bind();
m_program->setUniformValue("projection",projection);
m_program->setUniformValue("view",view);
glBindVertexArray(VAO);//绑定VAO
model.rotate(time,1.0f,5.0f,0.5f);
m_program->setUniformValue("model",model);
glDrawArrays(GL_TRIANGLES,0,36);
m_lightProgram->bind();
m_lightProgram->setUniformValue("projection",projection);
m_lightProgram->setUniformValue("view",view);
model.setToIdentity();
model.translate(lightPos);
model.rotate(1.0f,1.0f,5.0f,0.5f);
model.scale(0.2);
m_lightProgram->setUniformValue("model",model);
glBindVertexArray(lightVAO);//绑定VAO
glDrawArrays(GL_TRIANGLES,0,36);
// foreach(auto pos , cubePositions)
// {
// model.setToIdentity();
// model.translate(pos);
// //model.rotate(time,1.0f,5.0f,3.0f);
// m_program->setUniformValue("model",model);
// glDrawArrays(GL_TRIANGLES,0,36);
// }
}
void MyOpenGLWidget::resizeGL(int w, int h)
{
}
void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
qDebug()<key();
cameraSpeed = 2.5 * 100 / 1000.0;
switch (event->key()) {
case Qt::Key_W:{
cameraPos += cameraSpeed * cameraFront;
}
break;
case Qt::Key_S:{
cameraPos -= cameraSpeed * cameraFront;
}
break;
case Qt::Key_A:{
cameraPos -= cameraSpeed * cameraRight;
}
break;
case Qt::Key_D:{
cameraPos += cameraSpeed * cameraRight;
}
break;
default:
break;
}
update();
}
float PI = 3.1415926;
QPoint deltaPos;
void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
static float yaw = -90;
static float pitch = 0;
static QPoint lastPos(width()/2,height()/2);
auto currentPos = event->pos();
deltaPos = currentPos-lastPos;
lastPos=currentPos;
float sensitivity = 0.1f;
deltaPos *= sensitivity;
yaw += deltaPos.x();
pitch -= deltaPos.y();
if(pitch > 89.0f) pitch = 89.0f;
if(pitch < -89.0f) pitch = -89.0f;
cameraFront.setX(cos(yaw*PI/180.0) * cos(pitch *PI/180));
cameraFront.setY(sin(pitch*PI/180));
cameraFront.setZ(sin(yaw*PI/180) * cos(pitch *PI/180));
cameraFront.normalize();
update();
}
void MyOpenGLWidget::wheelEvent(QWheelEvent *event)
{
if(fov >= 1.0f && fov <= 75.0f)
fov -= event->angleDelta().y()/120;
if(fov <= 1.0f)
fov = 1.0f;
if(fov >= 75.0f)
fov = 75.0f;
update();
}
顶点着色器和片段着色器
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 outNormal;
out vec3 FragPos;
void main()
{
outNormal = mat3(transpose(inverse(model))) * normal;
FragPos = vec3(model * vec4(position,1.0));
gl_Position = projection * view * model * vec4(position,1.0);
}
#version 330 core
out vec4 color;
uniform vec3 objColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 viewPos;
in vec3 outNormal;
in vec3 FragPos;
void main()
{
//ambinet
float ambinetStrength = 0.1;
vec3 ambient = ambinetStrength * lightColor;
//diffuse
vec3 norm = normalize(outNormal);
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) * objColor;
color = vec4(result,1.0f);
}
qt+opengl实现
https://download.csdn.net/download/wzz953200463/87893447https://download.csdn.net/download/wzz953200463/87893447