本文将采用Dead Reckoning算法实现一个有向距离场的生成工具,并实现一个如下的简单变形效果,当然对于SDF应用远不止于此,诸如原神的脸部阴影之类的,这个网上很多就不在这里详细讲了。该算法的优势相较于遍历全局耗时更少,虽有一定的精度下降,但相较于近似方法消除了产生的棱角,毕竟对于一张1024*1024的图要遍历全局的时间都够下楼买杯奶茶再上来了,而采用该算法可以在2秒内计算完成。

首先先创建一个ComputeShader和一个脚本



现在我们打开脚本
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateSDFTexture : EditorWindow
{
}
继承EditorWindow来写一个简单的工具界面
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateSDFTexture : EditorWindow
{
private static CreateSDFTexture window;
[MenuItem("Tools/距离场图像生成")]
private static void CreateSDF()
{
window = EditorWindow.GetWindow<CreateSDFTexture>("距离场贴图生成器");
window.Show();
window.minSize = new Vector2(200, 300);
}
}
我们将工具写在”Tools/距离场图像生成“下面,工具窗口名字叫做"距离场贴图生成器",窗口尺寸为200*300;
我们的工具的目的是将一张二值位图,转换成一张SDF图,所以我们需要传入的只有一张Texture2D,那现在我们就声明一张public的Texture2D,并让他在窗口中被绘制出来。
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateSDFTexture : EditorWindow
{
public Texture2D SourceTex;
private static CreateSDFTexture window;
private SerializedProperty m_texProperty;
private SerializedObject m_serObj;
[MenuItem("Tools/距离场图像生成")]
private static void CreateSDF()
{
window = EditorWindow.GetWindow<CreateSDFTexture>("距离场贴图生成器");
window.Show();
window.minSize = new Vector2(200, 300);
}
private void OnEnable()
{
m_serObj = new SerializedObject(this);
m_texProperty = m_serObj.FindProperty("SourceTex");
}
private void DrawTextureProperties()
{
EditorGUILayout.BeginVertical(); //开始绘制工具面板
EditorGUILayout.LabelField("源图像");//在面板上添加一块区域并显示文字
EditorGUILayout.PropertyField(m_texProperty, true);//是否绘制包含子项的属性
EditorGUILayout.EndVertical();//结束绘制
m_serObj.ApplyModifiedProperties();//应用属性修改
}
private void OnGUI()//在鼠标放在工具窗口上时调用
{
DrawTextureProperties();
}
}


接下来我们创建一个名叫ComputeSDF的函数来执行SDF(有向距离场)的计算,并在OnGUI中去调用
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateSDFTexture : EditorWindow
{
public Texture2D SourceTex;
private static CreateSDFTexture window;
private SerializedProperty m_texProperty;
private SerializedObject m_serObj;
[MenuItem("Tools/距离场图像生成")]
private static void CreateSDF()
{
window = EditorWindow.GetWindow<CreateSDFTexture>("距离场贴图生成器");
window.Show();
window.minSize = new Vector2(200, 300);
}
private void OnEnable()
{
m_serObj = new SerializedObject(this);
m_texProperty = m_serObj.FindProperty("SourceTex");
}
private void DrawTextureProperties()
{
EditorGUILayout.BeginVertical(); //开始绘制工具面板
EditorGUILayout.LabelField("源图像");//在面板上添加一块区域并显示文字
EditorGUILayout.PropertyField(m_texProperty, true);//是否绘制包含子项的属性
EditorGUILayout.EndVertical();//结束绘制
m_serObj.ApplyModifiedProperties();//应用属性修改
}
private void OnGUI()//在鼠标放在工具窗口上时调用
{
DrawTextureProperties();
ComputeSDF();
}
private void ComputeSDF()
{
if (GUILayout.Button("创建距离场贴图并保存"))
{
}
}
}
完成上面操作后让我们来再次打开工具看看

是不是多了个按钮, 但我们能发现按了这个按钮并没有什么用,因为到这里我们才写完了工具界面,我们会在后面来实现计算SDF的功能。