2025-06-08 00:39:11 +09:00

288 lines
10 KiB
C#

using System.IO;
using UnityEngine;
using UnityEditor;
namespace VolumetricFogAndMist2 {
public class NoiseGenerator : EditorWindow {
[SerializeField]
int size = 256;
[SerializeField, Range(0, 1f)]
float offset = 0;
[SerializeField, Range(1, 12)]
int octaves = 6;
[SerializeField]
float lacunarity = 2f;
[SerializeField, Range(0, 1f)]
float persistance = 0.5f;
[SerializeField]
float rangeMin = 0, rangeMax = 1;
SerializedObject serializedObject;
SerializedProperty sizeProp, offsetProp, rangeMinProp, rangeMaxProp;
SerializedProperty octavesProp, lacunarityProp, persistanceProp;
Texture2D noiseTexture, textureAsset;
Material previewTextureMat;
GUIStyle titleLabelStyle;
Color titleColor;
float noiseMinValue, noiseMaxValue;
float[] values;
Color[] colors;
bool requestRebuild;
[MenuItem("Window/Volumetric Fog \x8B& Mist/Noise Generator...", false, 1001)]
public static void ShowWindow() {
NoiseGenerator window = GetWindow<NoiseGenerator>("Noise Generator", true);
window.minSize = new Vector2(400, 400);
window.Show();
}
void OnEnable() {
titleColor = EditorGUIUtility.isProSkin ? new Color(0.52f, 0.66f, 0.9f) : new Color(0.12f, 0.16f, 0.4f);
ScriptableObject target = this;
serializedObject = new SerializedObject(target);
sizeProp = serializedObject.FindProperty("size");
octavesProp = serializedObject.FindProperty("octaves");
offsetProp = serializedObject.FindProperty("offset");
lacunarityProp = serializedObject.FindProperty("lacunarity");
persistanceProp = serializedObject.FindProperty("persistance");
rangeMinProp = serializedObject.FindProperty("rangeMin");
rangeMaxProp = serializedObject.FindProperty("rangeMax");
RebuildTexture();
LoadTexture();
}
void OnGUI() {
EditorGUIUtility.labelWidth = 120;
serializedObject.Update();
if (titleLabelStyle == null) {
titleLabelStyle = new GUIStyle(EditorStyles.label);
}
titleLabelStyle.normal.textColor = titleColor;
titleLabelStyle.fontStyle = FontStyle.Bold;
EditorGUILayout.Separator();
// Draw noise texture
if (noiseTexture != null) {
if (previewTextureMat == null) {
previewTextureMat = Resources.Load<Material>("VoxelPlay/PreviewTexture");
}
EditorGUILayout.LabelField(new GUIContent("Noise Preview"), titleLabelStyle);
Rect space = EditorGUILayout.BeginVertical();
GUILayout.FlexibleSpace();
EditorGUILayout.EndVertical();
space.width -= 5;
space.x = 5;
space.width = Mathf.Min(space.height, space.width);
EditorGUI.DrawPreviewTexture(space, noiseTexture, previewTextureMat, ScaleMode.ScaleToFit);
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Texture Asset", GUILayout.Width(120));
textureAsset = (Texture2D)EditorGUILayout.ObjectField(textureAsset, typeof(Texture2D), false);
if (textureAsset != null) {
if (GUILayout.Button("Release", GUILayout.Width(100))) {
textureAsset = null;
requestRebuild = true;
}
}
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck()) {
LoadTexture();
}
EditorGUILayout.Separator();
if (textureAsset == null) {
EditorGUILayout.LabelField(new GUIContent("Noise Generator"), titleLabelStyle);
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(sizeProp);
if (sizeProp.intValue < 4) {
sizeProp.intValue = 4;
}
EditorGUILayout.PropertyField(octavesProp);
EditorGUILayout.PropertyField(lacunarityProp);
EditorGUILayout.PropertyField(persistanceProp);
EditorGUILayout.PropertyField(offsetProp);
EditorGUILayout.PropertyField(rangeMinProp, new GUIContent("Min Value", "Minimum value for noise."));
EditorGUILayout.PropertyField(rangeMaxProp, new GUIContent("Max Value", "Maximum value for noise."));
if (EditorGUI.EndChangeCheck()) {
requestRebuild = true;
}
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Refresh", GUILayout.Width(80))) {
requestRebuild = true;
}
GUI.enabled = noiseTexture != null;
if (GUILayout.Button("Create Texture Asset", GUILayout.Width(150))) {
CreateTextureAsset();
GUIUtility.ExitGUI();
return;
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
}
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Separator();
if (requestRebuild && textureAsset == null) {
requestRebuild = false;
RebuildTexture();
GUIUtility.ExitGUI();
}
}
void RebuildTexture() {
if (values == null || values.Length != size * size) {
values = new float[size * size];
}
float maxValue = float.MinValue;
float minValue = float.MaxValue;
GeneratePerlinNoise(ref minValue, ref maxValue);
// normalize values
float range = maxValue - minValue;
if (range > 0) {
float fixedMin = rangeMin;
float fixedRange = rangeMax - rangeMin;
for (int index = 0; index < values.Length; index++) {
float v = (values[index] - minValue) / range;
v = fixedMin + (v * fixedRange);
if (v < 0) {
v = 0;
} else if (v > 1) {
v = 1;
}
values[index] = v;
}
}
FillTexture();
}
void GeneratePerlinNoise(ref float minValue, ref float maxValue) {
Vector2[] pows = new Vector2[octaves];
for (int k = 0; k < pows.Length; k++) {
pows[k].x = Mathf.Max(1f, Mathf.Pow(lacunarity, (k + 1)));
pows[k].y = Mathf.Pow(persistance, k);
}
float offsetValue = offset * size;
for (int index = 0, y = 0; y < size; y++) {
float yf = (float)y / size;
for (int x = 0; x < size; x++) {
float xf = (float)x / size;
float v = 1f;
for (int o = 0; o < octaves; o++) {
int frequency = (int)pows[o].x;
float amplitude = pows[o].y;
float xx = xf * frequency + offsetValue;
float yy = yf * frequency + offsetValue;
float ov = NoiseTools.GetTilablePerlinValue(xx, yy, frequency, frequency) + 0.5f;
v += amplitude * ov;
}
values[index++] = v;
if (v < minValue) {
minValue = v;
}
if (v > maxValue) {
maxValue = v;
}
}
}
}
void FillTexture() {
if (noiseTexture == null || noiseTexture.width != size) {
noiseTexture = new Texture2D(size, size, TextureFormat.ARGB32, false);
}
// update texture
if (colors == null || colors.Length != values.Length) {
colors = new Color[size * size];
}
Color c = new Color(1, 1, 1);
noiseMaxValue = float.MinValue;
noiseMinValue = float.MaxValue;
for (int index = 0; index < values.Length; index++) {
float v = values[index];
if (v < noiseMinValue) {
noiseMinValue = v;
}
if (v > noiseMaxValue) {
noiseMaxValue = v;
}
c.r = c.g = c.b = v;
colors[index] = c;
}
noiseTexture.SetPixels(colors);
noiseTexture.Apply();
}
void LoadTexture() {
if (textureAsset == null)
return;
size = textureAsset.width;
Color[] colors = textureAsset.GetPixels();
values = new float[colors.Length];
for (int k = 0; k < colors.Length; k++) {
values[k] = colors[k].r;
}
FillTexture();
}
void CreateTextureAsset() {
byte[] bytes = noiseTexture.EncodeToPNG();
string filename = "NoiseTexture" + System.DateTime.Now.Ticks;
string path = Application.dataPath;
File.WriteAllBytes(path + "/" + filename + ".png", bytes);
AssetDatabase.Refresh();
Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/" + filename + ".png");
if (tex != null) {
TextureImporter importer = AssetImporter.GetAtPath("Assets/" + filename + ".png") as TextureImporter;
if (importer != null) {
importer.isReadable = true;
importer.SaveAndReimport();
Selection.activeObject = tex;
EditorGUIUtility.PingObject(tex);
}
}
}
}
}