ParticleEffect.fx 6.4 KB

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