SDF(signed distance field)
Posted dx1313113
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDF(signed distance field)相关的知识,希望对你有一定的参考价值。
一般来说,无论2d或者3d资产都有隐式(implicit)和显式(explicit)两种存储方式,比如3d模型就可以用mesh直接存储模型数据,也可以用sdf、点云(point cloud)、神经网络(nerual rendering)来表示,2d资产(这里指贴图)也是如此。比如贴图一般直接使用rgb、hsv等参数来进行表示,但这样子再放大图片后会出现锯齿,所以想要获取高清的图像就需要较大的存储空间,这时候就需要矢量表示,在2d贴图中sdf就是为了这种需求产生的。
SDF(Signed Distance Field)在3d和2d中都有对应的应用。在3d中光线追踪对于性能的消耗过大,所以sdf常常被用来作为物体的隐式表达,配合ray marching达到接近光线追踪的效果,也有比如deepSDF这种对于模型的隐式表达方面的应用。在2d中,sdf常常被用来表示字体,原神的面部渲染中阴影部分贴图也是基于sdf生成的。
SDF的本质就是存储每个点到图形的最近距离,即将模型划出一个表面,在模型表面外侧的点数值大于0,在模型表面内侧的点数值小于0
对于任意的给定点,距离函数能够给出其到一个物体上最近点的最小距离(这个距离可能是带符号的)。
此外,SDF也具有一些比较好的性质,例如混合一个移动边界时,比如希望得到A、B时刻之间某时刻的边界时,SDF就能取得比较好的结果,如下图所示,试图混合A、B时刻之间的边界,如果直接混合 lerp(A,B) 可能得到如灰色区域所示的结果,但如果将该边界转换成SDF后,即 SDF(A) 、 SDF(B) ,再进行混合 lerp(SDF(A),SDF(B)) ,再将混合后的SDF还原得到最终结果 SDF−1(lerp(SDF(A),SDF(B))) :
或者对两个不同结构的物体进行混合时,可以混合它们的距离函数。
SDF可以被用来做ray marching,来解决光线和SDF的求交问题,这背后有一个key idea:某一点SDF的值等价于其附近的安全距离,从一点出发在每个step沿着ray的方向移动SDF(p)的距离,此处的p指的是当前step时的那个点。该方法对于运动物体(刚体)可行,对于形变物体需要重新计算SDF。
此外,SDF能被用于估计大概的percentage of occlusion,即SDF的值一定程度上反应观察者能够看到的“安全”角度,该角度越小意味着越少的可见性,阴影应该越黑。下图中下方灰点表示shading point,该射线指向面光源中心,通过计算安全角度近似估计可见性。
具体算法流程(在ray marching的过程中,为了得到这个最小“安全”角度,记录下每一个step时对应的角度,并选择其中最小的角度作为最终结果。):
- 在ray marching每一步计算安全角度,分别得到p1、p2、p3
- 根据p1、p2、p3计算出其中最小的安全角度
- 根据该最小安全角度,近似得到可见性
在实时渲染中,为了节约计算量可以把arcsin去掉,因为SDF(p)与p到o距离的比值已经可以反映夹角的大小,最终可以写为:
mink⋅SDF(p)/|p−o|,1.0 ,其中越大的k,可以得到越接近1.0的值,会使得半影区域的过渡带越小,阴影也会越“硬”。
优缺点
优点:速度快(这里忽略SDF的生成过程,与shadow map相比,该方法更快,基于shadow map的方法时间开销主要使用在生成shadow map,此外当渲染本身使用Ray Marching方法时,使用SDF生成阴影更加方便);高质量。
缺点:需要预计算(生成SDF);需要高存储(目前有一些方法使用层次化存储结构,在不同层次使用不同粒度);可能有artifacts。
基于SDF渲染字体
18号字体
18号字体放大15倍
基于sdf渲染字体放大15倍
相比常规的渲染方式,基于SDF渲染文字可无限放大并保持清晰,几乎没有开销就可实现描边,发光,抗锯齿等效果.且它只需要很小的纹理缓存SDF信息即可.
所谓SDF(Signed-distance-field),就是将每个像素存储的颜色值换成距离文字轮廓最短距离,当像素在文字内,则用正数距离,在文字外则用负数距离,文字轮廓距离则是零,因此只要判断像素如果是正数,就输出颜色,否则丢弃颜色即可.
该技术由Valve开发半条命2时提出,当时主要用于渲染图片,之后被广泛用于其他技术中,用于渲染字体仅是其中一项.
相对比常规的渲染方式,除了片段着色器的差别外,主要差别在于生成的纹理缓存.
常规渲染方式的纹理缓存大致如下:
一个纹理只存一个字号
一个纹理存储多个字号
它们都有一个共同点:每个像素存储的信息都是颜色.而sdf每个像素存储的是距离,因此它能提供矢量信息.(怎么存储多个字号, 可查看合并图集)
SDF纹理
SDF渲染字体在网上有很多资料,但我翻遍了百度,只找到一个可运行的文字SDF生成工具,在我反复调试后,发现这个工具生成的SDF是错的,迫不得已我只好花20分钟重写了一个,算法也简单,无非就是暴搜+阀值控制,生成4096*4096的SDF,i7 7700k大概需要1分钟.
描边
内发光
外发光
效果
以上是关于SDF(signed distance field)的主要内容,如果未能解决你的问题,请参考以下文章