GpuParticlePerpendicularBottom.fx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //////////////////////////////////////////////////////////////////////////////
  2. // 2008 Electronic Arts Inc
  3. //
  4. // GPU geometry particle with two perpendicular quads and the pivot point in the bottom
  5. //////////////////////////////////////////////////////////////////////////////
  6. #define SUPPORT_FOG 1
  7. // Windows shader compiler runs out of vertex shader constants on this shader.
  8. // Save some constants by not declare the indirect constant range for skinning.
  9. // This is safe to do, because the next skinned mesh that is rendered will have to set them up again anyway.
  10. // Do not do this on Xenon though, as this causes debug errors about contentions of literal and user constants.
  11. #if defined(EA_PLATFORM_WINDOWS)
  12. #define NO_SKINNING_MATRICES
  13. #endif
  14. #include "Common.fxh"
  15. #include "CommonParticle.fxh"
  16. //
  17. // Vertex data
  18. //
  19. // P - Is the pivot point for reference.
  20. //
  21. // 0 5
  22. // | \ / |
  23. // | \ / | +z
  24. // | \/ | |
  25. // | / \ | |
  26. // | 4 \ | |
  27. // | | 1 | -x <-------+
  28. // 3 | | | \
  29. // \| | 6 \
  30. // |\ / \
  31. // | \P / | +y
  32. // | /\ |
  33. // | / \|
  34. // 7 2
  35. //
  36. float3 fixup(float3 p)
  37. {
  38. return -p.xyz + float3(0.5, 0, 0);
  39. }
  40. STATICARRAY const float3 GEOMETRY_VERTEX_CORNERS[MAX_VERTICES_PER_PARTICLE] =
  41. {
  42. // First horizontal quad.
  43. fixup(float3(-0.5, -0.5, 0)),
  44. fixup(float3(-0.5, 0.5, 0)),
  45. fixup(float3(0.5, 0.5, 0)),
  46. fixup(float3(0.5, -0.5, 0)),
  47. // Second vertical quad.
  48. fixup(float3(-0.5, 0, -0.5)),
  49. fixup(float3(-0.5, 0, 0.5)),
  50. fixup(float3(0.5, 0, 0.5)),
  51. fixup(float3(0.5, 0, -0.5)),
  52. // NOT USED
  53. float3(0.0f, 0.0f, 0.0f)
  54. };
  55. STATICARRAY const float2 GEOMETRY_VERTEX_TEXCOORDS[MAX_VERTICES_PER_PARTICLE] =
  56. {
  57. // First horizontal quad.
  58. float2(0.0f, 0.0f),
  59. float2(0.0f, 1.0f),
  60. float2(1.0f, 1.0f),
  61. float2(1.0f, 0.0f),
  62. // Second vertical quad.
  63. float2(0.0f, 0.0f),
  64. float2(0.0f, 1.0f),
  65. float2(1.0f, 1.0f),
  66. float2(1.0f, 0.0f),
  67. // NOT USED
  68. float2(0.0f, 0.0f)
  69. };
  70. #include "CommonGeometryParticle.fxh"
  71. // ----------------------------------------------------------------------------
  72. // TECHNIQUE: HIGH ~ ULTRAHIGH (And XENON)
  73. // ----------------------------------------------------------------------------
  74. technique Default
  75. {
  76. pass P0
  77. <
  78. USE_EXPRESSION_EVALUATOR("Particle")
  79. >
  80. {
  81. VertexShader = ARRAY_EXPRESSION_VS( VS_Array_H, (GeometryUpdate.RotationType - 1), compile VS_VERSION ParticleVertexShader_Xenon(GeometryUpdate.RotationType - 1) );
  82. PixelShader = ARRAY_EXPRESSION_PS( PS_Array_H, (!ShouldDrawParticleSoft ? SOFTBLEND_DISABLED : ((Draw.ShaderType == ShaderType_Alpha) ? SOFTBLEND_ALPHA : SOFTBLEND_ADDITIVE)) * PS_Multiplier_ShaderType
  83. + (Fog.IsEnabled ? ((Draw.ShaderType == ShaderType_Additive || Draw.ShaderType == ShaderType_AdditiveAlphaTest || Draw.ShaderType == ShaderType_Multiply) ? FogMode_Additive : FogMode_Opaque) : FogMode_Disabled),
  84. compile PS_VERSION ParticlePixelShader_Xenon()
  85. );
  86. ZEnable = true;
  87. ZFunc = ZFUNC_INFRONT;
  88. ZWriteEnable = false;
  89. CullMode = None;
  90. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType);
  91. }
  92. }
  93. #if ENABLE_LOD
  94. // ----------------------------------------------------------------------------
  95. // TECHNIQUE: LOW
  96. // ----------------------------------------------------------------------------
  97. technique Default_L
  98. {
  99. pass P0
  100. <
  101. USE_EXPRESSION_EVALUATOR("Particle")
  102. >
  103. {
  104. VertexShader = ARRAY_EXPRESSION_VS( VS_Array_L, (GeometryUpdate.RotationType - 1), NULL );
  105. PixelShader = compile PS_2_0 ParticlePixelShader_L();
  106. ZEnable = true;
  107. ZFunc = ZFUNC_INFRONT;
  108. ZWriteEnable = false;
  109. CullMode = None;
  110. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType);
  111. }
  112. }
  113. #endif // #if ENABLE_LOD
  114. // ----------------------------------------------------------------------------
  115. // SHADER: MEDIUM
  116. // ----------------------------------------------------------------------------
  117. struct ParticleVSOutput_M
  118. {
  119. float4 Position : POSITION;
  120. float2 ParticleTexCoord : TEXCOORD0;
  121. float4 Color : COLOR0;
  122. float3 Fog : TEXCOORD1; // This is just a scalar, but PS1.1 can't replicate-swizzle, so replicate scalar into a vector in vertex shader
  123. float Depth : TEXCOORD2; // For _CreateShadowMap technique
  124. float3 NextFrameTexCoord : TEXCOORD3; // for interpolating between two frames
  125. };
  126. // ----------------------------------------------------------------------------
  127. ParticleVSOutput_M ParticleVertexShader_M(float4 StartPositionLifeInFrames : POSITION,
  128. float4 StartVelocityCreationFrame : TEXCOORD0, float2 SeedAndIndex : TEXCOORD1,
  129. uniform int fogMode)
  130. {
  131. ParticleVSOutput_M Out;
  132. // decode vertex data
  133. float3 StartPosition = StartPositionLifeInFrames.xyz;
  134. float LifeInFrames = StartPositionLifeInFrames.w;
  135. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  136. float CreationFrame = StartVelocityCreationFrame.w;
  137. float Seed = SeedAndIndex.x;
  138. float Index = SeedAndIndex.y;
  139. // particle system works with frames, so first convert time to frame
  140. // rather than converting everything else to time
  141. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  142. // first eliminate dead particles
  143. if (age > LifeInFrames)
  144. Index = 0;
  145. float relativeAge = age / LifeInFrames;
  146. float3 particlePosition;
  147. float size;
  148. float2x2 zRotationMatrix;
  149. Particle_ComputePhysics(particlePosition, size, zRotationMatrix,
  150. age, StartPosition, StartVelocity, Seed);
  151. // Calculate vertex position
  152. float2 vertexCorner = VertexCorners[Index];
  153. float2 relativeCornerPos = mul(vertexCorner, zRotationMatrix);
  154. float3 xVector = float3( View[0][0], View[1][0], View[2][0] );
  155. float3 zVector = float3( View[0][1], View[1][1], View[2][1] );
  156. float3 cornerPosition = particlePosition + size * (relativeCornerPos.x * xVector + relativeCornerPos.y * zVector);
  157. Out.Position = mul(float4(cornerPosition, 1), WorldViewProjection);
  158. Out.Depth = Out.Position.z / Out.Position.w;
  159. if (fogMode != FogMode_Disabled)
  160. {
  161. // Fog depends on world position, but world matrix should be identity.
  162. Out.Fog = CalculateFog(Fog, cornerPosition, GetEyePosition()).xxx;
  163. }
  164. else
  165. {
  166. Out.Fog = 0;
  167. }
  168. Particle_ComputeVideoTexture(age, Seed, vertexCorner, GetVertexTexCoord(vertexCorner), Out.ParticleTexCoord, Out.NextFrameTexCoord);
  169. // compute color
  170. Out.Color = Particle_ComputeColor(relativeAge, Seed, true);
  171. return Out;
  172. }
  173. // ----------------------------------------------------------------------------
  174. float4 ParticlePixelShader(ParticleVSOutput_M In, uniform int fogMode) : COLOR
  175. {
  176. float4 TextureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  177. float4 NextFrameColor = tex2D( SAMPLER(NextFrameTextureSampler), In.NextFrameTexCoord.xy);
  178. // do interpolation between two frames (for particles with video textures)
  179. float4 Color = lerp(TextureColor, NextFrameColor, In.NextFrameTexCoord.z) * In.Color;
  180. // Apply fog
  181. float3 fogStrength = saturate(In.Fog) ;
  182. if (fogMode == FogMode_Opaque)
  183. {
  184. // apply fog
  185. Color.xyz = lerp(Fog.Color, Color.xyz, fogStrength);
  186. }
  187. else if (fogMode == FogMode_Additive)
  188. {
  189. // Fog used with additive blending just needs to reduce the additive influence, not blend towards the fog color
  190. Color.xyz *= fogStrength;
  191. }
  192. return Color;
  193. }
  194. // ----------------------------------------------------------------------------
  195. // SHADER: CreateShadowMap
  196. // ----------------------------------------------------------------------------
  197. float4 CreateShadowMapPS(ParticleVSOutput_M In, uniform int shaderType) COLORTARGET
  198. {
  199. float4 textureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  200. float4 color = textureColor * In.Color;
  201. // Threshold where "alpha testing" or color equivalents set pixel to be opaque.
  202. // Needs to be much lower than common alpha test threshold as a single particle is usually quite transparent.
  203. const float opacityThreshold = 0.1;
  204. if (shaderType == ShaderType_Additive)
  205. {
  206. // The brighter the color the denser the particle. Clip dark areas.
  207. clip(dot(color, float3(1, 1, 1)) - 3 * opacityThreshold);
  208. }
  209. else if (shaderType == ShaderType_Multiply)
  210. {
  211. // The darker the color the denser the particle. Clip bright areas.
  212. clip(3 * opacityThreshold - dot(color, float3(1, 1, 1)));
  213. }
  214. else if (shaderType == ShaderType_AdditiveAlphaTest || shaderType == ShaderType_Alpha
  215. || shaderType == ShaderType_AlphaTest)
  216. {
  217. // Simulate alpha testing
  218. clip(color.a - opacityThreshold);
  219. }
  220. return In.Depth;
  221. }
  222. // ----------------------------------------------------------------------------
  223. float4 CreateShadowMapPS_Xenon( ParticleVSOutput_M In ) : COLOR
  224. {
  225. return CreateShadowMapPS( In, min(Draw.ShaderType, ShaderType_Multiply) );
  226. }
  227. // ----------------------------------------------------------------------------
  228. // TECHNIQUE: CreateShadowMap
  229. // ----------------------------------------------------------------------------
  230. #define PSCreateShadowMap_ShaderType \
  231. compile PS_2_0 CreateShadowMapPS(0), \
  232. compile PS_2_0 CreateShadowMapPS(ShaderType_Additive), \
  233. compile PS_2_0 CreateShadowMapPS(ShaderType_AdditiveAlphaTest), \
  234. compile PS_2_0 CreateShadowMapPS(ShaderType_Alpha), \
  235. compile PS_2_0 CreateShadowMapPS(ShaderType_AlphaTest), \
  236. compile PS_2_0 CreateShadowMapPS(ShaderType_Multiply)
  237. DEFINE_ARRAY_MULTIPLIER( PSCreateShadowMap_Multiplier_Final = 6 );
  238. #if SUPPORTS_SHADER_ARRAYS
  239. pixelshader PSCreateShadowMap_Array[PSCreateShadowMap_Multiplier_Final] =
  240. {
  241. PSCreateShadowMap_ShaderType
  242. };
  243. #endif
  244. // ----------------------------------------------------------------------------
  245. technique _CreateShadowMap
  246. {
  247. pass P0
  248. <
  249. USE_EXPRESSION_EVALUATOR("GPUParticle_CreateShadowMap")
  250. >
  251. {
  252. VertexShader = compile VS_2_0 ParticleVertexShader_M(FogMode_Disabled);
  253. PixelShader = ARRAY_EXPRESSION_PS( PSCreateShadowMap_Array,
  254. min(Draw.ShaderType, ShaderType_Multiply),
  255. compile PS_VERSION CreateShadowMapPS_Xenon()
  256. );
  257. ZEnable = true;
  258. ZFunc = ZFUNC_INFRONT;
  259. ZWriteEnable = true;
  260. CullMode = None;
  261. AlphaBlendEnable = false;
  262. AlphaTestEnable = false; // Handled in pixel shader
  263. }
  264. }