【learnOpenGL学习笔记_15】OpenGL模型加载实战 - 从零到一实现复杂模型渲染,加光照更好看

大家好,我是 同学小张,+v: jasper_8017 一起交流,持续学习AI大模型应用实战案例,持续分享,欢迎大家点赞+关注,订阅我的大模型专栏,共同学习和进步。
欢迎订阅专栏,即将涨价!


上篇文章我们实现了 Assimp 模型库的安装,并使用 Assimp 模型库加载了一个模型并进行了渲染。本文我们在此基础上,添加光照效果,巩固下学到的知识。

1. 修改顶点着色器

点光源的光照计算,需要知道法线方向和片段着色器位置,所以我们在顶点着色器中输出这两个值。

out vec3 outNormal; // 输出法线位置
out vec3 outFragPos; // 输出片段着色器位置

......

outFragPos = vec3(model * vec4(aPos, 1.0));
outNormal = aNormal;

2. 修改片段着色器

在片段着色器中,我们使用点光源的光照计算函数,计算每个点光源对当前片段着色器的影响,并累加到最终颜色中。主要的修改如下:

(1)接收法线和片段着色器位置

(2)定义点光源结构体和点光源数组

(3)点光源光照计算需要 viewPos 变量

(4)实现点光源光照计算函数

(5)点光源数组遍历,计算每个点光源对当前片段着色器的影响,最后累加到最终颜色中。

......

in vec3 outNormal;
in vec3 outFragPos;

struct PointLight {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float constant;
    float linear;
    float quadratic;
};
#define NR_POINT_LIGHTS 4
uniform PointLight pointLights[NR_POINT_LIGHTS];

uniform vec3 viewPos;

vec3 calculatePointLight(PointLight light, vec3 normal, vec3 viewDir, vec3 fragPos)
{
    vec3 lightDir = normalize(light.position - fragPos);
    // 计算漫反射强度
    float diff = max(dot(normal, lightDir), 0.0);
    // 计算镜面反射
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    // 计算衰减
    float distance = length(light.position - fragPos);
    float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
    // 将各个分量合并
    vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));
    vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
    ambient  *= attenuation;
    diffuse  *= attenuation;
    specular *= attenuation;
    return (ambient + diffuse + specular);
}

void main()
{    
    vec3 normal = normalize(outNormal);
    vec3 viewDir = normalize(viewPos - outFragPos);

    vec3 finalColor = vec3(0.0);
    for(int i = 0; i < NR_POINT_LIGHTS; i++)
    {
        finalColor += calculatePointLight(pointLights[i], normal, viewDir, outFragPos);
    }

    color = vec4(finalColor, 1.0);
}

3. 修改 C++ 代码

(1)在片段着色器中,我们使用了 viewPos 变量,所以需要在 C++ 代码中设置这个变量。

(2)在片段着色器中,我们使用了 PointLight 结构体,所以需要在 C++ 代码中设置这个结构体。

......

// 点光源
glm::vec3 lightColor = glm::vec3(1.0f, 0.0f, 1.0f);
ourShader.setVec3("pointLights[0].ambient", glm::vec3(0.05f, 0.05f, 0.05f) * lightColor);
ourShader.setVec3("pointLights[0].diffuse", glm::vec3(0.8f, 0.8f, 0.8f) * lightColor);
ourShader.setVec3("pointLights[0].specular", glm::vec3(1.0f, 1.0f, 1.0f));
ourShader.setFloat("pointLights[0].constant", 1.0f);
ourShader.setFloat("pointLights[0].linear", 0.09f);
ourShader.setFloat("pointLights[0].quadratic", 0.032f);
ourShader.setVec3("pointLights[0].position", pointLightPositions[0]);

ourShader.setVec3("pointLights[1].ambient", glm::vec3(0.05f, 0.05f, 0.05f) * lightColor);
ourShader.setVec3("pointLights[1].diffuse", glm::vec3(0.8f, 0.8f, 0.8f) * lightColor);
ourShader.setVec3("pointLights[1].specular", glm::vec3(1.0f, 1.0f, 1.0f));
ourShader.setFloat("pointLights[1].constant", 1.0f);
ourShader.setFloat("pointLights[1].linear", 0.09f);
ourShader.setFloat("pointLights[1].quadratic", 0.032f);
ourShader.setVec3("pointLights[1].position", pointLightPositions[1]);

ourShader.setVec3("pointLights[2].ambient", glm::vec3(0.05f, 0.05f, 0.05f) * lightColor);
ourShader.setVec3("pointLights[2].diffuse", glm::vec3(0.8f, 0.8f, 0.8f) * lightColor);
ourShader.setVec3("pointLights[2].specular", glm::vec3(1.0f, 1.0f, 1.0f));
ourShader.setFloat("pointLights[2].constant", 1.0f);
ourShader.setFloat("pointLights[2].linear", 0.09f);
ourShader.setFloat("pointLights[2].quadratic", 0.032f);
ourShader.setVec3("pointLights[2].position", pointLightPositions[2]);

ourShader.setVec3("pointLights[3].ambient", glm::vec3(0.05f, 0.05f, 0.05f) * lightColor);
ourShader.setVec3("pointLights[3].diffuse", glm::vec3(0.8f, 0.8f, 0.8f) * lightColor);
ourShader.setVec3("pointLights[3].specular", glm::vec3(1.0f, 1.0f, 1.0f));
ourShader.setFloat("pointLights[3].constant", 1.0f);
ourShader.setFloat("pointLights[3].linear", 0.09f);
ourShader.setFloat("pointLights[3].quadratic", 0.032f);
ourShader.setVec3("pointLights[3].position",pointLightPositions[3]);

4. 运行效果

添加光照后:

在这里插入图片描述

对比没有光照前:

在这里插入图片描述

美观了很多!

篇幅有限,完整程序可私信我获取。

如果觉得本文对你有帮助,麻烦点个赞和关注呗 ~~~


  • 大家好,我是 同学小张,持续学习C++进阶、OpenGL、WebGL知识AI大模型应用实战案例
  • 欢迎 点赞 + 关注 👏,持续学习持续干货输出
  • +v: jasper_8017 一起交流💬,一起进步💪。
  • 微信公众号搜同学小张 🙏

私信免费领取AI、C++等相关资料,持续收集更新中! 包括但不限于:

  1. 清华大学 - DeepSeek资料合集(多篇)

  2. DeepSeek指导手册(24页).pdf

  3. 《如何向 ChatGPT 提问以获得高质量答案:提示技巧工程完全指南》

  4. 《OpenAI:GPT 最佳实践(大白话编译解读版)》

  5. 人工智能精选电子书

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

同学小张

如果觉得有帮助,欢迎给我鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值