RainSplashInstanced.shader 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Upgrade NOTE: upgraded instancing buffer 'Props' to new syntax.
  2. // Author: Jason Ederle
  3. // Description: Sky Studio rain rendering.
  4. Shader "Funly/Sky Studio/Weather/Rain Splash Instanced"
  5. {
  6. Properties
  7. {
  8. [NoScaleOffset] _SpriteSheetTex ("Sprite Texture", 2D) = "white" {}
  9. _SpriteColumnCount ("Sprite Columns", int) = 1
  10. _SpriteRowCount ("Sprite Rows", int) = 1
  11. _SpriteItemCount ("Sprite Total Items", int) = 1
  12. _AnimationSpeed ("Animation Speed", int) = 25
  13. _Intensity ("Intensity", Range(0, 1)) = .7
  14. _TintColor("Tint Color", Color) = (1, 1, 1, 1)
  15. }
  16. SubShader
  17. {
  18. Tags { "RenderType"="Transparent" "Queue"="Transparent" }
  19. LOD 100
  20. Blend OneMinusDstColor One
  21. Cull Back
  22. Pass
  23. {
  24. CGPROGRAM
  25. #pragma target 3.0
  26. #pragma vertex vert
  27. #pragma fragment frag
  28. #pragma multi_compile_instancing
  29. #include "UnityCG.cginc"
  30. struct appdata
  31. {
  32. float4 vertex : POSITION;
  33. float2 uv : TEXCOORD0;
  34. UNITY_VERTEX_INPUT_INSTANCE_ID
  35. };
  36. struct v2f
  37. {
  38. float2 uv : TEXCOORD0;
  39. float4 vertex : SV_POSITION;
  40. float isOverSurface: TEXCOORD1;
  41. UNITY_VERTEX_INPUT_INSTANCE_ID
  42. };
  43. sampler2D _SpriteSheetTex;
  44. sampler2D _OverheadDepthTex;
  45. float4 _OverheadDepthPosition;
  46. float _OverheadDepthNearClip;
  47. float _OverheadDepthFarClip;
  48. float4 _TintColor;
  49. int _SpriteColumnCount;
  50. int _SpriteRowCount;
  51. int _SpriteItemCount;
  52. int _AnimationSpeed;
  53. float _Intensity;
  54. float _SplashGroundOffset;
  55. float _Scale;
  56. UNITY_INSTANCING_BUFFER_START(Props)
  57. UNITY_DEFINE_INSTANCED_PROP(float, _StartTime)
  58. #define _StartTime_arr Props
  59. UNITY_DEFINE_INSTANCED_PROP(float, _EndTime)
  60. #define _EndTime_arr Props
  61. UNITY_DEFINE_INSTANCED_PROP(float, _OverheadDepthU)
  62. #define _OverheadDepthU_arr Props
  63. UNITY_DEFINE_INSTANCED_PROP(float, _OverheadDepthV)
  64. #define _OverheadDepthV_arr Props
  65. UNITY_DEFINE_INSTANCED_PROP(float, _SplashStartYPosition)
  66. #define _SplashStartYPosition_arr Props
  67. UNITY_INSTANCING_BUFFER_END(Props)
  68. int GetSpriteTargetIndex(int itemCount, int animationSpeed, float startTime) {
  69. float delta = _Time.y - startTime;
  70. float timePerFrame = 1.0f / _AnimationSpeed;
  71. int frameIndex = (int)(delta / timePerFrame);
  72. return clamp(frameIndex, 0, _SpriteItemCount - 1);
  73. }
  74. float2 GetSpriteItemSize(float2 dimensions) {
  75. return float2(1.0f / dimensions.x, (1.0f / dimensions.x) * (dimensions.x / dimensions.y));
  76. }
  77. float2 GetSpriteSheetCoords(float2 uv, float2 dimensions, int targetFrameIndex, float2 itemSize, int numItems) {
  78. int rows = dimensions.y;
  79. int columns = dimensions.x;
  80. float2 scaledUV = float2(uv.x * itemSize.x, uv.y * itemSize.y);
  81. float2 offset = float2(
  82. (int)abs(targetFrameIndex) % (int)abs(columns) * itemSize.x,
  83. ((rows - 1) - (targetFrameIndex / (int)abs(columns))) * itemSize.y);
  84. return scaledUV + offset;
  85. }
  86. float2 GetAnimatedSpriteCoords(float2 uv, float startTime) {
  87. int spriteTileIndex = GetSpriteTargetIndex(_SpriteItemCount, _AnimationSpeed, startTime);
  88. float2 dimensions = float2(_SpriteColumnCount, _SpriteRowCount);
  89. float2 itemSize = GetSpriteItemSize(dimensions);
  90. return GetSpriteSheetCoords(uv, dimensions, spriteTileIndex, itemSize, _SpriteItemCount);
  91. }
  92. // Get a normal ranged value in [-1,1] range from a 0-1 percent value.
  93. float GetNormalRangeFromPercent(float percent) {
  94. return -1.0f + (2.0f * percent);
  95. }
  96. float3 GetDirectionFromPercent(float3 percentDir) {
  97. return float3(
  98. GetNormalRangeFromPercent(percentDir.x),
  99. GetNormalRangeFromPercent(percentDir.y),
  100. GetNormalRangeFromPercent(percentDir.z));
  101. }
  102. v2f vert (appdata v)
  103. {
  104. v2f o;
  105. UNITY_SETUP_INSTANCE_ID(v);
  106. UNITY_TRANSFER_INSTANCE_ID(v, o);
  107. float2 depthUV = float2(UNITY_ACCESS_INSTANCED_PROP(_OverheadDepthU_arr, _OverheadDepthU), UNITY_ACCESS_INSTANCED_PROP(_OverheadDepthV_arr, _OverheadDepthV));
  108. float4 checkUV = float4(depthUV, 0.0f, 0.0f);
  109. float4 overInfo = tex2Dlod(_OverheadDepthTex, checkUV);
  110. float depthValue = overInfo.a;
  111. float distanceFromCamera = _OverheadDepthNearClip + _OverheadDepthFarClip * depthValue;
  112. float4 worldPos = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0f));
  113. // BEGIN TESTING.
  114. float3 vertex = v.vertex.xyz;
  115. float3 surfaceNormal = GetDirectionFromPercent(overInfo.xyz);
  116. float3 up = normalize(surfaceNormal);
  117. float3 forward = normalize(cross(up, float3(1.0f, 0.0f, 0.0f)));
  118. float3 right = normalize(cross(up, forward));
  119. // Extract the original scale from the right axis vector.
  120. float scale = length(float3(unity_ObjectToWorld[0][0], unity_ObjectToWorld[0][1], unity_ObjectToWorld[0][1]));
  121. // Restore the scale values.
  122. up *= scale;
  123. forward *= scale;
  124. right *= scale;
  125. float4x4 objToWorld = unity_ObjectToWorld;
  126. objToWorld[0][0] = right.x;
  127. objToWorld[0][1] = right.y;
  128. objToWorld[0][2] = right.z;
  129. objToWorld[1][0] = up.x;
  130. objToWorld[1][1] = up.y;
  131. objToWorld[1][2] = up.z;
  132. objToWorld[2][0] = forward.x;
  133. objToWorld[2][1] = forward.y;
  134. objToWorld[2][2] = forward.z;
  135. worldPos = mul(objToWorld, float4(vertex, 1.0f));
  136. // END TESTING
  137. //worldPos = mul(unity_ObjectToWorld, float4(vertex.xyz, 1.0f));
  138. float adjustedOrigin = _OverheadDepthPosition.y - distanceFromCamera;
  139. worldPos.y += adjustedOrigin - UNITY_ACCESS_INSTANCED_PROP(_SplashStartYPosition_arr, _SplashStartYPosition);
  140. worldPos.xyz = worldPos.xyz + (surfaceNormal * _SplashGroundOffset);
  141. o.vertex = mul(UNITY_MATRIX_VP, worldPos);
  142. // Easy way to detect no collision is that empty fill color sets -1,-1,-1 which isn't normalized length of 1.
  143. o.isOverSurface = step(length(surfaceNormal), 1.1f) - .5f;
  144. o.uv = v.uv;
  145. return o;
  146. }
  147. fixed4 frag (v2f i) : SV_Target
  148. {
  149. UNITY_SETUP_INSTANCE_ID(i);
  150. clip(i.isOverSurface);
  151. float startTime = UNITY_ACCESS_INSTANCED_PROP(_StartTime_arr, _StartTime);
  152. float endTime = UNITY_ACCESS_INSTANCED_PROP(_EndTime_arr, _EndTime);
  153. float2 spriteUV = saturate(GetAnimatedSpriteCoords(i.uv, startTime));
  154. fixed4 spriteColor = tex2D(_SpriteSheetTex, spriteUV) * _Intensity * _TintColor;
  155. // Go transparent if the sprite completed its time loop.
  156. return spriteColor * step(_Time.y, endTime);
  157. }
  158. ENDCG
  159. }
  160. }
  161. FallBack "Unlit/Color"
  162. }