QT+OpenGL光照
本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主
颜色
现实生活中看到的物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的颜色
太阳光能被看见的白光是多找演的的组合
颜色的数据化的由红色,绿色和蓝色三个分量组成,他们通常被缩写为RGB
例如:珊瑚红色
QVector3D color(1.0f, 0.5f, 0.31f);
上图颜色的代码展示
// 灯光颜色
QVector3D lightColor(1.0f, 1.0f, 1.0f);
// 珊瑚红色
QVector3D toyColor(1.0f, 0.5f, 0.31f);
QVector3D result = lightColor * toyColor; // 分量相乘,不是点乘也不是叉乘
代码展示:
light.frag
#version 330 core
out vec4 FragColor;
uniform vec3 lightColor;
void main()
{
FragColor = vec4(lightColor, 1.0);
}
light.vert
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aTexCord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
void TurboOpenGLWidget::paintGL()
{
QMatrix4x4 model;
QMatrix4x4 view;
float time = m_time.elapsed() / 50.0;
model.rotate(time, 1.0f, 5.0f, 0.0f);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader_program_.bind();
glBindVertexArray(VAO);
QMatrix4x4 projection;
projection.perspective(camera_.getZoom(), float(width() / height()), 0.1, 100);
shader_program_.setUniformValue("projection", projection);
view = camera_.getViewMatrix();
switch(shape_)
{
case Rect:
shader_program_.setUniformValue("model", model);
shader_program_.setUniformValue("view", view);
for(const auto &item: cubePositions)
{
model.setToIdentity();
model.translate(item);
model.rotate(time, 1.0, 5.0, 0.5);
shader_program_.setUniformValue("model", model);
glDrawArrays(GL_TRIANGLES,0,36);
}
break;
}
glBindVertexArray(0);
glBindVertexArray(lightVAO);
light_shader_program_.bind();
light_shader_program_.setUniformValue("projection", projection);
light_shader_program_.setUniformValue("model", model);
light_shader_program_.setUniformValue("view", view);
model.setToIdentity();
model.translate(lightPos);
model.rotate(1.0, 1.0, 5.0, 0.5);
model.scale(0.2);
light_shader_program_.setUniformValue("model", model);
glDrawArrays(GL_TRIANGLES,0,36);
update();
}
效果展示
冯氏光照模型
冯氏光照模型的主要结构有三个:
- 环境光(ambient)
- 即使在黑暗情况下,通常也仍然有一些光亮
- 漫反射(diffuse)
- 模拟光源对物体的方向性影响
- 镜面反射(specular)
- 模拟有光泽物体表面上出现的亮点
I p h o n g = k a ⋅ I a m b i e n t + ∑ i = 1 n u m L i g h t s I i ⋅ ( k d ( L ^ i ⋅ N ^ ) + k s ⋅ ( R ^ i ⋅ V ^ ) n s h i n y ) I_{phong} = k_a\cdot I_{ambient} + \sum_{i = 1}^{numLights}I_i\cdot (k_d(\hat L_i\cdot \hat N) + k_s\cdot (\hat R_i \cdot \hat V)^{n^{shiny}}) Iphong=ka⋅Iambient+i=1∑numLightsIi⋅(kd(L^i⋅N^)+ks⋅(R^i⋅V^)nshiny)
其中 k a k d k s k_a k_d k_s kakdks是系数
环境光代码:
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
void main()
{
float ambientStrength = 0.2;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
向上面代码,如果我们只有环境光,会是如下效果,并不是完全黑的。
漫反射代码:
计算漫反射光照需要:
- 法向量:一个垂直于顶点表面的向量
- 定向的光线:作为光源的位置与片段的位置之间的向量差的方向向量;为了计算这个光线,我们需要光的位置向量和片段的位置向量
片段着色器:
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
in vec3 Normal;
in vec3 fragPos;
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;
vec3 result = (ambient + diffuse) * objectColor;
FragColor = vec4(result, 1.0);
}
镜面反射代码:
片段着色器:
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 viewPos;
in vec3 Normal;
in vec3 fragPos;
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);
}
法向量
-
如果模型矩阵执行了不等比例的缩放,顶点的改变导致法向量不再垂直与表面。
-
修复这个行为的诀窍是使用一个为法向量专门定制的模型矩阵。这个矩阵称之为法线矩阵
Normal = mat3(transpose(inverse(model))) * aNormal;