前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >实时渲染中角色的反走样

实时渲染中角色的反走样

原创
作者头像
serena
修改于 2021-08-03 06:56:10
修改于 2021-08-03 06:56:10
1.6K0
举报
文章被收录于专栏:社区的朋友们社区的朋友们

作者:李静翔

走样

在图形学渲染技术中,由于采样率不够会造成渲染结果的锯齿以及抖动,我们把这种现象称作走样。在离线渲染技术中,为了克服走样的问题,通常会增加每个像素中的采样点的个数,然后平均得到最终的颜色,这个方法是最自然的方法。在实时渲染技术中,也有类似的技术,比如MSAA等,但这种方法对计算资源的要求是成倍上升的,因此出现了很多其他的性能更优的方法。

基于NormalMap的反走样的方法以及由来

为了给大家一个直观的印象,可以访问这个demo:

http://www.selfshadow.com/sandbox/gloss.html

左图是走样的效果,右图是反走样的效果.

最早提出这个方法的是Nvidia的Michael Toksvig [1]. 该方法首先提出了一个重要概念,Normal Variation,也就是法线的变化。数学上来说就是把一个点周围的法线(已经归一化)加起来取平均然后算他的长度。试想一个绝对平整的表面,每个点的法线都是一样的,所以按照上述方法计算,得到的值是1.如果是一个比较粗糙的表面,每个点的法线都有各自的朝向,按照上述方法计算,得到的值小于1。作者并且提出了Toksvig因子的概念:

其中s是材质的密度,那个时候光照模型大部分是用的Blinn-Phong,因此该模型被改写为:

其中

是为了能量守恒而乘上的系数。但是在[2]中,作者认为公式推导不对,给了一个正确的方程

从公式可以看出,实现很简单,不用修改很多,但仅仅适用于Blinn模型。

基于物理真实的渲染

近年来,基于物理真实的光照模型开始在业界流行。该模型认为真实世界中的表面实际上是由很多微表面组成的:

基本方程为:

不同的研究人员对于D项,也叫法线分布函数(NDF),提出了自己的算法,目前大致有Cook-Torrance, Beckmann, GGX等。值得注意的是,D项里面包含了粗糙程度(roughness),用于描述表面的平整度。目前在游戏行业中,Beckmann和GGX是比较常用的模型。相比于Beckmann模型,GGX具有更长的拖尾效应,更符合物理真实效果。

基于物理真实的反走样

基于物理真实的渲染,很多学者提出了新的反走样的方法。因为在实时渲染中,在摄像机距离物体比较远时,都会用法线的mipmap渲染。这个从理论上就是错误的,因为反走样首先是把一个像素里的样本点都计算了以后,再去平均,用mipmap就是先对法线取平均再计算光照,所以是错误的。新的反走样方法跟上述方法的共同之处是根据每一级(level)的normalmipmap, 计算法线的变化(Normal Variation),然后衍生出不同的方案。下面介绍其中的几种:

  1. LEAN Mapping[3]。 这个方法主要是针对Beckmann模型提出的反走样方法。其计算光照的D方程为:

其中h是入射角与法线的夹角,b是法线,Σ是协相关矩阵,里面包含了roughness信息。Σ通过每一级的normalmap预处理得到。这个方法的优点是计算简单,但是需要修改渲染流水线模型。顺便提一句,作者之一MarcOlano现在也在Epic工作。

  1. SGGX[4]。通过看名字就能看出来,该反走样方法是针对GGX模型的,此方法主要是对GGX中的D项提出了新的算法:

其中ω为半角。

该模型支持一般表面的GGX材质以及衣物的GGX模型。对于一般表面的GGX材质,S项为:

其中x,y,z为法线的三个分量。该方法同时适用于离线和实时渲染。我们在Unreal Engine也尝试实现了D项。也顺便说一句,第一作者EricHeitz现在Unity任职。

  1. 上述两个方法对于渲染流水线的改动都比较大,对于游戏引擎来说修改的代价比较大。
  2. 文献[5]也提供了新的算法,而且算法简单,但是有局限性,比如要求平行光源,roughness不能太大。
  3. 目前UE取而代之的是用了改动更小的方案。下面我们开始介绍:

UE的材质反走样

  1. 目前的UE采用方案中,先把用户输入的roughness值转成强度值,然后UE根据法线的变化,计算出新的强度值,再把强度转换成新的roughness值。
  2. 我们采用了两种新的方法。在介绍新方法之前,我们先介绍球谐函数。球谐函数和傅立叶变化的本质是一样的,都是把一个信号分解成不同的分量,或者称作基。下图就是对于一个四阶的包含16个基的示意图:

基于这些基,一个复杂的信号或者图片就可以用几个简单的系数表示,当然基越多,就越接近于原信号。如果原信号是一个低频信号,那我们用少数的基也就够了。

  1. 文献[5]认为,一个像素内的多个样本的光照计算实际上就是物体表面的NDF(请注意区分GGX里的NDF)和BRDF的卷积。

基于上述原理,我们可以低频的物体表面的NDF也分解成球谐函数或者高频的NDF分解成von Mises-Fisher(VMF)函数,然后和BRDF的D项卷积。具体分解的过程可以查看文献[6]. 这样分解的好处是物体表面的NDF被表示成高斯函数,或类似高斯函数,同时BRDF的D项也可以做类似分解。大家知道卷积定理有一个非常重要的规则,就是两个高斯函数的卷积还是一个高斯函数,而且其结果和输入高斯函数的参数相关,因此不用通过暴力计算卷积。有了这个知识,这样我们的光照问题也就迎刃而解。最后可以得到下面简单的方程:

这个方程是一个简化版本的。在离线渲染中,实际上要用球谐函数或者VMF函数去拟合原来的normalmap,然后作者用了EM算法求解。该方程简单的描述了新的roughness和用户输入的roughness的关系,其中k由normalmap得到。这个方法在游戏1886得到了应用(http://www.gdcvault.com/play/1020162/Crafting-a-Next-Gen-Material)

  1. 我们尝试的另外一种方法是文献[7],他们把BRDF的D项也分解成了高斯函数:

因此我们也可以类似的得到新的Roughness。和上一条不同的地方仅仅是k的计算方法不同。

UE的反走样的使用

  1. 结束了上述让人昏昏欲睡的理论,下面看看UE中是如何使用的:
  2. UE中的材质支持物理真实的模型,可以看到材质节点包含了oughness
  1. 为了获得Roughness map,我们可以这样做:

https://docs.unrealengine.com/latest/INT/Engine/Content/Types/Textures/Composite/index.html

a) 导入包含alpha通道(用于后面把结果存入alpha通道)的法线贴图

b) 打开纹理,做如下设置:

c) 结果包含了对应于normalmapmipmap的各级roughnessmap:

结论

我们探索性的尝试了两种新的方法用于反走样,但具体那个方法更好,目前还没有明确的结论,将来在实践的工程中也许会有些新的结论。

引用

[1] Michael Toksvig. Mipmapping Normal Maps.

[2] Specular Showdown in the Wild West.

[3] Marc Olano, and Dan Baker. LEAN Mapping.

[4] Eric Heitz, Jonathan Dupuy, Cyril Crassin and Carsten Dachsbacher. The SGGX Microflake Distribution.

[5]Anton Kaplanyan, Stephen Hill, Anjul PatneyandAaron Lefohn. Filtering Distributions of Normals for Shading Antialiasing

[6] Charles Han, Bo Sun, Ravi Ramamoorthi and EitanGrinspun. Frequency Domain Normal Map Filtering.

[7] Ravi Ramanoorthi and Pat Hanrahan. A Signal-Processing Framework for Reflection.

[8] Jiaping Wang, Peiran Ren, Minmin Gong, John Snyder and Baining Guo. All-Frequency Rendering of Dynamic, Spatially-Varying Reflectance.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
调试 .NET Core 中的内存泄漏
当应用引用不再需要执行所需任务的对象时,可能会发生内存泄漏。 引用上述对象会使垃圾回收器无法回收所使用的内存,这通常会导致性能降低,并可能最终引发 OutOfMemoryException。
呆呆
2022/01/09
1.9K0
调试 .NET Core 中的高 CPU 使用率
本教程将介绍如何调试 CPU 使用率过高的情况。 使用提供的示例 ASP.NET Core Web 应用 源代码存储库,可以故意造成死锁。 终结点将停止响应并遇到线程累积问题。 你将了解如何使用各种工具,通过几条关键的诊断数据诊断此情况。
呆呆
2022/01/09
1.4K0
.NET Core 调试 CPU 爆高问题
在实际开发和生产环境中,.NET Core 应用程序遇到 CPU 使用率飙升的问题并不少见。CPU 高负载会直接影响应用程序的性能,进而影响用户体验。因此,及时识别并解决 CPU 爆高问题是开发者需要掌握的关键技能。
Michel_Rolle
2024/12/24
2.4K0
收集指标
本文适用范围:✔️ .NET Core 3.1 及更高版本 ✔️ .NET Framework 4.6.1 及更高版本
呆呆
2022/01/07
6670
浅入 .NET Core 中的内存和GC知识
【1】https://docs.microsoft.com/zh-cn/dotnet/standard/managed-code
痴者工良
2021/04/26
7330
《快来为你的 .NET 应用加个监控吧!》更新版本啦
CZGL.ProcessMetrics 是一个 Metrics 库,能够将程序的 GC、CPU、内存、机器网络、磁盘空间等信息记录下来,使用 Prometheus 采集信息,然后使用 Grafana 显示。
痴者工良
2021/07/20
5300
《快来为你的 .NET 应用加个监控吧!》更新版本啦
使用dotnet-monitor sidecar模式 dump docker运行的dotnet程序.
随着容器和云技术的发展, 大量的应用运行在云上的容器中, 它们的好处是毋庸置疑的, 例如极大的提高了我们的研发部署速度, 快速的扩缩容等等, 但是也存在一些小小的问题, 例如难以调试. 基于VM的部署我们可以通过安全的方式登录到主机上做一些你想做的事情, 但是云上的容器那就是不太方便了(目前AWS的ECS已经有类似docker exec的方式直接进入容器中了, 其他的云未作了解). 但是就算能进入容器也不意味着调试就好做了, 通常来说使用的镜像都是经过优化和精简的(如果要调式可能需要安装大量的组件).
旺财的城堡
2022/11/02
1.3K0
使用dotnet-monitor sidecar模式 dump docker运行的dotnet程序.
.NET 9 中的 RuntimeMetrics
.NET 9 中引入了 RuntimeMetrics,基于 dotnet 里的 metrics 实现 System.Diagnostic.Metrics.Meter 来生成 metrics 数据,包含了 CPU、内存、GC、JIT 以及线程等信息
JusterZhu
2025/01/23
650
.NET 9 中的 RuntimeMetrics
详解 Java 线上问题排查思路
因为通常线程数量会由线程池管理,一般不会超过我们设定的最大值;而线程“死锁”通常是人为代码问题,某个获得锁的线程没有释放锁,导致其他线程一直处于 Waiting 状态(或者 CAS 自旋状态)。
宫水三叶的刷题日记
2021/03/02
3.5K0
详解 Java 线上问题排查思路
讨论.NET Core 配置对GC 工作模式与内存的影响
https://mp.weixin.qq.com/s/PqhUzvFpzopU7rVRgdy7eg
yoyofx
2018/09/05
3.4K1
记一次 .NET 某风控管理系统 内存泄漏分析
上个月中旬,星球里的一位朋友在微信找我,说他的程序跑着跑着内存会不断的缓慢增长并无法释放,寻求如何解决 ?
玖柒的小窝
2021/11/02
5200
记一次 .NET 某风控管理系统 内存泄漏分析
体验了一把线上CPU100%及应用OOM的排查和解决过程
项目中默认使用 spring-cloud-sleuth-zipkin 依赖得到 zipkin-reporter。分析的版本发现是 zipkin-reporter版本是 2.7.3 。
全栈程序员站长
2022/07/20
5260
体验了一把线上CPU100%及应用OOM的排查和解决过程
记一次内存溢出问题的排查、分析过程及解决思路
这个测试工具的开发已有一段时间了,由于数据量过大,写入数据较慢,导致工具执行耗时较长,所以再次优化了实现方案,进行二阶段的程序开发。
软件测试君
2020/09/23
2.6K0
记一次内存溢出问题的排查、分析过程及解决思路
C# 内存管理机制及 WP 内存泄漏定位方法
C#内存管理机制及WP内存泄漏定位方法 一、C#的内存管理机制 1. 托管资源与非托管资源 什么是托管资源?托管资源通俗的理解就是,把资源交给.net去管理,这些资源主要是数据,比如我们的各种对象,这些对象的回收都由.net来处理。非托管资源则是.net无法进行管理的的资源,必须在程序中显示的进行释放,比如文件、网络连接等。 2. C#的内存区域 在C#中,内存大致分成3个区,分别是堆、栈、静态/常量存储区。 a. 静态存储区,Static变量(值类型或者引用类型的指针)及常量存储的区域。 b. 栈。 c.
微信终端开发团队
2018/01/29
4.4K1
C# 内存管理机制及 WP 内存泄漏定位方法
一次完整的JVM堆外内存泄漏故障排查记录
记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些「JVM内存分配的原理分析」以及「常用的JVM问题排查手段和工具分享」,希望对大家有所帮助。
Rude3Knife的公众号
2020/08/28
4.2K0
一次完整的JVM堆外内存泄漏故障排查记录
ASP.NET Core 性能优化最佳实践
本文提供了 ASP.NET Core 的性能最佳实践指南。 译文原文地址:https://docs.microsoft.com/en-us/aspnet/core/performance/perfor
newbe36524
2020/09/14
2.7K0
ASP.NET Core 性能优化最佳实践
Java 内存溢出(OOM)异常完全指南
Java 应用程序在启动时会指定所需要的内存大小,它被分割成两个不同的区域:Heap space(堆空间)和Permgen(永久代):
CG国斌
2020/05/15
4.9K0
【日活百万电商返利App】一次线上JVM问题定位排查
查看进程使用gc情况: jstat -gc 16969<pid> 5000(打印时间间隔)
用户2032165
2020/03/27
9710
【日活百万电商返利App】一次线上JVM问题定位排查
深度探秘.NET 5.0
今年11月10号 .NET 5.0 如约而至。这是.NET All in one后的第一个版本,虽然不是LTS(Long term support)版本,但是是生产环境可用的。
Jlion
2022/04/07
1.1K0
深度探秘.NET 5.0
Linux命令-查看内存、GC情况及jmap 用法
首先可以通过ps命令找到进程id,比如 ps -ef | grep kafka 可以看到kafka这个程序的进程id
chenchenchen
2020/05/27
12.4K0
相关推荐
调试 .NET Core 中的内存泄漏
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档