うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】ボロノイノイズテクスチャを生成する

Shader Graph の Voronoi をベースにエッジ距離を用いたボロノイテクスチャを生成できるコード

これを実行するとこのようなテクスチャが取得できます

また、Mathematics の package を利用しているので install しなければコンパイルエラーになります

using System.IO;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;

public class Voronoi
{
    [MenuItem("Tools/Voronoi")]
    private static void Generate()
    {
        var size = 128;
        var density = 5;
        var angleOffset = 10f;
        var seed = 0;
        
        var texture = new Texture2D(size, size, TextureFormat.ARGB32, false);
        for (var x = 0; x < size; x++)
        {
            for (var y = 0; y < size; y++)
            {
                var uv = new float2(x / (float) (size - 1), y / (float) (size - 1));
                var v = Calc(uv, density, angleOffset, seed);
                var color = new Color(v, v, v, 1f);
                texture.SetPixel(x, y, color);
            }
        }
        
        texture.Apply();

        var path = "Assets/voronoi.png";
        var png = texture.EncodeToPNG();
        File.WriteAllBytes(path, png);
    }
    
    private static float Calc(float2 uv, int density, float angleOffset, int seed)
    {
        var uv2 = uv * density;
        var n = math.floor(uv2);
        var f = math.frac(uv2);

        var mg = float2.zero;
        var mr = float2.zero;
        var md = 8f;
        var m = new float2x2(15.27f, 47.63f, 99.41f, 89.98f);
        for (var y = -1; y <= 1; y++)
        {
            for (var x = -1; x <= 1; x++)
            {
                var g = new float2(x, y);

                var uvr = math.frac(math.sin(math.mul(g + n, m)) * (46839.32f + seed));
                var o = new float2(
                    math.sin(uvr.y * angleOffset) * 0.5f + 0.5f,
                    math.cos(uvr.x * angleOffset) * 0.5f + 0.5f
                );

                var r = g + o - f;
                var d = math.dot(r, r);

                if (d < md)
                {
                    md = d;
                    mr = r;
                    mg = g;
                }
            }
        }

        md = 8f;
        for (var y = -2; y <= 2; y++)
        {
            for (var x = -2; x <= 2; x++)
            {
                var g = mg + new float2(x, y);
                var uvr = math.frac(math.sin(math.mul(g + n, m)) * (46839.32f + seed));

                var o = new float2(
                    math.sin(uvr.y * angleOffset) * 0.5f + 0.5f,
                    math.cos(uvr.x * angleOffset) * 0.5f + 0.5f
                );

                var r = g + o - f;

                if (math.dot(mr - r, mr - r) > 0.0001f)
                {
                    md = math.min(md, math.dot(0.5f * (mr + r), math.normalize(r - mr)));
                }
            }
        }
        return md ;
    }
}