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)
○ 模拟有光泽物体表面上出现的亮点
环境光代码:
#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;