CommonGeometryParticle.fxh 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. //////////////////////////////////////////////////////////////////////////////
  2. // 2008 Electronic Arts Inc
  3. //
  4. // Common GPU geometry particle FX Shader
  5. //////////////////////////////////////////////////////////////////////////////
  6. #ifndef _COMMON_GEOMETRY_PARTICLE_FXH_
  7. #define _COMMON_GEOMETRY_PARTICLE_FXH_
  8. //
  9. // draw params
  10. //
  11. SAMPLER_2D_BEGIN( ParticleTextureSampler,
  12. string UIWidget = "None";
  13. string SasBindAddress = "Particle.Draw.Texture";
  14. )
  15. MinFilter = Linear;
  16. MagFilter = Linear;
  17. MipFilter = Linear;
  18. AddressU = Clamp;
  19. AddressV = Clamp;
  20. SAMPLER_2D_END
  21. // $Note(WSK) - We shouldn't need to use a different sampler, and it actually doesn't work on ps3
  22. // We should be able to do the same for pc and xenon but since they are close to final,
  23. // we want to be safe and make this change for ps3 only
  24. #if defined(EA_PLATFORM_PS3)
  25. static const sampler2D NextFrameTextureSamplerSampler = ParticleTextureSamplerSampler;
  26. #else // #if defined(EA_PLATFORM_PS3)
  27. SAMPLER_2D_BEGIN( NextFrameTextureSampler,
  28. string UIWidget = "None";
  29. string SasBindAddress = "Particle.Draw.Texture";
  30. )
  31. MinFilter = Linear;
  32. MagFilter = Linear;
  33. MipFilter = Linear;
  34. AddressU = Clamp;
  35. AddressV = Clamp;
  36. SAMPLER_2D_END
  37. #endif // #if defined(EA_PLATFORM_PS3)
  38. // Used to see where the particle volume intersects an object.
  39. SAMPLER_2D_BEGIN( DepthTexture,
  40. string SasBindAddress = "WW3D.DepthTexture";
  41. )
  42. MinFilter = Linear;
  43. MagFilter = Linear;
  44. MipFilter = Point;
  45. AddressU = Clamp;
  46. AddressV = Clamp;
  47. SAMPLER_2D_END
  48. //--------------------------------- GENERAL STUFF --------------------------------------
  49. bool ShouldDrawParticleSoft
  50. <
  51. string UIWidget = "None";
  52. string SasBindAddress = "Particle.Draw.ShouldDrawParticleSoft";
  53. > = false;
  54. // Variationgs for handling fog in the pixel shader
  55. static const int FogMode_Disabled = 0;
  56. static const int FogMode_Opaque = 1;
  57. static const int FogMode_Additive = 2;
  58. // Transformations
  59. float4x4 WorldView : WorldView;
  60. float4x4 Projection : Projection;
  61. float4x4 WorldViewProjection : WorldViewProjection;
  62. float4x3 View : View;
  63. float4x4 ProjectionI : ProjectionInverse;
  64. #if defined(_WW3D_)
  65. #if !defined(USE_INDIRECT_CONSTANT)
  66. float3 EyePosition
  67. <
  68. string UIWidget = "None";
  69. string SasBindAddress = "Sas.Camera.Position";
  70. >;
  71. #endif // #if !defined(USE_INDIRECT_CONSTANT)
  72. float3 GetEyePosition()
  73. {
  74. return EyePosition;
  75. }
  76. #else // #if defined(_WW3D_)
  77. float4x3 ViewI : ViewInverse;
  78. float3 GetEyePosition()
  79. {
  80. return ViewI[3];
  81. }
  82. #endif // #if defined(_WW3D_)
  83. // Time (ie. material is animated)
  84. float Time : Time;
  85. // ----------------------------------------------------------------------------
  86. // SHADER: HIGH ~ ULTRAHIGH
  87. // ----------------------------------------------------------------------------
  88. struct ParticleVSOutput_H
  89. {
  90. float4 Position : POSITION;
  91. float2 ParticleTexCoord : TEXCOORD0;
  92. float4 Color : COLOR0;
  93. float3 Fog : TEXCOORD1; // This is just a scalar, but PS1.1 can't replicate-swizzle, so replicate scalar into a vector in vertex shader
  94. float Depth : TEXCOORD2; // For _CreateShadowMap technique
  95. float3 NextFrameTexCoord : TEXCOORD3; // for interpolating between two frames
  96. float4 NDCPosition : TEXCOORD4;
  97. float2 ZPositions : TEXCOORD5; // x is the particle z position, y is the ViewEyeDirection z component.
  98. };
  99. // Making this value smaller will increase the size of the transparent edge where
  100. // the particle intersects the background.
  101. #define PARTICLE_VOLUME_SCALE 1.5
  102. // For indexing the shader array based on what type of blend is needed for the particle draw type.
  103. #define SOFTBLEND_ADDITIVE 0
  104. #define SOFTBLEND_ALPHA 1
  105. #define SOFTBLEND_DISABLED 2
  106. // These are the FXParticleSystem_RotationType values in FXParticleBase.xsd minus 1. We subtract
  107. // 1 so that it's easier to index into a shader array.
  108. #define ROTATION_OFF 0
  109. #define ROTATE_AROUND_VELOCITY 1
  110. #define ROTATE_IN_WORLD_SPACE 2
  111. //
  112. // Geometry update params. These update every frame.
  113. //
  114. struct ParticleGeometryUpdate
  115. {
  116. float3 StartSizeMinimums;
  117. float3 StartSizeSpreads;
  118. float3 SizeRateMinimums;
  119. float3 SizeRateSpreads;
  120. float3 SizeDampingMinimums;
  121. float3 SizeDampingSpreads;
  122. float3 AngleMinimums;
  123. float3 AngleSpreads;
  124. float3 AngularRateMinimums;
  125. float3 AngularRateSpreads;
  126. float2 AngleDampingMin_AngleDampingSpread;
  127. int RotationType;
  128. };
  129. ParticleGeometryUpdate GeometryUpdate
  130. <
  131. string UIWidget = "None";
  132. string SasBindAddress = "Particle.GeometryUpdate";
  133. >
  134. #if !defined(EA_PLATFORM_PS3) // PS3 TODO - Does not like this being initialized.
  135. =
  136. {
  137. float3(0, 0, 0),
  138. float3(0, 0, 0),
  139. float3(0, 0, 0),
  140. float3(0, 0, 0),
  141. float3(0, 0, 0),
  142. float3(0, 0, 0),
  143. float3(0, 0, 0),
  144. float3(0, 0, 0),
  145. float3(0, 0, 0),
  146. float3(0, 0, 0),
  147. float2(0, 0),
  148. int(0)
  149. }
  150. #endif // #if !defined(EA_PLATFORM_PS3) // PS3 TODO - Does not like this being initialized.
  151. ;
  152. // ----------------------------------------------------------------------------
  153. float3 CalculateDampingIntegral(float3 damping, float age)
  154. {
  155. // The following computation is derived from this:
  156. // In the iterative integration we do: v = v' * damp, with v: new velocity, v' old velocity
  157. // To get the fixed function solution based only starting values, we need to integrate from 0 to t over the integral((damp ^ u) du).
  158. // The solution to the integral is (damp ^ u) / ln(damp).
  159. // Entering the two borders (0 and t) into it leads to: (damp ^ t - 1) / ln(damp)
  160. // The integral is undefined at 1.0, but it's approaching a good value (= age). Be pragmatic.
  161. //if (abs(damping - 1.0) < 0.0001)
  162. if (damping.x == 1.0)
  163. damping.x = 1.0001;
  164. if (damping.y == 1.0)
  165. damping.y = 1.0001;
  166. if (damping.z == 1.0)
  167. damping.z = 1.0001;
  168. return (pow(damping, age) - 1) / log(damping);
  169. }
  170. // ----------------------------------------------------------------------------
  171. float3 GeometryParticle_ComputeSize(float age, float particleSeed)
  172. {
  173. // start size, rate, and damping
  174. float3 sizeStart = GetRandomFloatValues(GeometryUpdate.StartSizeMinimums, GeometryUpdate.StartSizeSpreads, particleSeed, 3);
  175. float3 sizeRate = GetRandomFloatValues(GeometryUpdate.SizeRateMinimums, GeometryUpdate.SizeRateSpreads, particleSeed, 3);
  176. float3 sizeDamping = GetRandomFloatValues(GeometryUpdate.SizeDampingMinimums, GeometryUpdate.SizeDampingSpreads, particleSeed, 3);
  177. return sizeStart + sizeRate * CalculateDampingIntegral(sizeDamping, age);
  178. }
  179. // ----------------------------------------------------------------------------
  180. float3 GeometryParticle_ComputeAngles(float age, float particleSeed)
  181. {
  182. // start size, rate, and damping
  183. float3 angleStart = GetRandomFloatValues(GeometryUpdate.AngleMinimums, GeometryUpdate.AngleSpreads, particleSeed, 3);
  184. float3 angleRate = GetRandomFloatValues(GeometryUpdate.AngularRateMinimums, GeometryUpdate.AngularRateSpreads, particleSeed, 3);
  185. float angleDamping = GetRandomFloatValue(float2(GeometryUpdate.AngleDampingMin_AngleDampingSpread.x, GeometryUpdate.AngleDampingMin_AngleDampingSpread.y), particleSeed, 3);
  186. return angleStart + angleRate * CalculateDampingIntegral(angleDamping, age);
  187. }
  188. // ----------------------------------------------------------------------------
  189. float3 GeometryParticle_UpdatePosition(float3 startPosition, float3 startVelocity, float age, float particleSeed, out float3 finalVelocity)
  190. {
  191. // update particle position
  192. float velocityDamping = GetRandomFloatValue(Physics.VelocityDampingRange, particleSeed, 13);
  193. float integratedDampedVelocity = CalculateDampingIntegral(velocityDamping, age);
  194. finalVelocity = startVelocity * integratedDampedVelocity + (Physics.DriftVelocity + 0.5 * age * Physics.Gravity) * age;
  195. return startPosition + finalVelocity;
  196. }
  197. // ----------------------------------------------------------------------------
  198. // Modified from rwmath
  199. float3x3 Matrix33FromEulerXYZ(float3 euler)
  200. {
  201. float ci, cj, ch, si, sj, sh;
  202. sincos(euler.x, si, ci);
  203. sincos(euler.y, sj, cj);
  204. sincos(euler.z, sh, ch);
  205. float cc = ci * ch;
  206. float cs = ci * sh;
  207. float sc = si * ch;
  208. float ss = si * sh;
  209. return float3x3(
  210. cj * ch , cj * sh , -sj ,
  211. sj * sc - cs, sj * ss + cc, cj * si ,
  212. sj * cc + ss, sj * cs - sc, cj * ci
  213. );
  214. }
  215. float3x3 Matrix33FromEulerSinCosXYZ(float3 eulerSin, float3 eulerCos)
  216. {
  217. float ci, cj, ch, si, sj, sh;
  218. si = eulerSin.x;
  219. ci = eulerCos.x;
  220. sj = eulerSin.y;
  221. cj = eulerCos.y;
  222. sh = eulerSin.z;
  223. ch = eulerCos.z;
  224. float cc = ci * ch;
  225. float cs = ci * sh;
  226. float sc = si * ch;
  227. float ss = si * sh;
  228. return float3x3(
  229. cj * ch , cj * sh , -sj ,
  230. sj * sc - cs, sj * ss + cc, cj * si ,
  231. sj * cc + ss, sj * cs - sc, cj * ci
  232. );
  233. }
  234. // Build a look-at matrix so that the x-axis points along the given direction
  235. // Modified from Matrix3x4::Obj_Look_At
  236. float3x3 ObjectLookAt(float3 lookAtDirection)
  237. {
  238. float3 d = lookAtDirection;
  239. float len1 = length(d);
  240. float len2 = length(d.xy);
  241. float sinp, cosp; //sine and cosine of the pitch ("up-down" tilt about y)
  242. if (len1 != 0.0f)
  243. {
  244. sinp = d.z / len1;
  245. cosp = len2 / len1;
  246. }
  247. else
  248. {
  249. sinp = 0.0f;
  250. cosp = 1.0f;
  251. }
  252. float siny, cosy; //sine and cosine of the yaw ("left-right"tilt about z)
  253. if (len2 != 0.0f)
  254. {
  255. siny = d.y / len2;
  256. cosy = d.x / len2;
  257. }
  258. else
  259. {
  260. siny = 0.0f;
  261. cosy = 1.0f;
  262. }
  263. // Use 0 degree roll for now
  264. float sinRoll = 0.0;
  265. float cosRoll = 1.0;
  266. // Yaw rotation to projection of target in x-y plane and then pitch rotation
  267. return Matrix33FromEulerSinCosXYZ(float3(sinRoll, -sinp, siny), float3(cosRoll, cosp, cosy));
  268. }
  269. // ----------------------------------------------------------------------------
  270. ParticleVSOutput_H ParticleVertexShader_H(float4 StartPositionLifeInFrames : POSITION,
  271. float4 StartVelocityCreationFrame : TEXCOORD0, float2 SeedAndIndex : TEXCOORD1,
  272. uniform int rotationType)
  273. {
  274. ParticleVSOutput_H Out;
  275. // decode vertex data
  276. float3 StartPosition = StartPositionLifeInFrames.xyz;
  277. float LifeInFrames = StartPositionLifeInFrames.w;
  278. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  279. float CreationFrame = StartVelocityCreationFrame.w;
  280. float Seed = SeedAndIndex.x;
  281. float Index = SeedAndIndex.y;
  282. // particle system works with frames, so first convert time to frame
  283. // rather than converting everything else to time
  284. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  285. //////////////////////////////////////////
  286. // UPDATE CORNER POSITION
  287. //////////////////////////////////////////
  288. // Calculate the particle position based on the physics parameters.
  289. float3 finalVelocity;
  290. float3 particlePosition = GeometryParticle_UpdatePosition(StartPosition, StartVelocity, age, Seed, finalVelocity);
  291. // SCALE
  292. // The size can change depending on 3 factors (size, rate, and damping).
  293. float3 size = GeometryParticle_ComputeSize(age, Seed);
  294. float3 cornerPosition = GEOMETRY_VERTEX_CORNERS[Index] * size;
  295. // ROTATE
  296. // Depending on the rotation type we either rotate in world space
  297. // or we rotate around the velocity of the particle.
  298. if (rotationType != ROTATION_OFF)
  299. {
  300. float3 eulerAngles = GeometryParticle_ComputeAngles(age, Seed);
  301. float3x3 rotateMatrix = Matrix33FromEulerXYZ(eulerAngles);
  302. if (rotationType == ROTATE_AROUND_VELOCITY)
  303. {
  304. if (length(finalVelocity) < 0.001)
  305. {
  306. finalVelocity = StartVelocity;
  307. }
  308. float3x3 lookAt = ObjectLookAt(finalVelocity);
  309. rotateMatrix = mul(rotateMatrix, lookAt);
  310. }
  311. cornerPosition = mul(cornerPosition, rotateMatrix);
  312. }
  313. // TRANSLATE
  314. cornerPosition += particlePosition;
  315. //////////////////////////////////////////
  316. // PROJECT AND SETUP SOFT PARTICLES
  317. //////////////////////////////////////////
  318. float particleSize = size / PARTICLE_VOLUME_SCALE;
  319. float4 particlePosView = mul(float4(cornerPosition, 1), WorldView);
  320. Out.ZPositions.x = particlePosView.z / particleSize;
  321. // Finish projecting the position.
  322. float4 ndcPos = mul(particlePosView, Projection);
  323. Out.Position = ndcPos;
  324. Out.NDCPosition = ndcPos;
  325. Out.Depth = Out.Position.z / Out.Position.w;
  326. // Convert the position into a view vector to the far plane.
  327. float4 screenFarPlanePosition = float4(ndcPos.xy, 1, 1);
  328. float4 viewFarPlanePosition4 = mul(screenFarPlanePosition, ProjectionI);
  329. float3 viewFarPlanePosition = viewFarPlanePosition4.xyz / viewFarPlanePosition4.w;
  330. // We don't really want a vector to the far plane. We want the vector with a z length of 1,
  331. // so that we know how much in x-y we need to step per z-depth that we get from the depth texture.
  332. Out.ZPositions.y = (viewFarPlanePosition.z / viewFarPlanePosition.z) / particleSize;
  333. //////////////////////////////////////////
  334. // IDENTICAL TO GpuParticle.fx
  335. //////////////////////////////////////////
  336. // Fog depends on world position, but world matrix should be identity.
  337. Out.Fog = CalculateFog(Fog, cornerPosition, GetEyePosition()).xxx;
  338. Particle_ComputeVideoTexture(age, Seed, GEOMETRY_VERTEX_CORNERS[Index], GEOMETRY_VERTEX_TEXCOORDS[Index], Out.ParticleTexCoord, Out.NextFrameTexCoord);
  339. // compute color
  340. float relativeAge = age / LifeInFrames;
  341. Out.Color = Particle_ComputeColor(relativeAge, Seed, true);
  342. return Out;
  343. }
  344. // ----------------------------------------------------------------------------
  345. float4 SoftParticlePixelShader(ParticleVSOutput_H In, uniform int fogMode, uniform int blendMode) COLORTARGET
  346. {
  347. float3 ndcPosition = In.NDCPosition.xyz / In.NDCPosition.w;
  348. // Convert the position into texture space then grab the depth value from the
  349. // depth texture. Then, move along that vector by the depth to find the pixel position.
  350. float2 depthTexCoord = ndcPosition.xy * float2(0.5, -0.5) + 0.5;
  351. float backgroundDepth = tex2D(SAMPLER(DepthTexture), depthTexCoord).x;
  352. float backgroundPosView = backgroundDepth * In.ZPositions.y;
  353. // The closer the particle is to the background, the more transparent it is.
  354. float linearBlend = saturate(In.ZPositions.x - backgroundPosView);
  355. // do interpolation between two frames (for particles with video textures)
  356. float4 TextureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  357. float4 NextFrameColor = tex2D( SAMPLER(NextFrameTextureSampler), In.NextFrameTexCoord.xy);
  358. float4 Color = lerp(TextureColor, NextFrameColor, In.NextFrameTexCoord.z) * In.Color;
  359. // Modify the color (or alpha) of a the particle depending on how it's being drawn
  360. // so the particle has a soft edge to it.
  361. if (blendMode == SOFTBLEND_ALPHA)
  362. {
  363. Color.w *= linearBlend;
  364. }
  365. else if (blendMode == SOFTBLEND_ADDITIVE)
  366. {
  367. Color.xyz *= linearBlend;
  368. }
  369. // Apply fog
  370. float3 fogStrength = saturate(In.Fog) ;
  371. if (fogMode == FogMode_Opaque)
  372. {
  373. // apply fog
  374. Color.xyz = lerp(Fog.Color, Color.xyz, fogStrength);
  375. }
  376. else if (fogMode == FogMode_Additive)
  377. {
  378. // Fog used with additive blending just needs to reduce the additive influence, not blend towards the fog color
  379. Color.xyz *= fogStrength;
  380. }
  381. return Color;
  382. }
  383. // ----------------------------------------------------------------------------
  384. // SHADER: XENON
  385. // ----------------------------------------------------------------------------
  386. ParticleVSOutput_H ParticleVertexShader_Xenon(float4 StartPositionLifeInFrames : POSITION,
  387. float4 StartVelocityCreationFrame : TEXCOORD0, float2 SeedAndIndex : TEXCOORD1,
  388. uniform int rotationType)
  389. {
  390. return ParticleVertexShader_H(StartPositionLifeInFrames, StartVelocityCreationFrame, SeedAndIndex, GeometryUpdate.RotationType - 1);
  391. }
  392. float4 ParticlePixelShader_Xenon(ParticleVSOutput_H In ) : COLOR
  393. {
  394. return SoftParticlePixelShader( In,
  395. Fog.IsEnabled ? ((Draw.ShaderType == ShaderType_Additive || Draw.ShaderType == ShaderType_AdditiveAlphaTest || Draw.ShaderType == ShaderType_Multiply) ? FogMode_Additive : FogMode_Opaque) : FogMode_Disabled,
  396. !ShouldDrawParticleSoft ? SOFTBLEND_DISABLED : ((Draw.ShaderType == ShaderType_Alpha) ? SOFTBLEND_ALPHA : SOFTBLEND_ADDITIVE));
  397. }
  398. // ----------------------------------------------------------------------------
  399. // TECHNIQUE: HIGH ~ ULTRAHIGH (And XENON)
  400. // ----------------------------------------------------------------------------
  401. #define VS_ShaderType_H \
  402. compile VS_3_0 ParticleVertexShader_H(ROTATION_OFF), \
  403. compile VS_3_0 ParticleVertexShader_H(ROTATE_AROUND_VELOCITY), \
  404. compile VS_3_0 ParticleVertexShader_H(ROTATE_IN_WORLD_SPACE)
  405. DEFINE_ARRAY_MULTIPLIER( VS_Multiplier_Final_H = 3 );
  406. #if SUPPORTS_SHADER_ARRAYS
  407. vertexshader VS_Array_H[VS_Multiplier_Final_H] =
  408. {
  409. VS_ShaderType_H
  410. };
  411. #endif
  412. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_FogMode = 1 );
  413. #define PS_FogMode_H(drawType) \
  414. compile PS_3_0 SoftParticlePixelShader(FogMode_Disabled, drawType), \
  415. compile PS_3_0 SoftParticlePixelShader(FogMode_Opaque, drawType), \
  416. compile PS_3_0 SoftParticlePixelShader(FogMode_Additive, drawType)
  417. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_ShaderType = PS_Multiplier_FogMode * 3 );
  418. #define PS_ShaderType_H \
  419. PS_FogMode_H(SOFTBLEND_ADDITIVE), \
  420. PS_FogMode_H(SOFTBLEND_ALPHA), \
  421. PS_FogMode_H(SOFTBLEND_DISABLED)
  422. DEFINE_ARRAY_MULTIPLIER( PS_Multiplier_Final_H = PS_Multiplier_ShaderType * 3 );
  423. #if SUPPORTS_SHADER_ARRAYS
  424. pixelshader PS_Array_H[PS_Multiplier_Final_H] =
  425. {
  426. PS_ShaderType_H
  427. };
  428. #endif
  429. // ----------------------------------------------------------------------------
  430. // TECHNIQUE: LOW
  431. // ----------------------------------------------------------------------------
  432. struct ParticleVSOutput_L
  433. {
  434. float4 Position : POSITION;
  435. float2 ParticleTexCoord : TEXCOORD0;
  436. float4 Color : COLOR0;
  437. float Depth : TEXCOORD1; // For _CreateShadowMap technique
  438. };
  439. // ----------------------------------------------------------------------------
  440. ParticleVSOutput_L ParticleVertexShader_L(float4 StartPositionLifeInFrames : POSITION,
  441. float4 StartVelocityCreationFrame : TEXCOORD0, float2 SeedAndIndex : TEXCOORD1,
  442. uniform int rotationType)
  443. {
  444. ParticleVSOutput_L Out;
  445. // decode vertex data
  446. float3 StartPosition = StartPositionLifeInFrames.xyz;
  447. float LifeInFrames = StartPositionLifeInFrames.w;
  448. float3 StartVelocity = StartVelocityCreationFrame.xyz;
  449. float CreationFrame = StartVelocityCreationFrame.w;
  450. float Seed = SeedAndIndex.x;
  451. float Index = SeedAndIndex.y;
  452. // particle system works with frames, so first convert time to frame
  453. // rather than converting everything else to time
  454. float age = (Time * CLIENT_FRAMES_PER_SECOND - CreationFrame);
  455. //////////////////////////////////////////
  456. // UPDATE CORNER POSITION
  457. //////////////////////////////////////////
  458. // Calculate the particle position based on the physics parameters.
  459. float3 finalVelocity;
  460. float3 particlePosition = GeometryParticle_UpdatePosition(StartPosition, StartVelocity, age, Seed, finalVelocity);
  461. // SCALE
  462. // The size can change depending on 3 factors (size, rate, and damping).
  463. float3 size = GeometryParticle_ComputeSize(age, Seed);
  464. float3 cornerPosition = GEOMETRY_VERTEX_CORNERS[Index] * size;
  465. // ROTATE
  466. // Depending on the rotation type we either rotate in world space
  467. // or we rotate around the velocity of the particle.
  468. if (rotationType != ROTATION_OFF)
  469. {
  470. float3 eulerAngles = GeometryParticle_ComputeAngles(age, Seed);
  471. float3x3 rotateMatrix = Matrix33FromEulerXYZ(eulerAngles);
  472. if (rotationType == ROTATE_AROUND_VELOCITY)
  473. {
  474. if (length(finalVelocity) < 0.001)
  475. {
  476. finalVelocity = StartVelocity;
  477. }
  478. float3x3 lookAt = ObjectLookAt(finalVelocity);
  479. rotateMatrix = mul(rotateMatrix, lookAt);
  480. }
  481. cornerPosition = mul(cornerPosition, rotateMatrix);
  482. }
  483. // TRANSLATE
  484. cornerPosition += particlePosition;
  485. //////////////////////////////////////////
  486. // PROJECT
  487. //////////////////////////////////////////
  488. // Finish projecting the position.
  489. Out.Position = mul(float4(cornerPosition, 1), WorldViewProjection);
  490. Out.Depth = Out.Position.z / Out.Position.w;
  491. // texture coordinate
  492. Particle_ComputeVideoTextureNoNextFrame(age, Seed, GEOMETRY_VERTEX_TEXCOORDS[Index], Out.ParticleTexCoord);
  493. //////////////////////////////////////////
  494. // IDENTICAL TO GpuParticle.fx
  495. //////////////////////////////////////////
  496. // compute color
  497. float relativeAge = age / LifeInFrames;
  498. Out.Color = Particle_ComputeColor(relativeAge, Seed, true);
  499. return Out;
  500. }
  501. // ----------------------------------------------------------------------------
  502. float4 ParticlePixelShader_L(ParticleVSOutput_L In) : COLOR
  503. {
  504. float4 TextureColor = tex2D( SAMPLER(ParticleTextureSampler), In.ParticleTexCoord);
  505. float4 Color = TextureColor * In.Color;
  506. return Color;
  507. }
  508. #define VS_ShaderType_L \
  509. compile VS_2_0 ParticleVertexShader_L(ROTATION_OFF), \
  510. compile VS_2_0 ParticleVertexShader_L(ROTATE_AROUND_VELOCITY), \
  511. compile VS_2_0 ParticleVertexShader_L(ROTATE_IN_WORLD_SPACE)
  512. DEFINE_ARRAY_MULTIPLIER( VS_Multiplier_Final_L = 3 );
  513. #if SUPPORTS_SHADER_ARRAYS
  514. vertexshader VS_Array_L[VS_Multiplier_Final_L] =
  515. {
  516. VS_ShaderType_L
  517. };
  518. #endif
  519. #endif // _COMMON_GEOMETRY_PARTICLE_FXH_