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.

3276 lines
102 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. #include "mathlib/femodelbuilder.h"
  3. #include "tier1/utlhashtable.h"
  4. #include "tier1/utlsortvector.h"
  5. #include "tier1/heapsort.h"
  6. #include "bitvec.h"
  7. #include "tier1/utlpair.h"
  8. #include "modellib/clothhelpers.h"
  9. #include "tier1/utlstringtoken.h"
  10. #include "mathlib/feagglomerator.h"
  11. #include <algorithm>
  12. #include "femodel.inl"
  13. // this function is exclusively for use with invM0/(invM0+invM1) type of formulae
  14. // if one of the particles is almost infinite mass, I don't want to see any creep in its position (mostly for debugging)
  15. inline float SnapWeight01( float w )
  16. {
  17. Assert( w >= 0.0f && w <= 1.0f );
  18. return w < 1e-6f ? 0 : w > 0.99999f ? 1.0f : w;
  19. }
  20. inline float SnapWeight0( float w )
  21. {
  22. Assert( w >= 0.0f && w <= 1.0f );
  23. return w < 1e-12f ? 0 : w ;
  24. }
  25. inline bool Is0To1( float w )
  26. {
  27. return w >= 0 && w <= 1.0f;
  28. }
  29. inline void KeepIn01( float &ref )
  30. {
  31. if ( ref > 1.0f )
  32. {
  33. ref = 1.0f;
  34. }
  35. else if ( !( ref >= 0.0f ) ) // the "!" should catch inf or nan
  36. {
  37. ref = 0.0f;
  38. }
  39. }
  40. void CFeModelBuilder::BuildKelagerBends( )
  41. {
  42. CUtlVector< CUtlVector< uint16 > * > neighbors;
  43. neighbors.SetCount( m_Nodes.Count( ) );
  44. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  45. {
  46. ( neighbors[ i ] = new CUtlVector< uint16 > )->EnsureCapacity( 8 );
  47. }
  48. CVarBitVec staticNodes( m_Nodes.Count( ) );
  49. int nMaxValency = 0;
  50. for ( int i = 0; i < m_Elems.Count( ); ++i )
  51. {
  52. BuildElem_t elem = m_Elems[ i ];
  53. uint nElemEdges = elem.nNode[ 3 ] == elem.nNode[ 2 ] ? 3 : 4;
  54. for ( uint j = 0; j < nElemEdges; ++j )
  55. {
  56. uint j1 = ( j + 1 ) % nElemEdges;
  57. uint v0 = elem.nNode[ j ], v1 = elem.nNode[ j1 ];
  58. if ( j < elem.nStaticNodes )
  59. {
  60. staticNodes.Set( v0 );
  61. }
  62. if ( neighbors[ v0 ]->Find( v1 ) < 0 )
  63. {
  64. int v0elem = neighbors[ v0 ]->AddToTail( v1 );
  65. int v1elem = neighbors[ v1 ]->AddToTail( v0 );
  66. nMaxValency = Max( nMaxValency, Max( v0elem, v1elem ) + 1 );
  67. }
  68. }
  69. }
  70. // now we know which vertex is connected to which, and which is static
  71. CVarBitVec paired( nMaxValency );
  72. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  73. {
  74. const CUtlVector< uint16 > &ring = *( neighbors[ nNode ] );
  75. paired.ClearAll( );
  76. Vector v = m_Nodes[ nNode ].transform.m_vPosition;
  77. for ( int b0idx = 0; b0idx < ring.Count( ); ++b0idx )
  78. {
  79. if ( paired[ b0idx ] )
  80. continue;
  81. float flBestCos = -0.87f, flBestH0 = 0;
  82. int nBestB1idx = -1;
  83. int b0 = ring[ b0idx ];
  84. int isB0static = staticNodes[ b0 ];
  85. Vector vB0 = m_Nodes[ b0 ].transform.m_vPosition - v;
  86. for ( int b1idx = 0; b1idx < ring.Count( ); ++b1idx )
  87. {
  88. if ( b1idx == b0idx )
  89. continue;
  90. int b1 = ring[ b1idx ];
  91. if ( isB0static && staticNodes[ b1 ] )
  92. continue; // no need to check static-static
  93. Vector vB1 = m_Nodes[ b1 ].transform.m_vPosition - v;
  94. float flCos = DotProduct( vB1.Normalized( ), vB0.Normalized( ) );
  95. if ( flCos < flBestCos )
  96. {
  97. flBestCos = flCos;
  98. nBestB1idx = b1idx;
  99. flBestH0 = ( vB1 + vB0 ).Length( ) / 3.0f;
  100. }
  101. }
  102. if ( nBestB1idx >= 0 )
  103. {
  104. FeKelagerBend_t kbend;
  105. kbend.flHeight0 = flBestH0;
  106. kbend.m_nNode[ 0 ] = nNode;
  107. kbend.m_nNode[ 1 ] = b0;
  108. kbend.m_nNode[ 2 ] = ring[ nBestB1idx ];
  109. kbend.m_nFlags = 7;
  110. for ( int j = 0; j < 3; ++j )
  111. {
  112. if ( staticNodes[ kbend.m_nNode[ j ] ] )
  113. kbend.m_nFlags ^= 1 << j;
  114. }
  115. Assert( kbend.m_nFlags );
  116. m_KelagerBends.AddToTail( kbend );
  117. paired.Set( nBestB1idx );
  118. }
  119. }
  120. }
  121. neighbors.PurgeAndDeleteElements( );
  122. }
  123. void CFeModelBuilder::BuildAndSortRods( float flCurvatureAngle, bool bTriangulate ) // flCurvatureAngle is additional angle we can bend each side
  124. {
  125. CUtlHashtable< uint32, uint32 > edgeToRod;
  126. // TODO: filter out rods that connect invalid here?
  127. if ( m_bAddStiffnessRods )
  128. {
  129. if ( bTriangulate )
  130. {
  131. for ( int nElem = 0; nElem < m_Elems.Count(); ++nElem )
  132. {
  133. const BuildElem_t &elem = m_Elems[ nElem ];
  134. if ( elem.nNode[ 2 ] != elem.nNode[ 3 ] )
  135. {
  136. uint v0 = elem.nNode[ 1 ], v1 = elem.nNode[ 3 ];
  137. BuildRod( flCurvatureAngle, v0, v1, nElem, nElem, elem.nNode[ 0 ], elem.nNode[ 2 ], edgeToRod );
  138. }
  139. }
  140. }
  141. for ( int nEdge = 0; nEdge < m_FeEdgeDesc.Count(); ++nEdge )
  142. {
  143. FeEdgeDesc_t edge = m_FeEdgeDesc[ nEdge ];
  144. for ( uint nLong = 0; nLong < 2; ++nLong )
  145. {
  146. uint v0 = edge.nSide[ 0 ][ nLong ], v1 = edge.nSide[ 1 ][ nLong ];
  147. BuildRod( flCurvatureAngle, v0, v1, edge.nElem[ 0 ], edge.nElem[ 1 ], edge.nEdge[ 0 ], edge.nEdge[ 1 ], edgeToRod );
  148. }
  149. }
  150. }
  151. for ( int i = 0; i < m_Rods.Count( ); ++i )
  152. {
  153. FeRodConstraint_t &rod = m_Rods[ i ];
  154. if ( m_Nodes[ rod.nNode[ 0 ] ].nRank > m_Nodes[ rod.nNode[ 1 ] ].nRank )
  155. {
  156. rod.InvariantReverse( );
  157. }
  158. }
  159. HeapSort( m_Rods, [&] ( const FeRodConstraint_t &left, const FeRodConstraint_t &right ) {
  160. int nRankLeft = Min( m_Nodes[ left.nNode[ 0 ] ].nRank, m_Nodes[ left.nNode[ 1 ] ].nRank );
  161. int nRankRight = Min( m_Nodes[ right.nNode[ 0 ] ].nRank, m_Nodes[ right.nNode[ 1 ] ].nRank );
  162. if ( nRankLeft == nRankRight )
  163. {
  164. float flLeft = Min( left.flWeight0, 1 - left.flWeight0 );
  165. float flRight = Min( right.flWeight0, 1 - right.flWeight0 );
  166. return flLeft < flRight;
  167. }
  168. else
  169. {
  170. return nRankLeft < nRankRight;
  171. }
  172. } );
  173. }
  174. void CFeModelBuilder::BuildRod( float flCurvatureAngle, uint v0, uint v1, uint nElem0, uint nElem1, uint nEdgeV0, uint nEdgeV1, CUtlHashtable< uint32, uint32 > &edgeToRod )
  175. {
  176. if ( !m_Nodes[ v0 ].bSimulated && m_Nodes[ v1 ].bSimulated )
  177. return; // rods between static nodes don't work
  178. uint nRodV0 = v0 | ( v1 << 16 ), nRodV1 = v1 | ( v0 << 16 );
  179. float invM0 = m_Nodes[ v0 ].invMass, invM1 = m_Nodes[ v1 ].invMass;
  180. if ( invM1 + invM0 < 1e-12f )
  181. return; // doesn't matter, this rod is between two infinitely massive nodes
  182. Vector vEdge = ( m_Nodes[ nEdgeV1 ].transform.m_vPosition - m_Nodes[ nEdgeV0 ].transform.m_vPosition ).NormalizedSafe( Vector( 0, 0, 1 ) );
  183. float flRelaxedRodLength = ( m_Nodes[ v1 ].transform.m_vPosition - m_Nodes[ v0 ].transform.m_vPosition ).Length();
  184. float flSumSlack = m_Elems[ nElem0 ].flSlack + m_Elems[ nElem1 ].flSlack;
  185. // max distance happens when the two polygons are rotated around edge.nEdge[] so that v0, v1 and edge.nEdge[] are in one plane
  186. // then, the angle v0-edge.nEdge[1-nLong]-v1 is at its maximum, and is the sum of angles in each quad's plane
  187. float flMaxDist, flMinDist;
  188. if ( m_bRigidEdgeHinges )
  189. {
  190. flMaxDist = flMinDist = flRelaxedRodLength;
  191. }
  192. else
  193. {
  194. Vector vCenter = m_Nodes[ nEdgeV0 ].transform.m_vPosition;
  195. Vector vSide[ 2 ] = { m_Nodes[ v0 ].transform.m_vPosition - vCenter, m_Nodes[ v1 ].transform.m_vPosition - vCenter };
  196. float flSideProj[ 2 ] = { DotProduct( vSide[ 0 ], vEdge ), DotProduct( vSide[ 1 ], vEdge ) }; // projection of side vectors onto the hinge edge
  197. float flSideProjDelta = flSideProj[ 0 ] - flSideProj[ 1 ];
  198. Vector vSideHeight[ 2 ] = { vSide[ 0 ] - vEdge * flSideProj[ 0 ], vSide[ 1 ] - vEdge * flSideProj[ 1 ] };// orthogonal to the hinge components of the sides
  199. float h[ 2 ] = { vSideHeight[ 0 ].Length( ), vSideHeight[ 1 ].Length( ) };
  200. flMaxDist = sqrtf( Sqr( flSideProjDelta ) + Sqr( h[ 0 ] + h[ 1 ] ) ) + flSumSlack;
  201. // min distance happens when triangles are closed like a book at angle flCurvatureAngle. THe points on triangles are running in circles, so it's a distance between points on 2 circles in 3D
  202. Vector deltaMin( h[ 1 ] * cosf( flCurvatureAngle ) - h[ 0 ], h[1] * sinf( flCurvatureAngle ), flSideProjDelta );
  203. flMinDist = Min( deltaMin.Length() - flSumSlack, flRelaxedRodLength ); // the mindist cannot be higher than relaxed pose mindist
  204. }
  205. Assert( flMinDist <= flMaxDist * 1.0001f + FLT_EPSILON );
  206. UtlHashHandle_t hFind = edgeToRod.Find( nRodV0 );
  207. uint nRodVidx = 0;
  208. if ( hFind == edgeToRod.InvalidHandle( ) )
  209. {
  210. hFind = edgeToRod.Find( nRodV1 );
  211. nRodVidx = 1;
  212. }
  213. if ( hFind == edgeToRod.InvalidHandle( ) )
  214. {
  215. nRodVidx = 0;
  216. FeRodConstraint_t rod;
  217. rod.nNode[ 0 ] = v0;
  218. rod.nNode[ 1 ] = v1;
  219. rod.flRelaxationFactor = 1.0f;
  220. rod.flWeight0 = SnapWeight01( invM0 / ( invM1 + invM0 ) );
  221. rod.flMinDist = flMinDist;
  222. rod.flMaxDist = flMaxDist;
  223. int nRod = m_Rods.AddToTail( rod );
  224. edgeToRod.Insert( nRodV0, ( uint ) nRod );
  225. }
  226. else
  227. {
  228. FeRodConstraint_t &rod = m_Rods[ edgeToRod[ hFind ] ];
  229. Assert( nRodVidx == 0 ? ( rod.nNode[ 0 ] == v0 && rod.nNode[ 1 ] == v1 ) : ( rod.nNode[ 0 ] == v1 && rod.nNode[ 1 ] == v0 ) );
  230. rod.flMinDist = Min( rod.flMinDist, flMinDist );
  231. rod.flMaxDist = Max( rod.flMaxDist, flMaxDist );
  232. }
  233. }
  234. void CFeModelBuilder::BuildSprings( CUtlVector< FeSpringIntegrator_t > &springs )
  235. {
  236. CUtlHashtable< uint32 > created;
  237. springs.EnsureCapacity( m_Springs.Count() );
  238. for ( int i = 0; i < m_Springs.Count( ); ++i )
  239. {
  240. FeSpringIntegrator_t spring;
  241. spring.nNode[ 0 ] = m_Springs[ i ].nNode[ 0 ];
  242. spring.nNode[ 1 ] = m_Springs[ i ].nNode[ 1 ];
  243. if ( created.HasElement( spring.nNode[ 0 ] + ( uint( spring.nNode[ 1 ] ) << 16 ) ) )
  244. {
  245. continue;
  246. }
  247. const BuildNode_t &node0 = m_Nodes[ spring.nNode[ 0 ] ], &node1 = m_Nodes[ spring.nNode[ 1 ] ];
  248. if ( node1.invMass + node0.invMass < 1e-9f )
  249. {
  250. continue; // skip springs between pinned points
  251. }
  252. //float flAveDamping = ( node0.integrator.flPointDamping + node1.integrator.flPointDamping ) * 0.5f;
  253. float expd0 = expf( -node0.integrator.flPointDamping ), expd1 = expf( -node1.integrator.flPointDamping );
  254. // if particles are severely damped, or are massive, the spring should feel proportionally weaker:
  255. // the original Dota spring constants had dimentionality to compute force (not acceleration), so they
  256. // effectively (implicitly) were divided by mass to compute acceleration later
  257. spring.flSpringConstant = m_Springs[ i ].flSpringConstant * ( node1.invMass * expd1 + node0.invMass * expd0 );
  258. spring.flSpringDamping = m_Springs[ i ].flSpringDamping * ( node1.invMass * expd1 + node0.invMass * expd0 );
  259. if ( spring.flSpringConstant == 0 && spring.flSpringDamping == 0 )
  260. {
  261. continue; // this spring will never generate any force...
  262. }
  263. spring.flSpringRestLength = ( m_Nodes[ spring.nNode[ 0 ] ].transform.m_vPosition - m_Nodes[ spring.nNode[ 1 ] ].transform.m_vPosition ).Length();
  264. // make well-damped node to have effectively higher mass (lower invMass)
  265. // so, node0 damping greater => node0 invMass lower
  266. // because damping is an exponential function, this should figure out fine
  267. // also, node0 fixed => weight0 == 0, and vice versa
  268. spring.flNodeWeight0 = SnapWeight01( node0.invMass * expd0 / ( node1.invMass * expd1 + node0.invMass * expd0 ) );
  269. created.Insert( spring.nNode[ 0 ] + ( uint( spring.nNode[ 1 ] ) << 16 ) );
  270. created.Insert( spring.nNode[ 1 ] + ( uint( spring.nNode[ 0 ] ) << 16 ) );
  271. springs.AddToTail( spring );
  272. }
  273. }
  274. void CFeModelBuilder::BuildQuads( CUtlVector< FeQuad_t > &quads, bool bSkipTris )
  275. {
  276. quads.EnsureCapacity( m_Elems.Count( ) );
  277. uint nQuadCount[ 3 ] = { 0, 0, 0 };
  278. uint nLastStaticNodes = 2;
  279. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  280. {
  281. const BuildElem_t &buildElem = m_Elems[ nElem ];
  282. bool bIsQuad = buildElem.nNode[ 2 ] != buildElem.nNode[ 3 ];
  283. if ( bSkipTris && !bIsQuad )
  284. {
  285. continue; // skip this quad: it's really a triangle and we skip triangles
  286. }
  287. uint nStaticNodes = buildElem.nStaticNodes;
  288. Assert( nStaticNodes <= nLastStaticNodes ); // quads should already be sorted
  289. nLastStaticNodes = nStaticNodes;
  290. FeQuad_t quad;
  291. quad.flSlack = buildElem.flSlack;
  292. BuildNode_t node[ 4 ];
  293. for ( uint j = 0; j < 4; ++j )
  294. {
  295. node[ j ] = m_Nodes[ buildElem.nNode[ j ] ];
  296. }
  297. float flSumMass = 0;
  298. float flMass[ 4 ];
  299. for ( uint j = nStaticNodes; j < 4; ++j )
  300. {
  301. flSumMass += ( flMass[ j ] = 1.0f / Max( 1e-6f, node[ j ].invMass ) );
  302. }
  303. Vector vCoM = vec3_origin;
  304. float flWeight[ 4 ] = { 0,0,0,0}, flSumWeights = 0;
  305. for ( uint j = nStaticNodes; j < 4; ++j )
  306. {
  307. flWeight[ j ] = flMass[ j ] / flSumMass;
  308. vCoM += flWeight[ j ] * node[ j ].transform.m_vPosition;
  309. flSumWeights += flWeight[ j ];
  310. }
  311. const VectorAligned &p0 = node[ 0 ].transform.m_vPosition;
  312. const VectorAligned &p1 = node[ 1 ].transform.m_vPosition;
  313. const VectorAligned &p2 = node[ 2 ].transform.m_vPosition;
  314. const VectorAligned &p3 = node[ 3 ].transform.m_vPosition;
  315. // special case: the center of mass is assumed to be at or between the infinite-mass nodes
  316. switch ( nStaticNodes )
  317. {
  318. case 1:
  319. vCoM = p0;
  320. break;
  321. case 2:
  322. vCoM = ( p0 + p1 ) * 0.5f;
  323. break;
  324. }
  325. CFeBasis basis;
  326. if ( nStaticNodes == 2 )
  327. {
  328. basis.Init( p1 - p0, p2 + p3 - 2 * p0 );
  329. }
  330. else
  331. {
  332. basis.Init( p2 - p0, p3 - p1 );
  333. }
  334. Vector vShapeWorld[ 4 ];
  335. for ( uint j = 0; j < 4; ++j )
  336. {
  337. vShapeWorld[ j ] = node[ j ].transform.m_vPosition - vCoM;
  338. quad.nNode[ j ] = buildElem.nNode[ j ];
  339. quad.vShape[ j ].Init( basis.WorldToLocal( vShapeWorld[ j ] ), j < nStaticNodes ? 0.0f : SnapWeight0( flWeight[ j ] / flSumWeights ) );
  340. }
  341. quads.AddToTail( quad );
  342. nQuadCount[ nStaticNodes ] = quads.Count( );
  343. }
  344. m_nQuadCount[ 0 ] = quads.Count( );
  345. m_nQuadCount[ 1 ] = Max( nQuadCount[ 1 ], nQuadCount[ 2 ] );
  346. m_nQuadCount[ 2 ] = nQuadCount[ 2 ];
  347. }
  348. FeTri_t CFeModelBuilder::BuildTri( const BuildElem_t &buildElem, int nTriStaticNodes, int nSubTri )
  349. {
  350. FeTri_t tri;
  351. BuildNode_t node[ 3 ];
  352. for ( uint j = 0; j < 3; ++j )
  353. {
  354. tri.nNode[ j ] = buildElem.nNode[ j > 0 ? ( j + nSubTri ) : 0 ];
  355. node[ j ] = m_Nodes[ tri.nNode[ j ] ];
  356. }
  357. float flSumMass = 0;
  358. float flMass[ 3 ] = { 0, 0, 0 };
  359. for ( uint j = nTriStaticNodes; j < 3; ++j )
  360. {
  361. flSumMass += ( flMass[ j ] = 1.0f / Max( 1e-6f, node[ j ].invMass ) );
  362. }
  363. Vector vEdge1 = node[ 1 ].transform.m_vPosition - node[ 0 ].transform.m_vPosition, vEdge2 = node[ 2 ].transform.m_vPosition - node[ 0 ].transform.m_vPosition;
  364. CFeTriBasis basis( vEdge1, vEdge2 );
  365. AssertDbg( fabsf( DotProduct( basis.vAxisY, vEdge1 ) ) < 1e-4f * ( 1 + vEdge1.Length() ) );
  366. AssertDbg( CrossProduct( basis.vAxisX, vEdge1 ).Length( ) < 1e-4f * ( 1 + vEdge1.Length() ) );
  367. tri.v1x = vEdge1.Length( );
  368. tri.v2.x = DotProduct( vEdge2, basis.vAxisX );
  369. tri.v2.y = DotProduct( vEdge2, basis.vAxisY );
  370. tri.w1 = flMass[ 1 ] / flSumMass;
  371. tri.w2 = flMass[ 2 ] / flSumMass;
  372. return tri;
  373. }
  374. void CFeModelBuilder::BuildTris( CUtlVector< FeTri_t > &trisOut, bool bTriangulate )
  375. {
  376. CUtlVector< FeTri_t > tris[ 3 ];
  377. tris[ 0 ].EnsureCapacity( m_Elems.Count( ) * 2 );
  378. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  379. {
  380. const BuildElem_t &buildElem = m_Elems[ nElem ];
  381. bool bIsQuad = buildElem.nNode[ 2 ] != buildElem.nNode[ 3 ];
  382. if ( !bTriangulate && bIsQuad )
  383. {
  384. // this is a quad, skip
  385. continue;
  386. }
  387. tris[ buildElem.nStaticNodes ].AddToTail( BuildTri( buildElem, buildElem.nStaticNodes, 0 ) );
  388. if ( bIsQuad )
  389. {
  390. // add the second triangle of the quad ; it's 1 static node if the quad had 2 static nodes
  391. uint nTri2static = Min< uint >( 1u, buildElem.nStaticNodes );
  392. tris[ nTri2static ].AddToTail( BuildTri( buildElem, nTri2static, 1 ) );
  393. }
  394. }
  395. m_nTriCount[ 0 ] = tris[ 0 ].Count( ) + tris[ 1 ].Count( ) + tris[ 2 ].Count( );
  396. m_nTriCount[ 1 ] = tris[ 1 ].Count( ) + tris[ 2 ].Count( );
  397. m_nTriCount[ 2 ] = tris[ 2 ].Count( );
  398. trisOut.EnsureCapacity( m_nTriCount[ 0 ] );
  399. trisOut.AddVectorToTail( tris[ 2 ] );
  400. trisOut.AddVectorToTail( tris[ 1 ] );
  401. trisOut.AddVectorToTail( tris[ 0 ] );
  402. }
  403. void CFeModelBuilder::BuildFeEdgeDesc( )
  404. {
  405. struct Side_t
  406. {
  407. uint16 nNode[ 2 ];
  408. uint16 nElem;
  409. };
  410. CUtlHashtable< uint32, Side_t > edgeToVert;
  411. uint nNodeCount = ( uint )m_Nodes.Count(); NOTE_UNUSED( nNodeCount );
  412. for ( int nElement = 0; nElement < m_Elems.Count( ); ++nElement )
  413. {
  414. BuildElem_t elem = m_Elems[ nElement ];
  415. const uint nElemEdgeCount = 4;
  416. for ( uint nElemEdge = 0; nElemEdge < nElemEdgeCount; ++nElemEdge )
  417. {
  418. uint j1 = ( nElemEdge + 1 ) % nElemEdgeCount;
  419. if ( nElemEdge == j1 )
  420. continue; // skip degenerate edges
  421. uint32 n0 = elem.nNode[ nElemEdge ], n1 = elem.nNode[ j1 ];
  422. uint nEdgeV0 = n0 | ( n1 << 16 ), nEdgeV1 = n1 | ( n0 << 16 );
  423. int j2 = ( nElemEdge + 2 ) % nElemEdgeCount, j3 = ( nElemEdge + 3 ) % nElemEdgeCount;
  424. uint n2 = elem.nNode[ j2 ], n3 = elem.nNode[ j3 ];
  425. Assert( n3 < nNodeCount && n2 < nNodeCount && n1 < nNodeCount && n0 < nNodeCount );
  426. UtlHashHandle_t hFind = edgeToVert.Find( nEdgeV0 );
  427. uint nEdgeVidx = 0;
  428. if ( hFind == edgeToVert.InvalidHandle( ) )
  429. {
  430. hFind = edgeToVert.Find( nEdgeV1 );
  431. nEdgeVidx = 1;
  432. }
  433. if ( hFind == edgeToVert.InvalidHandle( ) )
  434. {
  435. Side_t side = { { (uint16)n2, (uint16)n3 }, (uint16)nElement };
  436. edgeToVert.Insert( nEdgeV0, side );
  437. }
  438. else
  439. {
  440. // found a matching edge!
  441. FeEdgeDesc_t edge;
  442. edge.nEdge[ 0 ] = n0;
  443. edge.nEdge[ 1 ] = n1;
  444. edge.nSide[ 0 ][ 0 ] = n2;
  445. edge.nSide[ 0 ][ 1 ] = n3;
  446. edge.nSide[ 1 ][ 0 ] = edgeToVert[ hFind ].nNode[ nEdgeVidx ];
  447. edge.nSide[ 1 ][ 1 ] = edgeToVert[ hFind ].nNode[ 1 - nEdgeVidx ];
  448. edge.nElem[ 0 ] = nElement;
  449. edge.nElem[ 1 ] = edgeToVert[ hFind ].nElem;
  450. m_FeEdgeDesc.AddToTail( edge );
  451. edgeToVert.RemoveByHandle( hFind );
  452. }
  453. }
  454. }
  455. }
  456. void CFeModelBuilder::BuildNodeSlack( float flSlackMultiplier )
  457. {
  458. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  459. {
  460. m_Nodes[ nNode ].flSlack = FLT_MAX;
  461. }
  462. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  463. {
  464. BuildElem_t elem = m_Elems[ nElem ];
  465. for ( int i = 0; i < 4; ++i )
  466. {
  467. int i1 = ( i + 1 ) % 4;
  468. uint n0 = elem.nNode[ i ], n1 = elem.nNode[ i1 ];
  469. if ( n0 != n1 )
  470. {
  471. float flSlack = flSlackMultiplier * ( m_Nodes[ n0 ].transform.m_vPosition - m_Nodes[ n1 ].transform.m_vPosition ).Length( );
  472. m_Nodes[ n0 ].flSlack = Min( m_Nodes[ n0 ].flSlack, flSlack );
  473. m_Nodes[ n1 ].flSlack = Min( m_Nodes[ n0 ].flSlack, flSlack );
  474. }
  475. }
  476. }
  477. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  478. {
  479. BuildElem_t &elem = m_Elems[ nElem ];
  480. elem.flSlack = FLT_MAX;
  481. for ( int i = 0; i < 4; ++i )
  482. {
  483. elem.flSlack = Min( elem.flSlack, m_Nodes[ elem.nNode[ i ] ].flSlack );
  484. }
  485. }
  486. }
  487. void CFeModelBuilder::BuildOldFeEdges( )
  488. {
  489. for ( int ei = 0; ei < m_FeEdgeDesc.Count( ); ++ei )
  490. {
  491. // found a matching edge!
  492. FeEdgeDesc_t edgeIn = m_FeEdgeDesc[ ei ];
  493. OldFeEdge_t edge;
  494. edge.m_nNode[ 0 ] = edgeIn.nEdge[ 0 ];
  495. edge.m_nNode[ 1 ] = edgeIn.nEdge[ 1 ];
  496. edge.m_nNode[ 2 ] = edgeIn.nSide[ 0 ][ 0 ];
  497. edge.m_nNode[ 3 ] = edgeIn.nSide[ 1 ][ 0 ];
  498. Vector x[ 4 ];
  499. for ( int k = 0; k < 4; ++k )
  500. x[ k ] = m_Nodes[ edge.m_nNode[ k ] ].transform.m_vPosition;
  501. Vector e[ 5 ] = { x[ 1 ] - x[ 0 ], x[ 2 ] - x[ 0 ], x[ 3 ] - x[ 0 ], x[ 2 ] - x[ 1 ], x[ 3 ] - x[ 1 ] };
  502. float cot0[ 5 ];
  503. // this is the factor f to make Q = fK^t * fK, see "Discrete IBM: Implementation", page 2 of "A Quadratic Bending Model for Inextensible Surfaces"
  504. float flInvAreasSqrt = sqrtf( 6.0f / ( CrossProduct( e[ 0 ], e[ 1 ] ).Length( ) + CrossProduct( e[ 0 ], e[ 2 ] ).Length( ) ) );
  505. for ( int k = 0; k < 5; ++k )
  506. cot0[ k ] = DotProduct( e[ 0 ], e[ k ] ) / CrossProduct( e[ 0 ], e[ k ] ).Length( ); // ( cosine / sine ), coincidentally a stable way to find a non-zero (non-degenerate) angle..
  507. edge.m_flK[ 0 ] = flInvAreasSqrt * ( cot0[ 3 ] + cot0[ 4 ] );
  508. edge.m_flK[ 1 ] = flInvAreasSqrt * ( cot0[ 1 ] + cot0[ 2 ] );
  509. edge.m_flK[ 2 ] = flInvAreasSqrt * ( -cot0[ 1 ] - cot0[ 3 ] );
  510. Vector n1 = CrossProduct( e[ 0 ], e[ 1 ] ), n2 = CrossProduct( e[ 0 ], e[ 2 ] );
  511. float e_sqr = e[ 0 ].LengthSqr( ), n1_len = n1.Length( ), n2_len = n2.Length( );
  512. float flTheta0 = atan2f( CrossProduct( n1, n2 ).Length( ), DotProduct( n1, n2 ) );
  513. edge.flThetaRelaxed = sinf( 0.5f * flTheta0 );
  514. edge.flThetaFactor = e_sqr / ( n1_len + n2_len );
  515. edge.t = 0.5f * DotProduct( e[ 2 ] + e[ 1 ], e[ 0 ] ) / e[ 0 ].LengthSqr( );
  516. edge.invA = flInvAreasSqrt;
  517. edge.c01 = cot0[ 1 ];
  518. edge.c02 = cot0[ 2 ];
  519. edge.c03 = cot0[ 3 ];
  520. edge.c04 = cot0[ 4 ];
  521. // virtual edge and axial normal
  522. m_OldFeEdges.AddToTail( edge );
  523. }
  524. }
  525. // return 1/(x0^2/invM0+x1^2/invM1)
  526. static inline float Compute1DInvInertiaTensor( float invM0, float x0, float invM1, float x1 )
  527. {
  528. if ( invM0 <= 1e-8f )
  529. {
  530. return invM1 <= 1e-8f || fabsf( x0 ) > 1e-6f ? 0.0f : invM1 / Sqr( x1 );
  531. }
  532. else
  533. {
  534. if ( invM1 <= 1e-8f )
  535. {
  536. return fabsf( x1 ) > 1e-6f ? 0.0f : invM0 / Sqr( x0 );
  537. }
  538. else
  539. {
  540. return 1.0f / ( Sqr( x0 ) / invM0 + Sqr( x1 ) / invM1 );
  541. }
  542. }
  543. }
  544. static inline float ComputeEdgeCenterOfMass( float a, float b )
  545. {
  546. return fabsf( b ) >= 1e-8f ? a / b : 0.5f;
  547. }
  548. static inline float CombineInvMasses( float invM0, float invM1 )
  549. {
  550. if ( invM0 <= 0 || invM1 <= 0 )
  551. return 0;
  552. return ( invM0 * invM1 ) / ( invM0 + invM1 ); // ( m0 + m1 ) ^ -1
  553. }
  554. void CFeModelBuilder::BuildAxialEdges( )
  555. {
  556. for ( int ei = 0; ei < m_FeEdgeDesc.Count( ); ++ei )
  557. {
  558. // found a matching edge!
  559. FeEdgeDesc_t edgeIn = m_FeEdgeDesc[ ei ];
  560. FeAxialEdgeBend_t edge;
  561. edge.nNode[ 0 ] = edgeIn.nEdge[ 0 ];
  562. edge.nNode[ 1 ] = edgeIn.nEdge[ 1 ];
  563. edge.nNode[ 2 ] = edgeIn.nSide[ 0 ][ 0 ];
  564. edge.nNode[ 3 ] = edgeIn.nSide[ 0 ][ 1 ];
  565. edge.nNode[ 4 ] = edgeIn.nSide[ 1 ][ 0 ];
  566. edge.nNode[ 5 ] = edgeIn.nSide[ 1 ][ 1 ];
  567. Vector x[ 4 ] = {
  568. m_Nodes[ edge.nNode[ 0 ] ].transform.m_vPosition,
  569. m_Nodes[ edge.nNode[ 1 ] ].transform.m_vPosition,
  570. ( m_Nodes[ edge.nNode[ 2 ] ].transform.m_vPosition + m_Nodes[ edge.nNode[ 3 ] ].transform.m_vPosition )* 0.5f,
  571. ( m_Nodes[ edge.nNode[ 4 ] ].transform.m_vPosition + m_Nodes[ edge.nNode[ 5 ] ].transform.m_vPosition )* 0.5f
  572. };
  573. // do we need to flip it? The direction of the bend depends on the ordering of nodes
  574. {
  575. Vector vApproximateAxis = ( x[ 1 ] + x[ 0 ] ) - ( x[ 2 ] + x[ 3 ] );
  576. Vector vEdge = x[ 1 ] - x[ 0 ], vVirtualEdge = x[ 2 ] - x[ 3 ];
  577. Vector vCrossEdges = CrossProduct( vEdge, vVirtualEdge );
  578. if ( DotProduct( vApproximateAxis, vCrossEdges ) < 0 )
  579. {
  580. // flip one of the edges around
  581. Swap( x[ 0 ], x[ 1 ] );
  582. Swap( edge.nNode[ 0 ], edge.nNode[ 1 ] );
  583. }
  584. }
  585. float invM[ 4 ] = {
  586. m_Nodes[ edge.nNode[ 0 ] ].invMass,
  587. m_Nodes[ edge.nNode[ 1 ] ].invMass,
  588. edge.nNode[ 2 ] == edge.nNode[ 3 ] ? m_Nodes[ edge.nNode[ 2 ] ].invMass : CombineInvMasses( m_Nodes[ edge.nNode[ 2 ] ].invMass, m_Nodes[ edge.nNode[ 3 ] ].invMass ),
  589. edge.nNode[ 4 ] == edge.nNode[ 5 ] ? m_Nodes[ edge.nNode[ 4 ] ].invMass : CombineInvMasses( m_Nodes[ edge.nNode[ 4 ] ].invMass, m_Nodes[ edge.nNode[ 5 ] ].invMass )
  590. };
  591. if ( invM[ 0 ] + invM[ 1 ] + invM[ 2 ] + invM[ 3 ] == 0 )
  592. {
  593. // nothing to keep bent, the static nodes at the fringes will take care of it
  594. continue;
  595. }
  596. Vector e[ 5 ] = { x[ 1 ] - x[ 0 ], x[ 2 ] - x[ 0 ], x[ 3 ] - x[ 0 ], x[ 2 ] - x[ 1 ], x[ 3 ] - x[ 1 ] };
  597. float cot0[ 5 ] = { 0 };
  598. // this is the factor f to make Q = fK^t * fK, see "Discrete IBM: Implementation", page 2 of "A Quadratic Bending Model for Inextensible Surfaces"
  599. //float flInvAreasSqrt = sqrtf( 6.0f / ( CrossProduct( e[ 0 ], e[ 1 ] ).Length() + CrossProduct( e[ 0 ], e[ 2 ] ).Length() ) );
  600. for ( int k = 1; k < 5; ++k )
  601. {
  602. cot0[ k ] = DotProduct( e[ 0 ], e[ k ] ) / CrossProduct( e[ 0 ], e[ k ] ).Length(); // ( cosine / sine ), coincidentally a stable way to find a non-zero (non-degenerate) angle..
  603. }
  604. Vector n1 = CrossProduct( e[ 0 ], e[ 1 ] ), n2 = CrossProduct( e[ 0 ], e[ 2 ] );
  605. // virtual edge and axial normal
  606. Vector eV = x[ 3 ] - x[ 2 ], an = CrossProduct( e[ 0 ], eV );
  607. float flAxialNormalLength = an.Length( );
  608. if ( flAxialNormalLength < 0.001f )
  609. continue;
  610. an /= flAxialNormalLength;
  611. float e0len = e[ 0 ].Length( ), eVlen = eV.Length( );
  612. Vector e0dir = e[ 0 ] / e0len;
  613. Vector side = CrossProduct( an, e0dir );
  614. float t2 = DotProduct( side, e[ 1 ] ), t3 = DotProduct( side, e[ 2 ] );
  615. // the indices are a misnomer; t correspond to x, e to e in "Discrete Quadratic Curvature Energies" by Wardetzky et al, page 28
  616. edge.tv = -t2 / ( t3 - t2 );
  617. Vector v23 = e[ 1 ] + eV * edge.tv;
  618. float f0len = DotProduct( v23, e0dir );
  619. edge.te = f0len / e0len;
  620. Vector v01 = e0dir * f0len;
  621. Assert( fabs( DotProduct( v01 - v23, e[ 0 ] ) ) < 0.001f && fabs( DotProduct( v01 - v23, eV ) ) < 0.001f );
  622. edge.flDist = ( v01 - v23 ).Length( );
  623. float c0len = ComputeEdgeCenterOfMass( e0len * invM[ 0 ], invM[ 0 ] + invM[ 1 ] ); // pretend x0 = 0, x1 = e0len, find the center of mass along that line
  624. float cVlen = ComputeEdgeCenterOfMass( eVlen * invM[ 2 ], invM[ 2 ] + invM[ 3 ] ); // pretend x2 = 0, x3 = eVlen, find the center of mass of the virtual edge
  625. // Inv Inertia Tensor is ( m0 * x0^2 + m1 * x1^2 )^-1 == m0^-1 * m1^-1 / ( m1^-1 * x0^2 + m0^-1 * x1^2 ) , we just compute it here
  626. float flI0inv = Compute1DInvInertiaTensor( invM[ 0 ], ( c0len ), invM[ 1 ], ( e0len - c0len ) );
  627. float flIVinv = Compute1DInvInertiaTensor( invM[ 2 ], ( cVlen ), invM[ 3 ], ( eVlen - cVlen ) );
  628. float /*f0len = edge.t01 * e0len,*/ fVlen = edge.tv * eVlen;
  629. float f0 = f0len - c0len, fV = fVlen - cVlen;
  630. if ( 1 )
  631. {
  632. // when applying impulse 1.0 to edge 0-1, and -1.0 to virtual edge 2-3, this is how much the x[.] vertices move
  633. float flReact[ 4 ] = {
  634. invM[ 0 ] - flI0inv * f0 * c0len, invM[ 1 ] + flI0inv * f0 * ( e0len - c0len ),
  635. -( invM[ 2 ] - flIVinv * fV * cVlen ), -( invM[ 3 ] + flIVinv * fV * ( eVlen - cVlen ) )
  636. };
  637. // reactions at the fulcrum points
  638. float flReact01 = edge.te * flReact[ 0 ] + ( 1 - edge.te ) * flReact[ 1 ], flReact23 = edge.tv * flReact[ 2 ] + ( 1 - edge.tv ) * flReact[ 3 ];
  639. float flReactSumAtFulcrum = flReact01 - flReact23; // applying impulse 1.0 at the connection between fulcrums, this is how much the gap closes
  640. if ( flReactSumAtFulcrum > 1e-8f )
  641. {
  642. edge.flWeight[ 0 ] = ( flReact[ 0 ] / flReactSumAtFulcrum );
  643. edge.flWeight[ 1 ] = ( flReact[ 1 ] / flReactSumAtFulcrum );
  644. edge.flWeight[ 2 ] = ( flReact[ 2 ] / flReactSumAtFulcrum );
  645. //if ( edge.nNode[ 2 ] == edge.nNode[ 3 ] )
  646. // edge.flWeight[ 2 ] *= 0.5f; // the same weight will be applied to the same node twice.. Careful! SIMD implementation doesn't need *=0.5! and scalar can easily avoid this, too
  647. edge.flWeight[ 3 ] = ( flReact[ 3 ] / flReactSumAtFulcrum );
  648. //if ( edge.nNode[ 4 ] == edge.nNode[ 5 ] )
  649. // edge.flWeight[ 3 ] *= 0.5f; // the same weight will be applied to the same node twice.. Careful! SIMD implementation doesn't need *=0.5! and scalar can easily avoid this, too
  650. Assert( invM[ 0 ] == 0 || invM[ 1 ] == 0 || invM[ 2 ] == 0 || invM[ 3 ] == 0 || fabsf( edge.flWeight[ 0 ] / invM[ 0 ] + edge.flWeight[ 1 ] / invM[ 1 ] + edge.flWeight[ 2 ] / invM[ 2 ] + edge.flWeight[ 3 ] / invM[ 3 ] ) < 1e-5f / ( invM[ 0 ] + invM[ 1 ] + invM[ 2 ] + invM[ 3 ] ) );
  651. m_AxialEdges.AddToTail( edge );
  652. }
  653. }
  654. else
  655. {
  656. // just apply impulse along the line between the edge and virtual edge.
  657. float flEdgeInvMass = CombineInvMasses( invM[ 0 ], invM[ 1 ] );
  658. // virtual edge will move against the direction, main edge will move along
  659. float flVirtEdgeReact = invM[ 2 ] * ( 1 - edge.tv ) + invM[ 3 ] * edge.tv;
  660. float flTotalReaction = flEdgeInvMass + flVirtEdgeReact; // this is how much the edge and virt edge close when applying impulse 1.0
  661. if ( flTotalReaction < FLT_EPSILON )
  662. continue; // we have nothing to move except one of the vertices on the real edge, and that'll be taken care of by quad contraints
  663. edge.flWeight[ 0 ] = edge.flWeight[ 1 ] = flEdgeInvMass / flTotalReaction;
  664. edge.flWeight[ 2 ] = - invM[ 2 ] / flTotalReaction;
  665. edge.flWeight[ 3 ] = -invM[ 3 ] / flTotalReaction;
  666. }
  667. }
  668. CFeModelBuilder *pThis = this;
  669. HeapSort( m_AxialEdges, [ pThis ]( const FeAxialEdgeBend_t &left, const FeAxialEdgeBend_t &right )
  670. {
  671. return pThis->GetRank( left ) < pThis->GetRank( right );
  672. }
  673. );
  674. }
  675. int CFeModelBuilder::ReconcileElemStaticNodes()
  676. {
  677. int nExtraStaticNodesFound = 0;
  678. // find out if any elements have 3+ static nodes and remove them; sort nodes in elements that have more static nodes than declared
  679. // we may FastRemove elements during this loop, so counting downwards is easiest
  680. for ( int nElem = m_Elems.Count(); nElem-- > 0; )
  681. {
  682. BuildElem_t &elem = m_Elems[ nElem ];
  683. int nExtraStatics = 0;
  684. {
  685. uint numNodes = elem.NumNodes();
  686. for ( uint j = elem.nStaticNodes; j < numNodes; ++j )
  687. {
  688. uint nNode = elem.nNode[ j ];
  689. if ( !m_Nodes[ nNode ].bSimulated )
  690. {
  691. ++nExtraStatics;
  692. }
  693. }
  694. }
  695. nExtraStaticNodesFound += nExtraStatics;
  696. elem.nStaticNodes += nExtraStatics;
  697. if ( nExtraStatics )
  698. {
  699. CUtlVectorAligned< BuildNode_t > &nodes = m_Nodes;
  700. // element is still dynamic; sort it and go on
  701. uint numNodes = elem.NumNodes();
  702. BubbleSort( elem.nNode, numNodes, [ &nodes ]( uint nLeftNode, uint nRightNode ) {
  703. return int( nodes[ nLeftNode ].bSimulated ) < int( nodes[ nRightNode ].bSimulated ); // sort: non-simulated, then simulated
  704. } );
  705. elem.nNode[ 3 ] = elem.nNode[ numNodes - 1 ];
  706. for ( elem.nStaticNodes = 0; elem.nStaticNodes < numNodes && !nodes[ elem.nNode[ elem.nStaticNodes ] ].bSimulated ; ++elem.nStaticNodes )
  707. continue;
  708. }
  709. if ( elem.nStaticNodes >= 3 )
  710. {
  711. // the whole element is static; remove it, mark all as static
  712. for ( uint j = elem.nStaticNodes; j < BuildElem_t::MAX_NODES; ++j )
  713. {
  714. BuildNode_t &refNode = m_Nodes[ elem.nNode[ j ] ];
  715. if ( refNode.bSimulated && !refNode.bForceSimulated )
  716. {
  717. refNode.bSimulated = false;
  718. nExtraStaticNodesFound++;
  719. elem.nStaticNodes++;
  720. }
  721. }
  722. // Note: we still need fully static elements to construct stiffness rods, perhaps some face angle constraints, and the analogs of 3-static-node quads
  723. //m_Elems.FastRemove( nElem );
  724. }
  725. }
  726. return nExtraStaticNodesFound;
  727. }
  728. int CFeModelBuilder::RemoveFullyStaticElems()
  729. {
  730. int nRemoved = 0;
  731. for ( int nElem = m_Elems.Count(); nElem-- > 0; )
  732. {
  733. BuildElem_t &elem = m_Elems[ nElem ];
  734. if ( elem.nStaticNodes >= 3 )
  735. {
  736. ++nRemoved;
  737. m_Elems.Remove( nElem ); // keep the order
  738. }
  739. }
  740. return nRemoved;
  741. }
  742. void CFeModelBuilder::BuildInvMassesAndSortNodes( )
  743. {
  744. // we don't remap anything, because we assume everything's downstream of this call
  745. Assert( m_AxialEdges.IsEmpty( ) && m_OldFeEdges.IsEmpty( ) && m_KelagerBends.IsEmpty( ) && m_FeEdgeDesc.IsEmpty( ) );
  746. CleanupElements();
  747. const int nInvalidRank = INT_MAX;
  748. CUtlVector< float > nodeMass;
  749. if ( m_bEnableExplicitNodeMasses )
  750. {
  751. nodeMass.SetCount( m_Nodes.Count( ) );
  752. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  753. {
  754. if ( m_Nodes[ i ].invMass > FLT_EPSILON )
  755. {
  756. nodeMass[ i ] = 1.0f / m_Nodes[ i ].invMass;
  757. }
  758. else
  759. {
  760. nodeMass[ i ] = 0;
  761. m_Nodes[ i ].bSimulated = false;
  762. }
  763. }
  764. }
  765. else
  766. {
  767. RecomputeMasses( nodeMass );
  768. BalanceGlobalMassMultipliers( nodeMass );
  769. }
  770. CUtlVector< CUtlSortVector< int >* >nodeConn; // nodes this node is connected to
  771. nodeConn.SetCount( m_Nodes.Count( ) );
  772. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  773. {
  774. m_Nodes[ nNode ].nRank = nInvalidRank;
  775. nodeConn[ nNode ] = new CUtlSortVector< int >( ); // this shouldn't normally be more than 8 elements, so even sorting this vector isn't a win, but the utility functions on Sortvector are convenient
  776. }
  777. // propagate static nodes
  778. do
  779. {
  780. // mark all nodes declared as static in Finite ELements, as static
  781. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  782. {
  783. const BuildElem_t &elem = m_Elems[ nElem ];
  784. for ( uint j = 0; j < elem.nStaticNodes; ++j )
  785. {
  786. uint nNode = elem.nNode[ j ];
  787. m_Nodes[ nNode ].bSimulated = false;
  788. }
  789. }
  790. }
  791. while ( ReconcileElemStaticNodes() );
  792. // slam nodes that are not simulated
  793. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  794. {
  795. if ( !m_Nodes[ i ].bSimulated )
  796. {
  797. nodeMass[ i ] = 0.0f;
  798. m_Nodes[ i ].invMass = 0.0f;
  799. }
  800. }
  801. // add node connectivity from elements
  802. for ( int nElem = 0; nElem < m_Elems.Count(); ++nElem)
  803. {
  804. const BuildElem_t &elem = m_Elems[ nElem ];
  805. if ( CountSimulatedNodesIn( elem ) >= 1 )
  806. {
  807. AssertDbg( elem.nNode[ 1 ] != elem.nNode[ 0 ] && elem.nNode[ 2 ] != elem.nNode[ 1 ] && elem.nNode[ 0 ] != elem.nNode[ 2 ] && elem.nNode[ 0 ] != elem.nNode[ 3 ] );
  808. for ( int j = 0; j < 3; ++j )
  809. {
  810. for ( int k = j + 1; k < 4; ++k )
  811. {
  812. nodeConn[ elem.nNode[ j ] ]->InsertIfNotFound( elem.nNode[ k ] );
  813. nodeConn[ elem.nNode[ k ] ]->InsertIfNotFound( elem.nNode[ j ] );
  814. }
  815. }
  816. }
  817. }
  818. // add node connectivity from rods
  819. for ( int nRod = 0; nRod < m_Rods.Count( ); )
  820. {
  821. const FeRodConstraint_t &rod = m_Rods[ nRod ];
  822. if ( CountSimulatedNodesIn( rod ) >= 1 )
  823. {
  824. nodeConn[ rod.nNode[ 0 ] ]->InsertIfNotFound( rod.nNode[ 1 ] );
  825. nodeConn[ rod.nNode[ 1 ] ]->InsertIfNotFound( rod.nNode[ 0 ] );
  826. ++nRod;
  827. }
  828. else
  829. {
  830. m_Rods.FastRemove( nRod );
  831. }
  832. }
  833. // invert accumulated masses
  834. if ( !m_bEnableExplicitNodeMasses )
  835. {
  836. bool bShouldReconcileElems = false;
  837. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  838. {
  839. BuildNode_t &refNode = m_Nodes[ nNode ];
  840. float flMassMultiplier = refNode.flMassMultiplier;
  841. float flMass = nodeMass[ nNode ] * ( flMassMultiplier > FLT_EPSILON ? flMassMultiplier : 1.0f ) + refNode.flMassBias;
  842. if ( flMass > 1e-8f )
  843. {
  844. refNode.invMass = 1.0f / flMass;
  845. }
  846. else if ( refNode.bForceSimulated && refNode.bSimulated )
  847. {
  848. refNode.invMass = 1.0f;
  849. }
  850. else
  851. {
  852. if ( refNode.bSimulated )
  853. {
  854. bShouldReconcileElems = true;
  855. }
  856. refNode.invMass = 0;
  857. refNode.bSimulated = false;
  858. }
  859. }
  860. if ( bShouldReconcileElems )
  861. {
  862. ReconcileElemStaticNodes();
  863. }
  864. }
  865. // set static nodes to invM = 0 (infinite mass)
  866. m_CtrlToNode.SetCount( m_Nodes.Count( ) );
  867. m_NodeToCtrl.Purge( );
  868. int nInvalidNode = -1; // m_Nodes.Count( );
  869. m_CtrlToNode.FillWithValue( nInvalidNode );
  870. // start ranking - building static part of Node->Ctrl map
  871. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  872. {
  873. if ( !m_Nodes[ nNode ].bSimulated )
  874. {
  875. m_Nodes[ nNode ].nRank = 0;
  876. m_CtrlToNode[ nNode ] = m_NodeToCtrl.AddToTail( nNode );
  877. }
  878. }
  879. int nRankBegin = 0, nRankEnd = m_NodeToCtrl.Count( ), nNextRank = 1;
  880. do
  881. {
  882. for ( int nParentIdx = nRankBegin; nParentIdx < nRankEnd; ++nParentIdx )
  883. {
  884. uint nParentNode = m_NodeToCtrl[ nParentIdx ];
  885. CUtlSortVector< int > *pConnNodes = nodeConn[ nParentNode ];
  886. for ( int e = 0; e < pConnNodes->Count( ); ++e )
  887. {
  888. uint nChildNode = ( *pConnNodes )[ e ];
  889. if( nChildNode != nParentNode && m_CtrlToNode[ nChildNode ] == nInvalidNode )
  890. {
  891. // this child node isn't mapped yet
  892. m_CtrlToNode[ nChildNode ] = m_NodeToCtrl.AddToTail( nChildNode );
  893. m_Nodes[ nChildNode ].nRank = nNextRank;
  894. }
  895. }
  896. }
  897. nRankBegin = nRankEnd;
  898. nRankEnd = m_NodeToCtrl.Count( );
  899. ++nNextRank;
  900. // find all nodes connected to this node
  901. }
  902. while ( nRankEnd > nRankBegin );
  903. // now add isolated islands of elements
  904. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  905. {
  906. const BuildElem_t &elem = m_Elems[ nElem ];
  907. for ( int j = 0; j < 4; ++j )
  908. {
  909. uint nNode = elem.nNode[ j ];
  910. if ( m_CtrlToNode[ nNode ] == nInvalidNode )
  911. {
  912. // isolated node
  913. m_Nodes[ nNode ].nRank = nNextRank;
  914. m_CtrlToNode[ nNode ] = m_NodeToCtrl.AddToTail( nNode );
  915. }
  916. }
  917. }
  918. for ( int nRod = 0; nRod < m_Rods.Count( ); ++nRod )
  919. {
  920. const FeRodConstraint_t &rod = m_Rods[ nRod ];
  921. for ( uint j = 0; j < 2; ++j )
  922. {
  923. uint nNode = rod.nNode[ j ];
  924. if ( m_CtrlToNode[ nNode ] == nInvalidNode )
  925. {
  926. // isolated rod
  927. m_Nodes[ nNode ].nRank = nNextRank;
  928. m_CtrlToNode[ nNode ] = m_NodeToCtrl.AddToTail( nNode );
  929. }
  930. }
  931. }
  932. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  933. {
  934. if ( m_CtrlToNode[ nNode ] == nInvalidNode )
  935. {
  936. m_CtrlToNode[ nNode ] = m_NodeToCtrl.AddToTail( nNode );
  937. }
  938. }
  939. HeapSort( m_NodeToCtrl, [&] ( int nLeft, int nRight ) {
  940. const BuildNode_t &left = m_Nodes[ nLeft ];
  941. const BuildNode_t &right = m_Nodes[ nRight ];
  942. int nLeftDynamic = left.invMass == 0.0f ? 0 : 1;
  943. int nRightDynamic = right.invMass == 0.0f ? 0 : 1;
  944. if ( nLeftDynamic == nRightDynamic )
  945. {
  946. if ( !nLeftDynamic )
  947. {
  948. // the first static nodes: we need "Locked" then "Free" rotation nodes.
  949. if ( left.bFreeRotation != right.bFreeRotation )
  950. {
  951. return ( left.bFreeRotation ? 1 : 0 ) < ( right.bFreeRotation ? 1 : 0 );
  952. }
  953. }
  954. if ( left.nRank == right.nRank )
  955. {
  956. return nLeft < nRight;
  957. }
  958. return left.nRank < right.nRank;
  959. }
  960. return nLeftDynamic < nRightDynamic;
  961. } );
  962. for ( int nNode = 0; nNode < m_NodeToCtrl.Count( ); ++nNode )
  963. {
  964. m_CtrlToNode[ m_NodeToCtrl[ nNode ] ] = nNode;
  965. }
  966. // permutation of nodes
  967. CUtlVectorAligned< BuildNode_t > newNodes;
  968. newNodes.SetCount( m_NodeToCtrl.Count( ) );
  969. for ( int i = 0; i < m_NodeToCtrl.Count( ); ++i )
  970. {
  971. newNodes[ i ] = m_Nodes[ m_NodeToCtrl[ i ] ];
  972. ConvertCtrlToNode( newNodes[ i ].nParent );
  973. ConvertCtrlToNode( newNodes[ i ].nFollowParent );
  974. }
  975. for ( int i = 0; i < m_CollisionSpheres.Count( ); ++i )
  976. {
  977. ConvertCtrlToNode( m_CollisionSpheres[ i ].m_nChild );
  978. ConvertCtrlToNode( m_CollisionSpheres[ i ].m_nParent );
  979. }
  980. for ( int i = 0; i < m_CollisionPlanes.Count(); ++i )
  981. {
  982. BuildCollisionPlane_t &plane = m_CollisionPlanes[ i ];
  983. ConvertCtrlToNode( plane.m_nChild );
  984. ConvertCtrlToNode( plane.m_nParent );
  985. }
  986. for ( int i = 0; i < m_PresetNodeBases.Count(); ++i )
  987. {
  988. FeNodeBase_t &nb = m_PresetNodeBases[ i ];
  989. ConvertCtrlToNode( nb.nNode );
  990. ConvertCtrlToNode( nb.nNodeX0 );
  991. ConvertCtrlToNode( nb.nNodeX1 );
  992. ConvertCtrlToNode( nb.nNodeY0 );
  993. ConvertCtrlToNode( nb.nNodeY1 );
  994. }
  995. for ( int i = 0; i < m_TaperedCapsuleStretches.Count(); ++i )
  996. {
  997. FeTaperedCapsuleStretch_t &tc = m_TaperedCapsuleStretches[ i ];
  998. ConvertCtrlToNode( tc.nNode[ 0 ] );
  999. ConvertCtrlToNode( tc.nNode[ 1 ] );
  1000. KeepIn01( tc.flStickiness );
  1001. if ( tc.flRadius[ 0 ] > tc.flRadius[ 1 ] )
  1002. {
  1003. Swap( tc.flRadius[ 0 ], tc.flRadius[ 1 ] );
  1004. Swap( tc.nNode[ 0 ], tc.nNode[ 1 ] );
  1005. }
  1006. }
  1007. for ( int i = m_SphereRigids.Count(); i-- > 0; )
  1008. {
  1009. FeSphereRigid_t &sr = m_SphereRigids[ i ];
  1010. ConvertCtrlToNode( sr.nNode );
  1011. KeepIn01( sr.flStickiness );
  1012. if ( sr.flRadius < 0.05f )
  1013. {
  1014. // this ball is too small to collide with anything meaningfully
  1015. m_SphereRigids.FastRemove( i );
  1016. }
  1017. }
  1018. for ( int i = m_TaperedCapsuleRigids.Count(); i-- > 0; )
  1019. {
  1020. FeTaperedCapsuleRigid_t &tc = m_TaperedCapsuleRigids[ i ];
  1021. ConvertCtrlToNode( tc.nNode );
  1022. KeepIn01( tc.flStickiness );
  1023. if ( tc.flRadius[ 0 ] > tc.flRadius[ 1 ] )
  1024. {
  1025. Swap( tc.flRadius[ 0 ], tc.flRadius[ 1 ] );
  1026. Swap( tc.vCenter[ 0 ], tc.vCenter[ 1 ] );
  1027. }
  1028. // is this a sphere?
  1029. if ( tc.flRadius[ 1 ] < 0.05f )
  1030. {
  1031. // this rod is too thin to collide meaningfully
  1032. m_TaperedCapsuleRigids.FastRemove( i );
  1033. }
  1034. else if ( ( tc.vCenter[ 0 ] - tc.vCenter[ 1 ] ).Length() <= tc.flRadius[ 1 ] - tc.flRadius[ 0 ] + 0.05f )
  1035. {
  1036. // this cone's tip hides in the base sphere; convert to a sphere
  1037. FeSphereRigid_t sr;
  1038. sr.flRadius = tc.flRadius[ 1 ];
  1039. sr.nNode = tc.nNode;
  1040. sr.nCollisionMask = tc.nCollisionMask;
  1041. m_SphereRigids.AddToTail( sr );
  1042. m_TaperedCapsuleRigids.FastRemove( i );
  1043. }
  1044. }
  1045. for ( int i = 0; i < m_FitInfluences.Count(); ++i )
  1046. {
  1047. FeFitInfluence_t &influence = m_FitInfluences[ i ];
  1048. ConvertCtrlToNode( influence.nMatrixNode );
  1049. ConvertCtrlToNode( influence.nVertexNode );
  1050. }
  1051. Assert( m_ReverseOffsets.Count() == 0 ); // Code path not tested: do we need to convert nBoneCtrl (ctrl->nodes)?
  1052. for ( int i = 0; i < m_ReverseOffsets.Count(); ++i )
  1053. {
  1054. FeNodeReverseOffset_t &revOffset = m_ReverseOffsets[ i ];
  1055. //ConvertCtrlToNode( revOffset.nBoneCtrl );
  1056. ConvertCtrlToNode( revOffset.nTargetNode );
  1057. }
  1058. m_Nodes.Swap( newNodes );
  1059. for ( m_nStaticNodes = 0, m_nRotLockStaticNodes = 0; m_nStaticNodes < m_Nodes.Count( ); m_nStaticNodes++ )
  1060. {
  1061. if ( m_Nodes[ m_nStaticNodes ].invMass > 0 )
  1062. break;
  1063. if ( !m_Nodes[ m_nStaticNodes ].bFreeRotation )
  1064. {
  1065. AssertDbg( m_nRotLockStaticNodes == m_nStaticNodes ); // if this assert fires, it means there are holes in the subarray of static non-rotating nodes
  1066. m_nRotLockStaticNodes = m_nStaticNodes + 1; // this node is locked-rotation
  1067. }
  1068. }
  1069. for ( uint i = 0; i < m_nRotLockStaticNodes; ++i )
  1070. {
  1071. AssertDbg( !m_Nodes[ i ].bFreeRotation );
  1072. }
  1073. // now that we have permuted the nodes, reindex all elements
  1074. for ( int i = 0; i < m_Elems.Count( ); ++i )
  1075. {
  1076. BuildElem_t &elem = m_Elems[ i ];
  1077. elem.nRank = INT_MAX;
  1078. for ( int j = 0; j < 4; ++j )
  1079. {
  1080. uint &refNodeIndex = elem.nNode[j];
  1081. refNodeIndex = m_CtrlToNode[ refNodeIndex ];
  1082. Assert( refNodeIndex < uint( m_Nodes.Count( ) ) );
  1083. Assert( uint( j ) < ( elem.nStaticNodes == 3 && elem.nNode[2] == elem.nNode[3] ? 4 : elem.nStaticNodes ) ? ( refNodeIndex < m_nStaticNodes ) : ( refNodeIndex >= m_nStaticNodes ) );
  1084. int nNodeRank = m_Nodes[ refNodeIndex ].nRank;
  1085. if ( nNodeRank < elem.nRank )
  1086. elem.nRank = nNodeRank;
  1087. }
  1088. }
  1089. for ( int i = 0; i < m_Rods.Count( ); ++i )
  1090. {
  1091. for ( int j = 0; j < 2; ++j )
  1092. {
  1093. m_Rods[ i ].nNode[ j ] = m_CtrlToNode[ m_Rods[ i ].nNode[ j ] ];
  1094. }
  1095. }
  1096. for ( int i = 0; i < m_Springs.Count( ); ++i )
  1097. {
  1098. for ( int j = 0; j < 2; ++j )
  1099. {
  1100. m_Springs[ i ].nNode[ j ] = m_CtrlToNode[ m_Springs[ i ].nNode[ j ] ];
  1101. }
  1102. }
  1103. std::stable_sort( m_Elems.begin(), m_Elems.end(), BuildElem_t::Order );
  1104. //HeapSort( m_Elems, BuildElem_t::Order );
  1105. // note: later we sort rods anyway
  1106. /*
  1107. HeapSort( m_Rods, [&] ( const FeRodConstraint_t &left, const FeRodConstraint_t &right ){
  1108. int nLeftRank = Min( m_Nodes[ left.nNode[ 0 ] ].nRank, m_Nodes[ left.nNode[ 1 ] ].nRank );
  1109. int nRightRank = Min( m_Nodes[ right.nNode[ 0 ] ].nRank, m_Nodes[ right.nNode[ 1 ] ].nRank );
  1110. return nLeftRank < nRightRank;
  1111. } );
  1112. */
  1113. }
  1114. int CFeModelBuilder::CountSimulatedNodesIn( const FeRodConstraint_t & rod )
  1115. {
  1116. int nResult = 0;
  1117. for ( int i = 0; i < 2; i++ )
  1118. {
  1119. if ( m_Nodes[ rod.nNode[ i ] ].bSimulated )
  1120. {
  1121. ++nResult;
  1122. }
  1123. }
  1124. return nResult;
  1125. }
  1126. int CFeModelBuilder::CountSimulatedNodesIn( const BuildElem_t& elem )
  1127. {
  1128. int nResult = 0;
  1129. for ( int i = 0; i < 4; i++ )
  1130. {
  1131. if ( i > 0 && elem.nNode[ i ] == elem.nNode[ i - 1 ] )
  1132. continue;
  1133. if ( m_Nodes[ elem.nNode[ i ] ].bSimulated )
  1134. {
  1135. ++nResult;
  1136. }
  1137. }
  1138. return nResult;
  1139. }
  1140. void CFeModelBuilder::BuildCtrlOffsets( )
  1141. {
  1142. int nBenignlyParentlessVirtualNodes = 0;
  1143. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  1144. {
  1145. const BuildNode_t &node = m_Nodes[ nNode ];
  1146. if ( !node.bVirtual )
  1147. {
  1148. continue;
  1149. }
  1150. if ( node.bSimulated && node.integrator.flAnimationForceAttraction == 0 && node.integrator.flAnimationVertexAttraction == 0 )
  1151. {
  1152. if ( !( m_nDynamicNodeFlags & FE_FLAG_ENABLE_FTL ) )
  1153. {
  1154. // this is a new-style cloth (not source1 compatible), no need to be ultra-conservative, so let's just skip the offsets for nodes that don't need it?
  1155. // unless we want to be able to dynamically tweak animation attraction in softbody
  1156. ++nBenignlyParentlessVirtualNodes;
  1157. continue;
  1158. }
  1159. }
  1160. int nParentNode = node.nParent;
  1161. if ( nParentNode < 0 )
  1162. continue; // there's no parent for this virtual node, that's fine, we'll just have no animation attraction because we'll have no animation on it
  1163. while ( nParentNode >= 0 && m_Nodes[ nParentNode ].bVirtual )
  1164. {
  1165. nParentNode = m_Nodes[ nParentNode ].nParent;
  1166. if ( nParentNode == node.nParent )
  1167. {
  1168. // parent node loop detected!
  1169. nParentNode = -1;
  1170. break;
  1171. }
  1172. }
  1173. if ( nParentNode < 0 )
  1174. {
  1175. Warning( "Cannot find real parent of virtual node %d:%s\n", nNode, node.pName );
  1176. continue;
  1177. }
  1178. if ( node.bOsOffset )
  1179. {
  1180. FeCtrlOsOffset_t offset;
  1181. offset.nCtrlChild = m_NodeToCtrl[ nNode ];
  1182. offset.nCtrlParent = m_NodeToCtrl[ nParentNode ];
  1183. m_CtrlOsOffsets.AddToTail( offset );
  1184. }
  1185. else
  1186. {
  1187. FeCtrlOffset_t offset;
  1188. offset.nCtrlChild = m_NodeToCtrl[ nNode ];
  1189. offset.nCtrlParent = m_NodeToCtrl[ nParentNode ];
  1190. offset.vOffset = m_Nodes[ nParentNode ].transform.TransformVectorByInverse( node.transform.m_vPosition );
  1191. m_CtrlOffsets.AddToTail( offset );
  1192. }
  1193. }
  1194. if ( nBenignlyParentlessVirtualNodes )
  1195. {
  1196. Msg( "%d/%d cloth nodes(verts) will simulate without any animation influence.\n", nBenignlyParentlessVirtualNodes, m_Nodes.Count() );
  1197. }
  1198. // sort just to have more a cache-friendly loop and more eye-friendly list; it's not necessary per se
  1199. HeapSort( m_CtrlOffsets, [] ( const FeCtrlOffset_t &left, const FeCtrlOffset_t &right ) {
  1200. return left.nCtrlChild < right.nCtrlChild;
  1201. } );
  1202. HeapSort( m_CtrlOsOffsets, [] ( const FeCtrlOsOffset_t &left, const FeCtrlOsOffset_t &right ) {
  1203. return left.nCtrlChild < right.nCtrlChild;
  1204. } );
  1205. }
  1206. // returns the number of inclusive collision ellipsoids
  1207. uint CFeModelBuilder::BuildCollisionSpheres( CUtlVector< FeCollisionSphere_t > &collisionSpheres )
  1208. {
  1209. for ( int i = m_CollisionSpheres.Count(); i-- > 0; )
  1210. {
  1211. BuildCollisionSphere_t &sphere = m_CollisionSpheres[ i ];
  1212. if ( sphere.IsDegenerate( ) || !m_Nodes[ sphere.m_nChild ].bSimulated )
  1213. {
  1214. m_CollisionSpheres.FastRemove( i );
  1215. }
  1216. else
  1217. {
  1218. KeepIn01( sphere.m_flStickiness );
  1219. }
  1220. }
  1221. HeapSort( m_CollisionSpheres, [] ( const BuildCollisionSphere_t &left, const BuildCollisionSphere_t&right ) {
  1222. if ( left.m_bInclusive != right.m_bInclusive )
  1223. return left.m_bInclusive > right.m_bInclusive;
  1224. if ( left.m_nChild != right.m_nChild )
  1225. return left.m_nChild < right.m_nChild;
  1226. return left.m_nParent < right.m_nParent;
  1227. } );
  1228. uint nInclusive = 0;
  1229. // while ( nInclusive < uint( m_CollisionEllipsoids.Count( ) ) && m_CollisionEllipsoids[ nInclusive ].m_bInclusive )
  1230. // {
  1231. // nInclusive++;
  1232. // }
  1233. collisionSpheres.SetCount( m_CollisionSpheres.Count( ) );
  1234. for ( int i = 0; i < m_CollisionSpheres.Count( ); ++i )
  1235. {
  1236. const BuildCollisionSphere_t &ce = m_CollisionSpheres[ i ];
  1237. FeCollisionSphere_t &fce = collisionSpheres[ i ];
  1238. if ( ce.m_bInclusive )
  1239. {
  1240. nInclusive = i + 1;
  1241. fce.m_flRFactor = 1.0f / Sqr( ce.m_flRadius );
  1242. }
  1243. else
  1244. {
  1245. fce.m_flRFactor = ce.m_flRadius;
  1246. }
  1247. fce.nChildNode = ce.m_nChild;
  1248. fce.nCtrlParent = m_NodeToCtrl[ ce.m_nParent ];
  1249. fce.m_vOrigin = ce.m_vOrigin;
  1250. }
  1251. return nInclusive;
  1252. }
  1253. // returns the number of inclusive collision ellipsoids
  1254. void CFeModelBuilder::BuildCollisionPlanes( CUtlVector< FeCollisionPlane_t > &collisionPlanes )
  1255. {
  1256. for ( int i = m_CollisionPlanes.Count(); i-- > 0; )
  1257. {
  1258. BuildCollisionPlane_t &plane = m_CollisionPlanes[ i ];
  1259. if ( plane.IsDegenerate( ) || !m_Nodes[ plane.m_nChild ].bSimulated )
  1260. {
  1261. m_CollisionPlanes.FastRemove( i );
  1262. }
  1263. else
  1264. {
  1265. KeepIn01( plane.m_flStickiness );
  1266. }
  1267. }
  1268. HeapSort( m_CollisionPlanes, [] ( const BuildCollisionPlane_t &left, const BuildCollisionPlane_t&right ) {
  1269. if ( left.m_nChild != right.m_nChild )
  1270. return left.m_nChild < right.m_nChild;
  1271. return left.m_nParent < right.m_nParent;
  1272. } );
  1273. // while ( nInclusive < uint( m_CollisionEllipsoids.Count( ) ) && m_CollisionEllipsoids[ nInclusive ].m_bInclusive )
  1274. // {
  1275. // nInclusive++;
  1276. // }
  1277. collisionPlanes.SetCount( m_CollisionPlanes.Count( ) );
  1278. for ( int i = 0; i < m_CollisionPlanes.Count( ); ++i )
  1279. {
  1280. const BuildCollisionPlane_t &source = m_CollisionPlanes[ i ];
  1281. FeCollisionPlane_t &fce = collisionPlanes[ i ];
  1282. fce.nChildNode = source.m_nChild;
  1283. fce.nCtrlParent = m_NodeToCtrl[ source.m_nParent ];
  1284. fce.m_Plane = source.m_Plane;
  1285. fce.m_Plane.m_vNormal.NormalizeInPlace( );
  1286. }
  1287. }
  1288. void CFeModelBuilder::BuildWorldCollisionNodes( CUtlVector< FeWorldCollisionParams_t > &worldCollisionParams, CUtlVector< uint16 > &worldCollisionNodes )
  1289. {
  1290. CUtlVectorAligned< BuildNode_t > &nodes = m_Nodes;
  1291. int nAdded = 0;
  1292. worldCollisionNodes.EnsureCapacity( nodes.Count( ) );
  1293. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  1294. {
  1295. if ( nodes[ i ].bWorldCollision && nodes[ i ].bSimulated )
  1296. {
  1297. nodes[ i ].flWorldFriction = Min( nodes[ i ].flWorldFriction, 1.0f );
  1298. nAdded++;
  1299. worldCollisionNodes.AddToTail( i );
  1300. }
  1301. }
  1302. if ( !nAdded )
  1303. return;
  1304. // sort by ascending "WorldFriction"; this lends itself to LOD-ing, as we can clamp out "world friction" close to "1" ("world friction" is a parameter from Source1; it's not a physical friction! )
  1305. HeapSort( worldCollisionNodes, [&nodes]( uint16 left, uint16 right ) {
  1306. if ( nodes[ left ].flWorldFriction != nodes[ right ].flWorldFriction )
  1307. {
  1308. return nodes[ left ].flWorldFriction < nodes[ right ].flWorldFriction;
  1309. }
  1310. return nodes[ left ].flGroundFriction > nodes[ right ].flGroundFriction;
  1311. } );
  1312. uint nBegin = 0;
  1313. do
  1314. {
  1315. // start the new block of parameters
  1316. FeWorldCollisionParams_t &params = worldCollisionParams[ worldCollisionParams.AddToTail( ) ];
  1317. BuildNode_t &beginNode = m_Nodes[ worldCollisionNodes[ nBegin ] ];
  1318. params.flWorldFriction = beginNode.flWorldFriction;
  1319. params.flGroundFriction = beginNode.flGroundFriction;
  1320. //uint nFirstNode = worldCollisionNodes[ nBegin ];
  1321. for ( params.nListBegin = nBegin, params.nListEnd = nBegin + 1; int( params.nListEnd ) < worldCollisionNodes.Count(); ++params.nListEnd )
  1322. {
  1323. uint nNextNode = worldCollisionNodes[ params.nListEnd ];
  1324. if ( m_Nodes[ nNextNode ].flWorldFriction - params.flWorldFriction > 0.1f
  1325. || m_Nodes[ nNextNode ].flGroundFriction - params.flGroundFriction >0.1f )
  1326. {
  1327. break; // time to start a new block of parameters
  1328. }
  1329. }
  1330. nBegin = params.nListEnd; // start the next batch of parameters
  1331. }
  1332. while ( int( nBegin ) < worldCollisionNodes.Count( ) );
  1333. }
  1334. FeFitWeight_t GetBestWeight( const CFeModelBuilder::FitWeightArray_t &array )
  1335. {
  1336. FeFitWeight_t fw = array[ 0 ];
  1337. for ( int i = 1; i < array.Count(); ++i )
  1338. {
  1339. if ( array[ i ].flWeight > fw.flWeight )
  1340. fw = array[ i ];
  1341. }
  1342. return fw;
  1343. }
  1344. struct CFitMatrixBuildInfo
  1345. {
  1346. public:
  1347. int m_nNodeIndex;
  1348. CFeModelBuilder::FitWeightArray_t m_StaticNodes;
  1349. CFeModelBuilder::FitWeightArray_t m_DynamicNodes;
  1350. CFitMatrixBuildInfo() : m_nNodeIndex( -1 ) { }
  1351. void AddNode( const FeFitWeight_t &w, bool bSimulated )
  1352. {
  1353. if ( bSimulated )
  1354. m_DynamicNodes.AddToTail( w );
  1355. else
  1356. m_StaticNodes.AddToTail( w );
  1357. }
  1358. static void Normalize( CUtlVector< FeFitWeight_t > &nodes )
  1359. {
  1360. if ( nodes.Count() )
  1361. {
  1362. float flSumWeights = 0;
  1363. for ( int nNode = 0; nNode < nodes.Count(); ++nNode )
  1364. {
  1365. FeFitWeight_t &w = nodes[ nNode ];
  1366. w.nDummy = 0;
  1367. flSumWeights += w.flWeight;
  1368. }
  1369. if ( flSumWeights <= FLT_EPSILON )
  1370. {
  1371. for ( int nNode = 0; nNode < nodes.Count(); ++nNode )
  1372. {
  1373. FeFitWeight_t &w = nodes[ nNode ];
  1374. w.flWeight = 1.0f / float( nodes.Count() );
  1375. }
  1376. }
  1377. else
  1378. {
  1379. for ( int nNode = 0; nNode < nodes.Count(); ++nNode )
  1380. {
  1381. FeFitWeight_t &w = nodes[ nNode ];
  1382. w.flWeight /= flSumWeights;
  1383. }
  1384. }
  1385. }
  1386. }
  1387. int Finish()
  1388. {
  1389. if ( m_nNodeIndex < 0 )
  1390. {
  1391. return 0; // we need a node to influence
  1392. }
  1393. // make sure our dummies are all zeroed out and weights are all summing up to 1.0 - not necessary if we don't use stretch min/max and (bracketing of singular values of Apq*Aqq^-1 matrix)
  1394. // Warning: These normalized weights don't work with FeedbackFitTransforms()
  1395. //Normalize( m_StaticNodes );
  1396. //Normalize( m_DynamicNodes );
  1397. // if we have no influences, we have no weight node
  1398. return m_StaticNodes.Count() + m_DynamicNodes.Count( );
  1399. }
  1400. uint GetMostInfluentialNode()const
  1401. {
  1402. if ( !m_StaticNodes.IsEmpty() )
  1403. return GetBestWeight( m_StaticNodes ).nNode;
  1404. if ( !m_DynamicNodes.IsEmpty() )
  1405. return GetBestWeight( m_DynamicNodes ).nNode;
  1406. return m_nNodeIndex;
  1407. }
  1408. };
  1409. Vector CFeModelBuilder::ComputeCenter( const FitWeightArray_t &weights )
  1410. {
  1411. Vector vVertSum = vec3_origin;
  1412. float flWeightSum = 0;
  1413. for ( int i = 0; i < weights.Count(); ++i )
  1414. {
  1415. const FeFitWeight_t &w = weights[ i ];
  1416. vVertSum += w.flWeight * m_Nodes[ w.nNode ].transform.m_vPosition;
  1417. flWeightSum += w.flWeight;
  1418. }
  1419. if ( flWeightSum > FLT_EPSILON )
  1420. return vVertSum / flWeightSum;
  1421. if ( weights.Count() > 0 )
  1422. return m_Nodes[ weights[ 0 ].nNode ].transform.m_vPosition;
  1423. return vec3_origin;
  1424. }
  1425. void CFeModelBuilder::BuildFitMatrices( MbaContext_t &context )
  1426. {
  1427. CUtlVector< CFitMatrixBuildInfo* > nodeFitMatrices;
  1428. nodeFitMatrices.SetCount( m_Nodes.Count() );
  1429. nodeFitMatrices.FillWithValue( NULL );
  1430. for ( int i = 0; i < m_FitInfluences.Count(); ++i )
  1431. {
  1432. FeFitInfluence_t &inf = m_FitInfluences[ i ];
  1433. if ( inf.flWeight <= 0 )
  1434. continue;
  1435. CFitMatrixBuildInfo*&info = nodeFitMatrices[ inf.nMatrixNode ];
  1436. if ( !info )
  1437. info = new CFitMatrixBuildInfo;
  1438. info->m_nNodeIndex = inf.nMatrixNode;
  1439. FeFitWeight_t fw;
  1440. fw.flWeight = inf.flWeight;
  1441. fw.nNode = inf.nVertexNode;
  1442. fw.nDummy = 0;
  1443. info->AddNode( fw, m_Nodes[ inf.nVertexNode ].bSimulated );
  1444. }
  1445. int nPrecomputeWeightCount = 0;
  1446. for ( int i = nodeFitMatrices.Count(); i-- > 0; )
  1447. {
  1448. if ( !nodeFitMatrices[ i ] )
  1449. nodeFitMatrices.FastRemove( i );
  1450. else if ( int nWeights = nodeFitMatrices[ i ]->Finish() )
  1451. {
  1452. // we keep this one
  1453. nPrecomputeWeightCount += nWeights;
  1454. }
  1455. else
  1456. {
  1457. delete nodeFitMatrices[ i ];
  1458. nodeFitMatrices.FastRemove( i );
  1459. }
  1460. }
  1461. // sort by the count of statics
  1462. HeapSort( nodeFitMatrices, []( CFitMatrixBuildInfo*pLeft, CFitMatrixBuildInfo*pRight ){ return pLeft->m_StaticNodes.Count() > pRight->m_StaticNodes.Count(); } );
  1463. context.fitMatrices.RemoveAll();
  1464. context.fitMatrices.EnsureCapacity( nodeFitMatrices.Count() );
  1465. context.fitWeights.RemoveAll();
  1466. context.fitWeights.EnsureCapacity( nPrecomputeWeightCount );
  1467. int nTooFewInfluences = 0;
  1468. CUtlString simpleFitList, complexFitList;
  1469. int nMatricesByStaticCount[ 3 ] = { 0, 0, 0 };
  1470. for ( int i = 0; i < nodeFitMatrices.Count(); ++i )
  1471. {
  1472. CFitMatrixBuildInfo *pInfo = nodeFitMatrices[ i ];
  1473. FeFitMatrix_t fm;
  1474. fm.nNode = pInfo->m_nNodeIndex;
  1475. fm.nCtrl = m_NodeToCtrl[ fm.nNode ];
  1476. Vector vFitCenter = ComputeCenter( pInfo->m_StaticNodes.Count() ? pInfo->m_StaticNodes : pInfo->m_DynamicNodes );
  1477. fm.vCenter = vFitCenter;
  1478. /*CovMatrix3 Aqq;
  1479. Aqq.Reset();
  1480. for ( FeFitWeight_t &w : pInfo->m_DynamicNodes )
  1481. {
  1482. Aqq.AddCov( m_Nodes[ w.nNode ].transform.m_vPosition - fm.vCenter, w.flWeight );
  1483. }
  1484. fm.AqqInv = Aqq.GetPseudoInverse();*/
  1485. fm.bone.m_vPosition = m_Nodes[ fm.nNode ].transform.m_vPosition - vFitCenter;
  1486. fm.bone.m_orientation = m_Nodes[ fm.nNode ].transform.m_orientation;
  1487. //fm.flStretchMax = fm.flStretchMin = 1.0f;
  1488. if ( pInfo->m_StaticNodes.Count() + pInfo->m_DynamicNodes.Count() < m_nFitMatrixMinInfluences )
  1489. {
  1490. // need to add a few more verts
  1491. nTooFewInfluences++;
  1492. uint nBestInfluence = pInfo->GetMostInfluentialNode();
  1493. if ( nBestInfluence < uint( m_Nodes.Count() ) )
  1494. {
  1495. // add the verts from this element to control this
  1496. // compute the orientation of this node,
  1497. // except we'll just stomp that orientation over our target node:
  1498. // the node that doesn't have enough influences to shape-fit it reliably
  1499. FeNodeBase_t nodeBase = BuildNodeBasisFast( m_Nodes, fm.nNode, *( m_NodeNeighbors[ nBestInfluence ] ));
  1500. m_NodeBases.AddToTail( nodeBase );
  1501. FeNodeReverseOffset_t revOffset;
  1502. revOffset.nBoneCtrl = fm.nCtrl;
  1503. revOffset.nTargetNode = nBestInfluence;
  1504. revOffset.vOffset = m_Nodes[ fm.nNode ].transform.TransformVectorByInverse( m_Nodes[ nBestInfluence ].transform.m_vPosition );
  1505. m_ReverseOffsets.AddToTail( revOffset );
  1506. simpleFitList.Append( " " ); simpleFitList.Append( m_Nodes[ fm.nNode ].pName );
  1507. continue;
  1508. }
  1509. else
  1510. {
  1511. Warning( "Too few simulated vertices bound to matrix %s\n", m_Nodes[ fm.nNode ].pName );
  1512. }
  1513. }
  1514. context.fitWeights.AddVectorToTail( pInfo->m_StaticNodes );
  1515. fm.nBeginDynamic = context.fitWeights.Count();
  1516. context.fitWeights.AddVectorToTail( pInfo->m_DynamicNodes );
  1517. fm.nEnd = context.fitWeights.Count();
  1518. context.fitMatrices.AddToTail( fm );
  1519. nMatricesByStaticCount[ Min( pInfo->m_StaticNodes.Count(), 2 ) ] = context.fitMatrices.Count();
  1520. complexFitList.Append( " " ); complexFitList.Append( m_Nodes[ fm.nNode ].pName );
  1521. }
  1522. if ( nTooFewInfluences )
  1523. {
  1524. Msg( "%d of %d driving bones have too few influences and were switched to simplified single-polygon shape-fit mode: {%s}\n%d matrices will shape-fit complex deformations: {%s}\n",
  1525. nTooFewInfluences,
  1526. nodeFitMatrices.Count(),
  1527. simpleFitList.Get(),
  1528. context.fitMatrices.Count(),
  1529. complexFitList.Get()
  1530. );
  1531. }
  1532. // make sure [0] >= [1] >= [2]
  1533. for ( int i = 3; i-- > 1; )
  1534. nMatricesByStaticCount[ i - 1 ] = Max( nMatricesByStaticCount[ i - 1 ], nMatricesByStaticCount[ i ] );
  1535. context.m_nFitMatrices1 = nMatricesByStaticCount[ 1 ];
  1536. context.m_nFitMatrices2 = nMatricesByStaticCount[ 2 ];
  1537. nodeFitMatrices.PurgeAndDeleteElements();
  1538. }
  1539. void CFeModelBuilder::RemoveStandaloneNodeBases( MbaContext_t &context )
  1540. {
  1541. CVarBitVec needBase( m_Nodes.Count() );
  1542. for ( int i = 0; i < m_ReverseOffsets.Count(); ++i )
  1543. {
  1544. needBase.Set( CtrlToNode( m_ReverseOffsets[ i ].nBoneCtrl ) );
  1545. }
  1546. // only leave those bases that are necessary to compute before revOffsets
  1547. int nRunningCount = 0;
  1548. for ( int i = 0; i < m_NodeBases.Count(); ++i )
  1549. {
  1550. if ( needBase.IsBitSet( i ) )
  1551. {
  1552. if ( i != nRunningCount )
  1553. {
  1554. m_NodeBases[ nRunningCount ] = m_NodeBases[ i ];
  1555. }
  1556. nRunningCount++;
  1557. }
  1558. }
  1559. m_NodeBases.SetCountNonDestructively( nRunningCount );
  1560. }
  1561. void CFeModelBuilder::BuildNodeFollowers( CUtlVector< FeFollowNode_t > &nodeFollowers )
  1562. {
  1563. nodeFollowers.Purge( );
  1564. nodeFollowers.EnsureCapacity( m_Nodes.Count( ) );
  1565. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  1566. {
  1567. FeFollowNode_t follower;
  1568. follower.flWeight = m_Nodes[ i ].flFollowWeight;
  1569. if ( follower.flWeight > 0.001f && m_Nodes[ i ].nFollowParent >= 0 && m_Nodes[ i ].bSimulated )
  1570. {
  1571. follower.nChildNode = i;
  1572. follower.nParentNode = m_Nodes[ i ].nFollowParent;
  1573. nodeFollowers.AddToTail( follower );
  1574. }
  1575. }
  1576. // note: we actually need to sort the followers, because following is generally order-dependent
  1577. // it shouldn't make a difference for Dota imported cloth, as there cohorts of nodes follow a single parent
  1578. // Just scan the node followers backwards here, to find if there are parents after children
  1579. CVarBitVec followers( m_Nodes.Count() );
  1580. for ( int i = nodeFollowers.Count(); i-- > 0; )
  1581. {
  1582. const FeFollowNode_t &fn = nodeFollowers[ i ];
  1583. if ( followers.IsBitSet( fn.nParentNode ) )
  1584. {
  1585. Warning( "FeModelBuilder: Follower #%d %s is following parent #%d %s, which is also a follower but is setup down the chain. The order should be parent-to-child. The follower chain may produce overly-soft or 1-tick-lagging results\n",
  1586. fn.nChildNode, m_Nodes[ fn.nChildNode ].pName, fn.nParentNode, m_Nodes[ fn.nParentNode ].pName );
  1587. }
  1588. followers.Set( fn.nChildNode );
  1589. }
  1590. }
  1591. void CFeModelBuilder::CleanupElements()
  1592. {
  1593. int nRemoved = 0;
  1594. for ( int nElem = m_Elems.Count(); nElem-- > 0; )
  1595. {
  1596. BuildElem_t &elem = m_Elems[ nElem ];
  1597. uint n0 = elem.nNode[ 0 ], n1 = elem.nNode[ 1 ], n2 = elem.nNode[ 2 ], n3 = elem.nNode[ 3 ];
  1598. Vector p0 = m_Nodes[ n0 ].transform.m_vPosition, p1 = m_Nodes[ n1 ].transform.m_vPosition, p2 = m_Nodes[ n2 ].transform.m_vPosition;
  1599. Vector vCross = CrossProduct( p1 - p0, p2 - p0 );
  1600. if ( vCross.Length() <= 1e-6f )
  1601. {
  1602. ++nRemoved;
  1603. if ( n2 != n3 )
  1604. {
  1605. ++nRemoved; // count quad as 2 tris for stats
  1606. }
  1607. m_Elems.FastRemove( nElem );
  1608. continue;
  1609. }
  1610. if ( n2 != n3 )
  1611. {
  1612. Vector p3 = m_Nodes[ n3 ].transform.m_vPosition;
  1613. if ( CrossProduct( p2 - p0, p3 - p0 ).Length() <= 1e-6f )
  1614. {
  1615. // make this a triangle, but save the rest of the element
  1616. ++nRemoved;
  1617. elem.nNode[ 3 ] = n2;
  1618. continue;
  1619. }
  1620. }
  1621. }
  1622. if ( nRemoved )
  1623. {
  1624. Warning( "Cloth removed %d degenerate triangles, %d elements remaining. Please clean up the mesh.\n", nRemoved, m_Elems.Count() );
  1625. }
  1626. }
  1627. void CFeModelBuilder::RecomputeMasses( CUtlVector< float >& nodeMass )
  1628. {
  1629. nodeMass.SetCount( m_Nodes.Count( ) );
  1630. nodeMass.FillWithValue( 0 ); // all unaccounted nodes are going to stay static
  1631. // accumulate the automatic node masses
  1632. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  1633. {
  1634. const BuildElem_t &elem = m_Elems[ nElem ];
  1635. for ( int nTriangulate = 0; nTriangulate < 2; ++nTriangulate )
  1636. {
  1637. uint n0 = elem.nNode[ 0 ], n1 = elem.nNode[ 1 + nTriangulate ], n2 = elem.nNode[ 2 + nTriangulate ];
  1638. if ( n1 == n2 )
  1639. continue;
  1640. Assert( n0 != n1 && n1 != n2 && n2 != n0 );
  1641. Vector p0 = m_Nodes[ n0 ].transform.m_vPosition, p1 = m_Nodes[ n1 ].transform.m_vPosition, p2 = m_Nodes[ n2 ].transform.m_vPosition;
  1642. Vector vCross = CrossProduct( p1 - p0, p2 - p0 );
  1643. float flSinArea = vCross.Length( );
  1644. Assert( flSinArea >= 1e-6f );
  1645. float cot0 = DotProduct( p1 - p0, p2 - p0 ) / flSinArea;
  1646. float cot1 = DotProduct( p2 - p1, p0 - p1 ) / flSinArea;
  1647. float cot2 = DotProduct( p0 - p2, p1 - p2 ) / flSinArea;
  1648. float x01sqr = ( p1 - p0 ).LengthSqr( );
  1649. float x12sqr = ( p2 - p1 ).LengthSqr( );
  1650. float x20sqr = ( p0 - p2 ).LengthSqr( );
  1651. float m0 = 0, m1 = 0, m2 = 0;
  1652. if ( cot0 > 0 && cot1 > 0 && cot2 > 0 )
  1653. {
  1654. // a good, unobtuse triangle
  1655. m0 = .125f * ( x01sqr * cot2 + x20sqr * cot1 );
  1656. m1 = .125f * ( x01sqr * cot2 + x12sqr * cot0 );
  1657. m2 = .125f * ( x20sqr * cot1 + x12sqr * cot0 );
  1658. }
  1659. else
  1660. {
  1661. // an obtuse triangle: when it becomes right, we cross over to split 50/25/25 between obtuse/sharp/sharp
  1662. float flAqtr = .125f * flSinArea; // quarter area of triangle
  1663. m0 = m1 = m2 = flAqtr;
  1664. // the obtuse angle should get 1/2 area
  1665. if ( cot0 < cot1 )
  1666. {
  1667. if ( cot0 < cot2 )
  1668. {
  1669. Assert( cot0 <= 0 );
  1670. m0 *= 2;
  1671. }
  1672. else
  1673. {
  1674. Assert( cot2 <= 0 );
  1675. m2 *= 2;
  1676. }
  1677. }
  1678. else
  1679. {
  1680. if ( cot1 < cot2 )
  1681. {
  1682. Assert( cot1 <= 0 );
  1683. m1 *= 2;
  1684. }
  1685. else
  1686. {
  1687. Assert( cot2 <= 0 );
  1688. m2 *= 2;
  1689. }
  1690. }
  1691. }
  1692. nodeMass[ n0 ] += m0;
  1693. nodeMass[ n1 ] += m1;
  1694. nodeMass[ n2 ] += m2;
  1695. }
  1696. }
  1697. // we're assuming linear density of 8 kg/in and area density of 1 kg/in^2, and they aren't compatible,
  1698. // but it doesn't matter if we don't have the same nodes participating in both rod and quad constraints.
  1699. // if we do, the auto-mass computation will be skewed, most likely, towards the ropes rather than cloth
  1700. for ( int nRod = 0; nRod < m_Rods.Count( ); ++nRod )
  1701. {
  1702. uint n0 = m_Rods[ nRod ].nNode[ 0 ], n1 = m_Rods[ nRod ].nNode[ 1 ];
  1703. float flLength = ( m_Nodes[ n0 ].transform.m_vPosition - m_Nodes[ n1 ].transform.m_vPosition ).Length( );
  1704. nodeMass[ n0 ] += 8 * flLength;
  1705. nodeMass[ n1 ] += 8 * flLength;
  1706. }
  1707. }
  1708. // make sure that for nodes that have "global" mass multipliers, we redistributes masses so that
  1709. // the mass ratios are exactly what the user specified. The absolute values of the masses are presumed
  1710. // to not be very important and are computed automatically to balance against the distances between nodes
  1711. // note: connectivity may make this hard to tune. If we have a couple of rags of very different scales,
  1712. // the mass ratios between the "global" and "local" nodes are going to be out of whack
  1713. void CFeModelBuilder::BalanceGlobalMassMultipliers( CUtlVector< float >& nodeMass )
  1714. {
  1715. float flComputedMassSum = 0, flOverrideMassSum = 0;
  1716. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  1717. {
  1718. if ( m_Nodes[ i ].bMassMultiplierGlobal && nodeMass[ i ] > 0 )
  1719. {
  1720. flComputedMassSum += nodeMass[ i ];
  1721. flOverrideMassSum += m_Nodes[ i ].flMassMultiplier;
  1722. }
  1723. }
  1724. if ( flOverrideMassSum > 0 && flComputedMassSum > 0 )
  1725. {
  1726. float flScale = flComputedMassSum / flOverrideMassSum;
  1727. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  1728. {
  1729. if ( m_Nodes[ i ].bMassMultiplierGlobal && nodeMass[ i ] > 0 )
  1730. {
  1731. nodeMass[ i ] = flScale * m_Nodes[ i ].flMassMultiplier;
  1732. }
  1733. }
  1734. }
  1735. }
  1736. bool Conflict( const FeRodConstraint_t &a, const FeRodConstraint_t &b )
  1737. {
  1738. return a.nNode[ 0 ] == b.nNode[ 0 ] || a.nNode[ 0 ] == b.nNode[ 1 ] || a.nNode[ 1 ] == b.nNode[ 0 ] || a.nNode[ 1 ] == b.nNode[ 1 ];
  1739. }
  1740. bool Conflict( const CFeModelBuilder::BuildElem_t &a, const CFeModelBuilder::BuildElem_t &b )
  1741. {
  1742. for ( int i = 0; i < 4; ++i )
  1743. {
  1744. for ( int j = 0; j < 4; ++j )
  1745. {
  1746. if ( a.nNode[ i ] == b.nNode[ j ] )
  1747. return true;
  1748. }
  1749. }
  1750. return false;
  1751. }
  1752. bool Conflict( const FeQuad_t &a, const FeQuad_t &b )
  1753. {
  1754. for ( int i = 0; i < 4; ++i )
  1755. {
  1756. for ( int j = 0; j < 4; ++j )
  1757. {
  1758. if ( a.nNode[ i ] == b.nNode[ j ] )
  1759. return true;
  1760. }
  1761. }
  1762. return false;
  1763. }
  1764. bool Conflict( const FeTri_t &a, const FeTri_t &b )
  1765. {
  1766. for ( int i = 0; i < 3; ++i )
  1767. {
  1768. for ( int j = 0; j < 3; ++j )
  1769. {
  1770. if ( a.nNode[ i ] == b.nNode[ j ] )
  1771. return true;
  1772. }
  1773. }
  1774. return false;
  1775. }
  1776. bool Conflict( const FeSpringIntegrator_t &a, const FeSpringIntegrator_t &b )
  1777. {
  1778. return a.nNode[ 0 ] == b.nNode[ 0 ] || a.nNode[ 0 ] == b.nNode[ 1 ] || a.nNode[ 1 ] == b.nNode[ 0 ] || a.nNode[ 1 ] == b.nNode[ 1 ];
  1779. }
  1780. void ListUsedNodes( const FeNodeBase_t &a, uint16 nNodes[ 5 ] )
  1781. {
  1782. nNodes[ 0 ] = a.nNode;
  1783. nNodes[ 1 ] = a.nNodeX0;
  1784. nNodes[ 2 ] = a.nNodeX1;
  1785. nNodes[ 3 ] = a.nNodeY0;
  1786. nNodes[ 4 ] = a.nNodeY1;
  1787. }
  1788. bool Conflict( const FeNodeBase_t &a, const FeNodeBase_t &b )
  1789. {
  1790. uint16 m[ 5 ], n[ 5 ];
  1791. ListUsedNodes( a, m );
  1792. ListUsedNodes( b, n );
  1793. for ( int i = 0; i < 5; ++i )
  1794. {
  1795. for ( int j = 0; j < 5; ++j )
  1796. {
  1797. if ( m[ i ] == n[ j ] )
  1798. return true;
  1799. }
  1800. }
  1801. return false;
  1802. }
  1803. template <typename T>
  1804. bool CanAddToSchedule( const CUtlVector< T > &schedule, const T &add, int nLanes )
  1805. {
  1806. for ( int j = ( schedule.Count( ) & ~( nLanes - 1 ) ); j < schedule.Count( ); ++j )
  1807. {
  1808. if ( Conflict( schedule[ j ], add ) )
  1809. return false;
  1810. }
  1811. return true;
  1812. }
  1813. template < typename T, typename TSimd >
  1814. void Schedule( CUtlVectorAligned< TSimd > *pOutput, const T *pInput, int nInputCount, int nLanes )
  1815. {
  1816. Assert( !( nLanes & ( nLanes - 1 ) ) );
  1817. CUtlVector< T > schedule, delayed;
  1818. delayed.CopyArray( pInput, nInputCount );
  1819. schedule.EnsureCapacity( delayed.Count( ) );
  1820. int nScheduleRoll = 0;
  1821. while ( delayed.Count( ) > 0 || ( schedule.Count( ) & ( nLanes - 1 ) ) )
  1822. {
  1823. bool bAdded = false;
  1824. //if ( !( i & ( nLanes - 1 ) ) )
  1825. for ( int j = delayed.Count( ); j-- > 0; )
  1826. {
  1827. if ( CanAddToSchedule( schedule, delayed[ j ], nLanes ) )
  1828. {
  1829. schedule.AddToTail( delayed[ j ] );
  1830. delayed.Remove( j );
  1831. bAdded = true;
  1832. break;
  1833. }
  1834. }
  1835. if ( !bAdded )
  1836. {
  1837. //try to find something else that we can solve twice per iteration
  1838. for ( int j = 0; j < schedule.Count( ); ++j )
  1839. {
  1840. int k = ( nScheduleRoll + j ) % schedule.Count( );
  1841. ++nScheduleRoll;
  1842. if ( CanAddToSchedule( schedule, schedule[ k ], nLanes ) )
  1843. {
  1844. T duplicate = schedule[ k ];
  1845. schedule.AddToTail( duplicate );
  1846. bAdded = true;
  1847. break;
  1848. }
  1849. }
  1850. if ( !bAdded )
  1851. {
  1852. // found nothing, just duplicate the last element, it's always safe
  1853. T safeDup = schedule.Tail( );
  1854. schedule.AddToTail( safeDup );
  1855. }
  1856. }
  1857. }
  1858. Assert( !( schedule.Count( ) & ( nLanes - 1 ) ) );
  1859. pOutput->SetCount( schedule.Count( ) / nLanes );
  1860. for ( int nScalar = 0, nSimd = schedule.Count( ) / nLanes; nSimd-- > 0; nScalar += nLanes )
  1861. {
  1862. ( *pOutput )[ nSimd ].Init( &schedule[ nScalar ] );
  1863. }
  1864. }
  1865. // build the sequences of node indices from parent to child that are used in reconstruction of node rotations
  1866. void CFeModelBuilder::BuildRopes( )
  1867. {
  1868. // mark "1" for nodes that are NOT ends of ropes, e.g. they:
  1869. // a) have rope (sub)chains hanging off of them
  1870. // b) have quads attached to them, so they can form their bases by looking at those quads
  1871. // c) have preset bases for any other reason
  1872. CVarBitVec skip( m_Nodes.Count( ) );
  1873. CVarBitVec hasBase( m_Nodes.Count() );
  1874. // skip already preset base
  1875. for ( int i = 0; i < m_NodeBases.Count(); ++i )
  1876. {
  1877. uint nNode = m_NodeBases[ i ].nNode;
  1878. skip.Set( nNode );
  1879. hasBase.Set( nNode );
  1880. }
  1881. // skip free nodes
  1882. for ( int i = 0; i < m_Nodes.Count(); ++i )
  1883. {
  1884. if ( m_Nodes[ i ].bSimulated && m_Nodes[ i ].bAnimRotation )
  1885. {
  1886. skip.Set( i );
  1887. }
  1888. }
  1889. if ( IsDebug() )
  1890. {
  1891. for ( int nElem = 0; nElem < m_Elems.Count(); ++nElem )
  1892. {
  1893. const BuildElem_t &elem = m_Elems[ nElem ];
  1894. AssertDbg( elem.nNode[ 1 ] != elem.nNode[ 0 ] && elem.nNode[ 2 ] != elem.nNode[ 1 ] && elem.nNode[ 0 ] != elem.nNode[ 2 ] );
  1895. // the first 3 nodes are unique, so there's at least a triangle here (hopefully non-degenerate), so we'll try to rely on that for base generation
  1896. for ( int c = 0; c < ARRAYSIZE( elem.nNode ); ++c )
  1897. {
  1898. BuildNode_t &node = m_Nodes[ elem.nNode[ c ] ]; NOTE_UNUSED( node );
  1899. Assert( skip.IsBitSet( elem.nNode[ c ] ) || !node.bSimulated || node.bVirtual ); // should've been set when computing node bases
  1900. }
  1901. }
  1902. }
  1903. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  1904. {
  1905. BuildNode_t &node = m_Nodes[ nNode ];
  1906. if ( !node.bSimulated || node.bVirtual )
  1907. {
  1908. // this can't be the tail of a rope
  1909. skip.Set( nNode );
  1910. hasBase.Set( nNode );
  1911. continue;
  1912. }
  1913. if ( node.nParent >= 0 )
  1914. {
  1915. // the parent can't be the tail because this node will be the tail
  1916. skip.Set( node.nParent );
  1917. }
  1918. }
  1919. // now we know which nodes are part of the chain
  1920. for ( int nTail = 0; nTail < m_Nodes.Count( ); ++nTail )
  1921. {
  1922. if ( m_Nodes[ nTail ].bSimulated && !m_Nodes[ nTail ].bVirtual && m_Nodes[ nTail ].nParent >= 0 && !skip.IsBitSet( nTail ) )
  1923. {
  1924. // starting from the tip of the chain, walk up to form a chain
  1925. CUtlVector< int > *pChain = new CUtlVector< int >;
  1926. for ( int nLink = nTail; ; nLink = m_Nodes[ nLink ].nParent )
  1927. {
  1928. if ( nLink < 0 )
  1929. {
  1930. // the chain unexpectedly terminated with a (previous) dynamic: ambiguous case, because where do we start the default transform?
  1931. AssertDbg( !pChain->IsEmpty( ) );
  1932. int nRoot = pChain->Tail( );
  1933. pChain->AddToTail( nRoot ); // just pretend the start of the chain will prime itself w.r.t. orientation.
  1934. break;
  1935. }
  1936. else
  1937. {
  1938. pChain->AddToTail( nLink );
  1939. if ( hasBase[ nLink ] )
  1940. {
  1941. // the chain is terminated with a static: the easiest case
  1942. break;
  1943. }
  1944. skip.Set( nLink );
  1945. }
  1946. }
  1947. pChain->Reverse();
  1948. m_Ropes.AddToTail( pChain );
  1949. }
  1950. }
  1951. }
  1952. void CFeModelBuilder::BuildFreeNodes( MbaContext_t &context )
  1953. {
  1954. CVarBitVec hasBase( m_Nodes.Count() );
  1955. for ( int i = 0; i < m_Ropes.Count(); ++i )
  1956. {
  1957. for ( int j = 1; j < m_Ropes[ i ]->Count(); ++j )
  1958. {
  1959. int nNode = m_Ropes[ i ]->Element( j );
  1960. AssertDbg( !hasBase[ nNode ] );
  1961. hasBase.Set( nNode );
  1962. }
  1963. }
  1964. for ( int i = 0; i < m_NodeBases.Count(); ++i )
  1965. {
  1966. int nNode = m_NodeBases[ i ].nNode;
  1967. AssertDbg( !hasBase[ nNode ] ); //
  1968. hasBase.Set( nNode );
  1969. }
  1970. for ( int i = 0; i < context.fitMatrices.Count(); ++i )
  1971. {
  1972. const FeFitMatrix_t &fm = context.fitMatrices[ i ];
  1973. hasBase.Set( fm.nNode );
  1974. }
  1975. for ( int nNode = 0; nNode < m_Nodes.Count(); ++nNode )
  1976. {
  1977. if ( m_Nodes[ nNode ].bSimulated )
  1978. {
  1979. if ( !hasBase.IsBitSet( nNode ) || m_Nodes[ nNode ].bAnimRotation )
  1980. {
  1981. AssertDbg( !hasBase.IsBitSet( nNode ) ); // we should have node that takes rotation from animation, and also has the rotation computed by ropes or by node bases - that'd be wasteful. but otherwise, this assert is harmless.
  1982. m_FreeNodes.AddToTail( nNode );
  1983. }
  1984. }
  1985. }
  1986. }
  1987. template <typename Functor >
  1988. CUtlPair< int, int > FindBestPair( const CUtlSortVector< int > &neighbors, Functor fn )
  1989. {
  1990. CUtlPair< int, int > best( 0, 0 );
  1991. float flBest = -FLT_MAX;
  1992. for ( int i = 0; i < neighbors.Count( ); ++i )
  1993. {
  1994. for ( int j = i + 1; j < neighbors.Count( ); ++j )
  1995. {
  1996. float flGrade = fn( neighbors[ i ], neighbors[ j ] );
  1997. if ( flGrade >= flBest )
  1998. {
  1999. flBest = flGrade;
  2000. best.first = neighbors[ i ];
  2001. best.second = neighbors[ j ];
  2002. }
  2003. }
  2004. }
  2005. return best;
  2006. }
  2007. bool IsIdentity( const Quaternion &q, float flBiasSqr = 1e-8f )
  2008. {
  2009. return q.x * q.x + q.y * q.y + q.z * q.z < flBiasSqr;
  2010. }
  2011. FeNodeBase_t CFeModelBuilder::BuildNodeBasisFast( uint nNode )
  2012. {
  2013. return BuildNodeBasisFast( m_Nodes, nNode, *( m_NodeNeighbors[ nNode ] ) );
  2014. }
  2015. FeNodeBase_t CFeModelBuilder::BuildNodeBasisFast( const CUtlVectorAligned< BuildNode_t > &nodes, uint nNode, const CUtlSortVector< int > &neighbors )
  2016. {
  2017. FeNodeBase_t basis;
  2018. V_memset( &basis, 0, sizeof( basis ) );
  2019. basis.nNode = nNode;
  2020. // find max-length axis
  2021. CUtlPair< int, int > axisXIndices = FindBestPair( neighbors,
  2022. [&nodes] ( uint n0, uint n1 )
  2023. {
  2024. return ( nodes[ n0 ].transform.m_vPosition - nodes[ n1 ].transform.m_vPosition ).Length( );
  2025. }
  2026. );
  2027. basis.nNodeX0 = axisXIndices.second;
  2028. basis.nNodeX1 = axisXIndices.first;
  2029. Vector vAxisX = ( nodes[ basis.nNodeX1 ].transform.m_vPosition - nodes[ basis.nNodeX0 ].transform.m_vPosition );
  2030. // find max-area cross-axis
  2031. CUtlPair< int, int > axisYIndices = FindBestPair( neighbors,
  2032. [&nodes, &vAxisX] ( uint n0, uint n1 )
  2033. {
  2034. return CrossProduct( nodes[ n0 ].transform.m_vPosition - nodes[ n1 ].transform.m_vPosition, vAxisX ).Length( );
  2035. }
  2036. );
  2037. basis.nNodeY0 = axisYIndices.second;
  2038. basis.nNodeY1 = axisYIndices.first;
  2039. Vector vAxisY = ( nodes[ basis.nNodeY1 ].transform.m_vPosition - nodes[ basis.nNodeY0 ].transform.m_vPosition ).NormalizedSafe( Vector( 0,0,-1 ) );
  2040. vAxisX = ( vAxisX - DotProduct( vAxisY, vAxisX ) * vAxisY );
  2041. float flAxisXlen = vAxisX.Length( );
  2042. if ( flAxisXlen <= 0.05f )
  2043. {
  2044. CUtlString list;
  2045. for ( int j = 0; j < neighbors.Count( ); ++j )
  2046. {
  2047. if ( j )
  2048. list += ", ";
  2049. list += nodes[ neighbors[ j ] ].pName;
  2050. }
  2051. Warning( "Degenerate finite element (%s), won't be able to compute good normals for node %d bone %s\n", list.Get( ), nNode, nodes[ nNode ].pName );
  2052. Vector vAxisXAlt = CrossProduct( nodes[ nNode ].transform.m_orientation.GetUp(), vAxisY );
  2053. float flAxisXAltLen = vAxisXAlt.Length( );
  2054. if ( flAxisXAltLen < 0.001f )
  2055. {
  2056. vAxisX = VectorPerpendicularToVector( vAxisY );
  2057. }
  2058. else
  2059. {
  2060. vAxisX = vAxisXAlt / flAxisXAltLen;
  2061. }
  2062. }
  2063. else
  2064. {
  2065. vAxisX /= flAxisXlen;
  2066. }
  2067. matrix3x4_t tmPredicted;
  2068. tmPredicted.InitXYZ( vAxisX, vAxisY, CrossProduct( vAxisX, vAxisY ), vec3_origin );
  2069. Assert( IsGoodWorldTransform( tmPredicted, 1.0f ) );
  2070. Quaternion qPredicted = MatrixQuaternion( tmPredicted );
  2071. basis.qAdjust = Conjugate( qPredicted ) * nodes[ nNode ].transform.m_orientation;
  2072. QuaternionNormalize( basis.qAdjust );
  2073. // there are a few special cases, when we can rearrange the axis order to get qAdjust to become identity
  2074. // that is more efficent to compute, we'll save a matrix multiplication per node
  2075. if ( IsIdentity( basis.qAdjust ) )
  2076. {
  2077. basis.qAdjust = quat_identity;
  2078. }
  2079. else if ( IsIdentity( basis.qAdjust * Quaternion( 0, 0, 1, 0 ) ) ) // 180 degree rotation around Z
  2080. {
  2081. // just flip X and Y axes to give adjust identity
  2082. Swap( basis.nNodeX0, basis.nNodeX1 );
  2083. Swap( basis.nNodeY0, basis.nNodeY1 );
  2084. basis.qAdjust = quat_identity;
  2085. }
  2086. else if ( IsIdentity( basis.qAdjust * Quaternion( 0, 1, 0, 0 ) ) ) // 180 degree rotation around Y
  2087. {
  2088. // just flip X axis to give adjust identity
  2089. Swap( basis.nNodeX0, basis.nNodeX1 );
  2090. basis.qAdjust = quat_identity;
  2091. }
  2092. else if ( IsIdentity( basis.qAdjust * Quaternion( 1, 0, 0, 0 ) ) ) // 180 degree rotation around X
  2093. {
  2094. // just flip X axis to give adjust identity
  2095. Swap( basis.nNodeY0, basis.nNodeY1 );
  2096. basis.qAdjust = quat_identity;
  2097. }
  2098. /* else
  2099. { // test, debug the clauses above with this
  2100. Swap( basis.nNodeX0, basis.nNodeX1 );
  2101. Swap( basis.nNodeY0, basis.nNodeY1 );
  2102. basis.qAdjust *= Quaternion( 0, 0, 1, 0 );
  2103. }
  2104. */
  2105. return basis;
  2106. }
  2107. void CFeModelBuilder::BuildNodeBases( )
  2108. {
  2109. BuildNodeBases( m_Nodes, m_Elems, m_PresetNodeBases, m_NodeBases, m_NodeNeighbors );
  2110. }
  2111. void CFeModelBuilder::BuildNodeBases( const CUtlVectorAligned< BuildNode_t > &nodes, const CUtlVector< BuildElem_t > &elems, const CUtlVector< FeNodeBase_t > &presetNodeBases, CUtlVector< FeNodeBase_t > &nodeBases, CUtlVectorOfPointers< CUtlSortVector< int > > &neighbors )
  2112. {
  2113. neighbors.SetCountAndInit( nodes.Count( ),
  2114. [] ( int nNode )
  2115. {
  2116. CUtlSortVector< int > *pResult = new CUtlSortVector< int >;
  2117. pResult->Insert( nNode ); // node is always a neighbor of itself..
  2118. return pResult;
  2119. }
  2120. );
  2121. for ( int nElem = 0; nElem < elems.Count( ); ++nElem )
  2122. {
  2123. const BuildElem_t &elem = elems[ nElem ];
  2124. AssertDbg( elem.nNode[ 1 ] != elem.nNode[ 0 ] && elem.nNode[ 2 ] != elem.nNode[ 1 ] && elem.nNode[ 0 ] != elem.nNode[ 2 ] );
  2125. int numNodes = elem.nNode[ 3 ] == elem.nNode[ 2 ] ? 3 : 4;
  2126. for ( int c = 0; c < numNodes; ++c )
  2127. {
  2128. for ( int d = 0; d < numNodes; ++d )
  2129. {
  2130. // add the previous and the next node
  2131. neighbors[ elem.nNode[ c ] ]->InsertIfNotFound( elem.nNode[ d ] );
  2132. }
  2133. }
  2134. }
  2135. // copy the preset node bases
  2136. nodeBases.EnsureCapacity( presetNodeBases.Count() );
  2137. CVarBitVec nodeWithBase( nodes.Count() );
  2138. for ( int i = 0; i < presetNodeBases.Count(); ++i )
  2139. {
  2140. const FeNodeBase_t &nb = presetNodeBases[ i ];
  2141. if ( !nodeWithBase.IsBitSet( nb.nNode ) )
  2142. {
  2143. nodeBases.AddToTail( nb );
  2144. nodeWithBase.Set( nb.nNode );
  2145. }
  2146. }
  2147. // compute additional bases
  2148. for ( int nNode = 0; nNode < nodes.Count( ); ++nNode )
  2149. {
  2150. if ( !nodeWithBase.IsBitSet( nNode ) && !( nodes[ nNode ].bSimulated && nodes[ nNode ].bAnimRotation ) )
  2151. {
  2152. CUtlSortVector< int > *pCheck = neighbors[ nNode ];
  2153. const BuildNode_t &node = nodes[ nNode ];
  2154. if ( pCheck->Count() >= 3 // we need at least 3 nodes to compute the basis
  2155. && ( !node.bVirtual || node.bNeedNodeBase ) // virtual nodes have no effect on animation, there's no need to do a complex computation of basis for them
  2156. && ( node.bSimulated || node.bFreeRotation ) // static nodes need not recompute their basis, they get it from animation; unless we explicitly specified we need a free-rotating locked/static/keyframed node. Then compute the rotation.
  2157. )
  2158. {
  2159. nodeBases.AddToTail( BuildNodeBasisFast( nodes, nNode, *( neighbors[ nNode ] ) ) );
  2160. nodeWithBase.Set( nNode );
  2161. }
  2162. }
  2163. }
  2164. }
  2165. int RopeIndexCount( const CUtlVectorOfPointers< CUtlVector< int > > &ropes )
  2166. {
  2167. int nCount = ropes.Count( );
  2168. for ( int i = 0; i < ropes.Count( ); ++i )
  2169. {
  2170. nCount += ropes[ i ]->Count( );
  2171. }
  2172. return nCount;
  2173. }
  2174. void CFeModelBuilder::ValidateBases( )
  2175. {
  2176. #ifdef DBGFLAG_ASSERT
  2177. int nLog = CommandLine( )->FindParm( "-log" );
  2178. CVarBitVec hasBase( m_Nodes.Count( ) );
  2179. for ( int i = 0; i < m_Ropes.Count( ); ++i )
  2180. {
  2181. for ( int j = 1; j < m_Ropes[ i ]->Count( ); ++j )
  2182. {
  2183. int nNode = m_Ropes[ i ]->Element( j );
  2184. AssertDbg( !hasBase[ nNode ] );
  2185. hasBase.Set( nNode );
  2186. }
  2187. }
  2188. for ( int i = 0; i < m_NodeBases.Count( ); ++i )
  2189. {
  2190. int nNode = m_NodeBases[ i ].nNode;
  2191. AssertDbg( !hasBase[ nNode ] ); //
  2192. hasBase.Set( nNode );
  2193. }
  2194. for ( int i = 0; i < m_FreeNodes.Count(); ++i )
  2195. {
  2196. hasBase.Set( m_FreeNodes[ i ] );
  2197. }
  2198. //--
  2199. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  2200. {
  2201. int nHasBase = hasBase[ nNode ] ? 1 : 0; NOTE_UNUSED( nHasBase );
  2202. int nSimulated = m_Nodes[ nNode ].bSimulated ? 1 : 0; NOTE_UNUSED( nSimulated );
  2203. //const char *pBoneName = m_Nodes[ nNode ].pName; NOTE_UNUSED( pBoneName );
  2204. Assert( nHasBase == nSimulated || m_Nodes[ nNode ].bVirtual || m_Nodes[ nNode ].bFreeRotation ); // we don't really care if virtual nodes have bases or not. In fact, it's probably better not to compute bases for them, but it may be necessary if real nodes' bases depend on them..
  2205. if ( m_Nodes[ nNode ].nParent < 0 )
  2206. {
  2207. if ( nLog )
  2208. {
  2209. PrintNodeTree( nNode, "" );
  2210. }
  2211. }
  2212. }
  2213. //
  2214. // Just print out the elements for eyeballing
  2215. //
  2216. for ( int nElem = 0; nElem < m_Elems.Count( ); ++nElem )
  2217. {
  2218. CUtlVectorFixedGrowable< const char *, 4 > names;
  2219. const BuildElem_t &elem = m_Elems[ nElem ];
  2220. int nPrefixLen = 1000;
  2221. for ( uint n = 0; n < elem.NumNodes( ); ++n )
  2222. {
  2223. const char *pName = m_Nodes[ elem.nNode[ n ] ].pName;
  2224. names.AddToTail( pName );
  2225. int nNewLen = 0;
  2226. for ( ; nNewLen < nPrefixLen && pName && pName[ nNewLen ] && names[ 0 ][ nNewLen ] == pName[ nNewLen ]; ++nNewLen )
  2227. continue;
  2228. nPrefixLen = nNewLen;
  2229. }
  2230. CUtlString list;
  2231. list.SetDirect( names[ 0 ], nPrefixLen );
  2232. list += "( ";
  2233. for ( int n = 0; n < names.Count( ); ++n )
  2234. {
  2235. if ( n )
  2236. list += ", ";
  2237. list += names[ n ] ? names[ n ] + nPrefixLen : "null";
  2238. }
  2239. list += " )";
  2240. if ( nLog )
  2241. {
  2242. Msg( "%s\n", list.Get( ) );
  2243. }
  2244. }
  2245. #endif
  2246. }
  2247. void CFeModelBuilder::PrintNodeTree( uint nRoot, const CUtlString &prefix )
  2248. {
  2249. const BuildNode_t &root = m_Nodes[ nRoot ];
  2250. Msg( "%s%s%s #%d", prefix.Get( ), root.pName, root.bSimulated ? " sim" : "", nRoot );
  2251. if ( root.flFollowWeight > 0 && root.nFollowParent >= 0 )
  2252. {
  2253. Msg( " - follow %s w%.3f", m_Nodes[ root.nFollowParent ].pName, root.flFollowWeight );
  2254. }
  2255. Msg( "\n" );
  2256. for ( int nChild = 0; nChild < m_Nodes.Count( ); ++nChild )
  2257. {
  2258. if ( m_Nodes[ nChild ].nParent == int( nRoot ) )
  2259. {
  2260. PrintNodeTree( nChild, prefix + " " );
  2261. }
  2262. }
  2263. }
  2264. void CFeModelBuilder::CheckIdentityCtrlOrder( )
  2265. {
  2266. if ( m_bIdentityCtrlOrder )
  2267. {
  2268. // convert all Ctrl-based indices to node-based indices
  2269. for ( int i = 0; i < m_CtrlOffsets.Count(); ++i )
  2270. {
  2271. FeCtrlOffset_t &offset = m_CtrlOffsets[ i ];
  2272. ConvertCtrlToNode( offset.nCtrlChild );
  2273. ConvertCtrlToNode( offset.nCtrlParent );
  2274. }
  2275. for ( int i = 0; i < m_CtrlOsOffsets.Count(); ++i )
  2276. {
  2277. FeCtrlOsOffset_t &offset = m_CtrlOsOffsets[ i ];
  2278. ConvertCtrlToNode( offset.nCtrlChild );
  2279. ConvertCtrlToNode( offset.nCtrlParent );
  2280. }
  2281. for ( int i = 0; i < m_ReverseOffsets.Count(); ++i )
  2282. {
  2283. FeNodeReverseOffset_t &revOffset = m_ReverseOffsets[ i ];
  2284. ConvertCtrlToNode( revOffset.nBoneCtrl );
  2285. }
  2286. m_NodeToCtrl.SetCount( m_Nodes.Count( ) );
  2287. m_CtrlToNode.SetCount( m_Nodes.Count( ) );
  2288. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  2289. {
  2290. m_NodeToCtrl[ i ] = i;
  2291. m_CtrlToNode[ i ] = i;
  2292. }
  2293. }
  2294. else
  2295. {
  2296. if ( m_NodeToCtrl.Count( ) == m_Nodes.Count( ) && m_CtrlToNode.Count( ) == m_Nodes.Count( ) )
  2297. {
  2298. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  2299. {
  2300. if ( m_NodeToCtrl[ i ] != i || m_CtrlToNode[ i ] != i )
  2301. return;
  2302. }
  2303. // we already have de facto identity order
  2304. m_bIdentityCtrlOrder = true;
  2305. }
  2306. }
  2307. }
  2308. bool CFeModelBuilder::HasLegacyStretchForce( ) const
  2309. {
  2310. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  2311. {
  2312. if ( m_Nodes[ i ].bSimulated && m_Nodes[ i ].flLegacyStretchForce != 0 )
  2313. {
  2314. return true;
  2315. }
  2316. }
  2317. return false;
  2318. }
  2319. template <typename Allocator >
  2320. void CFeModelBuilder::OnAllocateMultiBuffer( Allocator &subAlloc, MbaContext_t &context )
  2321. {
  2322. uint nDynCount = GetDynamicNodeCount();
  2323. subAlloc( m_pSimdRods, context.simdRods );
  2324. if ( subAlloc( m_pSimdQuads, m_nSimdQuadCount[ 0 ] ) )
  2325. {
  2326. for ( uint nSimdQuad = 0; nSimdQuad < m_nSimdQuadCount[ 2 ]; ++nSimdQuad )
  2327. {
  2328. m_pSimdQuads[ nSimdQuad ] = context.simdQuads[ 2 ][ nSimdQuad ];
  2329. }
  2330. for ( uint nSimdQuad = m_nSimdQuadCount[ 2 ]; nSimdQuad < m_nSimdQuadCount[ 1 ]; ++nSimdQuad )
  2331. {
  2332. m_pSimdQuads[ nSimdQuad ] = context.simdQuads[ 1 ][ nSimdQuad - m_nSimdQuadCount[ 2 ] ];
  2333. }
  2334. for ( uint nSimdQuad = m_nSimdQuadCount[ 1 ]; nSimdQuad < m_nSimdQuadCount[ 0 ]; ++nSimdQuad )
  2335. {
  2336. m_pSimdQuads[ nSimdQuad ] = context.simdQuads[ 0 ][ nSimdQuad - m_nSimdQuadCount[ 1 ] ];
  2337. }
  2338. }
  2339. if ( subAlloc( m_pSimdTris, m_nSimdTriCount[ 0 ] ) )
  2340. {
  2341. for ( uint nSimdTri = 0; nSimdTri < m_nSimdTriCount[ 2 ]; ++nSimdTri )
  2342. {
  2343. m_pSimdTris[ nSimdTri ] = context.simdTris[ 2 ][ nSimdTri ];
  2344. }
  2345. for ( uint nSimdTri = m_nSimdTriCount[ 2 ]; nSimdTri < m_nSimdTriCount[ 1 ]; ++nSimdTri )
  2346. {
  2347. m_pSimdTris[ nSimdTri ] = context.simdTris[ 1 ][ nSimdTri - m_nSimdTriCount[ 2 ] ];
  2348. }
  2349. for ( uint nSimdTri = m_nSimdTriCount[ 1 ]; nSimdTri < m_nSimdTriCount[ 0 ]; ++nSimdTri )
  2350. {
  2351. m_pSimdTris[ nSimdTri ] = context.simdTris[ 0 ][ nSimdTri - m_nSimdTriCount[ 1 ] ];
  2352. }
  2353. }
  2354. subAlloc( m_pSimdNodeBases, context.simdBases ); // must be aligned
  2355. subAlloc( m_pSimdSpringIntegrator, context.simdSprings );
  2356. subAlloc( m_pFitMatrices, context.fitMatrices );
  2357. if ( subAlloc( m_pInitPose, m_nCtrlCount ) )
  2358. {
  2359. for ( uint nCtrl = 0; nCtrl < m_nCtrlCount; ++nCtrl )
  2360. {
  2361. m_pInitPose[ nCtrl ] = m_CtrlToNode[ nCtrl ] >= 0 ? m_Nodes[ m_CtrlToNode[ nCtrl ] ].transform : g_TransformIdentity;
  2362. }
  2363. }
  2364. subAlloc( m_pCtrlName, context.nCtrlNameCount );
  2365. subAlloc( m_pNodeBases, m_NodeBases );
  2366. subAlloc( m_pReverseOffsets, m_ReverseOffsets );
  2367. subAlloc( m_pCtrlOffsets, m_CtrlOffsets );
  2368. subAlloc( m_pCtrlOsOffsets, m_CtrlOsOffsets );
  2369. subAlloc( m_pFollowNodes, context.nodeFollowers );
  2370. uint32 *pCtrlHash = subAlloc( m_pCtrlHash, context.nCtrlNameCount );
  2371. subAlloc( m_pQuads, context.quads );
  2372. subAlloc( m_pRods, m_Rods );
  2373. subAlloc( m_pTris, context.tris );
  2374. subAlloc( m_pAxialEdges, m_AxialEdges );
  2375. if ( subAlloc( m_pNodeIntegrator, context.nNodeIntegratorCount ) )
  2376. {
  2377. for ( uint nNode = 0; nNode < context.nNodeIntegratorCount; ++nNode )
  2378. {
  2379. m_pNodeIntegrator[ nNode ] = m_Nodes[ nNode ].integrator;
  2380. if ( nNode < m_nStaticNodes )
  2381. {
  2382. m_nStaticNodeFlags |= m_Nodes[ nNode ].GetDampingFlags( );
  2383. // note: flAnimationForceAttraction seemingly isn't used in source1 on static nodes, no need to premultiply
  2384. }
  2385. else
  2386. {
  2387. // <sergiy> Important fix: the springs (particularly animation force attraction) in Source1 were tuned to the "mass" of cloth particles
  2388. // Source2 computes accelerations directly, so we need to pre-divide by mass here. I forgot to do that in CL 2322760, fixed in 2532503.
  2389. // <sergiy> turns out I do predivide flAnimationForceAttraction by mass when importing CAuthClothParser::ParseLegacyDotaNodeGrid, so no need to do that here again.
  2390. // m_pNodeIntegrator[ nNode ].flAnimationForceAttraction *= m_Nodes[ nNode ].invMass;
  2391. m_nDynamicNodeFlags |= m_Nodes[ nNode ].GetDampingFlags();
  2392. }
  2393. }
  2394. }
  2395. subAlloc( m_pSpringIntegrator, context.springs );
  2396. if ( subAlloc( m_pNodeInvMasses, m_nNodeCount ) )
  2397. {
  2398. for ( int nNode = 0; nNode < m_Nodes.Count( ); ++nNode )
  2399. {
  2400. m_pNodeInvMasses[ nNode ] = m_Nodes[ nNode ].invMass;
  2401. }
  2402. }
  2403. subAlloc( m_pCollisionSpheres, context.collisionSpheres );
  2404. subAlloc( m_pCollisionPlanes, context.collisionPlanes );
  2405. subAlloc( m_pFitWeights, context.fitWeights );
  2406. if ( context.m_bHasNodeCollisionRadii )
  2407. {
  2408. if ( subAlloc( m_pNodeCollisionRadii, GetDynamicNodeCount() ) )
  2409. {
  2410. AssertDbg( m_Nodes.Count() == int( m_nNodeCount ) );
  2411. for ( uint nNode = m_nStaticNodes; nNode < m_nNodeCount; ++nNode )
  2412. {
  2413. m_pNodeCollisionRadii[ nNode - m_nStaticNodes ] = m_Nodes[ nNode ].flCollisionRadius;
  2414. }
  2415. }
  2416. }
  2417. else
  2418. {
  2419. m_pNodeCollisionRadii = NULL;
  2420. }
  2421. if ( context.m_bUsePerNodeLocalForce )
  2422. {
  2423. if ( subAlloc( m_pLocalForce, GetDynamicNodeCount() ) )
  2424. {
  2425. AssertDbg( m_Nodes.Count() == int( m_nNodeCount ) );
  2426. for ( uint nNode = m_nStaticNodes; nNode < m_nNodeCount; ++nNode )
  2427. {
  2428. m_pLocalForce[ nNode - m_nStaticNodes ] = m_Nodes[ nNode ].flLocalForce;
  2429. }
  2430. }
  2431. }
  2432. if ( context.m_bUsePerNodeLocalRotation )
  2433. {
  2434. if ( subAlloc( m_pLocalRotation, GetDynamicNodeCount() ) )
  2435. {
  2436. AssertDbg( m_Nodes.Count() == int( m_nNodeCount ) );
  2437. for ( uint nNode = m_nStaticNodes; nNode < m_nNodeCount; ++nNode )
  2438. {
  2439. m_pLocalRotation[ nNode - m_nStaticNodes ] = m_Nodes[ nNode ].flLocalRotation;
  2440. }
  2441. }
  2442. }
  2443. subAlloc( m_pWorldCollisionParams, context.worldCollisionParams );
  2444. subAlloc( m_pTaperedCapsuleStretches, m_TaperedCapsuleStretches );
  2445. subAlloc( m_pTaperedCapsuleRigids, m_TaperedCapsuleRigids );
  2446. subAlloc( m_pSphereRigids, m_SphereRigids );
  2447. if ( subAlloc( m_pLegacyStretchForce, context.nLegacyStretchForceCount ) )
  2448. {
  2449. for ( uint i = 0; i < context.nLegacyStretchForceCount; ++i )
  2450. {
  2451. m_pLegacyStretchForce[ i ] = m_Nodes[ i ].bSimulated ? m_Nodes[ i ].flLegacyStretchForce/* * m_Nodes[ i ].invMass*/ : 0.0f;
  2452. }
  2453. }
  2454. if ( !m_bIdentityCtrlOrder )
  2455. {
  2456. if ( subAlloc( m_pCtrlToNode, m_CtrlToNode.Count( ) ) )
  2457. {
  2458. for ( int i = 0; i < m_CtrlToNode.Count( ); ++i )
  2459. {
  2460. m_pCtrlToNode[ i ] = m_CtrlToNode[ i ];
  2461. }
  2462. }
  2463. if ( subAlloc( m_pNodeToCtrl, m_NodeToCtrl.Count( ) ) )
  2464. {
  2465. for ( int i = 0; i < m_NodeToCtrl.Count( ); ++i )
  2466. {
  2467. m_pNodeToCtrl[ i ] = m_NodeToCtrl[ i ];
  2468. }
  2469. }
  2470. }
  2471. else
  2472. {
  2473. // these get assigned NULL twice..
  2474. m_pCtrlToNode = NULL;
  2475. m_pNodeToCtrl = NULL;
  2476. }
  2477. subAlloc( m_pTreeChildren, m_TreeChildren );
  2478. subAlloc( m_pTreeParents, m_TreeParents );
  2479. if ( subAlloc( m_pTreeCollisionMasks, m_TreeParents.Count() ) )
  2480. {
  2481. V_memset( m_pTreeCollisionMasks, 0, sizeof( *m_pTreeCollisionMasks ) * ( 2 * nDynCount - 1 ) );
  2482. for ( uint i = 0; i < nDynCount; ++i )
  2483. {
  2484. m_pTreeCollisionMasks[ i ] = m_Nodes[ i + m_nStaticNodes ].nCollisionMask;
  2485. }
  2486. // propagate the mask to parents
  2487. for ( uint i = 0; i < 2 * nDynCount - 2; ++i )
  2488. {
  2489. m_pTreeCollisionMasks[ m_TreeParents[ i ] ] |= m_pTreeCollisionMasks[ i ];
  2490. }
  2491. }
  2492. subAlloc( m_pWorldCollisionNodes, context.worldCollisionNodes );
  2493. subAlloc( m_pFreeNodes, m_FreeNodes );
  2494. if ( subAlloc( m_pRopes, m_nRopeIndexCount ) )
  2495. {
  2496. uint nRopeRunningIndex = m_Ropes.Count( );
  2497. for ( int nRope = 0; nRope < m_Ropes.Count( ); ++nRope )
  2498. {
  2499. for ( int nLink = 0; nLink < m_Ropes[ nRope ]->Count( ); ++nLink )
  2500. {
  2501. m_pRopes[ nRopeRunningIndex++ ] = m_Ropes[ nRope ]->Element( nLink );
  2502. }
  2503. m_pRopes[ nRope ] = nRopeRunningIndex;
  2504. }
  2505. Assert( nRopeRunningIndex == m_nRopeIndexCount );
  2506. }
  2507. for ( uint nCtrl = 0; nCtrl < context.nCtrlNameCount; ++nCtrl )
  2508. {
  2509. int nNode = m_CtrlToNode[ nCtrl ];
  2510. subAlloc.String( m_pCtrlName[ nCtrl ], nNode >= 0 ? m_Nodes[ nNode ].pName : NULL );
  2511. }
  2512. if ( pCtrlHash )
  2513. {
  2514. for ( uint nCtrl = 0; nCtrl < context.nCtrlNameCount; ++nCtrl )
  2515. {
  2516. const char *pName = m_pCtrlName[ nCtrl ];
  2517. pCtrlHash[ nCtrl ] = pName ? MakeStringToken( pName ).m_nHashCode : 0;
  2518. }
  2519. }
  2520. }
  2521. float CFeModelBuilder::ElemNormalLength( const uint nNode[ 4 ] )
  2522. {
  2523. Vector p0 = m_Nodes[ nNode[ 0 ] ].transform.m_vPosition;
  2524. Vector p1 = m_Nodes[ nNode[ 1 ] ].transform.m_vPosition;
  2525. Vector p2 = m_Nodes[ nNode[ 2 ] ].transform.m_vPosition;
  2526. Vector p3 = m_Nodes[ nNode[ 3 ] ].transform.m_vPosition;
  2527. Vector vNormal = CrossProduct( p2 - p0, p3 - p1 );
  2528. return vNormal.Length();
  2529. }
  2530. Vector CFeModelBuilder::TriNormal( uint nNode0, uint nNode1, uint nNode2 )
  2531. {
  2532. Vector p0 = m_Nodes[ nNode0 ].transform.m_vPosition;
  2533. Vector p1 = m_Nodes[ nNode1 ].transform.m_vPosition;
  2534. Vector p2 = m_Nodes[ nNode2 ].transform.m_vPosition;
  2535. Vector vNormal = CrossProduct( p1 - p0, p2 - p0 );
  2536. return vNormal;
  2537. }
  2538. float CFeModelBuilder::NodeDist( uint nNode0, uint nNode1 )
  2539. {
  2540. const Vector &p0 = m_Nodes[ nNode0 ].transform.m_vPosition;
  2541. const Vector &p1 = m_Nodes[ nNode1 ].transform.m_vPosition;
  2542. return ( p0 - p1 ).Length();
  2543. }
  2544. void CFeModelBuilder::AdjustQuads()
  2545. {
  2546. CUtlVector< BuildElem_t > append;
  2547. // convert self-intersecting quads to nice-looking quads
  2548. for ( int i = 0; i < m_Elems.Count(); ++i )
  2549. {
  2550. BuildElem_t &elem = m_Elems[ i ];
  2551. if ( elem.NumNodes() < 4 )
  2552. {
  2553. // nothing to adjust
  2554. continue;
  2555. }
  2556. switch( elem.nStaticNodes )
  2557. {
  2558. case 2:
  2559. { // just a nicety: if we can, let's make this into a convex quad. it's not necessary (and impossible in case of diagonal statics)
  2560. Vector e0 = m_Nodes[ elem.nNode[ 1 ] ].transform.m_vPosition - m_Nodes[ elem.nNode[ 0 ] ].transform.m_vPosition;
  2561. Vector e2 = m_Nodes[ elem.nNode[ 2 ] ].transform.m_vPosition - m_Nodes[ elem.nNode[ 3 ] ].transform.m_vPosition;
  2562. if ( DotProduct( e2, e0 ) < 0 )
  2563. {
  2564. Swap( elem.nNode[ 3 ], elem.nNode[ 2 ] );
  2565. }
  2566. }
  2567. break;
  2568. case 1:
  2569. case 0:
  2570. {
  2571. float flNoPermValue = ElemNormalLength( elem.nNode );
  2572. uint nPerm1[ 4 ] = { elem.nNode[ 0 ], elem.nNode[ 2 ], elem.nNode[ 3 ], elem.nNode[ 1 ] };
  2573. uint nPerm2[ 4 ] = { elem.nNode[ 0 ], elem.nNode[ 3 ], elem.nNode[ 1 ], elem.nNode[ 2 ] };
  2574. float flPerm1Value = ElemNormalLength( nPerm1 );
  2575. float flPerm2Value = ElemNormalLength( nPerm2 );
  2576. uint *pBestPerm = NULL;
  2577. if ( flPerm1Value > flPerm2Value )
  2578. {
  2579. if ( flPerm1Value > flNoPermValue )
  2580. {
  2581. pBestPerm = nPerm1;
  2582. }
  2583. }
  2584. else
  2585. {
  2586. if ( flPerm2Value > flNoPermValue )
  2587. {
  2588. pBestPerm = nPerm2;
  2589. }
  2590. }
  2591. if ( pBestPerm )
  2592. {
  2593. elem.nNode[ 0 ] = pBestPerm[ 0 ];
  2594. elem.nNode[ 1 ] = pBestPerm[ 1 ];
  2595. elem.nNode[ 2 ] = pBestPerm[ 2 ];
  2596. elem.nNode[ 3 ] = pBestPerm[ 3 ];
  2597. }
  2598. }
  2599. break;
  2600. }
  2601. if ( m_flQuadBendTolerance < 1.0f && elem.nStaticNodes == 0 && elem.nNode[ 2 ] != elem.nNode[ 3 ] )
  2602. {
  2603. // check if the quad is bent too much, and triangulate if so
  2604. if ( NodeDist( elem.nNode[ 0 ], elem.nNode[ 2 ] ) > NodeDist( elem.nNode[ 1 ], elem.nNode[ 3 ] ) )
  2605. {
  2606. // try to make it so that triangulation (0,1,2) (2,3,0) produces the shortest diagonal (0,2)
  2607. uint nWasNode0 = elem.nNode[ 0 ];
  2608. elem.nNode[ 0 ] = elem.nNode[ 1 ];
  2609. elem.nNode[ 1 ] = elem.nNode[ 2 ];
  2610. elem.nNode[ 2 ] = elem.nNode[ 3 ];
  2611. elem.nNode[ 3 ] = nWasNode0;
  2612. }
  2613. // how much is it bent? compare sine of the bend angle with the limit
  2614. Vector n0 = TriNormal( elem.nNode[ 0 ], elem.nNode[ 1 ], elem.nNode[ 2 ] );
  2615. Vector n1 = TriNormal( elem.nNode[ 2 ], elem.nNode[ 3 ], elem.nNode[ 0 ] );
  2616. float flSinBendF = CrossProduct( n0, n1 ).Length(), flF = n0.Length() * n1.Length();
  2617. if ( flSinBendF > m_flQuadBendTolerance * flF )
  2618. {
  2619. // the bend is too great. Split the quad
  2620. BuildElem_t newElem = elem; // new element is (0,2,3,3)
  2621. newElem.nNode[ 1 ] = newElem.nNode[ 2 ];
  2622. newElem.nNode[ 2 ] = newElem.nNode[ 3 ];
  2623. append.AddToTail( newElem );
  2624. // convert old elem to (0,1,2,2) triangle
  2625. elem.nNode[ 3 ] = elem.nNode[ 2 ];
  2626. }
  2627. }
  2628. }
  2629. m_Elems.AddMultipleToTail( append.Count(), append.Base() );
  2630. }
  2631. bool CFeModelBuilder::Finish( bool bTriangulate, float flAddCurvature, float flSlackMultiplier )
  2632. {
  2633. //Schedule( , m_Elems.Base(), 4 ); NOTE_UNUSED( nElemSlack );
  2634. MbaContext_t context;
  2635. BuildInvMassesAndSortNodes( );
  2636. m_nNodeCount = m_Nodes.Count();
  2637. m_nCtrlCount = m_CtrlToNode.Count();
  2638. AdjustQuads();
  2639. BuildTree();
  2640. CheckIdentityCtrlOrder( );
  2641. BuildNodeBases( ); // all node bases are built; even those we won't need later
  2642. BuildRopes();
  2643. ValidateBases( );
  2644. BuildFeEdgeDesc( );
  2645. BuildNodeSlack( flSlackMultiplier );
  2646. BuildAndSortRods( clamp( flAddCurvature, 0.0f, 1.0f ) * M_PI, bTriangulate );
  2647. //BuildKelagerBends();
  2648. if ( m_bRigidEdgeHinges )
  2649. {
  2650. BuildAxialEdges();
  2651. }
  2652. RemoveFullyStaticElems(); // we don't need fully static quads anymore
  2653. if ( bTriangulate )
  2654. {
  2655. BuildTris( context.tris, true );
  2656. }
  2657. else
  2658. {
  2659. BuildTris( context.tris, false );
  2660. BuildQuads( context.quads, true );
  2661. }
  2662. Schedule( &context.simdRods, m_Rods.Base( ), m_Rods.Count( ), 4 );
  2663. Schedule( &context.simdQuads[ 0 ], context.quads.Base( ) + m_nQuadCount[ 1 ], m_nQuadCount[ 0 ] - m_nQuadCount[ 1 ], 4 );
  2664. Schedule( &context.simdQuads[ 1 ], context.quads.Base( ) + m_nQuadCount[ 2 ], m_nQuadCount[ 1 ] - m_nQuadCount[ 2 ], 4 );
  2665. Schedule( &context.simdQuads[ 2 ], context.quads.Base( ), m_nQuadCount[ 2 ], 4 );
  2666. m_nSimdQuadCount[ 0 ] = context.simdQuads[ 2 ].Count( ) + context.simdQuads[ 1 ].Count( ) + context.simdQuads[ 0 ].Count( );
  2667. m_nSimdQuadCount[ 1 ] = context.simdQuads[ 2 ].Count( ) + context.simdQuads[ 1 ].Count( );
  2668. m_nSimdQuadCount[ 2 ] = context.simdQuads[ 2 ].Count( );
  2669. Schedule( &context.simdTris[ 0 ], context.tris.Base( ) + m_nTriCount[ 1 ], m_nTriCount[ 0 ] - m_nTriCount[ 1 ], 4 );
  2670. Schedule( &context.simdTris[ 1 ], context.tris.Base( ) + m_nTriCount[ 2 ], m_nTriCount[ 1 ] - m_nTriCount[ 2 ], 4 );
  2671. Schedule( &context.simdTris[ 2 ], context.tris.Base( ), m_nTriCount[ 2 ], 4 );
  2672. m_nSimdTriCount[ 0 ] = context.simdTris[ 2 ].Count( ) + context.simdTris[ 1 ].Count( ) + context.simdTris[ 0 ].Count( );
  2673. m_nSimdTriCount[ 1 ] = context.simdTris[ 2 ].Count( ) + context.simdTris[ 1 ].Count( );
  2674. m_nSimdTriCount[ 2 ] = context.simdTris[ 2 ].Count( );
  2675. Schedule( &context.simdBases, m_NodeBases.Base( ), m_NodeBases.Count( ), 4 );
  2676. BuildSprings( context.springs );
  2677. Schedule( &context.simdSprings, context.springs.Base( ), context.springs.Count( ), 4 );
  2678. BuildCtrlOffsets( );
  2679. BuildNodeFollowers( context.nodeFollowers );
  2680. context.nCollisionEllipsoidsInclusive = BuildCollisionSpheres( context.collisionSpheres );
  2681. BuildCollisionPlanes( context.collisionPlanes );
  2682. BuildWorldCollisionNodes( context.worldCollisionParams, context.worldCollisionNodes );
  2683. BuildFitMatrices( context );
  2684. if ( m_bNeedBacksolvedBasesOnly )
  2685. RemoveStandaloneNodeBases( context );
  2686. BuildFreeNodes( context );
  2687. if ( HasLegacyStretchForce( ) )
  2688. {
  2689. context.nLegacyStretchForceCount = m_Nodes.Count();
  2690. }
  2691. else
  2692. {
  2693. context.nLegacyStretchForceCount = 0;
  2694. }
  2695. context.m_bHasNodeCollisionRadii = false;
  2696. for ( uint i = m_nStaticNodes; i < m_nNodeCount; ++i )
  2697. {
  2698. const BuildNode_t &node = m_Nodes[ i ];
  2699. if ( node.flCollisionRadius != 0 )
  2700. {
  2701. context.m_bHasNodeCollisionRadii = true;
  2702. break;
  2703. }
  2704. }
  2705. context.m_bUsePerNodeLocalRotation = false;
  2706. context.m_bUsePerNodeLocalForce = false;
  2707. if ( m_bUsePerNodeLocalForceAndRotation )
  2708. {
  2709. if ( m_nNodeCount > m_nStaticNodes )
  2710. {
  2711. m_flLocalForce = m_Nodes[ m_nStaticNodes ].flLocalForce; // find the max local force/rotation values and stick them into defaults
  2712. m_flLocalRotation = m_Nodes[ m_nStaticNodes ].flLocalRotation;
  2713. for ( uint i = m_nStaticNodes + 1; i < m_nNodeCount; ++i )
  2714. {
  2715. const BuildNode_t &node = m_Nodes[ i ];
  2716. if ( node.flLocalRotation != m_flLocalRotation )
  2717. {
  2718. context.m_bUsePerNodeLocalRotation = true;
  2719. m_flLocalRotation = Max( m_flLocalRotation, node.flLocalRotation );
  2720. }
  2721. if ( node.flLocalForce != m_flLocalForce )
  2722. {
  2723. context.m_bUsePerNodeLocalForce = true;
  2724. m_flLocalForce = Max( m_flLocalForce, node.flLocalForce );
  2725. }
  2726. }
  2727. if ( !( m_flLocalForce > 0 ) )
  2728. {
  2729. m_flLocalForce = 0;
  2730. context.m_bUsePerNodeLocalForce = false;
  2731. }
  2732. if ( !( m_flLocalRotation > 0 ) )
  2733. {
  2734. m_flLocalRotation = 0;
  2735. context.m_bUsePerNodeLocalRotation = false;
  2736. }
  2737. }
  2738. }
  2739. // m_nQuadCount[0] = m_Elems.Count( ); // already assigned in BuildQuads
  2740. m_nRodCount = m_Rods.Count( );
  2741. m_nSimdRodCount = context.simdRods.Count( );
  2742. m_nAxialEdgeCount = m_AxialEdges.Count( );
  2743. m_nRopeCount = m_Ropes.Count( );
  2744. m_nRopeIndexCount = RopeIndexCount( m_Ropes );
  2745. m_nNodeBaseCount = m_NodeBases.Count( );
  2746. m_nSimdNodeBaseCount = context.simdBases.Count( );
  2747. m_nSpringIntegratorCount = context.springs.Count( );
  2748. m_nSimdSpringIntegratorCount = context.simdSprings.Count( );
  2749. m_nCtrlOffsets = m_CtrlOffsets.Count();
  2750. m_nCtrlOsOffsets = m_CtrlOsOffsets.Count( );
  2751. m_nFollowNodeCount = context.nodeFollowers.Count( );
  2752. m_nCollisionPlanes = context.collisionPlanes.Count( );
  2753. m_nCollisionSpheres[ 0 ] = context.collisionSpheres.Count( );
  2754. m_nCollisionSpheres[ 1 ] = context.nCollisionEllipsoidsInclusive;
  2755. m_nWorldCollisionNodeCount = context.worldCollisionNodes.Count( );
  2756. m_nWorldCollisionParamCount = context.worldCollisionParams.Count( );
  2757. m_nFitWeightCount = context.fitWeights.Count();
  2758. m_nFitMatrixCount[ 0 ] = context.fitMatrices.Count();
  2759. m_nFitMatrixCount[ 1 ] = context.m_nFitMatrices1;
  2760. m_nFitMatrixCount[ 2 ] = context.m_nFitMatrices2;
  2761. m_nReverseOffsetCount = m_ReverseOffsets.Count();
  2762. m_nTaperedCapsuleStretchCount = m_TaperedCapsuleStretches.Count();
  2763. m_nTaperedCapsuleRigidCount = m_TaperedCapsuleRigids.Count();
  2764. m_nSphereRigidCount = m_SphereRigids.Count();
  2765. m_nFreeNodeCount = m_FreeNodes.Count();
  2766. context.nNodeIntegratorCount = GetDampingFlags( ) ? m_nNodeCount : 0;
  2767. context.nStringsMemSize = 0;
  2768. context.nCtrlNameCount = 0; // if there are no names given, there's no reason to create the array of ctrl names (or their hashes)
  2769. for ( int nCtrl = 0; nCtrl < m_CtrlToNode.Count( ); ++nCtrl )
  2770. {
  2771. int nNode = m_CtrlToNode[ nCtrl ];
  2772. if ( nNode >= 0 )
  2773. {
  2774. const char *pName = m_Nodes[ nNode ].pName;
  2775. if ( pName && *pName )
  2776. {
  2777. // there's a non-empty name
  2778. context.nStringsMemSize += V_strlen( pName ) + 1;
  2779. context.nCtrlNameCount = m_nCtrlCount;
  2780. }
  2781. }
  2782. }
  2783. if ( false ) // sorting is not strictly necessary and it obscures debugging
  2784. {
  2785. HeapSort( m_TaperedCapsuleStretches, []( const FeTaperedCapsuleStretch_t &left, const FeTaperedCapsuleStretch_t &right ) {
  2786. if ( left.nNode[ 1 ] != right.nNode[ 1 ] )
  2787. return left.nNode[ 1 ] < right.nNode[ 1 ];
  2788. if ( left.nNode[ 0 ] != right.nNode[ 0 ] )
  2789. return left.nNode[ 0 ] < right.nNode[ 0 ];
  2790. if ( left.flRadius[ 1 ] != right.flRadius[ 1 ] )
  2791. return left.flRadius[ 1 ] > right.flRadius[ 1 ];
  2792. if ( left.flRadius[ 0 ] != right.flRadius[ 0 ] )
  2793. return left.flRadius[ 0 ] > right.flRadius[ 0 ];
  2794. return false;
  2795. } );
  2796. RemoveDuplicates( m_TaperedCapsuleStretches );
  2797. HeapSort( m_TaperedCapsuleRigids, []( const FeTaperedCapsuleRigid_t &left, const FeTaperedCapsuleRigid_t &right ) {
  2798. return left.nNode < right.nNode;
  2799. } );
  2800. HeapSort( m_SphereRigids, []( const FeSphereRigid_t & left, const FeSphereRigid_t &right ) {
  2801. return left.nNode < right.nNode;
  2802. } );
  2803. }
  2804. ReallocateMultiBuffer( context );
  2805. if ( !m_bUnitlessDamping )
  2806. {
  2807. // make a pass over integrators - the dynamic node damping is defined w.r.t. mass outside of the FE model builder. But inside Fe model simulator, nodes are massless (only mass ratios are used)
  2808. // so we need to premultiply some entities by invMass
  2809. for ( uint i = m_nStaticNodes; i < context.nNodeIntegratorCount; ++i )
  2810. {
  2811. m_pNodeIntegrator[ i ].flPointDamping *= m_Nodes[ i ].invMass;
  2812. }
  2813. }
  2814. m_nTreeDepth = ComputeCollisionTreeDepthTopDown();
  2815. #ifdef DBGFLAG_ASSERTDEBUG
  2816. if ( m_nQuadCount[ 0 ] == m_Elems.Count() )
  2817. {
  2818. for ( uint nCtrl = 0; nCtrl < m_nQuadCount[ 2 ]; ++nCtrl )
  2819. {
  2820. Assert( m_Elems[ nCtrl ].nStaticNodes == 2 );
  2821. }
  2822. for ( uint nCtrl = m_nQuadCount[ 2 ]; nCtrl < m_nQuadCount[ 1 ]; ++nCtrl )
  2823. {
  2824. Assert( m_Elems[ nCtrl ].nStaticNodes == 1 );
  2825. }
  2826. for ( uint nCtrl = m_nQuadCount[ 1 ]; nCtrl < m_nQuadCount[ 0 ]; ++nCtrl )
  2827. {
  2828. Assert( m_Elems[ nCtrl ].nStaticNodes == 0 );
  2829. }
  2830. }
  2831. for ( uint nQuad = 0; nQuad < m_nQuadCount[ 2 ]; ++nQuad )
  2832. {
  2833. Assert( m_pQuads[ nQuad ].nNode[ 0 ] < m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 1 ] < m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 2 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 3 ] >= m_nStaticNodes );
  2834. }
  2835. for ( uint nQuad = m_nQuadCount[ 2 ]; nQuad < m_nQuadCount[ 1 ]; ++nQuad )
  2836. {
  2837. Assert( m_pQuads[ nQuad ].nNode[ 0 ] < m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 1 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 2 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 3 ] >= m_nStaticNodes );
  2838. }
  2839. for ( uint nQuad = m_nQuadCount[ 1 ]; nQuad < m_nQuadCount[ 0 ]; ++nQuad )
  2840. {
  2841. Assert( m_pQuads[ nQuad ].nNode[ 0 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 1 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 2 ] >= m_nStaticNodes && m_pQuads[ nQuad ].nNode[ 3 ] >= m_nStaticNodes );
  2842. }
  2843. Assert( m_nQuadCount[ 0 ] >= m_nQuadCount[ 1 ] && m_nQuadCount[ 1 ] >= m_nQuadCount[ 2 ] );
  2844. for ( uint nRod = 0; nRod < m_nRodCount; ++nRod )
  2845. {
  2846. AssertDbg( Is0To1( m_pRods[ nRod ].flWeight0 ) && Is0To1( m_pRods[ nRod ].flRelaxationFactor ) );
  2847. }
  2848. #endif
  2849. return true;
  2850. }
  2851. void CFeModelBuilder::BuildTree()
  2852. {
  2853. uint nDynNodeCount = GetDynamicNodeCount();
  2854. if ( nDynNodeCount < 2 )
  2855. return;
  2856. uint nStaticBaseIndex = m_nStaticNodes;
  2857. CFeAgglomerator agg( nDynNodeCount );
  2858. for ( uint nDynNode = 0; nDynNode < nDynNodeCount; ++nDynNode )
  2859. {
  2860. agg.SetNode( nDynNode, m_Nodes[ nDynNode + nStaticBaseIndex ].transform.m_vPosition );
  2861. }
  2862. for ( int nRod = 0; nRod < m_Rods.Count(); ++nRod )
  2863. {
  2864. const FeRodConstraint_t& rod = m_Rods[ nRod ];
  2865. if ( rod.nNode[ 0 ] >= nStaticBaseIndex && rod.nNode[ 1 ] >= nStaticBaseIndex )
  2866. {
  2867. agg.LinkNodes( rod.nNode[ 0 ] - nStaticBaseIndex, rod.nNode[ 1 ] - nStaticBaseIndex );
  2868. }
  2869. }
  2870. for ( int nElemIdx = 0; nElemIdx < m_Elems.Count(); ++nElemIdx )
  2871. {
  2872. const BuildElem_t& elem = m_Elems[ nElemIdx ];
  2873. if ( elem.nStaticNodes < 3 )
  2874. {
  2875. for ( int nElemIndex = elem.nStaticNodes + 1; nElemIndex < ARRAYSIZE( elem.nNode ); ++nElemIndex )
  2876. {
  2877. agg.LinkNodes( elem.nNode[ nElemIndex ] - nStaticBaseIndex, elem.nNode[ nElemIndex - 1 ] - nStaticBaseIndex );
  2878. }
  2879. if ( elem.nStaticNodes == 0 )
  2880. {
  2881. agg.LinkNodes( elem.nNode[ 0 ] - nStaticBaseIndex, elem.nNode[ ARRAYSIZE( elem.nNode ) - 1 ] - nStaticBaseIndex );
  2882. }
  2883. }
  2884. }
  2885. agg.Build( true );
  2886. Assert( agg.GetClusterCount() == int( nDynNodeCount * 2 - 1 ) );
  2887. m_TreeParents.SetCount( agg.GetClusterCount() );
  2888. for ( int nDynNode = 0; nDynNode < agg.GetClusterCount(); ++nDynNode )
  2889. {
  2890. m_TreeParents[ nDynNode ] = agg.GetCluster( nDynNode )->m_nParent;
  2891. }
  2892. m_TreeChildren.SetCount( agg.GetClusterCount() - nDynNodeCount );
  2893. for ( int nDynNode = nDynNodeCount; nDynNode < agg.GetClusterCount(); ++nDynNode )
  2894. {
  2895. for ( int nChildIndex = 0; nChildIndex < 2; ++nChildIndex )
  2896. {
  2897. uint nChild = agg.GetCluster( nDynNode )->m_nChild[ nChildIndex ];
  2898. m_TreeChildren[ nDynNode - nDynNodeCount ].nChild[ nChildIndex ] = nChild;
  2899. Assert( agg.GetCluster( nChild )->m_nParent == nDynNode );
  2900. }
  2901. }
  2902. }
  2903. int CFeModelBuilder::FindBuildNodeIndex( const char *pName )
  2904. {
  2905. for ( int i = 0; i < m_Nodes.Count(); ++i )
  2906. {
  2907. if ( !V_stricmp( m_Nodes[ i ].pName, pName ) )
  2908. {
  2909. return i;
  2910. }
  2911. }
  2912. return -1;
  2913. }