LearnOpenGL-光照-6.多光源

news2025/3/1 8:51:22

本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正

我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject

文章目录

  • 前言
  • 例子
    • 代码
    • 没有聚光灯效果
    • 有聚光灯效果

前言

  • 此节目的

    综合2.5投光物,在此节实现一个场景使用多个光源,物体根据不同光源而叠加颜色

    • 熟悉多光源如何计算物体颜色
    • 熟悉用glsl函数

例子

代码

  • glsl

    #version 330 core
    out vec4 FragColor;
    struct Material {
        sampler2D diffuse;  // 漫反射颜色分量从纹理采样
        sampler2D specular;//  镜面光照颜色分量从纹理采样
        float shininess;
    }; 
    // 平行光
    struct DirLight  {
        vec3 direction; // 从光源出发到全局的方向
    
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
    };
    // 点光源
    struct PointLight  {
        vec3 position;  
    
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
    
        float constant; // 常数
        float linear;   // 一次项
        float quadratic;// 二次项
    };
    
    uniform DirLight dirLight;
    #define NR_POINT_LIGHTS 4
    uniform PointLight pointLights[NR_POINT_LIGHTS];
    
    uniform Material material;
    
    in vec3 FragPos;
    in vec3 Normal;
    in vec2 TexCoords;// 纹理坐标
    
    uniform vec3 viewPos;
    
    // 计算平行光影响当前片段的颜色
    vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir){
        vec3 lightDir = normalize(-light.direction);// 取负变为光源的方向向量,用在计算漫反射和镜面光分量时
        // 漫反射光照分量
        float diff = max(dot(normal, lightDir), 0.0);// 得到光源对当前片段实际的漫反射影响
        // 镜面光光照分量
        vec3 reflectDir = reflect(-lightDir, normal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
        // 从纹理读取颜色分量
        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));
        return (ambient + diffuse + specular);
    }
    // 计算点光源影响当前片段的颜色
    vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir){
        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.0 / (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 norm = normalize(Normal);
        vec3 viewDir = normalize(viewPos - FragPos);
    
        // 平行光
        vec3 result = CalcDirLight(dirLight, norm, viewDir);
    
        // 点光源
        for(int i = 0; i < NR_POINT_LIGHTS; i++){
            result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
        }
        
        FragColor = vec4(result, 1.0);
    }
    
  • cpp

    lightingShader.use();
    lightingShader.setInt("material.diffuse", 0);
    lightingShader.setInt("material.specular", 1);
    lightingShader.setFloat("material.shininess", 32.0f);
    // 平行光
    lightingShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f);
    lightingShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f);
    lightingShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f);
    lightingShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f);
    
    // 点光源
    lightingShader.setVec3("pointLights[0].position", pointLightPositions[0]);
    lightingShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f);
    lightingShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f);
    lightingShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f);
    lightingShader.setFloat("pointLights[0].constant", 1.0f);
    lightingShader.setFloat("pointLights[0].linear", 0.09f);
    lightingShader.setFloat("pointLights[0].quadratic", 0.032f);
    
    lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]);
    lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f);
    lightingShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f);
    lightingShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f);
    lightingShader.setFloat("pointLights[1].constant", 1.0f);
    lightingShader.setFloat("pointLights[1].linear", 0.09f);
    lightingShader.setFloat("pointLights[1].quadratic", 0.032f);
    
    lightingShader.setVec3("pointLights[2].position", pointLightPositions[2]);
    lightingShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f);
    lightingShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f);
    lightingShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f);
    lightingShader.setFloat("pointLights[2].constant", 1.0f);
    lightingShader.setFloat("pointLights[2].linear", 0.09f);
    lightingShader.setFloat("pointLights[2].quadratic", 0.032f);
    
    lightingShader.setVec3("pointLights[3].position", pointLightPositions[3]);
    lightingShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f);
    lightingShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f);
    lightingShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f);
    lightingShader.setFloat("pointLights[3].constant", 1.0f);
    lightingShader.setFloat("pointLights[3].linear", 0.09f);
    lightingShader.setFloat("pointLights[3].quadratic", 0.032f);
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // view/projection transformations
        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
        glm::mat4 view = camera.GetViewMatrix();
        lightingShader.setMat4("projection", projection);
        lightingShader.setMat4("view", view);
        // 绑定漫反射贴图-出过错,放在绘制光源cube那里
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, texture3);
    
        glBindVertexArray(cubeVAO);
        for (unsigned int i = 0; i < 10; i++)
        {
            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, cubePositions[i]);
            float angle = 20.0f * i;
            model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
            lightingShader.setMat4("model", model);
    
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }
        // 绘画灯
        // world transformation
        glm::mat4 model;
    
        lightCubeShader.use();
        lightCubeShader.setMat4("projection", projection);
        lightCubeShader.setMat4("view", view);
        glBindVertexArray(cubeVAO);
        for (unsigned int i = 0; i < 4; i++) {
            model = glm::mat4(1.0f);
            model = glm::translate(model, pointLightPositions[i]);
            model = glm::scale(model, glm::vec3(0.2f));
            lightCubeShader.setMat4("model", model);
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }
        glfwSwapBuffers(window);
        glfwPollEvents();
    
  • 关键代码

    glsl

    #define NR_POINT_LIGHTS 4
    uniform PointLight pointLights[NR_POINT_LIGHTS];
    

    cpp

    lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]);
    lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f);
    

没有聚光灯效果

有聚光灯效果

  • 修改代码

    glsl

    .....
    struct Material {
        sampler2D diffuse;  // 漫反射颜色分量从纹理采样
        sampler2D specular;//  镜面光照颜色分量从纹理采样
        sampler2D spotLightDiffuse;//  聚光灯的漫反射颜色分量从纹理采样
        float shininess;
    }; 
    .....
    uniform SpotLight spotLight;
        // 计算点光源影响当前片段的颜色
    vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir){
        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.0 / (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()
    {
        ........
        // 点光源
        for(int i = 0; i < NR_POINT_LIGHTS; i++){
            result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
        }
        // 聚光灯
        result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
        
        FragColor = vec4(result, 1.0);
    }
    

    cpp

    unsigned int texture3 = loadTexture("assest/textures/spotlightimg.jpg");
    lightingShader.setInt("material.spotLightDiffuse", 2);
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // 聚光灯
        lightingShader.setVec3("spotLight.ambient", 0.1f, 0.1f, 0.1f);
        lightingShader.setVec3("spotLight.diffuse", 0.8f, 0.8f, 0.8f);
        lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f);
        lightingShader.setVec3("spotLight.position", camera.Position);
        lightingShader.setVec3("spotLight.direction", camera.Front);// direction是光照射方向
        lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));
        lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(17.5f)));
    
        lightingShader.setFloat("spotLight.constant", 1.0f);
        lightingShader.setFloat("spotLight.linear", 0.09f);
        lightingShader.setFloat("spotLight.quadratic", 0.032f);
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, texture3);
    
  • 效果

    请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/404896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超越语言界限,ChatGPT进化之路——Visual ChatGPT

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

操作系统复习

熟练掌握操作系统的定义&#xff0c;操作系统的特征&#xff0c;操作系统的功能熟练掌握多道程序设计的概念&#xff0c;单道程序设计和多道程序设计的区别&#xff0c;多道程序设计的优点熟悉操作系统接口的主要功能&#xff0c;系统调用的基本概念、类型、实现。操作系统接口…

【Mysql】库的操作

一、sql分类 1.DDL&#xff08;Data Defination Language&#xff09;数据定义语言 定义数据时候使用的sql语言 creat:建表、drop:删表、alter:改变 2.DML&#xff08;Data Manipulation Language&#xff09;数据操纵语言 对数据进行操作的sql语言 insert:插入、delet…

【打造家庭服务器系列03】Frp 实现内网穿透

一、概述 为什么要搞frp&#xff0c;因为我们的服务器处于家里面的网络&#xff0c;是没有公网IP的&#xff0c;所以直接通过ssh连接服务器&#xff0c;此时就需要一个中转来实现转发。 二、服务端配置 - Frp Server 以腾讯云为例&#xff0c;阿里云也一样。Frp 官方文档 -…

chatPDF | 别再自己读文献了!让chatGPT来帮你读吧!~

1写在前面 自从chatGPT开放API以后&#xff0c;相关基于此的app也是层出不穷。&#x1f92a; ChatGPT API是基于OpenAI的自然语言处理模型的API。&#x1f9d0; 基于这个API&#xff0c;开发人员可以通过程序调用和使用ChatGPT模型来解决各种文本相关的任务。&#x1f609; 其实…

Ubuntu软件包管理之apt与apt-get的区别

目录apt和apt-get发展史apt和apt-get命令对比常用命令举例更新存储库索引升级已安装的包列出所有可用安装包关键字搜索安装包安装软件卸载软件查看安装包信息清理没用的依赖包清理下载的缓存包清理残余的配置文件查看安装包的依赖参考apt和apt-get发展史 Debian 使用一套名为 …

STM32—LCD1602

LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 第 1 脚: VSS 为电源地 第 2 脚: VDD 接 5V 正电源 第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱&#xff0c;接地时对比度最…

C语言实现快速排序(hoare法、挖坑法、前后指针法与非递归实现)——不看后悔系列

目录 1. hoare法 方法与步骤 代码实现 2. 挖坑法 方法与步骤 代码实现 3. 前后指针法 方法与步骤 代码实现 4. 快速排序的缺点与优化 1.快速排序的缺点 2.快速排序的优化 ① 三数取中法选 key 代码实现 ② 小区间优化 代码实现 5. 快速排序的非递归实现 附录…

数据结构与算法基础(王卓)(16):KMP算法详解(代码实现)

实现代码的过程中 具体细节、问题&#xff1a; &#xff08;1&#xff09;&#xff1a;关于写Get_next函数的标题&#xff1a; 现象&#xff1a; PPT上写的是&#xff1a; void get_next(SString T, int &next[]) 然而并不能运行&#xff0c;而当我们去掉了引用符号&…

记录踩过的坑-Git

Git命令克隆很慢原命令&#xff1a;git clone -b r1.13.0 https://github.com/tensorflow/models.git现在替换为&#xff1a;git clone -b r1.13.0 https://github.com.cnpmjs.org/tensorflow/models.git也就是把原 URL 中的 github.com 替换为 github.com.cnpmjs.org&#xff…

设计模式第9式:迭代器模式

前言 我们有很多种方法可以把对象集中到一个集合中&#xff0c;比如列表、堆栈、散列表中。每种集合都有自己的特点和使用时机&#xff0c;但都有一个共同的需求&#xff1a;用户想要遍历这些对象。同时我们并不想用户看到集合的实现&#xff0c;本文将讲解如何让用户遍历对象…

JVM垃圾回收器详解

垃圾收集器没有在规范中进行过多的规定&#xff0c;可以由不同的厂商、不同版本的JVM来实现。由于JDK的版本处于高速迭代过程中&#xff0c;因此Java发展至今已经衍生了众多的GC版本。从不同角度分析垃圾收集器&#xff0c;可以将GC分为不同的类型。1、垃圾回收器分类1.1、按线…

国际安全领域顶会NDSS 2023录稿整理 (下)

隐私计算研习社 NDSS是网络和系统安全领域的四大顶级国际学术会议&#xff08;BIG4&#xff09;之一&#xff0c;第三十届会议于2023年2月27日到3月3日&#xff0c;在美国圣迭戈举办。本文将接着整理剩余论文&#xff0c;并对论文进行分类&#xff0c;感兴趣的小伙伴可以访问论…

【Linux】信号+再谈进程地址空间

目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生&#xff1f; 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais…

pinctrl和gpio子系统

一、pinctrl子系统简介Linux驱动讲究驱动分离与分层&#xff0c;pinctrl和gpio子系统就是驱动分离与分层思想下的产物&#xff0c;pinctrl子系统主要工作内容如下&#xff1a;获取设备树中的pin信息根据获取到的pin信息来设置pin的复用功能根据获取到的pin信息来设置pin的电气属…

Day914.安全认证架构演进:单块阶段 -SpringBoot与K8s云原生微服务实践

安全认证架构演进&#xff1a;单块阶段 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于安全认证架构演进&#xff1a;单块阶段的内容。 讲到安全认证的内容&#xff0c;就必然会提到两个点&#xff1a;认证 和 授权。 认证&#xff1a;我是谁授权&#xff1a;我能…

Spring中的事务@Transactional

Transactional可以添加在方法上 添加在方法上时&#xff0c;表示该方法出现了异常或者报错&#xff0c;而导致之前数据库没有进行回滚事件&#xff0c;也就是说如果在方法中&#xff0c;有报错&#xff0c;但是添加了Transactional 则会开始回滚。 Transactional 在异常被捕获…

剑指 Offer 29. 顺时针打印矩阵

剑指 Offer 29. 顺时针打印矩阵 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2…

【OpenCV技能树】——OpenCV基础

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; 目前正在进行 OpenCV技能树的学习&#xff0c;OpenCV是学习图像处理理论知识比较好的一个途径&#xff0c;至少比看书本来得实在。本专栏文章主要记录学习Op…

Apache apisix默认密钥漏洞(CVE-2020-13945)

目录漏洞描述影响版本漏洞复现声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。漏洞描述 Apache APISIX 是一个动态、实时、高…