Unity 手把手教你实现有向距离场(SDF)图像生成工具(2)【猴子都能学会】
Unity 手把手教你实现有向距离场(SDF)图像生成工具(1)【猴子都能学会】 - 哔哩哔哩 (bilibili.com)
在上一篇文章中我们完成了工具窗口的绘制, 现在就开始实现基本功能。
首先我们需要判断贴图是否为空
然后声明一个私有变量用来储存我们保存图像的路径
接下来实现一个窗口来保存贴图

这里直接调用unity的API就行了,再判断一下路径是否为空
现在我们点击按钮就会出现一个保存窗口了,但点了保存后依然什么也没有发生。
现在我们再声明一个私有的ComputeShader,并把我们刚刚创建的ComputeShader给上去
这里通过路径去加载我们的ComputeShader,所以注意这里路径是你ComputeShader所在的位置不要写错了
现在我们再声明两个int类型的变量用来保存图像的宽度和高度。
然后我们把图像的宽度和高度赋值给sourcWidth和sourceHeight
好了接下来我们再来写一个函数,该函数将读取贴图的边界条件,所以我们需要向该函数传入一张Texture2D。
首先我们需要判断一下传入的图片是否为可读,使用该工具必须把传入的图像设置为可读才行,并且不能压缩,压缩会严重影响生成的SDF精度。
还记得我们最开始创建了一个ComputeShader吗?我们至此还没有对它进行任何修改,现在让我们来打开它,你会看到如下代码,这就是unity为我们生成的ComputeShader的模板
这里unity给我们写了注释,每个Kernel会和下面的功能相对应,我们可以在一个ComputeShader中写多个Kernel,他这里有个RWTexture2D<float4> Result; 这里的RW代表了RandomWrite(无序写入)的意思,我们接下来会利用ComputeShader,并行读取图像数据,所以数据的填充并没有先后顺序,如果我们只想读取图像,那么可以直接用Texture2D<float4>就可以了,[numthreads(8,8,1)]这个是我们多线程中非常重要的存在,它划分了我们的线程,[numthreads(x,y,z)]而其中x y z,并不是我们想写多少写多少想给多大给多大,我们需要满足x * y * z <= 1024; 而我们在ComputeShader中定义的线程和我们在C#中定义的线程组的乘积需要满足我们的线程总数。
我在上面对于ComputeShader做了一下简单介绍,当然还要明白,我们输入输出的不仅仅是贴图还能是结构体,所以接下来我们会利用ComputeShader将图像的边界条件存储在一个结构体里面输出出来。
接下来让我们看看如何输入一张图像,输出一个结构体。
我们现在在ComputeShader中声明一个结构体,里面只有一个int 类型叫edge。
再声明一个_Width,该变量由C#传入代表图像宽度,再需要一个传出的结构体RWStructuredBuffer<EdgePixel> Result;
让我们回到C#,我们声明一个结构体与ComputeShader的结构体对应,两者除了名字必须完全一致。
接下来我们创建一个ComputeBuffer去实现GPU与CPU的数据交换
我们基于上面对edgeBuffer赋值,并将数据传入ComputeShader参与计算
现在再回到ComputeShader,这里我们需要把二值图的边界找出来
现在我们返回C#中,我们需要再来一次并行计算将结构体的数组转换为一张图像
首先我们先声明一张RenderTexture来储存图像
现在我们回到ComputeShader写另一个kernel来生成图像,这里非常简单,唯一注意的是现在我们的图像变成了输出的对象,需要用RWTexture2D<float4>
现在我们再到C#中来执行这个Kernel生成图像
现在图像被保存在rt0中了,现在我们需要输出一张png格式图片,所以我们先声明一个Texture2D作为目标图像
现在我们ComputeSDF()中去调用我们之前写的两个方法
以上我们再来执行工具看看是不是能得到如下图像,如果可以说明之前的代码就成功了,距离的计算会在下一篇文章中讲解
