Skip to content

Instantly share code, notes, and snippets.

@Donnotron666
Created September 24, 2023 17:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Donnotron666/30655068434b7e725106c73f0e735113 to your computer and use it in GitHub Desktop.
Save Donnotron666/30655068434b7e725106c73f0e735113 to your computer and use it in GitHub Desktop.
CPU-Based Edge Detection
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Editor.Utility
{
public static class EdgeMapUtils
{
public const int EDGE_SIZE = 2;
public static void Update(IEnumerable<Sprite> spr)
{
foreach (var s in spr)
Update(s);
}
private static void Update(Sprite s)
{
//aaahaha, ok, oh boy. Yeah, scan the sprite on the cpu, look for edges and plug those into a texture
//make sprite readable
var test = s.texture;
var path = AssetDatabase.GetAssetPath(s);
var spriteTi = (TextureImporter)TextureImporter.GetAtPath(path);
spriteTi.isReadable = true;
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
//DO STUFF
var edges = BuildEdgeTexture(s);
var savedEdgePath = SaveEdges(s, path, edges);
//link it to sprite as a secondary map
SpriteUtils.TryAddSecondaryTexture(spriteTi, "_EdgeMap", savedEdgePath);
//put sprite back the way it was.
spriteTi.isReadable = false;
}
private static string SaveEdges(Sprite s, string path, Texture2D edges)
{
var folder = path.Remove(path.LastIndexOf(s.name) - 1);
EditorUtils.LazyCreateFolder(folder, "EdgeMaps");
var edgePath = $"{folder}/EdgeMaps/{s.name}_edges.png";
var bytes = edges.EncodeToPNG();
System.IO.File.WriteAllBytes(edgePath, bytes);
AssetDatabase.ImportAsset(edgePath, ImportAssetOptions.ForceSynchronousImport);
//AssetDatabase.CreateAsset(edges, edgePath);
var ti = AssetImporter.GetAtPath(edgePath) as TextureImporter;
ti.textureType = TextureImporterType.Sprite;
ti.filterMode = FilterMode.Point;
ti.textureCompression = TextureImporterCompression.Uncompressed;
ti.mipmapEnabled = false;
ti.alphaIsTransparency = false;
EditorUtility.SetDirty(ti);
ti.SaveAndReimport();
return edgePath;
}
private static Texture2D BuildEdgeTexture(Sprite s)
{
var edges = new Texture2D(s.texture.width, s.texture.height, TextureFormat.RGBA32, false);
for (int x = 0; x < s.texture.width; x++)
{
for (int y = 0; y < s.texture.height; y++)
{
edges.SetPixel(x, y, GetEdge(s, x, y));
}
}
edges.Apply();
return edges;
}
//encodes edge information into 1 channel of the texture
private static Color GetEdge(Sprite s, int x, int y)
{
//MY COUNTERPART IS CustomRenderGraphBlock.hlsl.getSpriteEdges_float
var col = new Color(0, 0, 0, 0);
var px = s.texture.GetPixel(x, y);
if (px.a < 1)
{
return col;
}
else
{
for (int edgeTest = EDGE_SIZE; edgeTest >= 0; edgeTest--)
{
float edgeAlpha = 1f - (float)edgeTest / ((float)EDGE_SIZE + 1f);
//test up
if (IsEdge(s, x, y + edgeTest))
col.r = edgeAlpha;
//test right
if (IsEdge(s, x + edgeTest, y))
col.g = edgeAlpha;
//test left
if (IsEdge(s, x - edgeTest, y))
col.b = edgeAlpha;
//test bot
if (IsEdge(s, x, y - edgeTest))
col.a = edgeAlpha;
}
}
return col;
}
private static bool IsEdge(Sprite s, int x, int y)
{
if (x < 0 || y < 0 || x >= s.texture.width || y >= s.texture.height)
return true;
else return s.texture.GetPixel(x, y).a == 0f;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment