GPUParticleDistortion.fx 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //////////////////////////////////////////////////////////////////////////////
  2. // ©2005 Electronic Arts Inc
  3. //
  4. // GPU vertex particle FX Shader
  5. //////////////////////////////////////////////////////////////////////////////
  6. #include "Common.fxh"
  7. #include "CommonParticle.fxh"
  8. int _SasGlobal : SasGlobal
  9. <
  10. string UIWidget = "None";
  11. int3 SasVersion = int3(1, 0, 0);
  12. string RenderBin = "Distorter";
  13. > = 0;
  14. SAMPLER_2D_BEGIN( NormalTexture,
  15. string UIWidget = "None";
  16. string SasBindAddress = "Particle.Draw.Texture";
  17. )
  18. MinFilter = Linear;
  19. MagFilter = Linear;
  20. MipFilter = Linear;
  21. AddressU = Wrap;
  22. AddressV = Wrap;
  23. SAMPLER_2D_END
  24. // Used to see where the particle volume intersects an object.
  25. SAMPLER_2D_BEGIN( DepthTexture,
  26. string SasBindAddress = "WW3D.DepthTexture";
  27. )
  28. MinFilter = Linear;
  29. MagFilter = Linear;
  30. MipFilter = Point;
  31. AddressU = Clamp;
  32. AddressV = Clamp;
  33. SAMPLER_2D_END
  34. //--------------------------------- GENERAL STUFF --------------------------------------
  35. bool ShouldDrawParticleSoft
  36. <
  37. string UIWidget = "None";
  38. string SasBindAddress = "Particle.Draw.ShouldDrawParticleSoft";
  39. > = false;
  40. // Transformations
  41. float4x4 WorldView : WorldView;
  42. float4x4 Projection: Projection;
  43. float4x4 WorldViewProjection : WorldViewProjection;
  44. float4x3 View : View;
  45. float4x3 World : World;
  46. float4x4 ProjectionI : ProjectionInverse;
  47. // Time (ie. material is animated)
  48. float Time : Time;
  49. // ----------------------------------------------------------------------------
  50. // SHADER: Default
  51. // ----------------------------------------------------------------------------
  52. struct ParticleVSOutput
  53. {
  54. float4 Position : POSITION;
  55. float2 ParticleTexCoord : TEXCOORD0;
  56. float4 Color : TEXCOORD1; // Not in color register to have increased range from -1 to 1
  57. float3x3 TangentToViewSpace : TEXCOORD2;
  58. float4 NDCPosition : TEXCOORD5;
  59. float2 ZPositions : TEXCOORD6; // x is the particle z position, y is the ViewEyeDirection z component.
  60. };
  61. // Making this value smaller will increase the size of the transparent edge where
  62. // the particle intersects the background.
  63. #define PARTICLE_VOLUME_SCALE 5
  64. // ----------------------------------------------------------------------------
  65. ParticleVSOutput ParticleVertexShader(
  66. float4 StartPositionLifeInFrames : POSITION,
  67. float4 StartVelocityCreationFrame : TEXCOORD0,
  68. float2 SeedAndIndex : TEXCOORD1)
  69. {
  70. ParticleVSOutput Out;
  71. // decode vertex data
  72. float3 StartPosition = StartPositionLifeInFrames.xyz;
  73. float LifeInFrames = StartPositionLifeInFrames.w;
  74. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  75. float CreationFrame = StartVelocityCreationFrame.w;
  76. float Seed = SeedAndIndex.x;
  77. float Index = SeedAndIndex.y;
  78. // particle system works with frames, so first convert time to frame
  79. // rather than converting everything else to time
  80. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  81. // first eliminate dead particles
  82. if (age > LifeInFrames)
  83. {
  84. Index = 0;
  85. }
  86. float relativeAge = age / LifeInFrames;
  87. float3 particlePosition;
  88. float size;
  89. float2x2 zRotationMatrix;
  90. Particle_ComputePhysics(particlePosition, size, zRotationMatrix,
  91. age, StartPosition, StartVelocity, Seed);
  92. // Calculate vertex position
  93. float2 vertexCorner = VertexCorners[Index];
  94. float2 relativeCornerPos = mul(vertexCorner, zRotationMatrix);
  95. float3 xVector = float3( View[0][0], View[1][0], View[2][0] );
  96. float3 zVector = float3( View[0][1], View[1][1], View[2][1] );
  97. float3 cornerPosition = particlePosition + size * (relativeCornerPos.x * xVector + relativeCornerPos.y * zVector);
  98. Out.Position = mul(float4(cornerPosition, 1), WorldViewProjection);
  99. //zVector = -zVector;
  100. float3 Normal = cross(xVector, zVector);
  101. float3 worldNormal = normalize(mul(Normal, (float3x3)World));
  102. float3 worldTangent = -zVector;
  103. float3 worldBinormal = -xVector; // This is inverted to what the normal mapping particles do as screen space xy is upside down otherwise
  104. float3x3 zRotation3D = float3x3(float3(zRotationMatrix[0], 0), float3(zRotationMatrix[1], 0), float3(0, 0, 1));
  105. // Build 3x3 tranform from tangent to world space
  106. float3x3 tangentToWorldSpace = mul(transpose(zRotation3D), float3x3(-worldBinormal, -worldTangent, worldNormal));
  107. Out.TangentToViewSpace = mul(tangentToWorldSpace, (float3x3)View);
  108. // Texture coordinate
  109. float randomIndex = GetRandomFloatValue(float2(0.0f, 1.0f), Seed, 7) * Draw.VideoTex_NumPerRow_LastFrame_SingleRow_isRand.y;
  110. randomIndex -= frac(randomIndex);
  111. float currentTexFrame = age * Draw.SpeedMultiplier + randomIndex;
  112. float2 texCoord = GetVertexTexCoord(vertexCorner);
  113. Out.ParticleTexCoord = Particle_ComputeVideoTextureDefault(currentTexFrame, texCoord);
  114. // Convert the particle position into view space so that we can get the distance
  115. // between the particle and the background.
  116. float particleSize = size / PARTICLE_VOLUME_SCALE;
  117. float4 particlePosView = mul(float4(cornerPosition, 1), WorldView);
  118. Out.ZPositions.x = particlePosView.z / particleSize;
  119. // Finish projecting the position.
  120. float4 ndcPos = mul(particlePosView, Projection);
  121. Out.Position = ndcPos;
  122. Out.NDCPosition = ndcPos;
  123. // Convert the position into a view vector to the far plane.
  124. float4 screenFarPlanePosition = float4(ndcPos.xy, 1, 1);
  125. float4 viewFarPlanePosition4 = mul(screenFarPlanePosition, ProjectionI);
  126. float3 viewFarPlanePosition = viewFarPlanePosition4.xyz / viewFarPlanePosition4.w;
  127. // We don't really want a vector to the far plane. We want the vector with a z length of 1,
  128. // so that we know how much in x-y we need to step per z-depth that we get from the depth texture.
  129. Out.ZPositions.y = (viewFarPlanePosition.z / viewFarPlanePosition.z) / particleSize;
  130. // compute color
  131. float4 color = Particle_ComputeColor(relativeAge, Seed, true);
  132. color.xyz = color.xyz * 2.0 - 1.0; // Unpack to treat the color as normal
  133. Out.Color = color;
  134. return Out;
  135. }
  136. // ----------------------------------------------------------------------------
  137. float4 SoftParticlePixelShader(ParticleVSOutput In, uniform bool shouldDrawParticleSoft) COLORTARGET
  138. {
  139. float4 normalMapSample = tex2D( SAMPLER(NormalTexture), In.ParticleTexCoord);
  140. // Get bump map normal
  141. float3 bumpNormal = normalMapSample.xyz * 2.0 - 1.0;
  142. bumpNormal = normalize(bumpNormal);
  143. float3 normal = mul(bumpNormal, In.TangentToViewSpace);
  144. float4 color = float4(In.Color.xyz * normal * 0.5 + 0.5, In.Color.w * normalMapSample.w);
  145. if (shouldDrawParticleSoft)
  146. {
  147. float3 ndcPosition = In.NDCPosition.xyz / In.NDCPosition.w;
  148. // Convert the position into texture space then grab the depth value from the
  149. // depth texture. Then, move along that vector by the depth to find the pixel position.
  150. float2 depthTexCoord = ndcPosition.xy * float2(0.5, -0.5) + 0.5;
  151. float backgroundDepth = tex2D(SAMPLER(DepthTexture), depthTexCoord).x;
  152. float backgroundPosView = backgroundDepth * In.ZPositions.y;
  153. // The closer the particle is to the background, the more transparent it is.
  154. float linearBlend = saturate(In.ZPositions.x - backgroundPosView);
  155. // Don't do soft particles for ground aligned particles, as they will often be almost fully transparent due to terrain proximity
  156. #if !defined(FORCE_PARTICLES_INTO_XY_PLANE)
  157. color.w *= linearBlend;
  158. #endif
  159. }
  160. return color;
  161. }
  162. // ----------------------------------------------------------------------------
  163. // SHADER: XENON
  164. // ----------------------------------------------------------------------------
  165. float4 ParticlePixelShader_Xenon(ParticleVSOutput In) : COLOR
  166. {
  167. return SoftParticlePixelShader(In, ShouldDrawParticleSoft);
  168. }
  169. // ----------------------------------------------------------------------------
  170. // TECHNIQUE: Default (High and up)
  171. // ----------------------------------------------------------------------------
  172. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_ShouldDrawParticleSoft_H = 1 );
  173. #define PS_ShouldDrawParticleSoft_H \
  174. compile PS_2_0 SoftParticlePixelShader(false), \
  175. compile PS_2_0 SoftParticlePixelShader(true)
  176. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_Final_H = PS_Multiplier_ShouldDrawParticleSoft_H * 2 );
  177. #if SUPPORTS_SHADER_ARRAYS
  178. pixelshader PS_Array_H[PS_Multiplier_Final_H] =
  179. {
  180. PS_ShouldDrawParticleSoft_H
  181. };
  182. #endif
  183. technique Default
  184. {
  185. pass P0
  186. <
  187. USE_EXPRESSION_EVALUATOR("Particle")
  188. >
  189. {
  190. VertexShader = compile VS_2_0 ParticleVertexShader();
  191. PixelShader = ARRAY_EXPRESSION_PS( PS_Array_H,
  192. ShouldDrawParticleSoft,
  193. compile PS_VERSION ParticlePixelShader_Xenon()
  194. );
  195. ZEnable = true;
  196. ZFunc = ZFUNC_INFRONT;
  197. ZWriteEnable = false;
  198. CullMode = None;
  199. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType);
  200. }
  201. }
  202. #if ENABLE_LOD
  203. // ----------------------------------------------------------------------------
  204. // TECHNIQUE: Default (Medium and up)
  205. // ----------------------------------------------------------------------------
  206. technique Default_M
  207. {
  208. pass P0
  209. <
  210. USE_EXPRESSION_EVALUATOR("Particle")
  211. >
  212. {
  213. VertexShader = compile VS_2_0 ParticleVertexShader();
  214. PixelShader = compile PS_2_0 SoftParticlePixelShader(false);
  215. ZEnable = true;
  216. ZFunc = ZFUNC_INFRONT;
  217. ZWriteEnable = false;
  218. CullMode = None;
  219. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType);
  220. }
  221. }
  222. // ----------------------------------------------------------------------------
  223. // TECHNIQUE: LowQuality
  224. // ----------------------------------------------------------------------------
  225. technique Default_L
  226. {
  227. // Disabled
  228. }
  229. #endif