VolumetricFogManagerEditor.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEngine.Rendering.Universal;
  4. namespace VolumetricFogAndMist2 {
  5. [CustomEditor(typeof(VolumetricFogManager))]
  6. public class VolumetricFogManagerEditor : Editor {
  7. SerializedProperty sun, moon, includeTransparent, transparentCullMode, includeSemiTransparent, alphaCutOff, flipDepthTexture, mainManager;
  8. SerializedProperty scattering, scatteringThreshold, scatteringIntensity, scatteringAbsorption, scatteringTint, scatteringHighQuality;
  9. SerializedProperty downscaling, downscalingEdgeDepthThreshold, blurPasses, blurDownscaling, blurSpread, blurHDR, blurEdgePreserve, blurEdgeDepthThreshold, ditherStrength;
  10. bool toggleOptimizeBuild;
  11. VolumetricFogShaderOptions shaderAdvancedOptionsInfo;
  12. int maxIterations;
  13. private void OnEnable() {
  14. sun = serializedObject.FindProperty("sun");
  15. moon = serializedObject.FindProperty("moon");
  16. includeTransparent = serializedObject.FindProperty("includeTransparent");
  17. transparentCullMode = serializedObject.FindProperty("transparentCullMode");
  18. includeSemiTransparent = serializedObject.FindProperty("includeSemiTransparent");
  19. alphaCutOff = serializedObject.FindProperty("alphaCutOff");
  20. flipDepthTexture = serializedObject.FindProperty("flipDepthTexture");
  21. mainManager = serializedObject.FindProperty("mainManager");
  22. scattering = serializedObject.FindProperty("scattering");
  23. scatteringThreshold = serializedObject.FindProperty("scatteringThreshold");
  24. scatteringIntensity = serializedObject.FindProperty("scatteringIntensity");
  25. scatteringAbsorption = serializedObject.FindProperty("scatteringAbsorption");
  26. scatteringTint = serializedObject.FindProperty("scatteringTint");
  27. scatteringHighQuality = serializedObject.FindProperty("scatteringHighQuality");
  28. downscaling = serializedObject.FindProperty("downscaling");
  29. downscalingEdgeDepthThreshold = serializedObject.FindProperty("downscalingEdgeDepthThreshold");
  30. blurPasses = serializedObject.FindProperty("blurPasses");
  31. blurDownscaling = serializedObject.FindProperty("blurDownscaling");
  32. blurSpread = serializedObject.FindProperty("blurSpread");
  33. blurHDR = serializedObject.FindProperty("blurHDR");
  34. blurEdgePreserve = serializedObject.FindProperty("blurEdgePreserve");
  35. blurEdgeDepthThreshold = serializedObject.FindProperty("blurEdgeDepthThreshold");
  36. ditherStrength = serializedObject.FindProperty("ditherStrength");
  37. ScanAdvancedOptions();
  38. }
  39. public override void OnInspectorGUI() {
  40. EditorGUILayout.Separator();
  41. UniversalRenderPipelineAsset pipe = UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
  42. if (pipe == null) {
  43. EditorGUILayout.HelpBox("Please assign the Universal Rendering Pipeline asset (go to Project Settings -> Graphics). You can use the UniversalRenderPipelineAsset included in the demo folder or create a new pipeline asset (check documentation for step by step setup).", MessageType.Error);
  44. return;
  45. }
  46. if (QualitySettings.renderPipeline != null) {
  47. pipe = QualitySettings.renderPipeline as UniversalRenderPipelineAsset;
  48. }
  49. if (!pipe.supportsCameraDepthTexture) {
  50. EditorGUILayout.HelpBox("Depth Texture option is required in Universal Rendering Pipeline asset!", MessageType.Error);
  51. if (GUILayout.Button("Go to Universal Rendering Pipeline Asset")) {
  52. Selection.activeObject = pipe;
  53. }
  54. EditorGUILayout.Separator();
  55. GUI.enabled = false;
  56. }
  57. if (VolumetricFogEditor.lastEditingFog != null) {
  58. if (GUILayout.Button("<< Back To Last Volumetric Fog")) {
  59. Selection.SetActiveObjectWithContext(VolumetricFogEditor.lastEditingFog, null);
  60. GUIUtility.ExitGUI();
  61. }
  62. }
  63. serializedObject.Update();
  64. EditorGUILayout.BeginVertical();
  65. EditorGUILayout.LabelField("General Settings", EditorStyles.boldLabel);
  66. EditorGUILayout.PropertyField(sun);
  67. EditorGUILayout.PropertyField(moon);
  68. EditorGUILayout.PropertyField(flipDepthTexture);
  69. EditorGUILayout.PropertyField(mainManager);
  70. EditorGUILayout.EndVertical();
  71. EditorGUILayout.Separator();
  72. EditorGUILayout.BeginVertical();
  73. EditorGUILayout.LabelField(new GUIContent("Custom Depth Pre-Pass", "Support for transparent or semi-transparent objects or needed custom depth pass."), EditorStyles.boldLabel);
  74. int transparentLayerMask = includeTransparent.intValue;
  75. DrawSectionField(includeTransparent, new GUIContent("Transparent Objects", "Specify which layers contain transparent objects that should be covered by fog"), transparentLayerMask != 0);
  76. if (transparentLayerMask != 0) {
  77. EditorGUI.indentLevel++;
  78. EditorGUILayout.PropertyField(transparentCullMode, new GUIContent("Cull Mode"));
  79. EditorGUI.indentLevel--;
  80. }
  81. int includeSemiTransparentMask = includeSemiTransparent.intValue;
  82. DrawSectionField(includeSemiTransparent, new GUIContent("Alpha Clipping", "Specify which smi-transparent objects (cutout materials) should be covered by fog."), includeSemiTransparentMask != 0);
  83. if (includeSemiTransparentMask != 0) {
  84. EditorGUI.indentLevel++;
  85. EditorGUILayout.PropertyField(alphaCutOff, new GUIContent("Alpha CutOff"), true);
  86. EditorGUILayout.BeginHorizontal();
  87. EditorGUILayout.LabelField(new GUIContent(""), GUIContent.none);
  88. if (GUILayout.Button("Refresh")) {
  89. DepthRenderPrePassFeature.DepthRenderPass.FindAlphaClippingRenderers();
  90. }
  91. EditorGUILayout.EndHorizontal();
  92. EditorGUI.indentLevel--;
  93. }
  94. if (includeTransparent.intValue != 0 || includeSemiTransparent.intValue != 0) {
  95. if (!DepthRenderPrePassFeature.installed) {
  96. EditorGUILayout.HelpBox("Transparent option requires 'DepthRendererPrePass Feature' added to the Universal Rendering Pipeline asset. Check the documentation for instructions.", MessageType.Warning);
  97. if (pipe != null && GUILayout.Button("Show Pipeline Asset")) Selection.activeObject = pipe;
  98. }
  99. if ((includeTransparent.intValue & includeSemiTransparent.intValue) != 0) {
  100. EditorGUILayout.HelpBox("The options 'Transparent Objects' and 'Alpha Clipping' should not overlap and include same objects. Make sure the specified layers are different in each option.", MessageType.Warning);
  101. }
  102. } else if (DepthRenderPrePassFeature.installed) {
  103. EditorGUILayout.HelpBox("No transparent objects included. Remove 'DepthRendererPrePass Feature' from the Universal Rendering Pipeline asset to save performance.", MessageType.Warning);
  104. if (pipe != null && GUILayout.Button("Show Pipeline Asset")) Selection.activeObject = pipe;
  105. }
  106. EditorGUILayout.EndVertical();
  107. EditorGUILayout.Separator();
  108. EditorGUILayout.BeginVertical();
  109. EditorGUILayout.LabelField(new GUIContent("Final Composition", "Support for off-screen rendering and composition to screen target. Allows optimizations like downsampling."), EditorStyles.boldLabel);
  110. EditorGUI.BeginChangeCheck();
  111. DrawSectionField(scattering, new GUIContent(scattering.displayName, scattering.tooltip), scattering.floatValue > 0);
  112. if (scattering.floatValue > 0) {
  113. EditorGUI.indentLevel++;
  114. EditorGUILayout.PropertyField(scatteringIntensity, new GUIContent("Brightness"));
  115. EditorGUILayout.PropertyField(scatteringThreshold, new GUIContent("Brightness Threshold"));
  116. EditorGUILayout.PropertyField(scatteringAbsorption, new GUIContent("Absorption"));
  117. EditorGUILayout.PropertyField(scatteringTint, new GUIContent("Tint Color"));
  118. EditorGUILayout.PropertyField(scatteringHighQuality, new GUIContent("High Quality"));
  119. EditorGUI.indentLevel--;
  120. }
  121. DrawSectionField(downscaling, new GUIContent(downscaling.displayName, downscaling.tooltip), downscaling.floatValue > 1);
  122. if (downscaling.floatValue > 1f) {
  123. EditorGUI.indentLevel++;
  124. EditorGUILayout.PropertyField(downscalingEdgeDepthThreshold, new GUIContent("Edge Threshold"));
  125. EditorGUI.indentLevel--;
  126. }
  127. DrawSectionField(blurPasses, new GUIContent(blurPasses.displayName, blurPasses.tooltip), blurPasses.intValue > 0);
  128. if (blurPasses.intValue > 0) {
  129. EditorGUI.indentLevel++;
  130. EditorGUILayout.PropertyField(blurDownscaling, new GUIContent("Downscaling"));
  131. EditorGUILayout.PropertyField(blurSpread, new GUIContent("Spread"));
  132. EditorGUILayout.PropertyField(blurEdgePreserve, new GUIContent("Preserve Edges"));
  133. if (blurEdgePreserve.boolValue) {
  134. EditorGUILayout.PropertyField(blurEdgeDepthThreshold, new GUIContent("Edge Threshold"));
  135. }
  136. EditorGUI.indentLevel--;
  137. }
  138. EditorGUILayout.PropertyField(blurHDR, new GUIContent("HDR"));
  139. if (EditorGUI.EndChangeCheck()) {
  140. EditorApplication.delayCall += () => UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
  141. }
  142. EditorGUILayout.PropertyField(ditherStrength);
  143. if (blurPasses.intValue > 0 || downscaling.floatValue > 1 || scattering.floatValue > 0) {
  144. if (!VolumetricFogRenderFeature.installed) {
  145. EditorGUILayout.HelpBox("These options require 'Volumetric Fog Render Feature' added to the Universal Rendering Pipeline asset. Check the documentation for instructions.", MessageType.Warning);
  146. if (pipe != null && GUILayout.Button("Show Pipeline Asset")) Selection.activeObject = pipe;
  147. }
  148. EditorGUILayout.HelpBox("When downscaling, blur or scattering options are enabled, fog volumes ignore render queue value. Select the render pass event in the Volumetric Fog Render Feature.", MessageType.Info);
  149. } else if (VolumetricFogRenderFeature.installed) {
  150. EditorGUILayout.HelpBox("No final composition options used (downscaling/blur/scattering). Consider removing 'Volumetric Fog Render Feature' from the Universal Rendering Pipeline asset to save performance.", MessageType.Warning);
  151. if (pipe != null && GUILayout.Button("Show Pipeline Asset")) Selection.activeObject = pipe;
  152. }
  153. EditorGUILayout.EndVertical();
  154. EditorGUILayout.Separator();
  155. bool shaderOptionsOpen = toggleOptimizeBuild;
  156. if (shaderOptionsOpen) {
  157. EditorGUILayout.BeginVertical(GUI.skin.box);
  158. }
  159. if (GUILayout.Button(toggleOptimizeBuild ? "Hide Shader Options" : "Shader Options", GUILayout.Width(150))) {
  160. toggleOptimizeBuild = !toggleOptimizeBuild;
  161. }
  162. if (toggleOptimizeBuild && shaderAdvancedOptionsInfo != null) {
  163. int optionsCount = shaderAdvancedOptionsInfo.options.Length;
  164. for (int k = 0; k < optionsCount; k++) {
  165. ShaderAdvancedOption option = shaderAdvancedOptionsInfo.options[k];
  166. if (option.hasValue) continue;
  167. EditorGUILayout.BeginHorizontal();
  168. EditorGUILayout.LabelField("", GUILayout.Width(10));
  169. bool prevState = option.enabled;
  170. bool newState = EditorGUILayout.Toggle(prevState, GUILayout.Width(18));
  171. if (prevState != newState) {
  172. shaderAdvancedOptionsInfo.options[k].enabled = newState;
  173. shaderAdvancedOptionsInfo.pendingChanges = true;
  174. GUIUtility.ExitGUI();
  175. return;
  176. }
  177. EditorGUILayout.LabelField(option.name);
  178. EditorGUILayout.EndHorizontal();
  179. EditorGUILayout.BeginHorizontal();
  180. EditorGUILayout.LabelField("", GUILayout.Width(10));
  181. EditorGUILayout.LabelField("", GUILayout.Width(18));
  182. GUIStyle wrapStyle = new GUIStyle(GUI.skin.label);
  183. wrapStyle.wordWrap = true;
  184. EditorGUILayout.LabelField(option.description, wrapStyle);
  185. EditorGUILayout.EndHorizontal();
  186. }
  187. EditorGUILayout.BeginHorizontal();
  188. EditorGUILayout.LabelField("", GUILayout.Width(10));
  189. EditorGUI.BeginChangeCheck();
  190. float prevLabelWidth = EditorGUIUtility.labelWidth;
  191. EditorGUIUtility.labelWidth = 100;
  192. maxIterations = EditorGUILayout.IntField(new GUIContent("Max Iterations", "The maximum number of raymarching steps."), maxIterations, GUILayout.Width(175));
  193. if (EditorGUI.EndChangeCheck()) {
  194. shaderAdvancedOptionsInfo.pendingChanges = true;
  195. }
  196. EditorGUIUtility.labelWidth = prevLabelWidth;
  197. EditorGUILayout.EndHorizontal();
  198. EditorGUILayout.Separator();
  199. EditorGUILayout.BeginHorizontal();
  200. if (GUILayout.Button("Refresh", GUILayout.Width(60))) {
  201. ScanAdvancedOptions();
  202. GUIUtility.ExitGUI();
  203. return;
  204. }
  205. if (!shaderAdvancedOptionsInfo.pendingChanges)
  206. GUI.enabled = false;
  207. if (GUILayout.Button("Save Changes", GUILayout.Width(110))) {
  208. shaderAdvancedOptionsInfo.SetOptionValue("MAX_ITERATIONS", maxIterations);
  209. shaderAdvancedOptionsInfo.UpdateAdvancedOptionsFile();
  210. GUIUtility.ExitGUI();
  211. }
  212. GUI.enabled = true;
  213. EditorGUILayout.EndHorizontal();
  214. }
  215. if (shaderOptionsOpen) {
  216. EditorGUILayout.EndVertical();
  217. }
  218. EditorGUILayout.Separator();
  219. EditorGUILayout.BeginVertical();
  220. EditorGUILayout.LabelField("Managers", EditorStyles.boldLabel);
  221. EditorGUILayout.BeginHorizontal();
  222. GUILayout.Label("Point Light Manager", GUILayout.Width(EditorGUIUtility.labelWidth));
  223. if (GUILayout.Button("Open", GUILayout.Width(150))) {
  224. Selection.activeGameObject = VolumetricFogManager.pointLightManager.gameObject;
  225. }
  226. EditorGUILayout.EndHorizontal();
  227. EditorGUILayout.BeginHorizontal();
  228. GUILayout.Label("Fog Void Manager", GUILayout.Width(EditorGUIUtility.labelWidth));
  229. if (GUILayout.Button("Open", GUILayout.Width(150))) {
  230. Selection.activeGameObject = VolumetricFogManager.fogVoidManager.gameObject;
  231. }
  232. EditorGUILayout.EndHorizontal();
  233. EditorGUILayout.EndVertical();
  234. EditorGUILayout.Separator();
  235. EditorGUILayout.BeginVertical();
  236. EditorGUILayout.LabelField("Tools", EditorStyles.boldLabel);
  237. EditorGUILayout.BeginHorizontal();
  238. GUILayout.Label("Noise Generator", GUILayout.Width(EditorGUIUtility.labelWidth));
  239. if (GUILayout.Button("Open", GUILayout.Width(150))) {
  240. NoiseGenerator window = EditorWindow.GetWindow<NoiseGenerator>("Noise Generator", true);
  241. window.minSize = new Vector2(400, 400);
  242. window.Show();
  243. }
  244. EditorGUILayout.EndHorizontal();
  245. EditorGUILayout.EndVertical();
  246. serializedObject.ApplyModifiedProperties();
  247. }
  248. void ScanAdvancedOptions() {
  249. if (shaderAdvancedOptionsInfo == null) {
  250. shaderAdvancedOptionsInfo = new VolumetricFogShaderOptions();
  251. }
  252. shaderAdvancedOptionsInfo.ReadOptions();
  253. maxIterations = shaderAdvancedOptionsInfo.GetOptionValue("MAX_ITERATIONS");
  254. }
  255. void DrawSectionField(SerializedProperty property, GUIContent content, bool active) {
  256. EditorGUILayout.PropertyField(property, new GUIContent(active ? content.text + " •" : content.text, content.tooltip));
  257. }
  258. }
  259. }