1. 光照

显示世界中,光照环境往往是相对复杂的。因为假设太阳作为世界的唯一光源,那么太阳光照在物体A上A将阳光进行反射后,A又做为一个新的光源共同作用于另一个物体B。所以于B来讲光源是复杂的。然而这只是其中一个因素,受制于天气、温度等其他情况我们需要考虑的因素更多。在OpenGL中我们仅考虑一些简单的模型,对现实情况进行一个近似的模拟。这一节中我们主要介绍一下冯氏光照模型。冯氏光照模型中主要有3个分量构成:

  • 环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。
  • 漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。
  • 镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。

接下来我们将逐一讲解这三个分量。

2. 环境光照

上文中提到了,真实世界中的光源情况是复杂的。如果对系统中的每一个光源都进行考虑,这种算法叫做全局照明算法。但是这种算法既开销高昂又极其复杂。我们使用环境光照来简化这个概念,即使用一个很小的常量光照颜色,叠加到实际光照颜色中。

我们看到此处直接用环境颜色与物体颜色相乘。这是因为当前阶段我们还没有添加光源。

3. 漫反射光照

当光线照射在平面上时会发生镜面反射,这是一个光学常识。但事实上真实世界中的物体表面一般都不是完全的平面而是凹凸不平的(微观上的凹凸不平),此时将发生漫反射。漫反射的结果就是,你不仅可以从光源的镜像角度可以观察到物体,从各个角度你都可以观察得到。不过漫反射的强度区域光源射入平面的夹角有关。通过实验,我们观察到当射入角度与平面法线夹角越小时,漫反射强度越强。

我们要在GL中模拟漫反射效果。从上述的叙述中我们知道,漫反射的关键因素在于法线夹角。那么也就是说,我们在GL中需要两点,第一个是法向量,第二个是光线射入的角度

法向量是相对于平面而言的,于点是没有意义的。而同一点在不同平面中对应的法向量也是不同的。这就决定了我们需要改造我们的顶点数据,传一组法向量给顶点着色器,此外绘制VAO时也不能以EBO绘制,而应该以VBO绘制。

虽然对灯的着色器使用不能完全利用的顶点数据看起来不是那么高效,但这些顶点数据已经从箱子对象载入后开始就储存在GPU的内存里了,所以我们并不需要储存新数据到GPU内存中。这实际上比给灯专门分配一个新的VBO更高效了。

4. 计算漫反射光照

顶点数据中我们传入了法向量,我们还需要一个角度。顶点着色器中我们是可以拿到顶点数据的,这时只要我们拿到光源的位置即可以计算出光的方向了,标准化以后就是方向向量了。光源的位置一般是相对固定的,我们可以用uniform变量在外界对着色器进行赋值。记得将光源坐标和顶点坐标都转化为世界坐标哦,或者保证光源坐标、顶点坐标和法向量在同一坐标系统内也可。法向量和方向向量都记得要标准化,这样他们点乘的结果才是两个向量的夹角余弦值。

最后,如果夹角余弦值小于零,我们认为这时无意义的,他将造成我们的漫反射分量为负值,而真实世界中,仅可能是无影响,而不会是负影响。所以我们小于0时我们取0。

片段着色器中的代码大概是这个样子的:

还有一件事,之前说过,要保证光源坐标、顶点坐标和法向量在同一坐标系统内。一般情况下我们会将他们转化为世界坐标,因为这更符合我们的直觉。我们要把法向量也转换到世界空间内。顶点数据中,你所写的法向量直觉上应该是局部坐标,所以要经过模型矩阵转换。此外,模型矩阵中我们也可能对物体进行非比例变化,这将导致我们的法向量发现也发生改变。所以在把法向量从局部坐标转化至世界坐标时,我们要经过法线矩阵的转换。我们可以通过逆矩阵和转置矩阵来变化模型矩阵。所以顶点着色器中我们的代码大概是这个样子的:

其中inverse()是求逆矩阵函数,transpose是求转置矩阵函数。

5. 镜面光照

那么,最后我们只要再将镜面反射叠加进去就好了。

跟漫反射的原理差不多,我们看到物体的颜色跟物体表面镜面反射的光线与我们观察的视角的夹角有关。当夹角越小时,那么镜面光的影响越大。与我们的效果就是,我们将看到一个高光。

那么我们还是需要两个方向向量,第一个是镜面光的方向向量,第二个是观察角度的方向向量

镜面光的方向我们可以根据光源方向及法向量通过反射计算出来。观察方向则是我们摄像机的位置与观察点所构成的向量。

所以我们的两个向量大概是这个样子的:

我们看到,观察方向需要我们传入一个摄像机位置,我们需要在渲染循环中将摄像机的世界坐标传给片段着色器。

计算反射光时,我们使用的是reflect函数。这个函数需要的是传入一个从光源指向平面的向量以及平面的法向量。这里之所以我们传入-lightDir是因为我们之前计算的lightDir是从平面指向光源的。

这里我们最好给一个镜面强度系数,以免当光源垂直照向平面时,我们的镜面光分量过于明亮。

两个向量获取后我们就可以计算他们的夹角来计算我们的镜面光分量了。

首先我们看镜面系数的计算方式,点乘求夹角余弦值后取大于0的值,然后调用pow函数。pow是取这个系数的指定次幂。我们指定了32,代表我们指定了他的反光度是32。一个物体的反光度越高,反射光的能力越强,散射得越少,高光点就会越小。在下面的图片里,你会看到不同反光度的视觉效果影响:

至此我们计算出镜面系数,用光源颜色乘镜面系数乘镜面强度系数后即可获得镜面分量。

最后的最后,我们将环境光照、漫反射光照及镜面光照进行叠加后,与物体颜色相乘,即可获得物体在冯氏光照光源影响下所展示的颜色了。

在光照着色器的早期,开发者曾经在顶点着色器中实现冯氏光照模型。在顶点着色器中做光照的优势是,相比片段来说,顶点要少得多,因此会更高效,所以(开销大的)光照计算频率会更低。然而,顶点着色器中的最终颜色值是仅仅只是那个顶点的颜色值,片段的颜色值是由插值光照颜色所得来的。结果就是这种光照看起来不会非常真实,除非使用了大量顶点。

在顶点着色器中实现的冯氏光照模型叫做Gouraud着色(Gouraud Shading),而不是冯氏着色(Phong Shading)。记住,由于插值,这种光照看起来有点逊色。冯氏着色能产生更平滑的光照效果。

OpenGL 基础光照详解的更多相关文章

  1. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  2. python 3.x 爬虫基础---Urllib详解

    python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 前言 爬虫也了解了一段时间了希望在半个月的时间内 ...

  3. RabbitMQ基础知识详解

    什么是MQ? MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中 ...

  4. Nmap扫描教程之基础扫描详解

    Nmap扫描教程之基础扫描详解 Nmap扫描基础扫描 当用户对Nmap工具了解后,即可使用该工具实施扫描.通过上一章的介绍,用户可知Nmap工具可以分别对主机.端口.版本.操作系统等实施扫描.但是,在 ...

  5. jmeter 基础功能详解

    jmeter 基础功能详解 thread group:包含一组线程,每个线程独立地执行测试计划. sampler:采样器,有多种不同的sample实现,用来发起各种请求,如http请求,jdbc请求, ...

  6. hadoop基础-SequenceFile详解

    hadoop基础-SequenceFile详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.SequenceFile简介 1>.什么是SequenceFile 序列文件 ...

  7. Cisco路由技术基础知识详解

    第一部分 请写出568A的线序(接触网络第一天就应该会的,只要你掐过,想都能想出来) .网卡MAC地址长度是(  )个二进制位(16进制与2进制的换算关系,只是换种方式问,不用你拿笔去算) A.12  ...

  8. RabbitMQ,Apache的ActiveMQ,阿里RocketMQ,Kafka,ZeroMQ,MetaMQ,Redis也可实现消息队列,RabbitMQ的应用场景以及基本原理介绍,RabbitMQ基础知识详解,RabbitMQ布曙

    消息队列及常见消息队列介绍 2017-10-10 09:35操作系统/客户端/人脸识别 一.消息队列(MQ)概述 消息队列(Message Queue),是分布式系统中重要的组件,其通用的使用场景可以 ...

  9. # OpenGL常用函数详解(持续更新)

    OpenGL常用函数详解(持续更新) 初始化 void glutInit(int* argc,char** argv)初始化GULT库,对应main函数的两个参数 void gultInitWindo ...

  10. 经典Spring入门基础教程详解

    经典Spring入门基础教程详解 https://pan.baidu.com/s/1c016cI#list/path=%2Fsharelink2319398594-201713320584085%2F ...

随机推荐

  1. 国产化之x64平台安装银河麒麟操作系统

    背景 某个项目需要实现基础软件全部国产化,其中操作系统指定银河麒麟v4,CPU使用飞腾处理器.飞腾处理器是ARMv8架构的,在之前的文章中介绍了使用QEMU模拟ARMv8架构安装银河麒麟操作系统的方式 ...

  2. Node版本更新及切换

    Node版本升级 # 清除npm缓存 npm cache clean -f # n模块是专门用来管理nodejs的版本,安装n模块 npm install -g n 1.Windows 由于n命令是在 ...

  3. 获取客户端真实 IP 地址的最佳实践

    一.背景 1. 业务上云带来性能收益 公司从去年全面推动业务上云,而以往 IDC 架构部署上,接入层采用典型的 4 层 LVS 多机房容灾架构,在业务高峰时期,扩容困难(受限于物理机资源和 LVS 内 ...

  4. Vue详解----一篇带你从头领悟到尾,享受飞升的感觉

    脚手架文件结构 """ ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ...

  5. Linux学习环境搭建(VMware虚拟机安装Linux)

    企业现状 目前绝大多数企业运维人员的工作环境都是Windows下通过SSH工具(如XShell等)远程连接千百里外的服务器进行管理和维护的. 而且学Linux运维,99.9%知识与硬件无关,用虚拟机足 ...

  6. opencv-python 车牌检测和识别

    首先利用级联分类器把车牌位置找到取出来,然后用ocr进行车牌识别. 1 OCR之Tesseract安装 Tesseract安装可以参考这个链接: https://blog.csdn.net/m0_53 ...

  7. JS遍历Json串并获取Key和Value

    //data为json串 for (var key in data) { console.log(key); console.log(data[key]); }

  8. selenium-wire兼容selenium和requests

    背景 在工作中UI自动化中可能会需要用到API来做一些数据准备或清理的事情,那UI操作是略低效的,但API操作相对高效. 而实战课就有这样一个案例,不过那个案例是UI操作和API分开的. 极少会遇到这 ...

  9. 虚拟机问题:VMware Workstation 与 Device/Credential Guard 不兼容。在禁用 Device/Credential Guard 后,可以运行

    解决办法:关闭Hyper-V功能. windows10使用VMware Workstation打开虚拟机时显示 VMware Workstation 与 Hyper-V 不兼容.请先从系统中移除 Hy ...

  10. Elasticsearch整合SpringBoot案例

    1.elasticsearch官方文档的使用与介绍 1.1.Rest客户端初始化官方文档链接: https://www.elastic.co/guide/en/elasticsearch/client ...