GPUParticleNormalMap.fx 15 KB

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