欢迎光临散文网 会员登陆 & 注册

Unity 手把手教你实现有向距离场(SDF)图像生成工具(3)【猴子都能学会】

2023-07-06 16:12 作者:今天摸鱼就好了  | 我要投稿

    通过上面一篇文章对于unity的并行操作作了一定的讲解,而本篇主要是去实现Dead Reckoning算法,说简单点就是用确定的去推算不确定的当然这样的结果可能不是正确的,所以我们这里需要正向与反向去遍历贴图消除错误。

Dead Reckoning的应用

    好了再次打开我们上次写好的脚本,并扩充一下我们储存边界条件的结构体

其中inTarget代表白色像素,X代表离该像素最近的边界像素的X的坐标,Y同理,distance代表了和最近像素之间的距离值,我们用下面一张图进行详细的讲解,每个方块代表一个像素,而白色部分代表我们的目标区域,也就是inTarget,之前我们判断一个像素是否在边界就是看这个像素的上下左右有没有黑色像素就行。

 现在我们将边界像素的X给该像素的位置的X值,Y给该像素的Y值,对于unity的图像坐标,左下角的像素为坐标原点,向右为X正方向,向上为Y正方向。

    在上一篇文章我们其实就已经找到了边界像素,也就是下图的红色部分

这里是将白色最外围作为边界,也可以将外面一圈黑色作为边界,本文这样做只是因为更简单而已

那么现在我们需要把所有红色区域的像素的distance设置为0,他们的坐标为自身坐标,intarget为1,而所有白色区域的坐标设置为无限大(给个很大的值就可以了),距离也同样是无限大,intarget为1,对于黑色区域也就是不需要我们考虑的区域他们的intarget给0,X和Y给无限大,因为本次我们只考虑目标区域以内的像素,距离也给无限大处理的边界属性应该和下图相同

该图像的坐标代表结构体中X和Y的值,而前面的图像代表的是像素位置

    好了,再让我们回到CoputeShader,将ComputeShader的结构体扩充

    值得注意在ComputeShader中的结构体必须和C#中对应,变量所在位置也要完全一致。

    现在我们按照刚才讲的将数据填充进去。

    到这里我们仅仅完成了Dead Reckoning算法所需要的准备工作,该算法由于需要用过去的值去推算现在的值,所以有个缺陷是不能做并行,只能在CPU中串行遍历两次。

    我们再声明一个函数来处理来处理这个结构体的数组 , 这里我们需要引用传值,将结构体数组的地址传过来。

    那么现在我们如何计算呢,首先是遍历元素的顺序,我们左下角是向右是X轴正方向,向上是Y轴正方向,所以我们正向遍历应该是从左到右从下到上来遍历像素

    现在我们将更新它的最近边界点坐标和与最近边界点的距离,在正向遍历时如下图,我们需要检测一个像素的相邻像素,也就是说正向我们需要检测左 , 左下 , 下 , 右下的像素,反向需要检测 右 , 右上 , 上 , 左上的像素。

绿色代表已经检测完成的像素,深绿色为正在检测的像素

    在我们正向遍历的时候,对于一个正在检测的像素我们去检测它相邻像素储存的距离值,如果 该像素的距离值 > 相邻像素的距离 + (该像素与相邻像素的距离) , 图中黄色数字代表“该像素与相邻像素的距离”,那么我们就把相邻像素的最近边界点赋值给该像素,并计算出该像素到最近边界点的距离


检测完成后该像素的值

    该算法具体实现如下

由于我们需要把距离储存在图像中所以距离值必须是0-1,这里我们用一个数值来储存最大距离值

    先写一个计算距离的函数

这个命名当时没注意到,

然后我们在这里调用这个方法,并将数值传给GPU计算

    让我们再来到ComputeShader这里就非常简单了,改一下我们上次写好的Kernel就可以了

然后我们就能用工具生成一张这样的距离场图像

这里简单写个shader对距离做个线性插值就可以实现图形变换了


Unity 手把手教你实现有向距离场(SDF)图像生成工具(3)【猴子都能学会】的评论 (共 条)

分享到微博请遵守国家法律