VFX.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Serialization;
  5. #if MATHEMATICS
  6. using Unity.Mathematics;
  7. #endif
  8. #if VFX_GRAPH
  9. using UnityEngine.VFX;
  10. #endif
  11. namespace sc.modeling.water.common.runtime
  12. {
  13. public static class VFX
  14. {
  15. public const string DEFAULT_EFFECT_GUID = "e4f6c7bafe287f84fa437a2c93276b5a";
  16. private const int MAX_EMITTERS = 16384;
  17. private static readonly Vector3 BOUNDS_PADDING = Vector3.one * 2f;
  18. #if MATHEMATICS
  19. public struct Emitter
  20. {
  21. /// <summary>
  22. /// Position in local-space of VFX Graph
  23. /// </summary>
  24. public float3 position;
  25. /// <summary>
  26. /// Velocity vector in local-space
  27. /// </summary>
  28. public float3 velocity;
  29. }
  30. [Serializable]
  31. public class PointCache
  32. {
  33. [SerializeField]
  34. public Texture2D positions;
  35. [SerializeField]
  36. public Texture2D velocities;
  37. public Bounds volumeBounds;
  38. private const string BoundsCenter = "Bounds Center";
  39. private static int BoundsCenterID = Shader.PropertyToID(BoundsCenter);
  40. private const string BoundsSize = "Bounds Size";
  41. private static int BoundsSizeID = Shader.PropertyToID(BoundsSize);
  42. private const string EmitterPositionsName = "Emitter Positions";
  43. private static int EmitterPositionsID = Shader.PropertyToID(EmitterPositionsName);
  44. private const string EmitterVelocitesName = "Emitter Velocity";
  45. private static int EmitterVelocitesID = Shader.PropertyToID(EmitterVelocitesName);
  46. public void SetData(List<Emitter> emitters, Bounds bounds)
  47. {
  48. if (emitters.Count == 0)
  49. {
  50. positions = Texture2D.blackTexture;
  51. velocities = Texture2D.blackTexture;
  52. return;
  53. }
  54. this.volumeBounds = bounds;
  55. if (emitters.Count-1 >= MAX_EMITTERS)
  56. {
  57. throw new Exception($"Maximum amount of particle emitters exceeded ({MAX_EMITTERS}). Change the spawning criteria so fewer emitters are created. Such as increasing distances, or using multiple components for different sections of the river.");
  58. }
  59. var emitterCount = math.clamp(emitters.Count, 1, MAX_EMITTERS);
  60. if (positions == null || positions.width != emitterCount)
  61. {
  62. positions = new Texture2D(emitterCount, 1, TextureFormat.RGBAFloat, false, true);
  63. positions.wrapMode = TextureWrapMode.Repeat;
  64. positions.name = $"Emitter Positions";
  65. }
  66. if (velocities == null || velocities.width != emitterCount)
  67. {
  68. velocities = new Texture2D(emitterCount, 1, TextureFormat.RGBAFloat, false, true);
  69. velocities.wrapMode = TextureWrapMode.Repeat;
  70. velocities.name = $"Emitter Velocity";
  71. }
  72. for (int i = 0; i < emitterCount; i++)
  73. {
  74. positions.SetPixel(i, 0, new Color(emitters[i].position.x, emitters[i].position.y, emitters[i].position.z, 1f));
  75. velocities.SetPixel(i, 0, new Color(emitters[i].velocity.x, emitters[i].velocity.y, emitters[i].velocity.z, 1f));
  76. }
  77. positions.Apply(false);
  78. velocities.Apply(false);
  79. }
  80. #if VFX_GRAPH
  81. public void ApplyToEffect(VisualEffect effect, bool clear = false)
  82. {
  83. if (effect && effect.visualEffectAsset)
  84. {
  85. if (effect.HasTexture(EmitterPositionsID))
  86. {
  87. //Note: A bug introduces in 2022.3 requires resetting the override state before a texture assignment.
  88. effect.ResetOverride(EmitterPositionsID);
  89. effect.SetTexture(EmitterPositionsID, clear || positions == null ? Texture2D.blackTexture : positions);
  90. effect.ResetOverride(EmitterVelocitesID);
  91. effect.SetTexture(EmitterVelocitesID, clear || velocities == null ? Texture2D.blackTexture : velocities);
  92. effect.ResetOverride(BoundsCenter);
  93. effect.SetVector3(BoundsCenterID, volumeBounds.center);
  94. effect.ResetOverride(BoundsSize);
  95. effect.SetVector3(BoundsSizeID, volumeBounds.size + BOUNDS_PADDING);
  96. }
  97. else
  98. {
  99. throw new Exception($"Failed to generate emitters. The VFX Graph \"{effect.visualEffectAsset.name}\" rendering output or point cache input is missing. " +
  100. $"This graph was constructed for the Universal Render Pipeline, it was likely imported without URP being installed. If you believe this is in error, open up the graph and recompile it.");
  101. }
  102. }
  103. }
  104. #endif
  105. #if VFX_GRAPH
  106. public static bool IsValidTargetEffect(VisualEffect effect)
  107. {
  108. if (effect && effect.visualEffectAsset)
  109. {
  110. /*
  111. List<VFXExposedProperty> props = new List<VFXExposedProperty>();
  112. targetEffect.visualEffectAsset.GetExposedProperties(props);
  113. Debug.Log($"Exposed properties: {props.Count}");
  114. foreach (var prop in props)
  115. {
  116. Debug.Log(prop.name);
  117. }
  118. */
  119. return effect.HasTexture(EmitterPositionsID);
  120. }
  121. return false;
  122. }
  123. #endif
  124. }
  125. #endif
  126. #if VFX_GRAPH
  127. public static void SetSortingOrder(VisualEffect effect, int sortingOrder)
  128. {
  129. if (effect)
  130. {
  131. Renderer vfxRenderer = effect.GetComponent<Renderer>();
  132. vfxRenderer.sortingOrder = sortingOrder;
  133. }
  134. }
  135. #endif
  136. }
  137. }