【GAMES202】Real-Time Global Illumination(screen space)1—实时全局光照(屏幕空间)1

news2025/2/28 21:12:56

一、Real-Time Global Illumination(in 3D cont.)

上篇只介绍了RSM,这里我们还会简要介绍另外两种在3D空间中做全局光照的方法,分别是LPV和VXGI。

1.Light Propagation Volumes (LPV)

首先我们知道Radiance在传播过程中是不会被改变的,这点我们都知道。

其次LPV将空间划分成了许多小格子,也叫Voxel(体素)。而这些Voxel就是用来传播间接光照的Radiance的。我们很容易知道直接光照,参考RSM的思路。然后通过知道哪些格子是次级光源来计算每个格子接受到的Radiance,这就是LPV的基本思路。

第一步,找到直接光打到的表面,这步和RSM无区别,当然,有多少光源就需要多少RSM。其次,也不是必须把所有被直接光打到的表面都当作次级光源,可以用采样的方式,我们之前都说过。这样我们就得到了一系列次级的虚拟的光源。

得到了次级光源我们就可以把它们注入到相应的格子里,变成格子的属性,这样我们就知道每个格子往各个方向的Radiance初始值都是多少,而这是个空间的分布,自然我们就可以用前面提到的SH压缩它。(工业界常用2阶) 

第三步就是传播了,那么Radiance如何传播呢?很简单,次级光源所在的格子里有向四周传播的Radiance,而Radiance又是按直线传播的。自然,一个格子6个面,穿过它上表面格子的Radiance自然就会被它上面的格子接受到,其它面的Radiance同理,同样其它的格子里的Radiance分布也可以用SH所表示(这里和RSM一样,我们不考虑传播过程中的Visibilty)。如此不断迭代,直到最后整个网格稳定下来。(差不多迭代4,5次)

第四步自然就是渲染了,对于任意的着色点,我们都知道它们在哪个格子里,我们还知道它们的Incident Radiance,就可以渲染了。 

当然,这其中会有问题,如上图所示。场景中的几何比划分的格子小的时候就会很容易发生这种情况。如图p点为直接光照照亮的点,它是次级光源,显然它右边有一面墙,它绝对不可能照到墙右边的部分,但由于LPV的Radiance是用格子存储的,我们会认为这个格子里都是相同的Radiance。于是墙右边被照亮了,这显然是错误的。但如果把格子划分的非常非常细,虽然可以解决这种问题,但随之而来的自然是存储量问题,以及Radiance传播的计算量问题。不过当然,我们可以自适应划分一些格子的分辨率,如工业界常用的Cascade方法。

2.Voxel Global Illumination(VXGI)

VXGI和RSM相同,是一个双Pass的算法(LPV相当于4Pass)。VXGI把场景彻底离散化成了体素(参考MineCraft/乐高积木)。并且还会把这些格子组成一个树形结构,有不同的层级。

所以与RSM不同的是,RSM的次级光源是每一个小片,而VXGI的次级光源是体素。

其次VXGI的第二个Pass与RSM和LPV都不同,它的第二个Pass从Camera出发,打出Camera Ray,而假设当Camera Ray打到某个Glossy材质对应的片元所在位置,自然就会变成一个锥形的分布,然后这个锥形与之前得到的次级光源所在体素相交,就可以知道这个着色点得到的贡献是多少了。

Pass1,计算直接光照,和RSM和LPV类似,但这里我们可以不再认为所有反射物都是Diffuse的了 ,这里我们会在Voxel体素中的表面上记录一个入射光的分布(如上图绿色所示),还会记录该表面的用来反射的法线分布(如上图橙色所示),并且我们还知道这个表面是Diffuse还是Glossy的自然就可以计算出它的出射分布,这比我们直接假设默认Diffuse的方法会准确一些。由此我们还可以在小格子记录分布后整合到更高的层级,形成一个层次结构。

Pass2从Camera出发发射的Camera Ray(假如是Glossy)经过着色点后会被反射成圆锥,我们叫它Ray cone,它会随着传播的距离增大而变大。之后计算它与哪些体素相交,再把贡献加在一起就可以了。不过既然Ray cone范围会越来越大,我们可以直接在之前体素的层次结构中找对应的层级体素记录的分布信息即可。这就是VXGI的基本思路。

而对于Diffuse物体,VXGI的发明者们的做法是用差不多8个圆锥来覆盖半球以此近似Diffuse的情况。

当然对于VXGI,它也有一些问题。首先我们要对整个场景进行体素化,这是需要预处理的,而如果是动态物体,那每一帧都要实时体素化,显然会非常慢。以及对于Diffuse的情况,圆锥增多,查询次数自然也会增多。

二、Real-Time Global Illumination (screen space)

屏幕空间限定了我们获取信息的范围,也就是说我们得到的信息仅仅能从屏幕上能看到的东西上获取,相当于一个后处理。而对于做GI之前,那我们能得到的信息自然也就是直接光照了。

Screen Space Ambient Occlusion (SSAO)—屏幕空间环境遮蔽

左图:带有AO  |  右图:无AO

环境遮蔽(Ambient Occlusion) —简称AO,简单的说就是物体缝隙间光线难以到达的地方会有些发暗的现象,如上图的对比图。

那么屏幕空间的环境遮蔽是什么呢?其实就是全局光照的一种近似,因为AO本身就是由全局光照造成的。并且我们只能通过在屏幕中获取的看到的可见信息来做,如法线,深度等。

(1)Idea

那么SSAO是怎么做的呢?首先,我们不知道着色点的间接光照是什么,但是我们可以假设它们的四面八方的间接光照是一个常数,也就是我们之前说的Blinn-Phong模型那样。

但是,相比于Blinn-Phong模型好的地方在于,虽然我们仍然假设四面八方的间接光照是一个常数,但不见得所有着色点都能接收到它,也就是我们考虑了Visibility,这样就会有几何的遮挡关系。

(2) Theory

左:AO较少 | 右:AO较多

从数学上来理解SSAO,自然就要回到咱们的渲染方程上来,同时回顾一下我们经常用的上图所示的约等式,它可以把Visibility项拆出去。

可以看到,拆出Visibilty项后就是上图蓝框里所示的部分,下面的积分就是π。那整个其实就是一个加权平均了,我们设为kA,它的值自然就是0~1。其次橙色框的部分实际上就是我们事先给定的数,BRDF是Diffuse的,所以是常数,间接光我们一开始也给定的是常数,所以就固定下来了。

(3)Deep understanding*(可忽略)

一个更深的理解,我们上一步已经说了拆出的Visibility项其实就是f(x)的加权平均。那我们更进一步,SSAO这个公式完全就可以理解成,在g(x)的覆盖范围内,f(x)的平均值是多少。而我们之前说过这个约等式要想准确符合的条件,这里由于g(x)我们上面说过是常数,那就肯定是smooth的,所以这个约等式是成立且准确的。

还有一个问题,我们拆分之后,按照拆分的约等式,为什么本来是对dω积分,现在变成了对cosθdω积分呢?如何解释这个问题呢?

这里我们引入另外一个概念,Projected solid angle—投影立体角,我们之前说立体角实际上对应了单位球面上一个面积,那自然,投影立体角是投影后的立体角,对应的就是单位球下单位元的一块面积。对投影立体角积分得到的自然就算单位圆的面积,也就是π*1*1,也就是π。所以我们上面写成对cosθdω积分实际上是对投影立体角积分,这也就解释了我们为什么能如此拆分。

(4)Compute

上面的Deep understanding只是为了更深层次的理解SSAO,实际上单从渲染方程上来看很简单,如上图,因为我们已经认定了BRDF和Li都是常数,那就都提出去就好了,积分中只剩Visibility项。

那现在我们怎么计算这个值呢?SSAO提供了一个方法,那就是在任何一个着色点的整个球的体积内采样,然后判断这些采样点能不能被着色点看到。那怎么判断采样点在物体内外呢?这要通过深度图来判断,深度图是我们在屏幕上看到的最浅深度,一定程度上描述了场景的几何,这时如果我们把采样点投影到Camera上,那么采样点的深度Zs和Z-Buffer中记录的最浅深度Z做比较,就可以知道采样点是不是在物体内了,若Zs>Z,那就说明采样点在物体内,反之则在物体外。

当然有一种意外情况,如上图中间的情况,几何体有一个拐角,但是由于我们的Z-Buffer记录的是最浅深度,所以无法区分这种情况。

还有个问题,我们判断整球没有意义,因为法线另外半球着色点是肯定看不到的,所以判断整球会造成一个很大的浪费,我们事实上只需要判断法线方向半球就足够了,但是在SSAO被发明的那个年代还无法从屏幕上获取法线,所以人们采取了另外一种方法:只有看不到的采样点(上图所示红点)占比超过50%的时候才考虑AO问题,然后只计算另一半的红点占比就可以了。因为产生AO一定程度上就是红点过半导致的。

当然,即使是这样,因为没有法线而导致的无法cos进行加权还是会导致结果没那么准确,只是一个近似。

(5)False occlusions

SSAO也会产生一些False occlusion的问题,如上图,近处的石凳对远处的地板居然产生了AO,这显然是不对的,两个物体离的这么远,石凳是不可能对地板产生遮蔽的。究其原因,是因为在地板球上的一些采样点投影到屏幕上之后和石凳的最浅深度比较的时候大于石凳的最浅深度,于是错误的认为是红点,所以产生了遮蔽。

如果减小采样半径,一定程度上可以解决问题,但是自然可能也会丢失一些True occlusion。也就是原本该遮挡的地方没有遮挡,一切都是取舍问题。

(6)Other

 • 采样问题

SSAO仍然做了采样,那么自然就有我们前面提到的所有采样方法共有的问题,采样点数量的取舍,越多的采样点自然意味着更好的质量,但会牺牲速度。

人们通常在使用SSAO时会使用较少的采样点生成一个Noisy的AO,然后再做一遍模糊,这样就能得到相对较好的结果,因为实际玩游戏的时候很少有人会盯着AO看。

 • HBAO—Horizon Based Ambient Occlusion

之前我们说,因为SSAO在发明的时候人们在屏幕上很难获取到法线,但是现在可以,于是就有了HBAO。有了法线,我们自然就知道要在哪半球采样,然后算之前的红点占比。

其次,有法线,我们还可以对各个方向进行加权了,就可以得到相对来说更准确的值。其次,HBAO不会有SSAO的False occlusion问题,因为它真的考虑了一定范围距离的问题。 


参考

GAMES202_Lecture_08 (ucsb.edu)

Lecture8 Real-time GLobal Illumination (screen space)_哔哩哔哩_bilibili

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

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

相关文章

9.3-day3-Don‘t let desire break through your will

你这个年龄 是站在阳光下都会发光的年纪 “岂能被欲望所控制”

Shell-AI:基于LLM实现自然语言理解的CLI工具

一、前言 随着AI技术的普及,部分技术领域的门槛逐步降低,比如非科班出身,非技术专业,甚至从未涉足技术领域,完全不懂服务器部署和运维,如今可以依托AI大模型非常轻松的掌握和使用相关技术,来解…

简单了解ICMP协议

目录 一、什么是ICMP协议? 二、ICMP如何工作? 三、ICMP报文格式 四、ICMP的作用 五、ICMP的典型应用 5.1 Ping程序 5.2 Tracert(Traceroute)路径追踪程序 一、什么是ICMP协议? ICMP因特网控制报文协议是一个差错报告机制,…

图文详解PhPStudy安装教程

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 官方下载 请在PhPStudy官方网站下载安装文件,官方链接如下:https://m.xp.cn/linux.html;图示如下: 请下载PhPStudy安装文件…

Nginx 502 Bad Gateway 错误的原因及解决方法

Nginx 502 Bad Gateway 错误的原因及解决方法 多数是后端问题也就是PHP的问题, 简单的情况可以刷新(不是一般的刷新哦,Ctrl F5 强制刷新)解决。在php服务当中,有两个参数非常的重要:max_requestst和max_c…

CentOS上使用Docker安装和部署kkFileView

🎈1 参考文档 kkFileView官方文档 🚀2 安装kkFileView 拉取Redis镜像。 docker pull keking/kkfileview启动docker容器。 docker run -it -d -p 8012:8012 keking/kkfileview --restart always解释: docker run redis # 从kkfileview镜像运行…

【进阶篇】MySQL分库分表详解

文章目录 0. 前言1. 垂直分库分表2. 水平分库分表 1. 理解过程及实现方案问题讨论衍生出分库分表策略借助成熟组件使用分库分表阶段完成后面临的问题1. 异地多活问题2. 数据迁移问题3. 分布式事务问题4. join查询的问题 分库分表的策略实现示例 2. 参考文档 0. 前言 假设有一个…

XSS的分析

目录 1、XSS的原理 2、XSS的攻击类型 2.1 反射型XSS 2.2 存储型XSS 2.3 DOM-based 型 2.4 基于字符集的 XSS 2.5 基于 Flash 的跨站 XSS 2.6 未经验证的跳转 XSS 3、复现 3.1 反射性 3.2 DOM-based型 1、XSS的原理 XSS的原理是恶意攻击者往 Web 页面里插入恶意可执行…

golong基础相关操作--一

package main//go语言以包作为管理单位,每个文件必须先声明包 //程序必须有一个main包 // 导入包,必须要要使用 // 变量声明了,必须要使用 import ("fmt" )/* * 包内部的变量 */ var aa 3var ss "kkk"var bb truevar …

在CentOS7上使用Docker安装和部署RabbitMQ

🚀 1 拉取RabbitMQ Docker镜像 首先,使用Docker命令从Docker Hub拉取RabbitMQ官方镜像。打开终端并运行以下命令: docker pull rabbitmq🚀 2 创建RabbitMQ容器 一旦镜像下载完成,使用以下命令创建RabbitMQ容器&…

SpringBoot整合Websocket(Java websocket怎么使用)

目录 1 Websocket是什么2 Websocket可以做什么3 Springboot整合Websocket3.1 服务端3.2 客户端 1 Websocket是什么 WebSocket 是一种基于 TCP 协议的全双工通信协议,可以在浏览器和服务器之间建立实时、双向的数据通信。可以用于在线聊天、在线游戏、实时数据展示等…

【Stable Diffusion安装】支持python3.11 window版

前言 主要的安装步骤是参考B站播放量第一的视频,但是那位阿婆主应该是没有编程经验,只强调使用3.10,而python最新版本是3.11。 理论上来说,只是一个小版本的不同,应该是可以安装成功了。自己摸索了下,挺费…

springboot使用logback配置彩色日志

springboot使用logback配置彩色日志 前言一、logback文件二、效果 前言 应该有很多同学发现,使用了logback以后,我们的控制台日志都变成灰色了,网络上搜到的logback配置大多数没有进行配色,所以会把springboot的默认配色方案给覆盖…

Unity中Shader的帧缓存区Clear(color+Z+stencil)

文章目录 前言一、什么是帧缓冲区二、片段运算三、随机扫描显示器(可以按照自定义路径绘制帧)四、光栅扫描显示器(从左到右,从上到下,依次绘制)五、缓冲的方式:单缓冲 和 双缓冲1、单缓冲2、双缓…

认识JVM的内存模型

从上一节了解到整个JVM大的内存区域,分为线程共享的heap(堆),MethodArea(方法区),和线程独享的 The pc Register(程序计数器)、Java Virtual Machine Stacks(…

2. postgresql并行扫描(1)——pg强制走并行扫描建表及参数配置

转载自:https://developer.aliyun.com/article/700370 1. 参数设置 1.1 postgresql.conf中修改 # 1、总的可开启的WORKER足够大 max_worker_processes 128# 2、所有会话同时执行并行计算的并行度足够大 max_parallel_workers64# 3、单个QUERY中并行计算NODE开…

测试验证平台

测试验证平台 1.功能说明: 模拟智能终端车端数据采集及上报的功能,提供数据管理平台的模拟和验证功能。 2.系统组成: 系统示意图 功能要求: 本地电脑实现Imx6配置功能,能够通过运行不同的脚本,模拟不…

C语言记录程序日志

我们写程序,不可能一次就写的一个bug都没有,必须要不停地修改,有可能自己调试已经没有问题了,发给客户后还是问题很多,这个时候跑到客户处解决问题就不现实了,自己不在还要找到问题的所在,最好的…

质谱技术对蛋白质进行鉴定

参考B站教学视频: 质谱如何鉴定蛋白质_哔哩哔哩_bilibili 针对该视频,别人的 笔记 质谱是一台体重秤,称的不是人,而是分子、原子的体重 不同分子有不同分子量是质谱仪工作的底层逻辑 图片来自:【蛋白组】蛋白质组定量技术的原理和…

如何设计一个好的游戏剧情(Part 1:主题的设定)

提醒:此教程仅仅为作者的一些经验和感悟,非专业教程,若介意请前往网上搜集或者书本查阅相关资料! 前言:游戏为什么要有剧情——游戏剧情的重要性 游戏剧情的重要性难以低估。一个精彩的剧情可以让玩家感受到强烈的情感…