ParticleEffect.fx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //-----------------------------------------------------------------------------
  2. // ParticleEffect.fx
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. // Camera parameters.
  8. float4x4 View;
  9. float4x4 Projection;
  10. float2 ViewportScale;
  11. // The current time, in seconds.
  12. float CurrentTime;
  13. // Parameters describing how the particles animate.
  14. float Duration;
  15. float DurationRandomness;
  16. float3 Gravity;
  17. float EndVelocity;
  18. float4 MinColor;
  19. float4 MaxColor;
  20. // These float2 parameters describe the min and max of a range.
  21. // The actual value is chosen differently for each particle,
  22. // interpolating between x and y by some random amount.
  23. float2 RotateSpeed;
  24. float2 StartSize;
  25. float2 EndSize;
  26. // Particle texture and sampler.
  27. sampler TextureSampler : register(s0) =
  28. sampler_state
  29. {
  30. MinFilter = Linear;
  31. MagFilter = Linear;
  32. MipFilter = Point;
  33. AddressU = Clamp;
  34. AddressV = Clamp;
  35. };
  36. // Vertex shader input structure describes the start position and
  37. // velocity of the particle, and the time at which it was created,
  38. // along with some random values that affect its size and rotation.
  39. struct VertexShaderInput
  40. {
  41. float2 Corner : POSITION0;
  42. float3 Position : POSITION1;
  43. float3 Velocity : NORMAL0;
  44. float4 Random : COLOR0;
  45. float Time : TEXCOORD0;
  46. };
  47. // Vertex shader output structure specifies the position and color of the particle.
  48. struct VertexShaderOutput
  49. {
  50. float4 Position : POSITION0;
  51. float4 Color : COLOR0;
  52. float2 TextureCoordinate : COLOR1;
  53. };
  54. // Vertex shader helper for computing the position of a particle.
  55. float4 ComputeParticlePosition(float3 position, float3 velocity,
  56. float age, float normalizedAge)
  57. {
  58. float startVelocity = length(velocity);
  59. // Work out how fast the particle should be moving at the end of its life,
  60. // by applying a constant scaling factor to its starting velocity.
  61. float endVelocity = startVelocity * EndVelocity;
  62. // Our particles have constant acceleration, so given a starting velocity
  63. // S and ending velocity E, at time T their velocity should be S + (E-S)*T.
  64. // The particle position is the sum of this velocity over the range 0 to T.
  65. // To compute the position directly, we must integrate the velocity
  66. // equation. Integrating S + (E-S)*T for T produces S*T + (E-S)*T*T/2.
  67. float velocityIntegral = startVelocity * normalizedAge +
  68. (endVelocity - startVelocity) * normalizedAge *
  69. normalizedAge / 2;
  70. position += normalize(velocity) * velocityIntegral * Duration;
  71. // Apply the gravitational force.
  72. position += Gravity * age * normalizedAge;
  73. // Apply the camera view and projection transforms.
  74. return mul(mul(float4(position, 1), View), Projection);
  75. }
  76. // Vertex shader helper for computing the size of a particle.
  77. float ComputeParticleSize(float randomValue, float normalizedAge)
  78. {
  79. // Apply a random factor to make each particle a slightly different size.
  80. float startSize = lerp(StartSize.x, StartSize.y, randomValue);
  81. float endSize = lerp(EndSize.x, EndSize.y, randomValue);
  82. // Compute the actual size based on the age of the particle.
  83. float size = lerp(startSize, endSize, normalizedAge);
  84. // Project the size into screen coordinates.
  85. return size * Projection._m11;
  86. }
  87. // Vertex shader helper for computing the color of a particle.
  88. float4 ComputeParticleColor(float4 projectedPosition,
  89. float randomValue, float normalizedAge)
  90. {
  91. // Apply a random factor to make each particle a slightly different color.
  92. float4 color = lerp(MinColor, MaxColor, randomValue);
  93. // Fade the alpha based on the age of the particle. This curve is hard coded
  94. // to make the particle fade in fairly quickly, then fade out more slowly:
  95. // plot x*(1-x)*(1-x) for x=0:1 in a graphing program if you want to see what
  96. // this looks like. The 6.7 scaling factor normalizes the curve so the alpha
  97. // will reach all the way up to fully solid.
  98. color.a *= normalizedAge * (1-normalizedAge) * (1-normalizedAge) * 6.7;
  99. return color;
  100. }
  101. // Vertex shader helper for computing the rotation of a particle.
  102. float2x2 ComputeParticleRotation(float randomValue, float age)
  103. {
  104. // Apply a random factor to make each particle rotate at a different speed.
  105. float rotateSpeed = lerp(RotateSpeed.x, RotateSpeed.y, randomValue);
  106. float rotation = rotateSpeed * age;
  107. // Compute a 2x2 rotation matrix.
  108. float c = cos(rotation);
  109. float s = sin(rotation);
  110. return float2x2(c, -s, s, c);
  111. }
  112. // Custom vertex shader animates particles entirely on the GPU.
  113. VertexShaderOutput ParticleVertexShader(VertexShaderInput input)
  114. {
  115. VertexShaderOutput output;
  116. // Compute the age of the particle.
  117. float age = CurrentTime - input.Time;
  118. // Apply a random factor to make different particles age at different rates.
  119. age *= 1 + input.Random.x * DurationRandomness;
  120. // Normalize the age into the range zero to one.
  121. float normalizedAge = saturate(age / Duration);
  122. // Compute the particle position, size, color, and rotation.
  123. output.Position = ComputeParticlePosition(input.Position, input.Velocity,
  124. age, normalizedAge);
  125. float size = ComputeParticleSize(input.Random.y, normalizedAge);
  126. float2x2 rotation = ComputeParticleRotation(input.Random.w, age);
  127. output.Position.xy += mul(input.Corner, rotation) * size * ViewportScale;
  128. output.Color = ComputeParticleColor(output.Position, input.Random.z, normalizedAge);
  129. output.TextureCoordinate = (input.Corner + 1) / 2;
  130. return output;
  131. }
  132. // Pixel shader for drawing particles.
  133. float4 ParticlePixelShader(VertexShaderOutput input) : COLOR0
  134. {
  135. return tex2D(TextureSampler, input.TextureCoordinate) * input.Color;
  136. }
  137. // Effect technique for drawing particles.
  138. technique Particles
  139. {
  140. pass P0
  141. {
  142. #if SM4
  143. VertexShader = compile vs_4_0_level_9_1 ParticleVertexShader();
  144. PixelShader = compile ps_4_0_level_9_1 ParticlePixelShader();
  145. #elif SM3
  146. VertexShader = compile vs_3_0 ParticleVertexShader();
  147. PixelShader = compile ps_3_0 ParticlePixelShader();
  148. #else
  149. VertexShader = compile vs_2_0 ParticleVertexShader();
  150. PixelShader = compile ps_2_0 ParticlePixelShader();
  151. #endif
  152. }
  153. }