NoiseGenerator.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. using System.IO;
  2. using UnityEngine;
  3. using UnityEditor;
  4. namespace VolumetricFogAndMist2 {
  5. public class NoiseGenerator : EditorWindow {
  6. [SerializeField]
  7. int size = 256;
  8. [SerializeField, Range(0, 1f)]
  9. float offset = 0;
  10. [SerializeField, Range(1, 12)]
  11. int octaves = 6;
  12. [SerializeField]
  13. float lacunarity = 2f;
  14. [SerializeField, Range(0, 1f)]
  15. float persistance = 0.5f;
  16. [SerializeField]
  17. float rangeMin = 0, rangeMax = 1;
  18. SerializedObject serializedObject;
  19. SerializedProperty sizeProp, offsetProp, rangeMinProp, rangeMaxProp;
  20. SerializedProperty octavesProp, lacunarityProp, persistanceProp;
  21. Texture2D noiseTexture, textureAsset;
  22. Material previewTextureMat;
  23. GUIStyle titleLabelStyle;
  24. Color titleColor;
  25. float noiseMinValue, noiseMaxValue;
  26. float[] values;
  27. Color[] colors;
  28. bool requestRebuild;
  29. [MenuItem("Window/Volumetric Fog \x8B& Mist/Noise Generator...", false, 1001)]
  30. public static void ShowWindow() {
  31. NoiseGenerator window = GetWindow<NoiseGenerator>("Noise Generator", true);
  32. window.minSize = new Vector2(400, 400);
  33. window.Show();
  34. }
  35. void OnEnable() {
  36. titleColor = EditorGUIUtility.isProSkin ? new Color(0.52f, 0.66f, 0.9f) : new Color(0.12f, 0.16f, 0.4f);
  37. ScriptableObject target = this;
  38. serializedObject = new SerializedObject(target);
  39. sizeProp = serializedObject.FindProperty("size");
  40. octavesProp = serializedObject.FindProperty("octaves");
  41. offsetProp = serializedObject.FindProperty("offset");
  42. lacunarityProp = serializedObject.FindProperty("lacunarity");
  43. persistanceProp = serializedObject.FindProperty("persistance");
  44. rangeMinProp = serializedObject.FindProperty("rangeMin");
  45. rangeMaxProp = serializedObject.FindProperty("rangeMax");
  46. RebuildTexture();
  47. LoadTexture();
  48. }
  49. void OnGUI() {
  50. EditorGUIUtility.labelWidth = 120;
  51. serializedObject.Update();
  52. if (titleLabelStyle == null) {
  53. titleLabelStyle = new GUIStyle(EditorStyles.label);
  54. }
  55. titleLabelStyle.normal.textColor = titleColor;
  56. titleLabelStyle.fontStyle = FontStyle.Bold;
  57. EditorGUILayout.Separator();
  58. // Draw noise texture
  59. if (noiseTexture != null) {
  60. if (previewTextureMat == null) {
  61. previewTextureMat = Resources.Load<Material>("VoxelPlay/PreviewTexture");
  62. }
  63. EditorGUILayout.LabelField(new GUIContent("Noise Preview"), titleLabelStyle);
  64. Rect space = EditorGUILayout.BeginVertical();
  65. GUILayout.FlexibleSpace();
  66. EditorGUILayout.EndVertical();
  67. space.width -= 5;
  68. space.x = 5;
  69. space.width = Mathf.Min(space.height, space.width);
  70. EditorGUI.DrawPreviewTexture(space, noiseTexture, previewTextureMat, ScaleMode.ScaleToFit);
  71. }
  72. EditorGUI.BeginChangeCheck();
  73. EditorGUILayout.BeginHorizontal();
  74. EditorGUILayout.LabelField("Texture Asset", GUILayout.Width(120));
  75. textureAsset = (Texture2D)EditorGUILayout.ObjectField(textureAsset, typeof(Texture2D), false);
  76. if (textureAsset != null) {
  77. if (GUILayout.Button("Release", GUILayout.Width(100))) {
  78. textureAsset = null;
  79. requestRebuild = true;
  80. }
  81. }
  82. EditorGUILayout.EndHorizontal();
  83. if (EditorGUI.EndChangeCheck()) {
  84. LoadTexture();
  85. }
  86. EditorGUILayout.Separator();
  87. if (textureAsset == null) {
  88. EditorGUILayout.LabelField(new GUIContent("Noise Generator"), titleLabelStyle);
  89. EditorGUI.BeginChangeCheck();
  90. EditorGUILayout.PropertyField(sizeProp);
  91. if (sizeProp.intValue < 4) {
  92. sizeProp.intValue = 4;
  93. }
  94. EditorGUILayout.PropertyField(octavesProp);
  95. EditorGUILayout.PropertyField(lacunarityProp);
  96. EditorGUILayout.PropertyField(persistanceProp);
  97. EditorGUILayout.PropertyField(offsetProp);
  98. EditorGUILayout.PropertyField(rangeMinProp, new GUIContent("Min Value", "Minimum value for noise."));
  99. EditorGUILayout.PropertyField(rangeMaxProp, new GUIContent("Max Value", "Maximum value for noise."));
  100. if (EditorGUI.EndChangeCheck()) {
  101. requestRebuild = true;
  102. }
  103. EditorGUILayout.BeginHorizontal();
  104. if (GUILayout.Button("Refresh", GUILayout.Width(80))) {
  105. requestRebuild = true;
  106. }
  107. GUI.enabled = noiseTexture != null;
  108. if (GUILayout.Button("Create Texture Asset", GUILayout.Width(150))) {
  109. CreateTextureAsset();
  110. GUIUtility.ExitGUI();
  111. return;
  112. }
  113. GUI.enabled = true;
  114. EditorGUILayout.EndHorizontal();
  115. }
  116. serializedObject.ApplyModifiedProperties();
  117. EditorGUILayout.Separator();
  118. if (requestRebuild && textureAsset == null) {
  119. requestRebuild = false;
  120. RebuildTexture();
  121. GUIUtility.ExitGUI();
  122. }
  123. }
  124. void RebuildTexture() {
  125. if (values == null || values.Length != size * size) {
  126. values = new float[size * size];
  127. }
  128. float maxValue = float.MinValue;
  129. float minValue = float.MaxValue;
  130. GeneratePerlinNoise(ref minValue, ref maxValue);
  131. // normalize values
  132. float range = maxValue - minValue;
  133. if (range > 0) {
  134. float fixedMin = rangeMin;
  135. float fixedRange = rangeMax - rangeMin;
  136. for (int index = 0; index < values.Length; index++) {
  137. float v = (values[index] - minValue) / range;
  138. v = fixedMin + (v * fixedRange);
  139. if (v < 0) {
  140. v = 0;
  141. } else if (v > 1) {
  142. v = 1;
  143. }
  144. values[index] = v;
  145. }
  146. }
  147. FillTexture();
  148. }
  149. void GeneratePerlinNoise(ref float minValue, ref float maxValue) {
  150. Vector2[] pows = new Vector2[octaves];
  151. for (int k = 0; k < pows.Length; k++) {
  152. pows[k].x = Mathf.Max(1f, Mathf.Pow(lacunarity, (k + 1)));
  153. pows[k].y = Mathf.Pow(persistance, k);
  154. }
  155. float offsetValue = offset * size;
  156. for (int index = 0, y = 0; y < size; y++) {
  157. float yf = (float)y / size;
  158. for (int x = 0; x < size; x++) {
  159. float xf = (float)x / size;
  160. float v = 1f;
  161. for (int o = 0; o < octaves; o++) {
  162. int frequency = (int)pows[o].x;
  163. float amplitude = pows[o].y;
  164. float xx = xf * frequency + offsetValue;
  165. float yy = yf * frequency + offsetValue;
  166. float ov = NoiseTools.GetTilablePerlinValue(xx, yy, frequency, frequency) + 0.5f;
  167. v += amplitude * ov;
  168. }
  169. values[index++] = v;
  170. if (v < minValue) {
  171. minValue = v;
  172. }
  173. if (v > maxValue) {
  174. maxValue = v;
  175. }
  176. }
  177. }
  178. }
  179. void FillTexture() {
  180. if (noiseTexture == null || noiseTexture.width != size) {
  181. noiseTexture = new Texture2D(size, size, TextureFormat.ARGB32, false);
  182. }
  183. // update texture
  184. if (colors == null || colors.Length != values.Length) {
  185. colors = new Color[size * size];
  186. }
  187. Color c = new Color(1, 1, 1);
  188. noiseMaxValue = float.MinValue;
  189. noiseMinValue = float.MaxValue;
  190. for (int index = 0; index < values.Length; index++) {
  191. float v = values[index];
  192. if (v < noiseMinValue) {
  193. noiseMinValue = v;
  194. }
  195. if (v > noiseMaxValue) {
  196. noiseMaxValue = v;
  197. }
  198. c.r = c.g = c.b = v;
  199. colors[index] = c;
  200. }
  201. noiseTexture.SetPixels(colors);
  202. noiseTexture.Apply();
  203. }
  204. void LoadTexture() {
  205. if (textureAsset == null)
  206. return;
  207. size = textureAsset.width;
  208. Color[] colors = textureAsset.GetPixels();
  209. values = new float[colors.Length];
  210. for (int k = 0; k < colors.Length; k++) {
  211. values[k] = colors[k].r;
  212. }
  213. FillTexture();
  214. }
  215. void CreateTextureAsset() {
  216. byte[] bytes = noiseTexture.EncodeToPNG();
  217. string filename = "NoiseTexture" + System.DateTime.Now.Ticks;
  218. string path = Application.dataPath;
  219. File.WriteAllBytes(path + "/" + filename + ".png", bytes);
  220. AssetDatabase.Refresh();
  221. Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/" + filename + ".png");
  222. if (tex != null) {
  223. TextureImporter importer = AssetImporter.GetAtPath("Assets/" + filename + ".png") as TextureImporter;
  224. if (importer != null) {
  225. importer.isReadable = true;
  226. importer.SaveAndReimport();
  227. Selection.activeObject = tex;
  228. EditorGUIUtility.PingObject(tex);
  229. }
  230. }
  231. }
  232. }
  233. }