RainSplashRenderer.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Funly.SkyStudio
  5. {
  6. // Render ground rain splashes using GPU instancing and sprite sheets for performance.
  7. public class RainSplashRenderer : BaseSpriteInstancedRenderer
  8. {
  9. Camera m_DepthCamera;
  10. float[] m_StartSplashYPositions = new float[kArrayMaxSprites];
  11. float[] m_DepthUs = new float[kArrayMaxSprites];
  12. float[] m_DepthVs = new float[kArrayMaxSprites];
  13. // We sync these values from the sky profile.
  14. float m_SplashAreaStart;
  15. float m_SplashAreaLength;
  16. float m_SplashScale;
  17. float m_SplashScaleVarience;
  18. float m_SplashItensity;
  19. float m_SplashSurfaceOffset;
  20. SkyProfile m_SkyProfile;
  21. float m_TimeOfDay;
  22. RainSplashArtItem m_Style;
  23. Bounds m_Bounds = new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f));
  24. void Start()
  25. {
  26. // Verify GPU instancing is supported.
  27. if (SystemInfo.supportsInstancing == false) {
  28. Debug.LogError("Can't render rain splashes since GPU instancing is not supported on this platform.");
  29. enabled = false;
  30. return;
  31. }
  32. WeatherDepthCamera depthController = FindObjectOfType<WeatherDepthCamera>();
  33. if (depthController == null) {
  34. Debug.LogError("Can't generate splashes without a RainDepthCamera in the scene");
  35. enabled = false;
  36. return;
  37. }
  38. m_DepthCamera = depthController.GetComponent<Camera>();
  39. }
  40. protected override Bounds CalculateMeshBounds()
  41. {
  42. return m_Bounds;
  43. }
  44. // Construct the data for a single particle.
  45. protected override BaseSpriteItemData CreateSpriteItemData()
  46. {
  47. return new RainSplashData();
  48. }
  49. protected override bool IsRenderingEnabled()
  50. {
  51. if (m_SkyProfile == null) {
  52. return false;
  53. }
  54. if (m_SkyProfile.IsFeatureEnabled(ProfileFeatureKeys.RainSplashFeature) == false) {
  55. return false;
  56. }
  57. if (m_ViewerCamera == null) {
  58. Debug.LogError("Can't render ground raindrops since no active camera has the MainCamera tag applied.");
  59. return false;
  60. }
  61. return true;
  62. }
  63. // Ask the subclass how many new instances we should create this frame.
  64. protected override int GetNextSpawnCount()
  65. {
  66. int delta = maxSprites - m_Active.Count;
  67. return delta > 0 ? delta : 0;
  68. }
  69. // Select where the next sprite will be rendered at.
  70. protected override void CalculateSpriteTRS(BaseSpriteItemData data, out Vector3 spritePosition, out Quaternion spriteRotation, out Vector3 spriteScale)
  71. {
  72. // Create some variety in rain drop sizes.
  73. float minScale = m_SplashScale * (1.0f - m_SplashScaleVarience);
  74. float uniformScale = Random.Range(minScale, m_SplashScale);
  75. spritePosition = data.spritePosition;
  76. spriteRotation = Quaternion.identity;
  77. spriteScale = new Vector3(uniformScale, uniformScale, uniformScale);
  78. }
  79. // Configure a new sprite item data object properties, (could be new or recycled).
  80. protected override void ConfigureSpriteItemData(BaseSpriteItemData data)
  81. {
  82. data.spritePosition = CreateWorldSplashPoint();
  83. data.delay = Random.Range(0.0f, .5f);
  84. }
  85. // Setup any per-instance data you need to pass.
  86. protected override void PrepareDataArraysForRendering(int instanceId, BaseSpriteItemData data)
  87. {
  88. RainSplashData splash = data as RainSplashData;
  89. // We could probably move this into the shader to save some CPU calculations if necessary.
  90. Vector3 screenPoint = m_DepthCamera.WorldToScreenPoint(splash.spritePosition);
  91. Vector2 cameraUV = new Vector2(screenPoint.x / m_DepthCamera.pixelWidth, screenPoint.y / m_DepthCamera.pixelHeight);
  92. splash.depthTextureUV = cameraUV;
  93. m_StartSplashYPositions[instanceId] = splash.spritePosition.y;
  94. m_DepthUs[instanceId] = splash.depthTextureUV.x;
  95. m_DepthVs[instanceId] = splash.depthTextureUV.y;
  96. }
  97. protected override void PopulatePropertyBlockForRendering(ref MaterialPropertyBlock propertyBlock)
  98. {
  99. propertyBlock.SetFloat("_Intensity", m_SplashItensity);
  100. propertyBlock.SetFloatArray("_OverheadDepthU", m_DepthUs);
  101. propertyBlock.SetFloatArray("_OverheadDepthV", m_DepthVs);
  102. propertyBlock.SetFloatArray("_SplashStartYPosition", m_StartSplashYPositions);
  103. propertyBlock.SetFloat("_SplashGroundOffset", m_SplashSurfaceOffset);
  104. }
  105. public void UpdateForTimeOfDay(SkyProfile skyProfile, float timeOfDay, RainSplashArtItem style)
  106. {
  107. m_SkyProfile = skyProfile;
  108. m_TimeOfDay = timeOfDay;
  109. m_Style = style;
  110. if (m_SkyProfile == null) {
  111. return;
  112. }
  113. SyncDataFromSkyProfile();
  114. }
  115. void SyncDataFromSkyProfile()
  116. {
  117. maxSprites = (int)m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashMaxConcurrentKey, m_TimeOfDay);
  118. m_SplashAreaStart = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashAreaStartKey, m_TimeOfDay);
  119. m_SplashAreaLength = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashAreaLengthKey, m_TimeOfDay);
  120. m_SplashScale = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashScaleKey, m_TimeOfDay);
  121. m_SplashScaleVarience = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashScaleVarienceKey, m_TimeOfDay);
  122. m_SplashItensity = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashIntensityKey, m_TimeOfDay);
  123. m_SplashSurfaceOffset = m_SkyProfile.GetNumberPropertyValue(ProfilePropertyKeys.RainSplashSurfaceOffsetKey, m_TimeOfDay);
  124. m_SplashScale *= m_Style.scaleMultiplier;
  125. m_SplashItensity *= m_Style.intensityMultiplier;
  126. m_SpriteSheetLayout.columns = m_Style.columns;
  127. m_SpriteSheetLayout.rows = m_Style.rows;
  128. m_SpriteSheetLayout.frameCount = m_Style.totalFrames;
  129. m_SpriteSheetLayout.frameRate = m_Style.animateSpeed;
  130. m_SpriteTexture = m_Style.spriteSheetTexture;
  131. m_TintColor = m_Style.tintColor * m_SkyProfile.GetColorPropertyValue(ProfilePropertyKeys.RainSplashTintColorKey, m_TimeOfDay);
  132. modelMesh = m_Style.mesh;
  133. renderMaterial = new Material(m_Style.material);
  134. }
  135. // TODO - Expose this so clients can easily override placement of rain splashes.
  136. Vector3 CreateWorldSplashPoint()
  137. {
  138. float angle = Random.Range(0.0f, -170.0f);
  139. Vector3 randomDirection = Quaternion.Euler(new Vector3(0.0f, angle, 0.0f)) * Vector3.right;
  140. float radius = Random.Range(m_SplashAreaStart, m_SplashAreaStart + m_SplashAreaLength);
  141. Vector3 splashPoint = randomDirection.normalized * radius;
  142. return m_ViewerCamera.transform.TransformPoint(splashPoint);
  143. }
  144. }
  145. }