查看原文
其他

Unity教程|立体渲染之Raymarching

2016-09-26 Unity官方 Unity官方平台

在立体渲染(Volumetric Rendering,为保持一致,本系列译文均称立体渲染)系列第一篇文章——Unity教程|立体渲染中,我们简单介绍了立体渲染的基本概念。对立体渲染不太熟悉的开发者,请先查阅第一篇文章


尽管传统着色器只能渲染材质的外壳,但还是有办法让光线穿透到材质内部的几何体,创造画面的深度。Raymarch就是最常用的技术,第一篇文章使用Raymarch技术在立方体内绘制了一个红色球体。本文将深入为大家介绍效率更高的Raymarch实现方案。


引言不严谨地说,当光线从相机发射到物体表面时,Unity 5光照引擎的标准行为是停止渲染。目前并没有内建机制能让这些射线穿透物体表面进入内部。为了补偿这个缺陷,我们引入了Raymarch技术。片段着色器包含要渲染的点的位置(世界坐标系下)以及从相机到物体的视线方向,我们手动延长这些射线,让它们射向仅存在于着色器代码中的自定义几何体。能实现该需求的着色器原型如下:



下文将提供raymarch函数的多种不同实现。


固定步长的Raymarch立体渲染系列文章第一篇中实现的Raymarch就使用了固定步长(Constant Step)。每一束射线都会沿视线方向延伸STEP_SIZE的长度,直到击中目标为止。上篇的示例将目标绘制为红色,而其他部分为白色。



固定步长的Raymarch可以通过下列代码实现:



上篇已经看到其渲染结果是看起来像平面的几何体:




下一篇要介绍的表面着色器将全权负责立体渲染的三维效果。但此前需要更好的方式来实现Raymarch

距离辅助的Raymarch
固定步长的Raymarch非常低效,原因是射线每次都会延长同样的长度,不会考虑到几何体填满立体空间的情况。对于着色器来说,无效循环的增加就意味着性能的下降。如果要实现实时的立体渲染,就必须找到更好更高效的解决方案。

我们需要一种方法来估算射线在遇到几何体之前到底要走多远。这就需要估算射线到达几何体的距离。上一篇文章中用到了sphereHit函数,它可以判断一个点是否存在于某个球体内:



对其稍作修改,将返回值从布尔值修改为距离:



现在该函数属于符号距离函数(signed distance function)家族。正如函数名称所示,它测量的返回值是可正可负的。当返回值为正数时,点在球体外。而返回值为负数时,点就在球体内。为零就表示点在球的表面。

sphereDistance能做的就是提供一个保守的预估距离,告诉我们射线在到达球体之前还要前进多远。不过如果没有进行适当的着色,立体渲染的结果还是比较单调的。本例中只渲染了一个球体,看起来似乎不重要。但如果使用更复杂的几何形状,这个技术就非常有价值了。下图(取自Distance Estimated 3D Fractals,经过距离估算的3D分形)呈现了Raymarch的工作原理。每条射线都会走过到达最近物体的距离。通过这样的方式,就可以大幅减少射线命中渲染体所需的步数了。


下面是距离辅助的Raymarch实现代码:



为了更好地理解它的工作原理,将表面着色替换为渐变色,来表示Raymarch命中几何体前究竟需要多少个步骤:




很明显,立刻就能找出面向相机的平面几何体,但是辨别边缘则要复杂许多。这种技术同样可以估算出到附近任意几何体之间的距离。

结论
本文介绍了实现实时Raymarch着色器实际可用的标准技术。射线会先保守估计到附近几何体的最近距离,再根据该距离进入立体空间。

下一篇文章将着重介绍使用距离函数创建基本几何体的方法,以及如何组合这些几何体以便得到您想要的任意形状。


本系列共有四篇教程,本文为第二篇,后面将继续更新,请保持关注。


本文来源于:alanzucconi.com

原作者:Alan Zucconi


更多实用Unity相关的技术文章:


Unity官方活动


Vision VR/AR Awards 2017大赛即将启动,亚洲区率先开启作品征集!

Unity全球两大VR大师齐聚北京,带来2016年最后一场纯技术VR Master Class


备受行业瞩目的VR/AR行业大会Vision VR/AR Summit Asia 2016即将在北京召开(轻触图片了解详情)!



点击“阅读原文”进入Unity官方中文社区!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存