Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

887 lines
28 KiB

  1. //===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: particle system code
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #include "particles/particles.h"
  8. #include "filesystem.h"
  9. #include "tier2/tier2.h"
  10. #include "tier2/fileutils.h"
  11. #include "tier1/UtlStringMap.h"
  12. #include "tier1/strtools.h"
  13. #ifdef USE_BLOBULATOR
  14. // TODO: These should be in public by the time the SDK ships
  15. #include "../common/blobulator/physics/physparticle.h"
  16. #include "../common/blobulator/physics/physparticlecache_inl.h"
  17. #include "../common/blobulator/physics/phystiler.h"
  18. #endif
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. class C_OP_RandomForce : public CParticleOperatorInstance
  22. {
  23. DECLARE_PARTICLE_OPERATOR( C_OP_RandomForce );
  24. uint32 GetWrittenAttributes( void ) const
  25. {
  26. return 0;
  27. }
  28. uint32 GetReadAttributes( void ) const
  29. {
  30. return 0;
  31. }
  32. virtual void AddForces( FourVectors *pAccumulatedForces,
  33. CParticleCollection *pParticles,
  34. int nBlocks,
  35. float flStrength,
  36. void *pContext ) const;
  37. Vector m_MinForce;
  38. Vector m_MaxForce;
  39. };
  40. void C_OP_RandomForce::AddForces( FourVectors *pAccumulatedForces,
  41. CParticleCollection *pParticles,
  42. int nBlocks,
  43. float flStrength,
  44. void *pContext ) const
  45. {
  46. FourVectors box_min,box_max;
  47. box_min.DuplicateVector( m_MinForce * flStrength );
  48. box_max.DuplicateVector( m_MaxForce * flStrength);
  49. box_max -= box_min;
  50. int nContext = GetSIMDRandContext();
  51. for(int i=0;i<nBlocks;i++)
  52. {
  53. pAccumulatedForces->x = AddSIMD(
  54. pAccumulatedForces->x, AddSIMD( box_min.x, MulSIMD( box_max.x, RandSIMD( nContext) ) ) );
  55. pAccumulatedForces->y = AddSIMD(
  56. pAccumulatedForces->y, AddSIMD( box_min.y, MulSIMD( box_max.y, RandSIMD( nContext) ) ) );
  57. pAccumulatedForces->z = AddSIMD(
  58. pAccumulatedForces->z, AddSIMD( box_min.z, MulSIMD( box_max.z, RandSIMD( nContext) ) ) );
  59. pAccumulatedForces++;
  60. }
  61. ReleaseSIMDRandContext( nContext );
  62. }
  63. DEFINE_PARTICLE_OPERATOR( C_OP_RandomForce, "random force", OPERATOR_GENERIC );
  64. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RandomForce )
  65. DMXELEMENT_UNPACK_FIELD( "min force", "0 0 0", Vector, m_MinForce )
  66. DMXELEMENT_UNPACK_FIELD( "max force", "0 0 0", Vector, m_MaxForce )
  67. END_PARTICLE_OPERATOR_UNPACK( C_OP_RandomForce )
  68. class C_OP_ParentVortices : public CParticleOperatorInstance
  69. {
  70. DECLARE_PARTICLE_OPERATOR( C_OP_ParentVortices );
  71. uint32 GetWrittenAttributes( void ) const
  72. {
  73. return 0;
  74. }
  75. uint32 GetReadAttributes( void ) const
  76. {
  77. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  78. }
  79. virtual void AddForces( FourVectors *pAccumulatedForces,
  80. CParticleCollection *pParticles,
  81. int nBlocks,
  82. float flStrength,
  83. void *pContext ) const;
  84. float m_flForceScale;
  85. Vector m_vecTwistAxis;
  86. bool m_bFlipBasedOnYaw;
  87. };
  88. struct VortexParticle_t
  89. {
  90. FourVectors m_v4Center;
  91. FourVectors m_v4TwistAxis;
  92. fltx4 m_fl4OORadius;
  93. fltx4 m_fl4Strength;
  94. };
  95. void C_OP_ParentVortices::AddForces( FourVectors *pAccumulatedForces,
  96. CParticleCollection *pParticles,
  97. int nBlocks,
  98. float flStrength,
  99. void *pContext ) const
  100. {
  101. if ( pParticles->m_pParent && ( pParticles->m_pParent->m_nActiveParticles ) )
  102. {
  103. FourVectors Twist_AxisInWorldSpace;
  104. Twist_AxisInWorldSpace.DuplicateVector( m_vecTwistAxis );
  105. Twist_AxisInWorldSpace.VectorNormalize();
  106. int nVortices = pParticles->m_pParent->m_nActiveParticles;
  107. VortexParticle_t *pVortices = ( VortexParticle_t * ) stackalloc( nVortices * sizeof( VortexParticle_t ) );
  108. for( int i = 0; i < nVortices; i++ )
  109. {
  110. pVortices[i].m_v4TwistAxis = Twist_AxisInWorldSpace;
  111. pVortices[i].m_fl4OORadius = ReplicateX4( 1.0 / ( 0.00001 + *( pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, i ) ) ) );
  112. pVortices[i].m_fl4OORadius = MulSIMD( pVortices[i].m_fl4OORadius, pVortices[i].m_fl4OORadius );
  113. pVortices[i].m_fl4Strength = ReplicateX4( m_flForceScale * flStrength * ( * ( pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA, i ) ) ) );
  114. float const *pXYZ = pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  115. pVortices[i].m_v4Center.x = ReplicateX4( pXYZ[0] );
  116. pVortices[i].m_v4Center.y = ReplicateX4( pXYZ[4] );
  117. pVortices[i].m_v4Center.z = ReplicateX4( pXYZ[8] );
  118. if ( m_bFlipBasedOnYaw )
  119. {
  120. float const *pYaw = pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_YAW, i );
  121. if ( pYaw[0] >= M_PI )
  122. {
  123. pVortices[i].m_v4Center *= Four_NegativeOnes;
  124. }
  125. }
  126. }
  127. size_t nPosStride;
  128. const FourVectors *pPos=pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &nPosStride );
  129. for(int i=0; i < nBlocks ; i++)
  130. {
  131. FourVectors v4SumForces;
  132. v4SumForces.x = Four_Zeros;
  133. v4SumForces.y = Four_Zeros;
  134. v4SumForces.z = Four_Zeros;
  135. for( int v = 0; v < nVortices; v++ )
  136. {
  137. FourVectors v4Ofs = *pPos;
  138. v4Ofs -= pVortices[v].m_v4Center;
  139. fltx4 v4DistSQ = v4Ofs * v4Ofs;
  140. bi32x4 bGoodLen = CmpGtSIMD( v4DistSQ, Four_Epsilons );
  141. v4Ofs.VectorNormalize();
  142. FourVectors v4Parallel_comp = v4Ofs;
  143. v4Parallel_comp *= ( v4Ofs * pVortices[v].m_v4TwistAxis );
  144. v4Ofs -= v4Parallel_comp;
  145. bGoodLen = AndSIMD( bGoodLen, CmpGtSIMD( v4Ofs * v4Ofs, Four_Epsilons ) );
  146. v4Ofs.VectorNormalize();
  147. FourVectors v4TangentialForce = v4Ofs ^ pVortices[v].m_v4TwistAxis;
  148. fltx4 fl4Strength = pVortices[v].m_fl4Strength;
  149. fl4Strength = MulSIMD( fl4Strength, MaxSIMD( Four_Zeros, SubSIMD( Four_Ones, MulSIMD( v4DistSQ, pVortices[v].m_fl4OORadius ) ) ) ); // scale so strength = 0.0 at radius or farther
  150. v4TangentialForce *= fl4Strength;
  151. v4TangentialForce.x = AndSIMD( v4TangentialForce.x, bGoodLen );
  152. v4TangentialForce.y = AndSIMD( v4TangentialForce.y, bGoodLen );
  153. v4TangentialForce.z = AndSIMD( v4TangentialForce.z, bGoodLen );
  154. v4SumForces += v4TangentialForce;
  155. }
  156. *( pAccumulatedForces++ ) += v4SumForces;
  157. pPos += nPosStride;
  158. }
  159. }
  160. }
  161. DEFINE_PARTICLE_OPERATOR( C_OP_ParentVortices, "Create vortices from parent particles", OPERATOR_GENERIC );
  162. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ParentVortices )
  163. DMXELEMENT_UNPACK_FIELD( "amount of force", "0", float, m_flForceScale )
  164. DMXELEMENT_UNPACK_FIELD( "twist axis", "0 0 1", Vector, m_vecTwistAxis )
  165. DMXELEMENT_UNPACK_FIELD( "flip twist axis with yaw","0", bool, m_bFlipBasedOnYaw )
  166. END_PARTICLE_OPERATOR_UNPACK( C_OP_ParentVortices )
  167. class C_OP_TwistAroundAxis : public CParticleOperatorInstance
  168. {
  169. DECLARE_PARTICLE_OPERATOR( C_OP_TwistAroundAxis );
  170. uint32 GetWrittenAttributes( void ) const
  171. {
  172. return 0;
  173. }
  174. uint32 GetReadAttributes( void ) const
  175. {
  176. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  177. }
  178. virtual void AddForces( FourVectors *pAccumulatedForces,
  179. CParticleCollection *pParticles,
  180. int nBlocks,
  181. float flStrength,
  182. void *pContext ) const;
  183. float m_fForceAmount;
  184. Vector m_TwistAxis;
  185. bool m_bLocalSpace;
  186. };
  187. void C_OP_TwistAroundAxis::AddForces( FourVectors *pAccumulatedForces,
  188. CParticleCollection *pParticles,
  189. int nBlocks,
  190. float flStrength,
  191. void *pContext ) const
  192. {
  193. FourVectors Twist_AxisInWorldSpace;
  194. Twist_AxisInWorldSpace.DuplicateVector( pParticles->TransformAxis( m_TwistAxis, m_bLocalSpace ) );
  195. Twist_AxisInWorldSpace.VectorNormalize();
  196. Vector vecCenter;
  197. pParticles->GetControlPointAtTime( 0, pParticles->m_flCurTime, &vecCenter );
  198. FourVectors Center;
  199. Center.DuplicateVector( vecCenter );
  200. size_t nPosStride;
  201. fltx4 ForceScale = ReplicateX4( m_fForceAmount * flStrength );
  202. const FourVectors *pPos=pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &nPosStride );
  203. for(int i=0;i<nBlocks;i++)
  204. {
  205. FourVectors ofs=*pPos;
  206. ofs -= Center;
  207. bi32x4 bGoodLen = CmpGtSIMD( ofs*ofs, Four_Epsilons );
  208. ofs.VectorNormalize();
  209. FourVectors parallel_comp=ofs;
  210. parallel_comp *= ( ofs*Twist_AxisInWorldSpace );
  211. ofs-=parallel_comp;
  212. bGoodLen = AndSIMD( bGoodLen, CmpGtSIMD( ofs*ofs, Four_Epsilons ) );
  213. ofs.VectorNormalize();
  214. FourVectors TangentialForce = ofs ^ Twist_AxisInWorldSpace;
  215. TangentialForce *= ForceScale;
  216. TangentialForce.x = AndSIMD( TangentialForce.x, bGoodLen );
  217. TangentialForce.y = AndSIMD( TangentialForce.y, bGoodLen );
  218. TangentialForce.z = AndSIMD( TangentialForce.z, bGoodLen );
  219. *(pAccumulatedForces++) += TangentialForce;
  220. pPos += nPosStride;
  221. }
  222. }
  223. DEFINE_PARTICLE_OPERATOR( C_OP_TwistAroundAxis, "twist around axis", OPERATOR_GENERIC );
  224. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_TwistAroundAxis )
  225. DMXELEMENT_UNPACK_FIELD( "amount of force", "0", float, m_fForceAmount )
  226. DMXELEMENT_UNPACK_FIELD( "twist axis", "0 0 1", Vector, m_TwistAxis )
  227. DMXELEMENT_UNPACK_FIELD( "object local space axis 0/1","0", bool, m_bLocalSpace )
  228. END_PARTICLE_OPERATOR_UNPACK( C_OP_TwistAroundAxis )
  229. class C_OP_AttractToControlPoint : public CParticleOperatorInstance
  230. {
  231. DECLARE_PARTICLE_OPERATOR( C_OP_AttractToControlPoint );
  232. uint32 GetWrittenAttributes( void ) const
  233. {
  234. return 0;
  235. }
  236. uint32 GetReadAttributes( void ) const
  237. {
  238. return 0;
  239. }
  240. virtual uint64 GetReadControlPointMask() const
  241. {
  242. return 1ULL << m_nControlPointNumber;
  243. }
  244. virtual void AddForces( FourVectors *pAccumulatedForces,
  245. CParticleCollection *pParticles,
  246. int nBlocks,
  247. float flStrength,
  248. void *pContext ) const;
  249. float m_fForceAmount;
  250. float m_fFalloffPower;
  251. int m_nControlPointNumber;
  252. };
  253. void C_OP_AttractToControlPoint::AddForces( FourVectors *pAccumulatedForces,
  254. CParticleCollection *pParticles,
  255. int nBlocks,
  256. float flStrength,
  257. void *pContext ) const
  258. {
  259. int power_frac=-4.0*m_fFalloffPower; // convert to what pow_fixedpoint_exponent_simd wants
  260. fltx4 fForceScale=ReplicateX4( -m_fForceAmount * flStrength );
  261. Vector vecCenter;
  262. pParticles->GetControlPointAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &vecCenter );
  263. FourVectors Center;
  264. Center.DuplicateVector( vecCenter );
  265. size_t nPosStride;
  266. const FourVectors *pPos=pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &nPosStride );
  267. for(int i=0;i<nBlocks;i++)
  268. {
  269. FourVectors ofs=*pPos;
  270. ofs -= Center;
  271. fltx4 len = ofs.length();
  272. ofs *= MulSIMD( fForceScale, ReciprocalSaturateSIMD( len )); // normalize and scale
  273. ofs *= Pow_FixedPoint_Exponent_SIMD( len, power_frac ); // * 1/pow(dist, exponent)
  274. bi32x4 bGood = CmpGtSIMD( len, Four_Epsilons );
  275. ofs.x = AndSIMD( bGood, ofs.x );
  276. ofs.y = AndSIMD( bGood, ofs.y );
  277. ofs.z = AndSIMD( bGood, ofs.z );
  278. *(pAccumulatedForces++) += ofs;
  279. pPos += nPosStride;
  280. }
  281. }
  282. DEFINE_PARTICLE_OPERATOR( C_OP_AttractToControlPoint, "Pull towards control point", OPERATOR_GENERIC );
  283. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_AttractToControlPoint )
  284. DMXELEMENT_UNPACK_FIELD( "amount of force", "0", float, m_fForceAmount )
  285. DMXELEMENT_UNPACK_FIELD( "falloff power", "2", float, m_fFalloffPower )
  286. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  287. END_PARTICLE_OPERATOR_UNPACK( C_OP_AttractToControlPoint )
  288. class C_OP_ForceBasedOnDistanceToPlane : public CParticleOperatorInstance
  289. {
  290. DECLARE_PARTICLE_OPERATOR( C_OP_ForceBasedOnDistanceToPlane );
  291. uint32 GetWrittenAttributes( void ) const
  292. {
  293. return 0;
  294. }
  295. uint32 GetReadAttributes( void ) const
  296. {
  297. return 0;
  298. }
  299. virtual uint64 GetReadControlPointMask() const
  300. {
  301. return 1ULL << m_nControlPointNumber;
  302. }
  303. virtual void AddForces( FourVectors *pAccumulatedForces,
  304. CParticleCollection *pParticles,
  305. int nBlocks,
  306. float flStrength,
  307. void *pContext ) const;
  308. float m_flMinDist;
  309. Vector m_vecForceAtMinDist;
  310. float m_flMaxDist;
  311. Vector m_vecForceAtMaxDist;
  312. Vector m_vecPlaneNormal;
  313. int m_nControlPointNumber;
  314. float m_flExponent;
  315. };
  316. void C_OP_ForceBasedOnDistanceToPlane::AddForces( FourVectors *pAccumulatedForces,
  317. CParticleCollection *pParticles,
  318. int nBlocks,
  319. float flStrength,
  320. void *pContext ) const
  321. {
  322. float flDeltaDistances = m_flMaxDist - m_flMinDist;
  323. fltx4 fl4OORange = Four_Zeros;
  324. if ( flDeltaDistances )
  325. {
  326. fl4OORange = ReplicateX4( 1.0 / flDeltaDistances );
  327. }
  328. Vector vecPointOnPlane = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  329. FourVectors v4PointOnPlane;
  330. v4PointOnPlane.DuplicateVector( vecPointOnPlane );
  331. FourVectors v4PlaneNormal;
  332. v4PlaneNormal.DuplicateVector( m_vecPlaneNormal );
  333. fltx4 fl4MinDist = ReplicateX4( m_flMinDist );
  334. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  335. FourVectors v4Force0;
  336. v4Force0.DuplicateVector( m_vecForceAtMinDist );
  337. FourVectors v4ForceDelta;
  338. v4ForceDelta.DuplicateVector( m_vecForceAtMaxDist - m_vecForceAtMinDist );
  339. int nPowValue = 4.0 * m_flExponent;
  340. for(int i=0 ; i < nBlocks ; i++)
  341. {
  342. FourVectors v4Ofs = *pXYZ;
  343. v4Ofs -= v4PointOnPlane;
  344. fltx4 fl4DistanceFromPlane = v4Ofs * v4PlaneNormal;
  345. fl4DistanceFromPlane = MulSIMD( SubSIMD( fl4DistanceFromPlane, fl4MinDist ), fl4OORange );
  346. fl4DistanceFromPlane = MaxSIMD( Four_Zeros, MinSIMD( Four_Ones, fl4DistanceFromPlane ) );
  347. fl4DistanceFromPlane = Pow_FixedPoint_Exponent_SIMD( fl4DistanceFromPlane, nPowValue );
  348. // now, calculate lerped force
  349. FourVectors v4OutputForce = v4ForceDelta;
  350. v4OutputForce *= fl4DistanceFromPlane;
  351. v4OutputForce += v4Force0;
  352. *( pAccumulatedForces++ ) += v4OutputForce;
  353. ++pXYZ;
  354. }
  355. }
  356. DEFINE_PARTICLE_OPERATOR( C_OP_ForceBasedOnDistanceToPlane, "Force based on distance from plane", OPERATOR_GENERIC );
  357. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ForceBasedOnDistanceToPlane )
  358. DMXELEMENT_UNPACK_FIELD( "Min distance from plane", "0", float, m_flMinDist )
  359. DMXELEMENT_UNPACK_FIELD( "Force at Min distance", "0 0 0", Vector, m_vecForceAtMinDist )
  360. DMXELEMENT_UNPACK_FIELD( "Max Distance from plane", "1", float, m_flMaxDist )
  361. DMXELEMENT_UNPACK_FIELD( "Force at Max distance", "0 0 0", Vector, m_vecForceAtMaxDist )
  362. DMXELEMENT_UNPACK_FIELD( "Plane Normal", "0 0 1", Vector, m_vecPlaneNormal )
  363. DMXELEMENT_UNPACK_FIELD( "Control point number", "0", int, m_nControlPointNumber )
  364. DMXELEMENT_UNPACK_FIELD( "Exponent", "1", float, m_flExponent )
  365. END_PARTICLE_OPERATOR_UNPACK( C_OP_ForceBasedOnDistanceToPlane )
  366. #undef USE_BLOBULATOR // TODO (Ilya): Must fix this code
  367. #ifdef USE_BLOBULATOR
  368. class C_OP_LennardJonesForce : public CParticleOperatorInstance
  369. {
  370. DECLARE_PARTICLE_OPERATOR( C_OP_LennardJonesForce );
  371. uint32 GetWrittenAttributes( void ) const
  372. {
  373. return 0;
  374. }
  375. uint32 GetReadAttributes( void ) const
  376. {
  377. return 0;
  378. }
  379. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  380. {
  381. //m_pParticleCache = new ParticleCache(m_fInteractionRadius);
  382. m_pPhysTiler = new PhysTiler(m_fInteractionRadius);
  383. }
  384. virtual void AddForces( FourVectors *pAccumulatedForces,
  385. CParticleCollection *pParticles,
  386. int nBlocks,
  387. float flStrength,
  388. void *pContext ) const;
  389. // TODO: Have to destroy PhysTiler in destructor somewhere!!!!
  390. //ParticleCache* m_pParticleCache;
  391. PhysTiler* m_pPhysTiler;
  392. float m_fInteractionRadius;
  393. float m_fSurfaceTension;
  394. float m_fLennardJonesRepulsion;
  395. float m_fLennardJonesAttraction;
  396. float m_fMaxRepulsion;
  397. float m_fMaxAttraction;
  398. private:
  399. //virtual void addParticleForce(PhysParticle* a, PhysParticleCacheNode* bcn, float flStrength, float ts) const;
  400. virtual void addParticleForce(PhysParticle* a, PhysParticle* b, float distSq, float flStrength, float ts) const;
  401. };
  402. // TODO: I should make sure I don't have divide by zero errors.
  403. // TODO: ts is not used
  404. void C_OP_LennardJonesForce::addParticleForce(PhysParticle* a, PhysParticle* b, float distSq, float flStrength, float ts) const
  405. {
  406. float d = sqrtf(distSq);
  407. //========================================================
  408. // based on equation of force between two molecules which is
  409. // factor * ((distance/bond_length)^-7 - (distance/bond_length)^-13)
  410. float f;
  411. if(a->group == b->group) // In the same group
  412. {
  413. float p = a->radius * 2.0f / (d+FLT_EPSILON);
  414. float p2 = p * p;
  415. float p4 = p2 * p2;
  416. // Surface tension:
  417. //Notes:
  418. // Can average the neighbor count between the two particles...
  419. // I tried this, and discovered that rather than averaging, I can take maybe take the
  420. // larger of the two neighbor counts, so the attraction between two particles on the surface will be strong, but
  421. // the attraction between a particle inside and a particle on the surface will be weak. I can also try
  422. // taking the min so that the attraction between a particle on the surface and a particle inside the fluid will
  423. // be strong, but the attraction between two particles completely on the inside will be weak.
  424. //
  425. // int symmetric_neighbor_count = min(a->neighbor_count, b->neighbor_count);
  426. //
  427. // Can try having neighbors only cause stronger attraction (no repulsion)
  428. // Can try lower exponents for the LennardJones forces.
  429. // This is a trick to prevent single particles from floating off... the less neighbors a particle has.. the more it sticks
  430. // This also tends to simulate surface tension
  431. float surface_tension_modifier = ((24.0f * m_fSurfaceTension) / (a->neighbor_count + b->neighbor_count + 0.1f)) + 1.0f;
  432. //float lennard_jones_force = fLennardJones * 2.0f * (p2 - (p4 * p4));
  433. float lennard_jones_force = m_fLennardJonesAttraction * p2 - m_fLennardJonesRepulsion*p4;
  434. f = surface_tension_modifier * lennard_jones_force;
  435. // This is some older code:
  436. //f = ((35.0f * LampScene::simulationSurfaceTension) / (a->neighbor_count + 0.1f)) * (p2 - (p4 * p4));
  437. // used to be 68'
  438. //float factor = (b->neighbor_count < 13 && neighbor_count < 13 ? 4.0f : 0.5f);
  439. //f = factor * (p2 - (p2 * p2 * p2 * p2));
  440. }
  441. else
  442. {
  443. // This was 3.5 ... made 3.0 so particles get closer when they collide
  444. if(d > a->radius * 3.0f) return;
  445. float p = a->radius * 4.0f / d;
  446. f = -1.0f * p * p;
  447. }
  448. // These checks are great to have, but are they really necessary?
  449. // It might also be good to have a limit on velocity
  450. // Attraction is a positive value.
  451. // Repulsion is negative.
  452. if(f < -m_fMaxRepulsion) f = -m_fMaxRepulsion;
  453. if(f > m_fMaxAttraction) f = m_fMaxAttraction;
  454. Point3D scaledr = (b->center - a->center) * (f/(d+FLT_EPSILON)); // Dividing by d scales distance down to a unit vector
  455. a->force.add(scaledr);
  456. b->force.subtract(scaledr);
  457. }
  458. void C_OP_LennardJonesForce::AddForces( FourVectors *pAccumulatedForces,
  459. CParticleCollection *pParticles,
  460. int nBlocks,
  461. float flStrength,
  462. void *pContext ) const
  463. {
  464. int nParticles = pParticles->m_nActiveParticles; // Not sure if this is correct!
  465. size_t nPosStride;
  466. const FourVectors *pPos=pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &nPosStride );
  467. // The +4 is because particles are stored by PET in blocks of 4
  468. // However, not every block is full. Thus, nParticles may be
  469. // less than nBlocks*4. Could get rid of this if the swizzling/unswizzling
  470. // loop were better written.
  471. static SmartArray<PhysParticle> imp_particles_sa; // This doesn't specify alignment, might have problems with SSE
  472. while(imp_particles_sa.size < nParticles+4)
  473. {
  474. imp_particles_sa.pushAutoSize(PhysParticle());
  475. }
  476. /*
  477. size_t nPrevPosStride;
  478. const FourVectors *pPrevPos=pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, &nPrevPosStride );
  479. */
  480. //m_pParticleCache->beginFrame();
  481. //m_pParticleCache->beginTile(nParticles);
  482. m_pPhysTiler->beginFrame(Point3D(0.0f, 0.0f, 0.0f));
  483. // Unswizzle from the FourVectors format into particles
  484. for(int i=0, p=0;i<nBlocks;i++)
  485. {
  486. FourVectors ofs=*pPos;
  487. PhysParticle* particle = &(imp_particles_sa[p]);
  488. particle->force.clear();
  489. if(p < nParticles)
  490. {
  491. particle->center = ofs.Vec(0);
  492. particle->group = 0;
  493. particle->neighbor_count = 0;
  494. m_pPhysTiler->insertParticle(particle);
  495. }
  496. p++;
  497. particle = &(imp_particles_sa[p]);
  498. particle->force.clear();
  499. if(p < nParticles)
  500. {
  501. particle->center = ofs.Vec(1);
  502. particle->group = 0;
  503. particle->neighbor_count = 0;
  504. m_pPhysTiler->insertParticle(particle);
  505. }
  506. p++;
  507. particle = &(imp_particles_sa[p]);
  508. particle->force.clear();
  509. if(p < nParticles)
  510. {
  511. particle->center = ofs.Vec(2);
  512. particle->group = 0;
  513. particle->neighbor_count = 0;
  514. m_pPhysTiler->insertParticle(particle);
  515. }
  516. p++;
  517. particle = &(imp_particles_sa[p]);
  518. particle->force.clear();
  519. if(p < nParticles)
  520. {
  521. particle->center = ofs.Vec(3);
  522. particle->group = 0;
  523. particle->neighbor_count = 0;
  524. m_pPhysTiler->insertParticle(particle);
  525. }
  526. p++;
  527. pPos += nPosStride;
  528. }
  529. m_pPhysTiler->processTiles();
  530. float timeStep = 1.0f; // This should be customizable
  531. float nearNeighborInteractionRadius = 2.3f;
  532. float nearNeighborInteractionRadiusSq = nearNeighborInteractionRadius * nearNeighborInteractionRadius;
  533. PhysParticleCache* pCache = m_pPhysTiler->getParticleCache();
  534. // Calculate number of near neighbors for each particle
  535. for(int i = 0; i < nParticles; i++)
  536. {
  537. PhysParticle *b1 = &(imp_particles_sa[i]);
  538. PhysParticleAndDist* node = pCache->get(b1);
  539. while(node->particle != NULL)
  540. {
  541. PhysParticle* b2 = node->particle;
  542. // Compare addresses of the two particles. This makes sure we apply a force only once between a pair of particles.
  543. if(b1 < b2 && node->distSq < nearNeighborInteractionRadiusSq)
  544. {
  545. b1->neighbor_count++;
  546. b2->neighbor_count++;
  547. }
  548. node++;
  549. }
  550. }
  551. // Calculate forces on particles due to other particles
  552. for(int i = 0; i < nParticles; i++)
  553. {
  554. PhysParticle *b1 = &(imp_particles_sa[i]);
  555. PhysParticleAndDist* node = pCache->get(b1);
  556. while(node->particle != NULL)
  557. {
  558. PhysParticle* b2 = node->particle;
  559. // Compare addresses of the two particles. This makes sure we apply a force only once between a pair of particles.
  560. if(b1 < b2)
  561. {
  562. addParticleForce(b1, b2, node->distSq, flStrength, timeStep);
  563. }
  564. node++;
  565. }
  566. }
  567. /*
  568. for(ParticleListNode* bit3 = particles; bit3; bit3 = bit3->next)
  569. {
  570. Particle* b = bit3->particle;
  571. b->prev_group = b->group; // Set prev group
  572. //b1->addDirDragForce();
  573. b->move(ts); // Move the particle (it should never be used again until next iteration)
  574. }
  575. */
  576. m_pPhysTiler->endFrame();
  577. // Swizzle forces back into FourVectors format
  578. for(int i=0;i<nBlocks;i++)
  579. {
  580. pAccumulatedForces->X(0) += imp_particles_sa[i*4].force[0];
  581. pAccumulatedForces->Y(0) += imp_particles_sa[i*4].force[1];
  582. pAccumulatedForces->Z(0) += imp_particles_sa[i*4].force[2];
  583. pAccumulatedForces->X(1) += imp_particles_sa[i*4+1].force[0];
  584. pAccumulatedForces->Y(1) += imp_particles_sa[i*4+1].force[1];
  585. pAccumulatedForces->Z(1) += imp_particles_sa[i*4+1].force[2];
  586. pAccumulatedForces->X(2) += imp_particles_sa[i*4+2].force[0];
  587. pAccumulatedForces->Y(2) += imp_particles_sa[i*4+2].force[1];
  588. pAccumulatedForces->Z(2) += imp_particles_sa[i*4+2].force[2];
  589. pAccumulatedForces->X(3) += imp_particles_sa[i*4+3].force[0];
  590. pAccumulatedForces->Y(3) += imp_particles_sa[i*4+3].force[1];
  591. pAccumulatedForces->Z(3) += imp_particles_sa[i*4+3].force[2];
  592. pAccumulatedForces++;
  593. }
  594. }
  595. DEFINE_PARTICLE_OPERATOR( C_OP_LennardJonesForce, "lennard jones force", OPERATOR_GENERIC );
  596. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LennardJonesForce )
  597. DMXELEMENT_UNPACK_FIELD( "interaction radius", "4", float, m_fInteractionRadius )
  598. DMXELEMENT_UNPACK_FIELD( "surface tension", "1", float, m_fSurfaceTension )
  599. DMXELEMENT_UNPACK_FIELD( "lennard jones attractive force", "1", float, m_fLennardJonesAttraction )
  600. DMXELEMENT_UNPACK_FIELD( "lennard jones repulsive force", "1", float, m_fLennardJonesRepulsion )
  601. DMXELEMENT_UNPACK_FIELD( "max repulsion", "100", float, m_fMaxRepulsion )
  602. DMXELEMENT_UNPACK_FIELD( "max attraction", "100", float, m_fMaxAttraction )
  603. END_PARTICLE_OPERATOR_UNPACK( C_OP_LennardJonesForce )
  604. #endif
  605. class C_OP_TimeVaryingForce : public CParticleOperatorInstance
  606. {
  607. DECLARE_PARTICLE_OPERATOR( C_OP_TimeVaryingForce );
  608. uint32 GetWrittenAttributes( void ) const
  609. {
  610. return 0;
  611. }
  612. uint32 GetReadAttributes( void ) const
  613. {
  614. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  615. }
  616. virtual void AddForces( FourVectors *pAccumulatedForces,
  617. CParticleCollection *pParticles,
  618. int nBlocks,
  619. float flStrength,
  620. void *pContext ) const;
  621. float m_flStartLerpTime;
  622. Vector m_StartingForce;
  623. float m_flEndLerpTime;
  624. Vector m_EndingForce;
  625. };
  626. void C_OP_TimeVaryingForce::AddForces( FourVectors *pAccumulatedForces,
  627. CParticleCollection *pParticles,
  628. int nBlocks,
  629. float flStrength,
  630. void *pContext ) const
  631. {
  632. FourVectors box_min,box_max;
  633. box_min.DuplicateVector( m_StartingForce * flStrength );
  634. box_max.DuplicateVector( m_EndingForce * flStrength);
  635. box_max -= box_min;
  636. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  637. fltx4 fl4StartTime = ReplicateX4( m_flStartLerpTime );
  638. fltx4 fl4OODuration = ReplicateX4( 1.0 / ( m_flEndLerpTime - m_flStartLerpTime ) );
  639. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  640. for(int i=0;i<nBlocks;i++)
  641. {
  642. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  643. fl4Age = MulSIMD( fl4OODuration, SubSIMD( fl4Age, fl4StartTime ) );
  644. fl4Age = MaxSIMD( Four_Zeros, MinSIMD( Four_Ones, fl4Age ) );
  645. FourVectors v4Force = box_max;
  646. v4Force *= fl4Age;
  647. v4Force += box_min;
  648. (*pAccumulatedForces) += v4Force;
  649. ++pAccumulatedForces;
  650. ++pCreationTime;
  651. }
  652. }
  653. DEFINE_PARTICLE_OPERATOR( C_OP_TimeVaryingForce, "time varying force", OPERATOR_GENERIC );
  654. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_TimeVaryingForce )
  655. DMXELEMENT_UNPACK_FIELD( "time to start transition", "0", float, m_flStartLerpTime )
  656. DMXELEMENT_UNPACK_FIELD( "starting force", "0 0 0", Vector, m_StartingForce )
  657. DMXELEMENT_UNPACK_FIELD( "time to end transition", "10", float, m_flEndLerpTime )
  658. DMXELEMENT_UNPACK_FIELD( "ending force", "0 0 0", Vector, m_EndingForce )
  659. END_PARTICLE_OPERATOR_UNPACK( C_OP_TimeVaryingForce )
  660. class C_OP_TurbulenceForce : public CParticleOperatorInstance
  661. {
  662. DECLARE_PARTICLE_OPERATOR( C_OP_TurbulenceForce );
  663. uint32 GetWrittenAttributes( void ) const
  664. {
  665. return 0;
  666. }
  667. uint32 GetReadAttributes( void ) const
  668. {
  669. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  670. }
  671. virtual void AddForces( FourVectors *pAccumulatedForces,
  672. CParticleCollection *pParticles,
  673. int nBlocks,
  674. float flStrength,
  675. void *pContext ) const;
  676. float m_flNoiseCoordScale[4];
  677. Vector m_vecNoiseAmount[4];
  678. };
  679. void C_OP_TurbulenceForce::AddForces( FourVectors *pAccumulatedForces,
  680. CParticleCollection *pParticles,
  681. int nBlocks,
  682. float flStrength,
  683. void *pContext ) const
  684. {
  685. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  686. fltx4 fl4Scales[4];
  687. FourVectors v4Amounts[4];
  688. for( int i = 0; i < ARRAYSIZE( fl4Scales ); i++ )
  689. {
  690. fl4Scales[i] = ReplicateX4( m_flNoiseCoordScale[i] );
  691. v4Amounts[i].DuplicateVector( m_vecNoiseAmount[i] );
  692. }
  693. for(int i=0;i<nBlocks;i++)
  694. {
  695. for( int j = 0; j < ARRAYSIZE( fl4Scales ); j++ )
  696. {
  697. FourVectors ppos = *pXYZ;
  698. ppos *= fl4Scales[j];
  699. ppos = DNoiseSIMD( ppos );
  700. ppos *= v4Amounts[j];
  701. (*pAccumulatedForces) += ppos;
  702. }
  703. ++pAccumulatedForces;
  704. ++pXYZ;
  705. }
  706. }
  707. DEFINE_PARTICLE_OPERATOR( C_OP_TurbulenceForce, "turbulent force", OPERATOR_GENERIC );
  708. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_TurbulenceForce )
  709. DMXELEMENT_UNPACK_FIELD( "Noise scale 0", "1", float, m_flNoiseCoordScale[0] )
  710. DMXELEMENT_UNPACK_FIELD( "Noise amount 0", "1 1 1", Vector, m_vecNoiseAmount[0] )
  711. DMXELEMENT_UNPACK_FIELD( "Noise scale 1", "0", float, m_flNoiseCoordScale[1] )
  712. DMXELEMENT_UNPACK_FIELD( "Noise amount 1", ".5 .5 .5", Vector, m_vecNoiseAmount[1] )
  713. DMXELEMENT_UNPACK_FIELD( "Noise scale 2", "0", float, m_flNoiseCoordScale[2] )
  714. DMXELEMENT_UNPACK_FIELD( "Noise amount 2", ".25 .25 .25", Vector, m_vecNoiseAmount[2] )
  715. DMXELEMENT_UNPACK_FIELD( "Noise scale 3", "0", float, m_flNoiseCoordScale[3] )
  716. DMXELEMENT_UNPACK_FIELD( "Noise amount 3", ".125 .125 .125", Vector, m_vecNoiseAmount[3] )
  717. END_PARTICLE_OPERATOR_UNPACK( C_OP_TurbulenceForce )
  718. void AddBuiltInParticleForceGenerators( void )
  719. {
  720. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_RandomForce );
  721. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_TwistAroundAxis );
  722. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_ParentVortices );
  723. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_AttractToControlPoint );
  724. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_TimeVaryingForce );
  725. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_TurbulenceForce );
  726. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_ForceBasedOnDistanceToPlane );
  727. #ifdef USE_BLOBULATOR
  728. REGISTER_PARTICLE_OPERATOR( FUNCTION_FORCEGENERATOR, C_OP_LennardJonesForce );
  729. #endif
  730. }