【OpenGL手册-13】光源和颜色模型

news2024/9/24 19:25:17

文章目录

  • 一、说明
  • 二、颜色综述
  • 三、灯光场景
  • 四、光源位置

一、说明

   光源和颜色模型也是OpenGL的重要模型之一,我们将光源也看成是一个物体,这个物体特点是,不仅可以自己移动位置,而且要和其它物体颜色进行反射运算,从而发出最后颜色结果。请看详细内容。

二、颜色综述

   我们在前几章中简要使用和操作了颜色,但从未正确定义它们。在这里,我们将讨论什么是颜色,并开始为即将到来的照明章节构建场景。

   在现实世界中,颜色可以采用任何已知的颜色值,每个对象都有自己的颜色。在数字世界中,我们需要将(无限的)真实颜色映射到(有限的)数字值,因此并非所有现实世界的颜色都可以用数字表示。颜色使用 和 分量(通常缩写为 )以数字形式表示red。green在blue的RGB范围内,仅使用这 3 个值的不同组合,[0,1]我们就可以表示几乎任何颜色。例如,要获得珊瑚色,我们将颜色向量定义为:

glm::vec3 coral(1.0f, 0.5f, 0.31f);  

或者(python版):

import pyrr
v = pyrr.Vector3([1.,0.5.,0.31])

   我们在现实生活中看到的物体的颜色并不是它实际具有的颜色,而是它的颜色反映来自物体的颜色。物体不吸收(拒绝)的颜色就是我们感知到的颜色。例如,太阳光被认为是白光,是许多不同颜色的总和(如您在图片中看到的那样)。如果我们将白光照在一个蓝色玩具上,它会吸收除蓝色之外的所有白色子颜色。由于玩具不吸收蓝色部分,所以它会被反射。反射光进入我们的眼睛,使玩具看起来像是蓝色的。下图显示了珊瑚色玩具反射的几种不同强度的颜色:
在这里插入图片描述
   您可以看到,白色阳光是所有可见颜色的集合,物体吸收了这些颜色的很大一部分。它只反射那些代表物体颜色的颜色,这些颜色的组合就是我们所看到的(在本例中是珊瑚色)。

   从技术上来说,这有点复杂,但我们将在 PBR 章节中讨论这个问题。
   这些颜色反射规则直接适用于图形领域。当我们在 OpenGL 中定义光源时,我们希望赋予该光源一种颜色。在上一段中,我们有一个白色,因此我们也将赋予光源白色。如果我们将光源的颜色与物体的颜色值相乘,则得到的颜色将是物体的反射颜色(因此是其感知颜色)。让我们重新审视我们的玩具(这次使用珊瑚色值),看看我们如何在图形领域计算其感知颜色。我们通过在光和物体颜色向量之间进行分量相乘来获得结果颜色向量:

glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);

或者(python版):

import pyrr
lightColor=pyrr.Vector3([1.,1.,1])    #光源颜色
toyColor=pyrr.Vector3([1.0 , 0.5 , 0.31 ]) 
result = lightColor * toyColor;        # = (1.0f, 0.5f, 0.31f);

   我们可以看到,玩具的颜色吸收了大部分白光,但根据其自身的颜色值反射了几个红色、绿色和蓝色值。这表示颜色在现实生活中如何发挥作用。因此,我们可以将物体的颜色定义为它从光源反射的每个颜色成分的数量。

   现在,如果我们使用绿光会发生什么?

glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);

或者(python版):

import pyrr
lightColor=pyrr.Vector3([0.,1.,0])    #光源颜色
toyColor=pyrr.Vector3([1.0 , 0.5 , 0.31 ]) 
result = lightColor * toyColor;        # = (0, 0.5f, 0);

   我们可以看到,玩具没有红光和蓝光可以吸收和/或反射。玩具还吸收了一半的绿光,但也反射了一半的绿光。我们感知到的玩具颜色将是深绿色。我们可以看到,如果我们使用绿光,只有绿色成分可以被反射,从而被感知到;没有红色和蓝色被感知到。结果,珊瑚物体突然变成了深绿色物体。让我们再举一个深橄榄绿色光的例子:

glm::vec3 lightColor(0.33f, 0.42f, 0.18f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.33f, 0.21f, 0.06f);

三、灯光场景

   在接下来的章节中,我们将通过大量使用颜色来模拟真实世界的照明,从而创建有趣的视觉效果。由于现在我们将使用光源,我们希望将它们显示为场景中的视觉对象,并添加至少一个对象来模拟照明。

我们首先需要一个物体来投射光线,我们将使用前几章中著名的立方体容器。我们还需要一个灯光物体来显示光源在 3D 场景中的位置。为了简单起见,我们也将用立方体来表示光源(我们已经有了顶点数据,对吧?)。

   因此,填充顶点缓冲区对象、设置顶点属性指针以及所有这些步骤现在对您来说应该很熟悉了,所以我们不会带您完成这些步骤。如果您仍然不知道这些步骤是怎么回事,我建议您在继续之前先查看前面的章节,并尽可能完成练习。

   因此,我们首先需要的是顶点着色器来绘制容器。容器的顶点位置保持不变(尽管这次我们不需要纹理坐标),因此代码应该没有什么新东西。

   我们将使用上一章中精简版的顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
} 

   确保更新顶点数据和属性指针以匹配新的顶点着色器(如果您愿意,您实际上可以保持纹理数据和属性指针处于活动状态;我们现在只是不使用它们)。

   因为我们还要渲染一个光源立方体,所以我们想为光源生成一个新的 VAO。我们可以使用相同的 VAO 渲染光源,然后在模型矩阵上进行一些光位置变换,但在接下来的章节中,我们将经常更改容器对象的顶点数据和属性指针,我们不希望这些更改传播到光源对象(我们只关心光立方体的顶点位置),所以我们将创建一个新的 VAO:

unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
// we only need to bind to the VBO, the container's VBO's data already contains the data.
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// set the vertex attribute 
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

代码应该相对简单。现在我们创建了容器和光源立方体,还剩下一件事需要定义,那就是容器和光源的片段着色器:

#version 330 core
out vec4 FragColor;
  
uniform vec3 objectColor;
uniform vec3 lightColor;

void main()
{
    FragColor = vec4(lightColor * objectColor, 1.0);
}

   片段着色器从统一变量中接受对象颜色和光颜色。在这里,我们将光的颜色与对象的(反射)颜色相乘,就像我们在本章开头讨论的那样。同样,这个着色器应该很容易理解。让我们用白光将对象的颜色设置为上一节的珊瑚色:

// don't forget to use the corresponding shader program first (to set the uniform)
lightingShader.use();
lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor",  1.0f, 1.0f, 1.0f);

   还有一点需要注意,当我们在下一章开始更新这些照明着色器时,光源立方体也会受到影响,而这并不是我们想要的。我们不希望光源物体的颜色受到照明计算的影响,而是将光源与其他物体隔离开来。我们希望光源具有恒定的明亮颜色,不受其他颜色变化的影响(这让它看起来就像光源立方体真的是光源)。

   为了实现这一点,我们需要创建第二组着色器,用于绘制光源立方体,这样可以避免照明着色器的任何更改。顶点着色器与照明顶点着色器相同,因此您只需复制源代码即可。光源立方体的片段着色器通过在灯上定义恒定的白色来确保立方体的颜色保持明亮:

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0); // set all 4 vector values to 1.0
}

   当我们想要渲染时,我们希望使用刚刚定义的照明着色器来渲染容器对象(或可能是许多其他对象),而当我们想要绘制光源时,我们会使用光源的着色器。在照明章节中,我们将逐步更新照明着色器,以慢慢实现更逼真的效果。

四、光源位置

   光源立方体的主要用途是显示光的来源。我们通常会在场景中的某个位置定义光源的位置,但这只是没有视觉意义的位置。为了显示光源的实际位置,我们会在光源的同一位置渲染一个立方体。我们使用光源立方体着色器渲染此立方体,以确保无论场景的光照条件如何,立方体始终保持白色。

   因此让我们声明一个全局vec3变量来表示光源在世界空间坐标中的位置:

glm::vec3 lightPos(1.2f, 1.0f, 2.0f);

   然后,我们将光源立方体平移到光源的位置,并在渲染之前将其缩小:

model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f)); 

   最终光源立方体的渲染代码看起来应该像这样:

lightCubeShader.use();
// set the model, view and projection matrix uniforms
[...]
// draw the light cube object
glBindVertexArray(lightCubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);

   将所有代码片段注入到适当的位置,即可生成一个干净的 OpenGL 应用程序,该应用程序已正确配置,可用于进行照明实验。如果一切顺利,它应该如下所示:
在这里插入图片描述
   现在真的没什么可看的,但我保证在接下来的章节中它会变得更有趣。

   如果您难以找出应用程序整体中所有代码片段的组合位置,请检查此处的源代码并仔细研究代码/注释。

   现在我们对颜色有了相当多的了解,并创建了一个用于实验照明的基本场景,我们可以跳到下一章,真正的魔法从那里开始。

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

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

相关文章

应急响应-网页篡改-技术操作只指南

初步判断 网页篡改事件区别于其他安全事件地明显特点是:打开网页后会看到明显异常。 业务系统某部分出现异常字词 网页被篡改后,在业务系统某部分网页可能出现异常字词,例如,出现赌博、色情、某些违法APP推广内容等。2019年4月…

【一小时学会Charles抓包详细教程】初识Charles (1)

🚀 个人主页 极客小俊 ✍🏻 作者简介:程序猿、设计师、技术分享 🐋 希望大家多多支持, 我们一起学习和进步! 🏅 欢迎评论 ❤️点赞💬评论 📂收藏 📂加关注 Charles介绍 …

1、pyton环境的安装-windows系统下

python官网 https://www.python.org/ 点击黄色的按钮,下载完成,如下: 双击安装,我现在以3.10.4版本进行安装说明: 一定要勾选上下边的to path,然后选择自定义安装 全选,点击next 选择要安装的路…

HTML大雪纷飞

目录 写在前面 HTML简介 完整代码 代码分析 运行结果 系列文章 写在后面 写在前面 小编又又又出现啦!这次小编给大家带来大雪纷飞HTML版,不需要任何的环境,只要有一个浏览器,就可以随时随地下一场大雪哦! HTM…

从金蝶云星空到旺店通·企业奇门通过接口配置打通数据

从金蝶云星空到旺店通企业奇门通过接口配置打通数据 对接系统金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上,提供了标准的管理模式;通过标准的业务架构:多会计准则、多币别、多地点、多组织、多税制应用框架等,有…

QT:协议概述

文章目录 概念帧结构:通信流程 示例:请求帧:响应帧: 概念 帧结构: | SOF (1 byte) | Frame Length (1 byte) | Command (1 byte) | Data Field (N bytes) | Checksum (1 byte) | 通信流程 示例: 请求帧&a…

ld链接文件

文章目录 1. sections缩写2. 链接脚本2.1 MEMORY(内存命令)2.1.1 作用2.1.2 格式 2.2 SECTIONS(段命令)2.2.1 作用2.2.2 格式 2.3 特殊符号含义2.4 通配符2.5 Eg 1. sections缩写 2. 链接脚本 https://www.cnblogs.com/jianhua19…

如何处理 Google Chrome中的代理服务器错误?

如果您在 Google Chrome 浏览器中遇到代理服务器错误,您可以采取一些步骤来排除故障并解决问题。代理服务器充当您的设备和互联网之间的中介,与其相关的错误有时会破坏您的浏览体验。以下是帮助您解决该问题的一些步骤: 1. 检查您的互联网连接…

shell脚本编译成二进制文件shc

文章目录 1. 安装shc2. 使用shc编译Shell脚本3. 执行二进制文件4. 编译后执行效率 将Shell脚本转换为二进制执行文件,可以使用 shc工具。 shc是一个Shell编译器,它可以将Shell脚本编译成二进制文件。以下是详细步骤: 1. 安装shc 在大多数L…

图片缩放随心所欲,自定义保存尽在掌控,解锁全新图片处理神器,轻松驾驭视觉创作之旅!

在数字化浪潮汹涌的今天,图片作为视觉信息的核心载体,已经渗透到我们生活的方方面面。一张精美的图片,往往能够成为我们表达思想、分享生活的得力助手。然而,面对大小不一、格式各异的图片,如何轻松实现缩放并自定义保…

新火种AI|警钟长鸣!教唆自杀,威胁人类,破坏生态,AI的“反攻”值得深思...

作者:小岩 编辑:彩云 在昨天的文章中,我们提到了谷歌的AI Overview竟然教唆情绪低迷的网友“从金门大桥跳下去”。很多人觉得,这只是AI 模型的一次错误判断,不会有人真的会因此而照做。但现实就是比小说电影中的桥段…

Jetpack架构组件_2. 数据绑定库

1.理论基础 数据绑定库是一个支持库,可让您使用声明性格式(而不是以程序化方式)将布局中的界面组件绑定到应用中的数据源。 布局通常使用调用界面框架方法的代码在 activity 中定义。例如,以下代码会调用 findViewById() 来查找 T…

一键秒删TXT文本符号,释放工作效率新高度,轻松应对海量文本处理挑战!

在这个信息爆炸的时代,我们每天都会面对海量的文本信息。而在处理这些文本时,你是否曾经因为各种符号的干扰而头疼不已?现在,我们为你带来了一款高效批量处理工具,它能够一键删除TXT文本中的符号,让你的工作…

面试八-存泄漏是什么,有哪几种,怎么解决?

一、内存泄漏几种情况 当使用基类指针指向派生类对象时,如果基类的析构函数不是虚函数,那么在使用基类指针来删除这个对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。这就导致了派生类中的资源无法正确释放&#xff…

前端使用JavaScript实现一个LRU缓存

引言 LRU(Least Recently Used)算法是一种广泛应用于内存管理和缓存系统的策略,在微前端、状态管理以及性能优化等场景下,合理使用缓存机制能够有效提升应用性能。本文将介绍LRU算法的基本原理,并通过JavaScript实现案…

MySQL(进阶)--索引

目录 一.存储引擎 1.MySQL体系结构​编辑 2.存储引擎简介 3.存储引擎特点 (1.InnoDB (2.MyISAM (3.Memory 4.存储引擎选择 二.索引 1.索引概述 2.索引结构 3.索引分类 4.索引语法 (1.创建索引 (2.查看索引 (3.删除索引 5.SQL性能分析 (1.SQL执行频率 (2.慢查…

Linux——Dockerfile部分参数(1)

在这里我们来整理一下docker容器、dockerfile、docker镜像的关系: dockerfile是面向开发的,发布项目做镜像的时候就要编写dockerfile文件。 dockerfile:构建文件,定义了一切的步骤,源代码。 dockerImanges&#xff1a…

为什么Facebook Marketplace无法使用?如何解决?

Facebook Marketplace是一个允许用户买卖商品的平台,由于其在Facebook内的便捷性,它逐渐成为了一个受欢迎的在线交易市场。然而,做Facebook跨境电商,很多人会面临的情况就是无法使用Facebook Marketplace。这到底是什么原因&#…

PSexec工具横向移动

一. 其他横向工具和命令介绍 之前我们讲解了IPC,PTH,PTK,PTH,其实这些东西都是用来进行认证的 IPC:使用明文的账号密码进行认证 PTH:使用NTLM-hash值进行认证 PTK:使用AES秘钥进行认证 PTT:使用票据进行认证认证通过之后如何实现远程上线内网其他的机器&#xff0…

23种设计模式全面总结 | 快速复习(附PDF+MD版本)

本篇文章是对于23种设计模式的一个全面的总结,受限于文章篇幅无法对每个设计模式做到全面的解析,但几乎每个设计模式都提供了案例和类图结构,非常适合快速复习和在学习设计模式之前的全预习把握。 💡文章的 pdf markdown 版本可通…