找回密码
 立即注册
查看: 340|回复: 0

【unity Tools】各类噪音生成器

[复制链接]
发表于 2022-1-3 12:00 | 显示全部楼层 |阅读模式
【简介】
感觉并没有什么含金量,只是感觉,在网络上找噪音图算法好麻烦,需要动用到SD来拿噪音,所以干脆自己在unity里面写了一个噪音,可以拿去扩展,生成各类数学图形都行。花了一个晚上做完的成果,稍微优化了工具性能。
【正文】
在unity打开工具的过程中,先进行界面初始化以及设置工具的位置:



界面初始化

接着,本人进行主界面设置,主要通过枚举来定义宽和高,以及定义了噪音选择,开放噪音缩放和噪音位移的接口:



噪音宽高的设置

文件汇入设置:



设置噪音选项

接下来,我们不需要每一帧都重新计算,只有改变时才计算:



改变时才计算

在生成贴图的时候,我们主要是通过对贴图的每一个像素进行计算,算完设置像素并且应用修改:



像素计算

接着在像素计算中,首先通过uv的重算,把像素映射回uv上面,然后进行相对应的噪音计算:



重算uv,然后进行噪音计算

perlin噪音比较简单,汇入mathf即可,在后面噪音主要借助着色器的uv计算方式进行计算,便可以得到对应结果,其他三个噪音直接通过uv的计算便可以得到对应的结果:



简单噪音



cellular噪音



fbm噪音

最后保存文件:



设置保存按钮



解包PNG,避免文件重名进行文件存在判断重写i

我们还可以设置一个小窗口展示纹理:



展示纹理



效果图

=========================================
【代码】
using System.IO;
using UnityEngine;
using UnityEditor;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class NoiseGenerater : EditorWindow
{
    //【噪音选项设置】
    public enum NOISEOPTIONS
    {
        PerlinNoise = 0,
        SimpleNoise = 1,
        cellular_noise = 2,
        fbm=3
    }
    public NOISEOPTIONS noiseoption;

    //【噪音宽度设置】
    public enum NOISEWIDTH
    {
        W1 = 1,
        W2 = 2,
        W4 = 4,
        W8 = 8,
        W16 = 16,
        W32 = 32,
        W64 = 64,
        W128 = 128,
        W256 = 256,
        W512 = 512,
        W1024 = 1024,
    }
    public NOISEWIDTH noisewidthoption = NOISEWIDTH.W256;
    //【噪音高度设置】
    public enum NOISEHEIGHT
    {
        H1 = 1,
        H2 = 2,
        H4 = 4,
        H8 = 8,
        H16 = 16,
        H32 = 32,
        H64 = 64,
        H128 = 128,
        H256 = 256,
        H512 = 512,
        H1024 = 1024,
    }
    public NOISEHEIGHT noiseheightoption = NOISEHEIGHT.H256;

    int width = 256;//宽度
    int height = 256;//高度
    float scale = 1.0f;//缩放
    float offsetX = 10.0f;//X位移
    float offsetY = 10.0f;//Y位移
    string AssetsName = "SaveImages";//保存文件夹名字
    Texture2D texture;//纹理初始化
    Vector2 scrollPos;//界面DropDown

    [MenuItem("Tools/Free Birdの噪音生成器")]
    #region 界面初始化
    static void Init()
    {
        EditorWindow window = GetWindow<NoiseGenerater>();
        window.Show();
    }
    #endregion

    #region 上一帧设置
    class NoiseTextureSetting
    {
        public int width = 1;
        public int height = 1;
        public float scale = 1;
        public NOISEOPTIONS noiseoption = NOISEOPTIONS.PerlinNoise;
        public float offsetX = 0;
        public float offsetY = 0;
    }
    NoiseTextureSetting noiseTextureSetting = new NoiseTextureSetting();
    #endregion

    #region 主界面设置
    private void OnGUI()
    {
        noiseoption = (NOISEOPTIONS)EditorGUILayout.EnumPopup("噪音选项设置:", noiseoption);//设置噪音选择
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, true, true);//DropDown避免界面过死
        var dirPath = Application.dataPath + "/" + AssetsName + "/";
        GUILayout.Label("文件夹路径:"+ dirPath);//当前保存文件夹名字
        AssetsName = EditorGUILayout.TextField(AssetsName);//文件夹名字设置

        GUILayout.BeginHorizontal();
        GUILayout.Label("噪音宽 = ");
        noisewidthoption = (NOISEWIDTH)EditorGUILayout.EnumPopup(noisewidthoption);//噪音宽度设置
        width = (int)noisewidthoption;
        GUILayout.Label("噪音高 = ");
        noiseheightoption =(NOISEHEIGHT)EditorGUILayout.EnumPopup(noiseheightoption);//噪音高度设置
        height = (int)noiseheightoption;
        GUILayout.Label("噪音缩放 = ");
        scale = EditorGUILayout.Slider(scale, 0.0f, 100.0f);//噪音缩放设置
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("噪音位移X = ");
        offsetX = EditorGUILayout.FloatField(offsetX);//噪音位移设置
        GUILayout.Label("噪音位移Y = ");
        offsetY = EditorGUILayout.FloatField(offsetY);//噪音位移设置
        GUILayout.EndHorizontal();

        if (NoiseCheck(width,height,scale,noiseoption,offsetX,offsetY))
        {
            texture = GenerateTexture();//新建贴图
        }

        GUI.skin.button.wordWrap = true;
        if (GUILayout.Button("保存图像"))
        {
            SaveTexture(texture);//保存图像
        }

        GUILayout.Label("纹理浏览:");
        EditorGUI.DrawPreviewTexture(new Rect(25, 120, width, height), texture);//纹理浏览
        EditorGUILayout.EndScrollView();

        NoiseSettingSave();
    }
    #endregion

    #region 设置保存
    void NoiseSettingSave()
    {
        noiseTextureSetting.width = width;
        noiseTextureSetting.height = height;
        noiseTextureSetting.scale = scale;
        noiseTextureSetting.noiseoption = noiseoption;
        noiseTextureSetting.offsetX = offsetX;
        noiseTextureSetting.offsetY = offsetY;
    }

    bool NoiseCheck(int width,int height,float scale,NOISEOPTIONS noiseoption,float offsetX,float offsetY)
    {
        if (noiseTextureSetting.width == width && noiseTextureSetting.height == height&& noiseTextureSetting.scale == scale&& noiseTextureSetting.noiseoption == noiseoption && noiseTextureSetting.offsetX == offsetX && noiseTextureSetting.offsetY == offsetY)
        {
            return false;
        }
        return true;
    }
    #endregion

    #region 保存图像函数
    void SaveTexture(Texture2D texture)
    {
        byte[] bytes = texture.EncodeToPNG();//读取图像为PNG
        var dirPath = Application.dataPath + "/" + AssetsName + "/";//当前文件夹路径
        Debug.Log("生成路径:" + dirPath);//生成路径位置
        if (!Directory.Exists(dirPath))
        {
            Directory.CreateDirectory(dirPath);//没有路径则生成
        }
        for (int i = 0; i < 1000; i++)
        {
            if (!File.Exists(dirPath + "Image" + "(" + i + ")" + ".png"))
            {
                File.WriteAllBytes(dirPath + "Image" + "(" + i + ")" + ".png", bytes);//写入文件里面
                break;
            }
        }
    }
    #endregion

    #region 生成贴图的主函数
    Texture2D GenerateTexture()
    {
        Texture2D texture = new Texture2D(width, height);//新建贴图

        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Color color = CalculateColor(x, y);//计算颜色,遍历像素
                texture.SetPixel(x, y, color);//设置像素颜色
            }
        }
        texture.Apply();//应用贴图修改

        return texture;
    }
    #endregion

    #region 颜色计算结果
    Color CalculateColor(int x, int y)
    {
        float xCoord = (float)x / width * scale + offsetX;//UV X
        float yCoord = (float)y / height * scale + offsetY;//UV Y
        float sample = 1;

        switch (noiseoption)
        {
            case NOISEOPTIONS.PerlinNoise:
                sample = Mathf.PerlinNoise(xCoord, yCoord);//Perlin噪音直接输出
                break;
            case NOISEOPTIONS.SimpleNoise:
                sample = value_noise(new Vector2(xCoord, yCoord));//简单噪音
                break;
            case NOISEOPTIONS.cellular_noise:
                sample = cellular_noise(new Vector2(xCoord, yCoord));//cellular噪音
                break;
            case NOISEOPTIONS.fbm:
                sample = fbm(new Vector2(xCoord, yCoord));//fbm噪音
                break;
            default:
                break;
        }

        return new Color(sample, sample, sample);//输出颜色
    }
    #endregion

    #region 数学库
    Vector2 mod(Vector2 coord, float a)
    {
        return new Vector2(coord.x % a, coord.y % a);
    }
    float fract(float x)
    {
        return x - Mathf.Floor(x);
    }
    Vector2 fract(Vector2 x)
    {
        return new Vector2(x.x - Mathf.Floor(x.x), x.y - Mathf.Floor(x.y));
    }
    Vector2 floor(Vector2 x)
    {
        return new Vector2(Mathf.Floor(x.x), Mathf.Floor(x.y));
    }
    float rand(Vector2 coord)
    {
        // prevents randomness decreasing from coordinates too large
        coord = mod(coord, 10000.0f);
        // returns "random" float between 0 and 1
        return fract(Mathf.Sin(Vector2.Dot(coord, new Vector2(12.9898f, 78.233f))) * 43758.5453f);
    }
    float mix(float x,float y,float level)
    {
        return x * (1 - level) + y * level;
    }
    Vector2 rand2(Vector2 coord)
    {
        // prevents randomness decreasing from coordinates too large
        coord = mod(coord, 10000.0f);
        // returns "random" vec2 with x and y between 0 and 1
        return fract((new Vector2(Mathf.Sin(Vector2.Dot(coord, new Vector2(127.1f, 311.7f))), Mathf.Sin(Vector2.Dot(coord, new Vector2(269.5f, 183.3f))))) * 43758.5453f);
    }
    #endregion

    #region 简单噪音

    float value_noise(Vector2 coord)
    {
        Vector2 i = floor(coord);
        Vector2 f = fract(coord);

        // 4 corners of a rectangle surrounding our point
        float tl = rand(i);
        float tr = rand(i + new Vector2(1.0f, 0.0f));
        float bl = rand(i + new Vector2(0.0f, 1.0f));
        float br = rand(i + new Vector2(1.0f, 1.0f));

        Vector2 cubic = f * f * (new Vector2(3.0f, 3.0f) - 2.0f * f);

        float topmix = mix(tl, tr, cubic.x);
        float botmix = mix(bl, br, cubic.x);
        float wholemix = mix(topmix, botmix, cubic.y);

        return wholemix;

    }
    #endregion

    #region cellular噪音
    float cellular_noise(Vector2 coord)
    {
        Vector2 i = floor(coord);
        Vector2 f = fract(coord);

        float min_dist = 99999.0f;
        // going through the current tile and the tiles surrounding it
        for (float x = -1.0f; x <= 1.0; x++)
        {
            for (float y = -1.0f; y <= 1.0; y++)
            {

                // generate a random point in each tile,
                // but also account for whether it's a farther, neighbouring tile
                Vector2 node = rand2(i + new Vector2(x, y)) + new Vector2(x, y);

                // check for distance to the point in that tile
                // decide whether it's the minimum
                float dist = Mathf.Sqrt((f - node).x * (f - node).x + (f - node).y * (f - node).y);
                min_dist = Mathf.Min(min_dist, dist);
            }
        }
        return min_dist;
    }
    #endregion

    #region fbm噪音
    float fbm(Vector2 coord)
    {
        int OCTAVES = 4;

        float normalize_factor = 0.0f;
        float value = 0.0f;
        float scale = 0.5f;

        for (int i = 0; i < OCTAVES; i++)
        {
            value += Mathf.PerlinNoise(coord.x,coord.y) * scale;
            normalize_factor += scale;
            coord *= 2.0f;
            scale *= 0.5f;
        }
        return value / normalize_factor;
    }
    #endregion

}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-22 23:38 , Processed in 0.074204 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表