GPUParticleNormalMap.fx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. //////////////////////////////////////////////////////////////////////////////
  2. // ©2005 Electronic Arts Inc
  3. //
  4. // GPU vertex particle FX Shader
  5. //////////////////////////////////////////////////////////////////////////////
  6. #define USE_INTERACTIVE_LIGHTS 1
  7. #define SUPPORT_CLOUDS 1
  8. #define SUPPORT_FOG 1
  9. #define SUPPORT_GLOBAL_LIGHTS 1
  10. #include "Common.fxh"
  11. #include "CommonParticle.fxh"
  12. // ----------------------------------------------------------------------------
  13. // draw params
  14. // ----------------------------------------------------------------------------
  15. SAMPLER_2D_BEGIN( ParticleTextureSampler,
  16. string UIWidget = "None";
  17. string SasBindAddress = "Particle.Draw.Texture";
  18. )
  19. MinFilter = Linear;
  20. MagFilter = Linear;
  21. MipFilter = Linear;
  22. AddressU = Clamp;
  23. AddressV = Clamp;
  24. SAMPLER_2D_END
  25. // $Note(WSK) - We shouldn't need to use a different sampler, and it actually doesn't work on ps3
  26. // We should be able to do the same for pc and xenon but since they are close to final,
  27. // we want to be safe and make this change for ps3 only
  28. #if defined(EA_PLATFORM_PS3)
  29. static const sampler2D NextFrameTextureSamplerSampler = ParticleTextureSamplerSampler;
  30. #else // #if defined(EA_PLATFORM_PS3)
  31. SAMPLER_2D_BEGIN( NextFrameTextureSampler,
  32. string UIWidget = "None";
  33. string SasBindAddress = "Particle.Draw.Texture";
  34. )
  35. MinFilter = Linear;
  36. MagFilter = Linear;
  37. MipFilter = Linear;
  38. AddressU = Clamp;
  39. AddressV = Clamp;
  40. SAMPLER_2D_END
  41. #endif // #if defined(EA_PLATFORM_PS3)
  42. SAMPLER_2D_BEGIN( NormalTextureSampler,
  43. string UIWidget = "None";
  44. string SasBindAddress = "Particle.Draw.DetailTexture";
  45. )
  46. MinFilter = Linear;
  47. MagFilter = Linear;
  48. MipFilter = Linear;
  49. AddressU = Wrap;
  50. AddressV = Wrap;
  51. SAMPLER_2D_END
  52. //--------------------------------- GENERAL STUFF --------------------------------------
  53. // Variationgs for handling fog in the pixel shader
  54. static const int FogMode_Disabled = 0;
  55. static const int FogMode_Opaque = 1;
  56. static const int FogMode_Additive = 2;
  57. // Transformations
  58. float4x4 WorldViewProjection : WorldViewProjection;
  59. float4x3 View : View;
  60. float4x3 World : World;
  61. // Time (ie. material is animated)
  62. float Time : Time;
  63. // ----------------------------------------------------------------------------
  64. // SHADER: Default
  65. // ----------------------------------------------------------------------------
  66. struct ParticleVSOutput
  67. {
  68. float4 Position : POSITION;
  69. float2 ParticleTexCoord : TEXCOORD0;
  70. // float4 ShadowMapTexCoord : TEXCOORD1;
  71. float4 Color : COLOR0;
  72. // float3 Fog : TEXCOORD2; // This is just a scalar, but PS1.1 can't replicate-swizzle, so replicate scalar into a vector in vertex shader
  73. float Depth : TEXCOORD3; // For _CreateShadowMap technique
  74. float3 NextFrameTexCoord : TEXCOORD4; // for interpolating between two frames
  75. float4 LightVector[NumDirectionalLights] : TEXCOORD5;
  76. };
  77. // ----------------------------------------------------------------------------
  78. ParticleVSOutput ParticleVertexShader(
  79. float4 StartPositionLifeInFrames : POSITION,
  80. float4 StartVelocityCreationFrame : TEXCOORD0,
  81. float2 SeedAndIndex : TEXCOORD1,
  82. uniform int fogMode)
  83. {
  84. USE_DIRECTIONAL_LIGHT_INTERACTIVE(DirectionalLight, 0);
  85. ParticleVSOutput Out;
  86. // decode vertex data
  87. float3 StartPosition = StartPositionLifeInFrames.xyz;
  88. float LifeInFrames = StartPositionLifeInFrames.w;
  89. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  90. float CreationFrame = StartVelocityCreationFrame.w;
  91. float Seed = SeedAndIndex.x;
  92. float Index = SeedAndIndex.y;
  93. // particle system works with frames, so first convert time to frame
  94. // rather than converting everything else to time
  95. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  96. // first eliminate dead particles
  97. if (age > LifeInFrames)
  98. Index = 0;
  99. float relativeAge = age / LifeInFrames;
  100. float3 particlePosition;
  101. float size;
  102. float2x2 zRotationMatrix;
  103. Particle_ComputePhysics(particlePosition, size, zRotationMatrix,
  104. age, StartPosition, StartVelocity, Seed);
  105. // Calculate vertex position
  106. float2 vertexCorner = VertexCorners[Index];
  107. float2 relativeCornerPos = mul(vertexCorner, zRotationMatrix);
  108. float3 xVector = float3( View[0][0], View[1][0], View[2][0] );
  109. float3 zVector = float3( View[0][1], View[1][1], View[2][1] );
  110. float3 cornerPosition = particlePosition + size * (relativeCornerPos.x * xVector + relativeCornerPos.y * zVector);
  111. Out.Position = mul(float4(cornerPosition, 1), WorldViewProjection);
  112. Out.Depth = Out.Position.z / Out.Position.w;
  113. //zVector = -zVector;
  114. float3 Normal = cross(xVector, zVector);
  115. float3 worldNormal = normalize(mul(Normal, (float3x3)World));
  116. float3 worldTangent = -zVector;
  117. float3 worldBinormal = xVector;
  118. float3x3 zRotation3D = float3x3(float3(zRotationMatrix[0], 0), float3(zRotationMatrix[1], 0), float3(0, 0, 1));
  119. // Build 3x3 tranform from object to tangent space
  120. float3x3 worldToTangentSpace = mul(transpose(float3x3(-worldBinormal, -worldTangent, worldNormal)), zRotation3D);
  121. for (int i = 0; i < NumDirectionalLights; i++)
  122. {
  123. // Compute lighting direction in tangent space
  124. Out.LightVector[i] = float4(mul(DirectionalLight[i].Direction, worldToTangentSpace), 0);
  125. }
  126. // if (fogMode != FogMode_Disabled)
  127. // {
  128. // // Fog depends on world position, but world matrix should be identity.
  129. // Out.Fog = CalculateFog(Fog, cornerPosition, GetEyePosition()).xxx;
  130. // }
  131. // else
  132. // {
  133. // Out.Fog = 0;
  134. // }
  135. // Texture coordinate
  136. float randomIndex = GetRandomFloatValue(float2(0.0f, 1.0f), Seed, 7) * Draw.VideoTex_NumPerRow_LastFrame_SingleRow_isRand.y;
  137. randomIndex -= frac(randomIndex);
  138. float currentTexFrame = age * Draw.SpeedMultiplier + randomIndex;
  139. float2 texCoord = GetVertexTexCoord(vertexCorner);
  140. Out.ParticleTexCoord = Particle_ComputeVideoTextureDefault(currentTexFrame, texCoord);
  141. Out.NextFrameTexCoord.xy = Particle_ComputeVideoTextureDefault(currentTexFrame + 1.0, texCoord);
  142. Out.NextFrameTexCoord.z = frac(currentTexFrame);
  143. // compute color
  144. float4 Color = Particle_ComputeColor(relativeAge, Seed, true);
  145. Out.Color = Color;
  146. // Out.ShadowMapTexCoord = CalculateShadowMapTexCoord(ShadowInfo, cornerPosition);
  147. return Out;
  148. }
  149. // ----------------------------------------------------------------------------
  150. float4 ParticlePixelShader(ParticleVSOutput In, uniform int fogMode) COLORTARGET
  151. {
  152. float4 Color = In.Color;
  153. float4 TextureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  154. float4 NextFrameColor = tex2D( SAMPLER(NextFrameTextureSampler), In.NextFrameTexCoord.xy);
  155. // Get bump map normal
  156. float3 bumpNormal = (float3)tex2D( SAMPLER(NormalTextureSampler), In.ParticleTexCoord) * 2.0 - 1.0;
  157. bumpNormal = normalize(bumpNormal * 10);
  158. float4 color = In.Color * TextureColor;// * 2;
  159. #if defined(EA_PLATFORM_PS3)
  160. float3 diffuselighting = 1.0;
  161. #else // #if defined(EA_PLATFORM_PS3)
  162. float3 diffuselighting = 0;
  163. for (int i = 0; i < NumDirectionalLights; i++)
  164. {
  165. // Compute lighting
  166. float diffuse = max(0, dot(bumpNormal, /*normalize*/(In.LightVector[i].xyz)));
  167. diffuselighting += DirectionalLight[i].Color * NoCloudMultiplier * diffuse;
  168. }
  169. #endif // #if defined(EA_PLATFORM_PS3)
  170. color.xyz *= diffuselighting;
  171. // Apply fog
  172. // float3 fogStrength = saturate(In.Fog) ;
  173. // if (fogMode == FogMode_Opaque)
  174. // {
  175. // // apply fog
  176. // Color.xyz = lerp(Fog.Color, Color.xyz, fogStrength);
  177. // }
  178. // else if (fogMode == FogMode_Additive)
  179. // {
  180. // // Fog used with additive blending just needs to reduce the additive influence, not blend towards the fog color
  181. // Color.xyz *= fogStrength;
  182. // }
  183. return color;
  184. }
  185. // ----------------------------------------------------------------------------
  186. float4 ParticlePixelShader_Xenon( ParticleVSOutput In ) : COLOR
  187. {
  188. return ParticlePixelShader( In, Fog.IsEnabled ? ((Draw.ShaderType == ShaderType_Additive || Draw.ShaderType == ShaderType_AdditiveAlphaTest || Draw.ShaderType == ShaderType_Multiply) ? FogMode_Additive : FogMode_Opaque) : FogMode_Disabled );
  189. }
  190. // ----------------------------------------------------------------------------
  191. // TECHNIQUE: DEFAULT
  192. // ----------------------------------------------------------------------------
  193. #define PS_ShaderType \
  194. compile PS_2_0 ParticlePixelShader(FogMode_Disabled), \
  195. compile PS_2_0 ParticlePixelShader(FogMode_Opaque), \
  196. compile PS_2_0 ParticlePixelShader(FogMode_Additive)
  197. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_Final = 3 );
  198. #if SUPPORTS_SHADER_ARRAYS
  199. pixelshader PS_Array[PS_Multiplier_Final] =
  200. {
  201. PS_ShaderType
  202. };
  203. #endif
  204. // ----------------------------------------------------------------------------
  205. technique Default_M
  206. {
  207. pass P0
  208. <
  209. USE_EXPRESSION_EVALUATOR("Particle")
  210. >
  211. {
  212. VertexShader = compile VS_2_0 ParticleVertexShader(FogMode_Opaque);
  213. PixelShader = ARRAY_EXPRESSION_PS( PS_Array,
  214. Fog.IsEnabled ? ((Draw.ShaderType == ShaderType_Additive || Draw.ShaderType == ShaderType_AdditiveAlphaTest || Draw.ShaderType == ShaderType_Multiply) ? FogMode_Additive : FogMode_Opaque) : FogMode_Disabled,
  215. compile PS_VERSION ParticlePixelShader_Xenon()
  216. );
  217. ZEnable = true;
  218. ZFunc = ZFUNC_INFRONT;
  219. ZWriteEnable = false;
  220. CullMode = None;
  221. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType); }
  222. }
  223. #if ENABLE_LOD
  224. // ----------------------------------------------------------------------------
  225. // SHADER: LowQuality
  226. // ----------------------------------------------------------------------------
  227. struct ParticleVSLowOutput
  228. {
  229. float4 Position : POSITION;
  230. float2 ParticleTexCoord : TEXCOORD0;
  231. float4 Color : COLOR0;
  232. };
  233. // ----------------------------------------------------------------------------
  234. ParticleVSLowOutput ParticleVertexShaderLow(float4 StartPositionLifeInFrames : POSITION,
  235. float4 StartVelocityCreationFrame : TEXCOORD0, float2 SeedAndIndex : TEXCOORD1)
  236. {
  237. ParticleVSLowOutput Out;
  238. // decode vertex data
  239. float3 StartPosition = StartPositionLifeInFrames.xyz;
  240. float LifeInFrames = StartPositionLifeInFrames.w;
  241. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  242. float CreationFrame = StartVelocityCreationFrame.w;
  243. float Seed = SeedAndIndex.x;
  244. float Index = SeedAndIndex.y;
  245. // particle system works with frames, so first convert time to frame
  246. // rather than converting everything else to time
  247. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  248. // first eliminate dead particles
  249. if (age > LifeInFrames)
  250. Index = 0;
  251. float relativeAge = age / LifeInFrames;
  252. float3 particlePosition;
  253. float size;
  254. float2x2 zRotationMatrix;
  255. Particle_ComputePhysics_Simplified(particlePosition, size, zRotationMatrix,
  256. age, StartPosition, StartVelocity, Seed);
  257. // Calculate vertex position
  258. float2 vertexCorner = VertexCorners[Index];
  259. float2 relativeCornerPos = mul(vertexCorner, zRotationMatrix);
  260. float3 xVector = float3( View[0][0], View[1][0], View[2][0] );
  261. float3 zVector = float3( View[0][1], View[1][1], View[2][1] );
  262. float3 cornerPosition = particlePosition + size * (relativeCornerPos.x * xVector + relativeCornerPos.y * zVector);
  263. Out.Position = mul(float4(cornerPosition, 1), WorldViewProjection);
  264. // texture coordinate
  265. float2 texCoord = GetVertexTexCoord(vertexCorner);
  266. Out.ParticleTexCoord = Particle_ComputeVideoTextureDefault(age * Draw.SpeedMultiplier, texCoord);
  267. // compute color
  268. Out.Color = Particle_ComputeColor(relativeAge, Seed, false);
  269. return Out;
  270. }
  271. // ----------------------------------------------------------------------------
  272. float4 ParticlePixelShaderLow(ParticleVSLowOutput In) : COLOR
  273. {
  274. float4 TextureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  275. float4 Color = TextureColor * In.Color;
  276. return Color;
  277. }
  278. // ----------------------------------------------------------------------------
  279. // TECHNIQUE: LowQuality
  280. // ----------------------------------------------------------------------------
  281. technique _Default_L
  282. {
  283. pass P0
  284. <
  285. USE_EXPRESSION_EVALUATOR("Particle")
  286. >
  287. {
  288. VertexShader = compile VS_2_0 ParticleVertexShaderLow();
  289. PixelShader = compile PS_2_0 ParticlePixelShaderLow();
  290. ZEnable = true;
  291. ZFunc = ZFUNC_INFRONT;
  292. ZWriteEnable = false;
  293. CullMode = None;
  294. SETUP_ALPHA_BLEND_AND_TEST(Draw.ShaderType);
  295. }
  296. }
  297. #endif // #if ENABLE_LOD
  298. // ----------------------------------------------------------------------------
  299. // SHADER: ShadowMap
  300. // ----------------------------------------------------------------------------
  301. float4 CreateShadowMapPS(ParticleVSOutput In, uniform int shaderType) COLORTARGET
  302. {
  303. float4 textureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  304. float4 color = textureColor * In.Color;
  305. // Threshold where "alpha testing" or color equivalents set pixel to be opaque.
  306. // Needs to be much lower than common alpha test threshold as a single particle is usually quite transparent.
  307. const float opacityThreshold = 0.1;
  308. if (shaderType == ShaderType_Additive)
  309. {
  310. // The brighter the color the denser the particle. Clip dark areas.
  311. clip(dot(color, float3(1, 1, 1)) - 3 * opacityThreshold);
  312. }
  313. else if (shaderType == ShaderType_Multiply)
  314. {
  315. // The darker the color the denser the particle. Clip bright areas.
  316. clip(3 * opacityThreshold - dot(color, float3(1, 1, 1)));
  317. }
  318. else if (shaderType == ShaderType_AdditiveAlphaTest || shaderType == ShaderType_Alpha
  319. || shaderType == ShaderType_AlphaTest)
  320. {
  321. // Simulate alpha testing
  322. clip(color.a - opacityThreshold);
  323. }
  324. return In.Depth;
  325. }
  326. // ----------------------------------------------------------------------------
  327. float4 CreateShadowMapPS_Xenon( ParticleVSOutput In ) : COLOR
  328. {
  329. return CreateShadowMapPS( In, min(Draw.ShaderType, ShaderType_Multiply) );
  330. }
  331. // ----------------------------------------------------------------------------
  332. // TECHNIQUE: CreateShadowMap
  333. // ----------------------------------------------------------------------------
  334. #define PSCreateShadowMap_ShaderType \
  335. compile PS_2_0 CreateShadowMapPS(0), \
  336. compile PS_2_0 CreateShadowMapPS(ShaderType_Additive), \
  337. compile PS_2_0 CreateShadowMapPS(ShaderType_AdditiveAlphaTest), \
  338. compile PS_2_0 CreateShadowMapPS(ShaderType_Alpha), \
  339. compile PS_2_0 CreateShadowMapPS(ShaderType_AlphaTest), \
  340. compile PS_2_0 CreateShadowMapPS(ShaderType_Multiply)
  341. DEFINE_ARRAY_MULTIPLIER( PSCreateShadowMap_Multiplier_Final = 6 );
  342. #if SUPPORTS_SHADER_ARRAYS
  343. pixelshader PSCreateShadowMap_Array[PSCreateShadowMap_Multiplier_Final] =
  344. {
  345. PSCreateShadowMap_ShaderType
  346. };
  347. #endif
  348. // ----------------------------------------------------------------------------
  349. technique _CreateShadowMap
  350. {
  351. pass P0
  352. <
  353. USE_EXPRESSION_EVALUATOR("GPUParticle_CreateShadowMap")
  354. >
  355. {
  356. VertexShader = compile VS_2_0 ParticleVertexShader(FogMode_Disabled);
  357. PixelShader = ARRAY_EXPRESSION_PS( PSCreateShadowMap_Array,
  358. min(Draw.ShaderType, ShaderType_Multiply),
  359. compile PS_VERSION CreateShadowMapPS_Xenon()
  360. );
  361. ZEnable = true;
  362. ZFunc = ZFUNC_INFRONT;
  363. ZWriteEnable = true;
  364. CullMode = None;
  365. AlphaBlendEnable = false;
  366. AlphaTestEnable = false; // Handled in pixel shader
  367. }
  368. }