2
0

GpuParticleSimulate.bsl 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "$ENGINE$/GpuParticleTileVertex.bslinc"
  2. #include "$ENGINE$/PerCameraData.bslinc"
  3. #include "$ENGINE$/PerObjectData.bslinc"
  4. shader GpuParticleSimulate
  5. {
  6. variations
  7. {
  8. DEPTH_COLLISIONS = { 0, 1, 2 };
  9. };
  10. mixin GpuParticleTileVertex;
  11. #if DEPTH_COLLISIONS
  12. mixin PerCameraData;
  13. mixin PerObjectData;
  14. #endif
  15. code
  16. {
  17. Texture2D gPosAndTimeTex;
  18. [alias(gPosAndTimeTex)]
  19. SamplerState gPosAndTimeSampler
  20. {
  21. Filter = MIN_MAG_MIP_POINT;
  22. };
  23. Texture2D gVelocityTex;
  24. [alias(gVelocityTex)]
  25. SamplerState gVelocitySampler
  26. {
  27. Filter = MIN_MAG_MIP_POINT;
  28. };
  29. Texture3D gVectorFieldTex;
  30. [alias(gVectorFieldTex)]
  31. SamplerState gVectorFieldSampler
  32. {
  33. AddressU = CLAMP;
  34. AddressV = CLAMP;
  35. AddressW = CLAMP;
  36. };
  37. #if DEPTH_COLLISIONS
  38. Texture2D gDepthTex;
  39. Texture2D gNormalsTex;
  40. [alias(gDepthTex)]
  41. SamplerState gDepthSampler
  42. {
  43. Filter = MIN_MAG_MIP_POINT;
  44. };
  45. [alias(gNormalsTex)]
  46. SamplerState gNormalsSampler;
  47. Texture2D gSizeRotationTex;
  48. [alias(gSizeRotationTex)]
  49. SamplerState gSizeRotationSampler
  50. {
  51. Filter = MIN_MAG_MIP_POINT;
  52. };
  53. Texture2D gCurvesTex;
  54. [alias(gCurvesTex)]
  55. SamplerState gCurvesSampler;
  56. #endif
  57. cbuffer VectorFieldParams
  58. {
  59. float3 gFieldBounds;
  60. float gFieldIntensity;
  61. float3 gFieldTiling;
  62. float gFieldTightness;
  63. float4x4 gWorldToField;
  64. float3x3 gFieldToWorld;
  65. };
  66. cbuffer Params
  67. {
  68. uint gNumVectorFields;
  69. uint gNumIterations;
  70. float gDT;
  71. float gDrag;
  72. float3 gAcceleration;
  73. };
  74. #if DEPTH_COLLISIONS
  75. cbuffer DepthCollisionParams
  76. {
  77. float gCollisionRange;
  78. float gRestitution;
  79. float gDampening;
  80. float gCollisionRadiusScale;
  81. float2 gSizeScaleCurveOffset;
  82. float2 gSizeScaleCurveScale;
  83. };
  84. void integrateWithDepthCollisions(
  85. float3 inPosition, float3 inVelocity,
  86. out float3 outPosition, out float3 outVelocity,
  87. float dt,
  88. float3 acceleration, float radius)
  89. {
  90. // Integrate as normal
  91. float3 deltaPosPerSec = inVelocity + acceleration * 0.5f;
  92. float3 deltaPos = deltaPosPerSec * dt;
  93. outPosition = inPosition + deltaPos;
  94. outVelocity = inVelocity + acceleration;
  95. // Determine potential collision point (edge of the particle sphere in the direction of travel)
  96. float3 dirOffset = normalize(deltaPos) * radius;
  97. float3 offsetPointWrld = inPosition + dirOffset;
  98. float4 offsetPointClip = mul(gMatViewProj, float4(offsetPointWrld, 1.0f));
  99. float2 offsetPointNdc = offsetPointClip.xy / offsetPointClip.w;
  100. // Potential collision point out of view
  101. if(any(abs(offsetPointNdc.xy) > float2(1.0f, 1.0f)))
  102. return;
  103. float2 offsetPointUV = NDCToUV(offsetPointNdc);
  104. float sampledDepth = convertFromDeviceZ(gDepthTex.Sample(gDepthSampler, offsetPointUV).r);
  105. // Potential collision point too far away from sampled depth
  106. if(abs(-offsetPointClip.w - sampledDepth) >= gCollisionRange)
  107. return;
  108. float3 hitPointWrld = NDCToWorld(offsetPointNdc.xy, sampledDepth);
  109. float3 hitPointNormal = gNormalsTex.Sample(gNormalsSampler, offsetPointUV).xyz * 2.0f - 1.0f;
  110. float4 hitPlane = float4(hitPointNormal, dot(hitPointNormal, hitPointWrld));
  111. float speedToPlane = dot(hitPlane.xyz, deltaPos);
  112. // Moving away from the collision plane
  113. if(speedToPlane >= 0.0f)
  114. return;
  115. // Check if capsule (sweeped sphere) intersects the plane
  116. float distToOldPos = dot(inPosition, hitPlane.xyz) - hitPlane.w;
  117. float distToNewPos = dot(outPosition, hitPlane.xyz) - hitPlane.w;
  118. if(distToOldPos >= -radius && distToNewPos <= radius)
  119. {
  120. // Separate velocity into perpendicular and tangent velocity
  121. // Note: This is using mid-velocity for both position and velocity integration. Velocity integration should
  122. // should use the full acceleration value, but we'll keep it imprecise to avoid another calculation.
  123. float3 perpVelocity = dot(deltaPosPerSec, hitPlane.xyz) * hitPlane.xyz;
  124. float3 tanVelocity = deltaPosPerSec - perpVelocity;
  125. outVelocity = (1.0f - gDampening) * tanVelocity - gRestitution * perpVelocity;
  126. float t = (distToOldPos - radius) / -speedToPlane;
  127. outPosition = inPosition + deltaPos * t + outVelocity * (1.0f - t) * dt;
  128. }
  129. }
  130. #endif
  131. float3 evaluateVectorField(float3 pos, float scale, out float3 velocity, out float tightness)
  132. {
  133. if(gNumVectorFields == 0)
  134. {
  135. velocity = 0.0f;
  136. tightness = 0.0f;
  137. return 0.0f;
  138. }
  139. float3 uv = mul(gWorldToField, float4(pos, 1.0f)).xyz;
  140. uv -= floor(uv * gFieldTiling);
  141. float3 smp = gVectorFieldTex.Sample(gVectorFieldSampler, uv);
  142. smp = mul(gFieldToWorld, smp);
  143. velocity = gFieldIntensity * gFieldTightness * smp;
  144. tightness = gFieldTightness;
  145. return gFieldIntensity * smp;
  146. }
  147. void fsmain(VStoFS input,
  148. out float4 outPosAndTime : SV_Target0,
  149. out float4 outVelocityAndTimeScale : SV_Target1)
  150. {
  151. float4 posAndTime = gPosAndTimeTex.Sample(gPosAndTimeSampler, input.uv0);
  152. float4 velocityAndTimeScale = gVelocityTex.Sample(gVelocitySampler, input.uv0);
  153. float3 position = posAndTime.xyz;
  154. float time = posAndTime.w;
  155. float3 velocity = velocityAndTimeScale.xyz;
  156. float timeScale = velocityAndTimeScale.w;
  157. for(uint i = 0; i < gNumIterations; i++)
  158. {
  159. time += gDT * timeScale;
  160. // Constant acceleration
  161. float3 totalForce = gAcceleration;
  162. // Evaluate vector field
  163. float3 fieldVelocity;
  164. float fieldTightness;
  165. totalForce += evaluateVectorField(posAndTime.xyz, 1.0f, fieldVelocity, fieldTightness);
  166. velocity = lerp(velocity, fieldVelocity, fieldTightness);
  167. // Drag
  168. totalForce -= gDrag * velocity;
  169. // Integrate
  170. float3 acceleration = totalForce * gDT;
  171. #if DEPTH_COLLISIONS
  172. float2 size = gSizeRotationTex.Sample(gSizeRotationSampler, input.uv0).xy;
  173. float2 sizeScaleCurveUV = gSizeScaleCurveOffset + time * gSizeScaleCurveScale;
  174. float2 sizeScale = gCurvesTex.Sample(gCurvesSampler, sizeScaleCurveUV, 0).xy;
  175. // TODO - Apply world transform scale
  176. size *= 0.5f * sizeScale;
  177. float collisionRadius = min(size.x, size.y) * gCollisionRadiusScale;
  178. #if DEPTH_COLLISIONS == 2
  179. position = mul(gMatWorld, float4(position, 1.0f)).xyz;
  180. velocity = mul(gMatWorld, float4(velocity, 0.0f)).xyz;
  181. #endif
  182. float3 outPosition;
  183. float3 outVelocity;
  184. integrateWithDepthCollisions(
  185. position, velocity,
  186. outPosition, outVelocity,
  187. gDT,
  188. acceleration, collisionRadius);
  189. #if DEPTH_COLLISIONS == 2
  190. position = mul(gMatInvWorld, float4(outPosition, 1.0f)).xyz;
  191. velocity = mul(gMatInvWorld, float4(outVelocity, 0.0f)).xyz;
  192. #else
  193. position = outPosition;
  194. velocity = outVelocity;
  195. #endif
  196. #else
  197. position += (velocity + acceleration * 0.5f) * gDT;
  198. velocity += acceleration;
  199. #endif
  200. }
  201. outPosAndTime.xyz = position;
  202. outPosAndTime.w = time;
  203. outVelocityAndTimeScale.xyz = velocity;
  204. outVelocityAndTimeScale.w = timeScale;
  205. }
  206. };
  207. };