ParticleGUI.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. using UnityEngine;
  2. using UnityEditorInternal;
  3. using System.Linq;
  4. using System.Collections.Generic;
  5. using UnityEngine.Rendering;
  6. using UnityEngine.Scripting.APIUpdating;
  7. namespace UnityEditor.Rendering.Universal.ShaderGUI
  8. {
  9. [MovedFrom("UnityEditor.Rendering.LWRP.ShaderGUI")] public static class ParticleGUI
  10. {
  11. public enum ColorMode
  12. {
  13. Multiply,
  14. Additive,
  15. Subtractive,
  16. Overlay,
  17. Color,
  18. Difference
  19. }
  20. public static class Styles
  21. {
  22. public static GUIContent colorMode = new GUIContent("Color Mode",
  23. "Controls how the Particle color and the Material color blend together.");
  24. public static GUIContent flipbookMode = new GUIContent("Flip-Book Blending",
  25. "Blends the frames in a flip-book together in a smooth animation.");
  26. public static GUIContent softParticlesEnabled = new GUIContent("Soft Particles",
  27. "Makes particles fade out when they get close to intersecting with the surface of other geometry in the depth buffer.");
  28. public static GUIContent softParticlesNearFadeDistanceText =
  29. new GUIContent("Near",
  30. "The distance from the other surface where the particle is completely transparent.");
  31. public static GUIContent softParticlesFarFadeDistanceText =
  32. new GUIContent("Far",
  33. "The distance from the other surface where the particle is completely opaque.");
  34. public static GUIContent cameraFadingEnabled = new GUIContent("Camera Fading",
  35. "Makes particles fade out when they get close to the camera.");
  36. public static GUIContent cameraNearFadeDistanceText =
  37. new GUIContent("Near",
  38. "The distance from the camera where the particle is completely transparent.");
  39. public static GUIContent cameraFarFadeDistanceText =
  40. new GUIContent("Far", "The distance from the camera where the particle is completely opaque.");
  41. public static GUIContent distortionEnabled = new GUIContent("Distortion",
  42. "Creates a distortion effect by making particles perform refraction with the objects drawn before them.");
  43. public static GUIContent distortionStrength = new GUIContent("Strength",
  44. "Controls how much the Particle distorts the background. ");
  45. public static GUIContent distortionBlend = new GUIContent("Blend",
  46. "Controls how visible the distortion effect is. At 0, there’s no visible distortion. At 1, only the distortion effect is visible, not the background.");
  47. public static GUIContent VertexStreams = new GUIContent("Vertex Streams",
  48. "The vertex streams needed for this Material to function properly.");
  49. public static string streamPositionText = "Position (POSITION.xyz)";
  50. public static string streamNormalText = "Normal (NORMAL.xyz)";
  51. public static string streamColorText = "Color (COLOR.xyzw)";
  52. public static string streamUVText = "UV (TEXCOORD0.xy)";
  53. public static string streamUV2Text = "UV2 (TEXCOORD0.zw)";
  54. public static string streamAnimBlendText = "AnimBlend (TEXCOORD1.x)";
  55. public static string streamTangentText = "Tangent (TANGENT.xyzw)";
  56. public static GUIContent streamApplyToAllSystemsText = new GUIContent("Fix Now",
  57. "Apply the vertex stream layout to all Particle Systems using this material");
  58. public static string undoApplyCustomVertexStreams = L10n.Tr("Apply custom vertex streams from material");
  59. public static GUIStyle vertexStreamIcon = new GUIStyle();
  60. }
  61. private static ReorderableList vertexStreamList;
  62. public struct ParticleProperties
  63. {
  64. // Surface Option Props
  65. public MaterialProperty colorMode;
  66. // Advanced Props
  67. public MaterialProperty flipbookMode;
  68. public MaterialProperty softParticlesEnabled;
  69. public MaterialProperty cameraFadingEnabled;
  70. public MaterialProperty distortionEnabled;
  71. public MaterialProperty softParticlesNearFadeDistance;
  72. public MaterialProperty softParticlesFarFadeDistance;
  73. public MaterialProperty cameraNearFadeDistance;
  74. public MaterialProperty cameraFarFadeDistance;
  75. public MaterialProperty distortionBlend;
  76. public MaterialProperty distortionStrength;
  77. public ParticleProperties(MaterialProperty[] properties)
  78. {
  79. // Surface Option Props
  80. colorMode = BaseShaderGUI.FindProperty("_ColorMode", properties, false);
  81. // Advanced Props
  82. flipbookMode = BaseShaderGUI.FindProperty("_FlipbookBlending", properties);
  83. softParticlesEnabled = BaseShaderGUI.FindProperty("_SoftParticlesEnabled", properties);
  84. cameraFadingEnabled = BaseShaderGUI.FindProperty("_CameraFadingEnabled", properties);
  85. distortionEnabled = BaseShaderGUI.FindProperty("_DistortionEnabled", properties, false);
  86. softParticlesNearFadeDistance = BaseShaderGUI.FindProperty("_SoftParticlesNearFadeDistance", properties);
  87. softParticlesFarFadeDistance = BaseShaderGUI.FindProperty("_SoftParticlesFarFadeDistance", properties);
  88. cameraNearFadeDistance = BaseShaderGUI.FindProperty("_CameraNearFadeDistance", properties);
  89. cameraFarFadeDistance = BaseShaderGUI.FindProperty("_CameraFarFadeDistance", properties);
  90. distortionBlend = BaseShaderGUI.FindProperty("_DistortionBlend", properties, false);
  91. distortionStrength = BaseShaderGUI.FindProperty("_DistortionStrength", properties, false);
  92. }
  93. }
  94. public static void SetupMaterialWithColorMode(Material material)
  95. {
  96. var colorMode = (ColorMode) material.GetFloat("_ColorMode");
  97. switch (colorMode)
  98. {
  99. case ColorMode.Multiply:
  100. material.DisableKeyword("_COLOROVERLAY_ON");
  101. material.DisableKeyword("_COLORCOLOR_ON");
  102. material.DisableKeyword("_COLORADDSUBDIFF_ON");
  103. break;
  104. case ColorMode.Overlay:
  105. material.DisableKeyword("_COLORCOLOR_ON");
  106. material.DisableKeyword("_COLORADDSUBDIFF_ON");
  107. material.EnableKeyword("_COLOROVERLAY_ON");
  108. break;
  109. case ColorMode.Color:
  110. material.DisableKeyword("_COLOROVERLAY_ON");
  111. material.DisableKeyword("_COLORADDSUBDIFF_ON");
  112. material.EnableKeyword("_COLORCOLOR_ON");
  113. break;
  114. case ColorMode.Difference:
  115. material.DisableKeyword("_COLOROVERLAY_ON");
  116. material.DisableKeyword("_COLORCOLOR_ON");
  117. material.EnableKeyword("_COLORADDSUBDIFF_ON");
  118. material.SetVector("_BaseColorAddSubDiff", new Vector4(-1.0f, 1.0f, 0.0f, 0.0f));
  119. break;
  120. case ColorMode.Additive:
  121. material.DisableKeyword("_COLOROVERLAY_ON");
  122. material.DisableKeyword("_COLORCOLOR_ON");
  123. material.EnableKeyword("_COLORADDSUBDIFF_ON");
  124. material.SetVector("_BaseColorAddSubDiff", new Vector4(1.0f, 0.0f, 0.0f, 0.0f));
  125. break;
  126. case ColorMode.Subtractive:
  127. material.DisableKeyword("_COLOROVERLAY_ON");
  128. material.DisableKeyword("_COLORCOLOR_ON");
  129. material.EnableKeyword("_COLORADDSUBDIFF_ON");
  130. material.SetVector("_BaseColorAddSubDiff", new Vector4(-1.0f, 0.0f, 0.0f, 0.0f));
  131. break;
  132. }
  133. }
  134. public static void FadingOptions(Material material, MaterialEditor materialEditor, ParticleProperties properties)
  135. {
  136. // Z write doesn't work with fading
  137. bool hasZWrite = (material.GetInt("_ZWrite") != 0);
  138. if(!hasZWrite)
  139. {
  140. // Soft Particles
  141. {
  142. EditorGUI.showMixedValue = properties.softParticlesEnabled.hasMixedValue;
  143. var enabled = properties.softParticlesEnabled.floatValue;
  144. EditorGUI.BeginChangeCheck();
  145. enabled = EditorGUILayout.Toggle(Styles.softParticlesEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
  146. if (EditorGUI.EndChangeCheck())
  147. {
  148. materialEditor.RegisterPropertyChangeUndo("Soft Particles Enabled");
  149. properties.softParticlesEnabled.floatValue = enabled;
  150. }
  151. if (enabled >= 0.5f)
  152. {
  153. EditorGUI.indentLevel++;
  154. BaseShaderGUI.TwoFloatSingleLine(new GUIContent("Surface Fade"),
  155. properties.softParticlesNearFadeDistance,
  156. Styles.softParticlesNearFadeDistanceText,
  157. properties.softParticlesFarFadeDistance,
  158. Styles.softParticlesFarFadeDistanceText,
  159. materialEditor);
  160. EditorGUI.indentLevel--;
  161. }
  162. }
  163. // Camera Fading
  164. {
  165. EditorGUI.showMixedValue = properties.cameraFadingEnabled.hasMixedValue;
  166. var enabled = properties.cameraFadingEnabled.floatValue;
  167. EditorGUI.BeginChangeCheck();
  168. enabled = EditorGUILayout.Toggle(Styles.cameraFadingEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
  169. if (EditorGUI.EndChangeCheck())
  170. {
  171. materialEditor.RegisterPropertyChangeUndo("Camera Fading Enabled");
  172. properties.cameraFadingEnabled.floatValue = enabled;
  173. }
  174. if (enabled >= 0.5f)
  175. {
  176. EditorGUI.indentLevel++;
  177. BaseShaderGUI.TwoFloatSingleLine(new GUIContent("Distance"),
  178. properties.cameraNearFadeDistance,
  179. Styles.cameraNearFadeDistanceText,
  180. properties.cameraFarFadeDistance,
  181. Styles.cameraFarFadeDistanceText,
  182. materialEditor);
  183. EditorGUI.indentLevel--;
  184. }
  185. }
  186. // Distortion
  187. if (properties.distortionEnabled != null)
  188. {
  189. EditorGUI.showMixedValue = properties.distortionEnabled.hasMixedValue;
  190. var enabled = properties.distortionEnabled.floatValue;
  191. EditorGUI.BeginChangeCheck();
  192. enabled = EditorGUILayout.Toggle(Styles.distortionEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
  193. if (EditorGUI.EndChangeCheck())
  194. {
  195. materialEditor.RegisterPropertyChangeUndo("Distortion Enabled");
  196. properties.distortionEnabled.floatValue = enabled;
  197. }
  198. if (enabled >= 0.5f)
  199. {
  200. EditorGUI.indentLevel++;
  201. materialEditor.ShaderProperty(properties.distortionStrength, Styles.distortionStrength);
  202. EditorGUI.BeginChangeCheck();
  203. EditorGUI.showMixedValue = properties.distortionStrength.hasMixedValue;
  204. var blend = EditorGUILayout.Slider(Styles.distortionBlend, properties.distortionBlend.floatValue, 0f, 1f);
  205. if(EditorGUI.EndChangeCheck())
  206. properties.distortionBlend.floatValue = blend;
  207. EditorGUI.indentLevel--;
  208. }
  209. }
  210. EditorGUI.showMixedValue = false;
  211. }
  212. }
  213. public static void DoVertexStreamsArea(Material material, List<ParticleSystemRenderer> renderers, bool useLighting = false)
  214. {
  215. EditorGUILayout.Space();
  216. // Display list of streams required to make this shader work
  217. bool useNormalMap = false;
  218. bool useFlipbookBlending = (material.GetFloat("_FlipbookBlending") > 0.0f);
  219. if(material.HasProperty("_BumpMap"))
  220. useNormalMap = material.GetTexture("_BumpMap");
  221. // Build the list of expected vertex streams
  222. List<ParticleSystemVertexStream> streams = new List<ParticleSystemVertexStream>();
  223. List<string> streamList = new List<string>();
  224. streams.Add(ParticleSystemVertexStream.Position);
  225. streamList.Add(Styles.streamPositionText);
  226. if (useLighting || useNormalMap)
  227. {
  228. streams.Add(ParticleSystemVertexStream.Normal);
  229. streamList.Add(Styles.streamNormalText);
  230. if (useNormalMap)
  231. {
  232. streams.Add(ParticleSystemVertexStream.Tangent);
  233. streamList.Add(Styles.streamTangentText);
  234. }
  235. }
  236. streams.Add(ParticleSystemVertexStream.Color);
  237. streamList.Add(Styles.streamColorText);
  238. streams.Add(ParticleSystemVertexStream.UV);
  239. streamList.Add(Styles.streamUVText);
  240. if (useFlipbookBlending)
  241. {
  242. streams.Add(ParticleSystemVertexStream.UV2);
  243. streamList.Add(Styles.streamUV2Text);
  244. streams.Add(ParticleSystemVertexStream.AnimBlend);
  245. streamList.Add(Styles.streamAnimBlendText);
  246. }
  247. vertexStreamList = new ReorderableList(streamList, typeof(string), false, true, false, false);
  248. vertexStreamList.drawHeaderCallback = (Rect rect) => {
  249. EditorGUI.LabelField(rect, "Vertex Streams");
  250. };
  251. vertexStreamList.DoLayoutList();
  252. // Display a warning if any renderers have incorrect vertex streams
  253. string Warnings = "";
  254. List<ParticleSystemVertexStream> rendererStreams = new List<ParticleSystemVertexStream>();
  255. foreach (ParticleSystemRenderer renderer in renderers)
  256. {
  257. renderer.GetActiveVertexStreams(rendererStreams);
  258. if (!rendererStreams.SequenceEqual(streams))
  259. Warnings += "-" + renderer.name + "\n";
  260. }
  261. if (!string.IsNullOrEmpty(Warnings))
  262. {
  263. EditorGUILayout.HelpBox(
  264. "The following Particle System Renderers are using this material with incorrect Vertex Streams:\n" +
  265. Warnings, MessageType.Error, true);
  266. // Set the streams on all systems using this material
  267. if (GUILayout.Button(Styles.streamApplyToAllSystemsText, EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
  268. {
  269. Undo.RecordObjects(renderers.Where(r => r != null).ToArray(), Styles.undoApplyCustomVertexStreams);
  270. foreach (ParticleSystemRenderer renderer in renderers)
  271. {
  272. renderer.SetActiveVertexStreams(streams);
  273. }
  274. }
  275. }
  276. }
  277. public static void SetMaterialKeywords(Material material)
  278. {
  279. // Setup particle + material color blending
  280. SetupMaterialWithColorMode(material);
  281. // Is the material transparent, this is set in BaseShaderGUI
  282. bool isTransparent = material.GetTag("RenderType", false) == "Transparent";
  283. // Z write doesn't work with distortion/fading
  284. bool hasZWrite = (material.GetInt("_ZWrite") != 0);
  285. // Flipbook blending
  286. if (material.HasProperty("_FlipbookBlending"))
  287. {
  288. var useFlipbookBlending = (material.GetFloat("_FlipbookBlending") > 0.0f);
  289. CoreUtils.SetKeyword(material, "_FLIPBOOKBLENDING_ON", useFlipbookBlending);
  290. }
  291. // Soft particles
  292. var useSoftParticles = false;
  293. if (material.HasProperty("_SoftParticlesEnabled"))
  294. {
  295. useSoftParticles = (material.GetFloat("_SoftParticlesEnabled") > 0.0f && isTransparent);
  296. if (useSoftParticles)
  297. {
  298. var softParticlesNearFadeDistance = material.GetFloat("_SoftParticlesNearFadeDistance");
  299. var softParticlesFarFadeDistance = material.GetFloat("_SoftParticlesFarFadeDistance");
  300. // clamp values
  301. if (softParticlesNearFadeDistance < 0.0f)
  302. {
  303. softParticlesNearFadeDistance = 0.0f;
  304. material.SetFloat("_SoftParticlesNearFadeDistance", 0.0f);
  305. }
  306. if (softParticlesFarFadeDistance < 0.0f)
  307. {
  308. softParticlesFarFadeDistance = 0.0f;
  309. material.SetFloat("_SoftParticlesFarFadeDistance", 0.0f);
  310. }
  311. // set keywords
  312. material.SetVector("_SoftParticleFadeParams",
  313. new Vector4(softParticlesNearFadeDistance,
  314. 1.0f / (softParticlesFarFadeDistance - softParticlesNearFadeDistance), 0.0f, 0.0f));
  315. }
  316. else
  317. {
  318. material.SetVector("_SoftParticleFadeParams", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
  319. }
  320. CoreUtils.SetKeyword(material, "_SOFTPARTICLES_ON", useSoftParticles);
  321. }
  322. // Camera fading
  323. var useCameraFading = false;
  324. if (material.HasProperty("_CameraFadingEnabled") && isTransparent)
  325. {
  326. useCameraFading = (material.GetFloat("_CameraFadingEnabled") > 0.0f);
  327. if (useCameraFading)
  328. {
  329. var cameraNearFadeDistance = material.GetFloat("_CameraNearFadeDistance");
  330. var cameraFarFadeDistance = material.GetFloat("_CameraFarFadeDistance");
  331. // clamp values
  332. if (cameraNearFadeDistance < 0.0f)
  333. {
  334. cameraNearFadeDistance = 0.0f;
  335. material.SetFloat("_CameraNearFadeDistance", 0.0f);
  336. }
  337. if (cameraFarFadeDistance < 0.0f)
  338. {
  339. cameraFarFadeDistance = 0.0f;
  340. material.SetFloat("_CameraFarFadeDistance", 0.0f);
  341. }
  342. // set keywords
  343. material.SetVector("_CameraFadeParams",
  344. new Vector4(cameraNearFadeDistance, 1.0f / (cameraFarFadeDistance - cameraNearFadeDistance),
  345. 0.0f, 0.0f));
  346. }
  347. else
  348. {
  349. material.SetVector("_CameraFadeParams", new Vector4(0.0f, Mathf.Infinity, 0.0f, 0.0f));
  350. }
  351. }
  352. // Distortion
  353. if (material.HasProperty("_DistortionEnabled"))
  354. {
  355. var useDistortion = (material.GetFloat("_DistortionEnabled") > 0.0f) && isTransparent;
  356. CoreUtils.SetKeyword(material, "_DISTORTION_ON", useDistortion);
  357. if (useDistortion)
  358. material.SetFloat("_DistortionStrengthScaled", material.GetFloat("_DistortionStrength") * 0.1f);
  359. }
  360. var useFading = (useSoftParticles || useCameraFading) && !hasZWrite;
  361. CoreUtils.SetKeyword(material, "_FADING_ON", useFading);
  362. }
  363. }
  364. } // namespace UnityEditor