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

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

2023年07月04日 17:23--浏览 · --点赞 · --评论
粉丝:419文章:12

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

GIF

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

如何创建ComputeShader
给ComputeShader命名为ComputePixel
脚本命名为CreateSDFTexture

现在我们打开脚本

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的功能。

投诉或建议