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.

1219 lines
41 KiB

  1. #include "movieobjects/dmemodel.h"
  2. #include "movieobjects/dmemesh.h"
  3. #include "compileclothproxy.h"
  4. #include "mdlobjects/clothproxymesh.h"
  5. #include "mathlib/femodelbuilder.h"
  6. const char *g_pDefaultClothRootBoneName = "$cloth_root";
  7. CClothProxyCompiler *g_pClothProxyCompiler = NULL;
  8. CClothProxyCompiler::CClothProxyCompiler( CAuthPhysFx *pAuthFx )
  9. : m_pAuthFx( pAuthFx )
  10. , m_nProxyMeshes( 0 )
  11. {
  12. m_nRootFxNode = pAuthFx->FindNodeIndex( g_pDefaultClothRootBoneName );
  13. }
  14. void CClothProxyCompiler::Init( const CVClothProxyMeshOptions &clothProxyMeshList )
  15. {
  16. Assert( IsEmpty() ); // calling Init() twice would not be too bad now, but it wouldn't be expected
  17. m_Options = clothProxyMeshList;
  18. if ( m_Options.m_bCreateStaticBone )
  19. {
  20. GetOrCreateClothRootBone();
  21. }
  22. m_nIslandCount = 0;
  23. m_NodeToIslandMap.Purge();
  24. }
  25. void CClothProxyCompiler::Append( CDmeModel *pModel, float flClothEnableThreshold, const CVClothProxyMesh &proxy )
  26. {
  27. Assert( m_NodeToIslandMap.Count() == 0 ); // we didn't finish yet
  28. pModel->ZUp( true );
  29. CDmeModel *pDmeModelModel = pModel->GetValueElement< CDmeModel >( "model" );
  30. if ( pDmeModelModel && pDmeModelModel != pModel )
  31. {
  32. pDmeModelModel->ZUp( true );
  33. }
  34. CDmeModel *pDmeModelSkeleton = pModel->GetValueElement< CDmeModel >( "skeleton" );
  35. if ( pDmeModelSkeleton && pDmeModelSkeleton != pModel )
  36. {
  37. pDmeModelSkeleton->ZUp( true );
  38. }
  39. CModelContext context( this, pModel, flClothEnableThreshold, proxy );
  40. //CDmeTransformList *pBindPose = pModel->FindBaseState( "bind" );
  41. int nBaseQuad = m_pAuthFx->m_Quads.Count();
  42. int nChildCount = pModel->GetChildCount();
  43. for ( int nChild = 0; nChild < nChildCount; ++nChild )
  44. {
  45. if ( CDmeDag *pChild = pModel->GetChild( nChild ) )
  46. {
  47. AppendDag( context, pChild );
  48. }
  49. }
  50. if ( proxy.m_bFlexClothBorders )
  51. {
  52. for ( int nQuad = nBaseQuad; nQuad < m_pAuthFx->m_Quads.Count(); ++nQuad )
  53. {
  54. MarkFreeRotatingNodes( m_pAuthFx->m_Quads[ nQuad ] );
  55. }
  56. }
  57. }
  58. // look through all planes in all the meshes (supposedly everything's convex..)
  59. // find the plane farthest from each node (should we add "cloth_plane_collision_enable" attribute ?) and the most-bound bone
  60. // that's going to be the plane and parent bone for collision
  61. void CClothProxyCompiler::AppendPlaneCollision( CDmeModel *pModel )
  62. {
  63. pModel->ZUp( true );
  64. CDmeModel *pDmeModelModel = pModel->GetValueElement< CDmeModel >( "model" );
  65. if ( pDmeModelModel && pDmeModelModel != pModel )
  66. {
  67. pDmeModelModel->ZUp( true );
  68. }
  69. CVClothProxyMesh proxy;
  70. CModelContext context( this, pModel, 0, proxy );
  71. CDmeModel *pDmeModelSkeleton = pModel->GetValueElement< CDmeModel >( "skeleton" );
  72. if ( pDmeModelSkeleton && pDmeModelSkeleton != pModel )
  73. {
  74. pDmeModelSkeleton->ZUp( true );
  75. }
  76. int nChildCount = pModel->GetChildCount();
  77. for ( int nChild = 0; nChild < nChildCount; ++nChild )
  78. {
  79. if ( CDmeDag *pChild = pModel->GetChild( nChild ) )
  80. {
  81. AppendPlaneCollisionDag( context, pChild );
  82. }
  83. }
  84. }
  85. void CClothProxyCompiler::AppendPlaneCollisionDag( CModelContext &modelContext, CDmeDag *pDmeDag )
  86. {
  87. if ( CDmeMesh *pMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() ) )
  88. {
  89. matrix3x4_t tm;
  90. pDmeDag->GetAbsTransform( tm );
  91. AppendPlaneCollisionMesh( modelContext, pMesh, tm );
  92. }
  93. int nChildCount = pDmeDag->GetChildCount();
  94. for ( int nChild = 0; nChild < nChildCount; ++nChild )
  95. {
  96. CDmeDag *pChild = pDmeDag->GetChild( nChild );
  97. AppendPlaneCollisionDag( modelContext, pChild );
  98. }
  99. }
  100. void CClothProxyCompiler::AppendPlaneCollisionMesh( CModelContext &modelContext, CDmeMesh *pMesh, const matrix3x4_t &tm )
  101. {
  102. CMeshContext context( this, &modelContext, pMesh, tm, m_nProxyMeshes );
  103. if ( !context.m_AttrPos )
  104. {
  105. Warning( "No position data found in mesh %s\n", pMesh->GetName() );
  106. return; // something's wrong if we have no positions
  107. }
  108. // for each existing physical cloth vertex (CAuthPhysFx::Node), find the best (farthest) plane
  109. struct BestPlane_t
  110. {
  111. RnPlane_t m_WorldPlane; // the plane is in joint space
  112. Vector m_vPosition;
  113. float m_flDistance;
  114. int m_nDmeJointParent; // this is the Dme Joint Index of the
  115. };
  116. CUtlVector< BestPlane_t > bestPlanes;
  117. bestPlanes.SetCount( m_pAuthFx->m_Nodes.Count() );
  118. for ( int nNode = 0; nNode < m_pAuthFx->m_Nodes.Count(); ++nNode )
  119. {
  120. bestPlanes[ nNode ].m_nDmeJointParent = -1;
  121. bestPlanes[ nNode ].m_flDistance = -1; // find some sane distance
  122. bestPlanes[ nNode ].m_vPosition = m_pAuthFx->m_Nodes[ nNode ].m_Transform.m_vPosition;
  123. }
  124. int nNonRigidPolygons = 0, nRejectedTests = 0, nTotalTests = 0;
  125. EnumerateFaces( pMesh, context.m_pBindState, NULL,
  126. [ &bestPlanes, &context, &nNonRigidPolygons, &modelContext, &nRejectedTests, &nTotalTests ]( int nPos[], int nCount )
  127. {
  128. // find this plane's parent joint
  129. int nParentJoint = context.FindMostBoundJoint( nPos[ 0 ], 1.0f );
  130. if ( nParentJoint < 0 )
  131. {
  132. ++nNonRigidPolygons;
  133. return;
  134. }
  135. for ( int i = 1; i < nCount; ++i )
  136. {
  137. int nOtherParentJoint = context.FindMostBoundJoint( nPos[ i ], 1.0f );
  138. if ( nOtherParentJoint != nParentJoint )
  139. {
  140. ++nNonRigidPolygons;
  141. return;
  142. }
  143. };
  144. Vector vCenter = vec3_origin, vNormal = vec3_origin, vPrev = context.m_AttrPos.m_Data[ nPos[ nCount - 1 ] ];
  145. for ( int i = 0; i < nCount; i++ )
  146. {
  147. Vector vNext = context.m_AttrPos.m_Data[ nPos[ i ] ];
  148. vCenter += vNext;
  149. // this is Newell normal algorithm, it's general and robust
  150. vNormal.x += ( vPrev.y - vNext.y ) * ( vNext.z + vPrev.z );
  151. vNormal.y += ( vPrev.z - vNext.z ) * ( vNext.x + vPrev.x );
  152. vNormal.z += ( vPrev.x - vNext.x ) * ( vNext.y + vPrev.y );
  153. vPrev = vNext;
  154. }
  155. vCenter /= nCount;
  156. Vector vWorldCenter = VectorTransform( vCenter, context.m_MeshTransform );
  157. Vector vWorldNormal = VectorRotate( vNormal, context.m_MeshTransform ).Normalized();
  158. RnPlane_t worldPlane;
  159. worldPlane.m_vNormal = vWorldNormal;
  160. worldPlane.m_flOffset = DotProduct( vWorldNormal, vWorldCenter );
  161. nTotalTests += bestPlanes.Count();
  162. for ( int i = 0; i < bestPlanes.Count(); ++i )
  163. {
  164. BestPlane_t &bp = bestPlanes[ i ];
  165. float flDist = worldPlane.Distance( bp.m_vPosition );
  166. if ( flDist < 0 )
  167. {
  168. nRejectedTests++;
  169. }
  170. else if ( flDist >= bp.m_flDistance )
  171. {
  172. bp.m_flDistance = flDist;
  173. bp.m_nDmeJointParent = nParentJoint;
  174. bp.m_WorldPlane = worldPlane;
  175. }
  176. }
  177. } );
  178. if ( nNonRigidPolygons )
  179. {
  180. Msg( "Plane collision for cloth %s: Ignoring %d polygons because they aren't rigidly bound to a bone", pMesh->GetName(), nNonRigidPolygons );
  181. }
  182. if ( nRejectedTests > nTotalTests / 2 )
  183. {
  184. Msg( "Plane collision for cloth %s: Rejected %d/%d plane-node combos; are the normals wrong on the collision?", pMesh->GetName(), nRejectedTests, nTotalTests );
  185. }
  186. CVarBitVec fitNodes( m_pAuthFx->m_Nodes.Count() );
  187. for ( int i = 0; i < m_pAuthFx->m_FitInfluences.Count(); ++i )
  188. {
  189. fitNodes.Set( m_pAuthFx->m_FitInfluences[ i ].nMatrixNode );
  190. }
  191. for ( int nNode = 0; nNode < m_pAuthFx->m_Nodes.Count(); ++nNode )
  192. {
  193. const BestPlane_t &bestPlane = bestPlanes[ nNode ];
  194. if ( m_pAuthFx->m_Nodes[ nNode ].m_bSimulated
  195. && bestPlane.m_nDmeJointParent >= 0
  196. && !fitNodes.IsBitSet( nNode )
  197. //&& bestPlane.m_flDistance > 0
  198. )
  199. {
  200. CAuthPhysFx::CCollisionPlane plane;
  201. plane.m_nChildBone = nNode;
  202. plane.m_nParentBone = modelContext.MapJointToFxBone( bestPlane.m_nDmeJointParent, false );
  203. plane.m_flStickiness = 0;
  204. const CTransform &tmParent = m_pAuthFx->m_Nodes[ plane.m_nParentBone ].m_Transform;
  205. plane.m_Plane.m_vNormal = VectorRotate( bestPlane.m_WorldPlane.m_vNormal, Conjugate( tmParent.m_orientation ) );
  206. plane.m_Plane.m_flOffset = bestPlane.m_WorldPlane.m_flOffset - DotProduct( tmParent.m_vPosition, bestPlane.m_WorldPlane.m_vNormal );
  207. m_pAuthFx->m_CollisionPlanes.AddToTail( plane );
  208. }
  209. }
  210. }
  211. void CClothProxyCompiler::MarkFreeRotatingNodes( const CAuthPhysFx::CQuad &quad )
  212. {
  213. // make sure the appropriate static nodes are marked as FreeRotating
  214. int nSimNodes = 0, nStaticNodes = 0;
  215. int nNodes = ( quad.m_nNodes[ 3 ] == quad.m_nNodes[ 2 ] ) ? 3 : 4;
  216. for ( int j = 0; j < nNodes; ++j )
  217. {
  218. if ( m_pAuthFx->m_Nodes[ quad.m_nNodes[ j ] ].m_bSimulated )
  219. {
  220. nSimNodes++;
  221. }
  222. else
  223. {
  224. nStaticNodes++;
  225. }
  226. }
  227. if ( nSimNodes >= 2 && nStaticNodes > 0 )
  228. {
  229. // we have a freely moving quad
  230. for ( int j = 0; j < nNodes; ++j )
  231. {
  232. CAuthPhysFx::CBone &node = m_pAuthFx->m_Nodes[ quad.m_nNodes[ j ] ];
  233. if ( !node.m_bSimulated )
  234. {
  235. node.m_bFreeRotation = true;
  236. node.m_bNeedNodeBase = true;
  237. }
  238. }
  239. }
  240. }
  241. void CClothProxyCompiler::AlignNodes()
  242. {
  243. // align nodes that need node base : they can be arbitrary orientation, and we can choose the orientation that makes it cheaper to compute them for animation
  244. CVarBitVec needBase( m_pAuthFx->m_Nodes.Count() );
  245. for ( int nNode = 0; nNode < m_pAuthFx->m_Nodes.Count(); ++nNode )
  246. {
  247. if ( m_pAuthFx->m_Nodes[ nNode ].m_bNeedNodeBase )
  248. {
  249. needBase.Set( nNode );
  250. }
  251. }
  252. m_pAuthFx->AlignNodes( needBase );
  253. }
  254. void CClothProxyCompiler::Cook( )
  255. {
  256. AlignNodes();
  257. }
  258. void CClothProxyCompiler::AppendDag( CModelContext &context, CDmeDag *pDag )
  259. {
  260. if( CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() ) )
  261. {
  262. matrix3x4_t tm;
  263. pDag->GetAbsTransform( tm );
  264. AppendMesh( context, pMesh, tm );
  265. }
  266. int nChildCount = pDag->GetChildCount();
  267. for ( int nChild = 0; nChild < nChildCount; ++nChild )
  268. {
  269. CDmeDag *pChild = pDag->GetChild( nChild );
  270. AppendDag( context, pChild );
  271. }
  272. }
  273. void Aggregate( Quaternion &q, const Quaternion &p )
  274. {
  275. if ( QuaternionDotProduct( p, q ) > 0 )
  276. {
  277. q = q + p;
  278. }
  279. else
  280. {
  281. q = q - p;
  282. }
  283. }
  284. // each vertex potentially has multiple normals and tangents associated with it. Average those out to make a reasonable orientations
  285. void ClothBoneOrientFromNormals( CClothProxyCompiler::CMeshContext &context )
  286. {
  287. // we only have normals
  288. for ( int nPosIndex = 0; nPosIndex < context.m_AttrPos.m_IndexData.Count(); ++nPosIndex )
  289. {
  290. int nDmePos = context.m_AttrPos.m_IndexData[ nPosIndex ];
  291. if ( CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nDmePos ) )
  292. {
  293. Aggregate( pFxBone->m_Transform.m_orientation, RotateBetween( Vector( 0, 0, 1 ), context.m_AttrNormal[ nPosIndex ] ) );
  294. }
  295. }
  296. }
  297. void ClothBoneOrientFromNormalsAndTangents( CClothProxyCompiler::CMeshContext &context )
  298. {
  299. // we only have normals
  300. for ( int nPosIndex = 0; nPosIndex < context.m_AttrPos.m_IndexData.Count(); ++nPosIndex )
  301. {
  302. int nDmePos = context.m_AttrPos.m_IndexData[ nPosIndex ];
  303. if ( CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nDmePos ) )
  304. {
  305. Vector vNormal = context.m_AttrNormal[ nPosIndex ];
  306. vNormal.NormalizeInPlace();
  307. Vector vTangent = context.m_AttrTangent[ nPosIndex ];
  308. vTangent = vTangent - DotProduct( vTangent, vNormal ) * vNormal;
  309. vTangent.NormalizeInPlace();
  310. Vector vCotangent = CrossProduct( vTangent, vNormal );
  311. matrix3x4_t tm;
  312. tm.InitXYZ( vCotangent, vTangent, vNormal, vec3_origin );
  313. Aggregate( pFxBone->m_Transform.m_orientation, MatrixQuaternion( tm ) );
  314. }
  315. }
  316. }
  317. void CClothProxyCompiler::OrientClothBones( CMeshContext &context )
  318. {
  319. if ( !context.m_AttrNormal )
  320. {
  321. // TODO: implement computing a nice orientation from positions only
  322. return;
  323. }
  324. if ( !context.m_AttrTangent )
  325. {
  326. ClothBoneOrientFromNormals( context );
  327. }
  328. else
  329. {
  330. ClothBoneOrientFromNormalsAndTangents( context );
  331. }
  332. for ( int nDmePos = 0; nDmePos < context.m_DmePosToFxBone.Count(); ++nDmePos )
  333. {
  334. int nFxBone = context.m_DmePosToFxBone[ nDmePos ];
  335. if ( nFxBone >= 0 )
  336. {
  337. Quaternion &q = m_pAuthFx->m_Nodes[ nFxBone ].m_Transform.m_orientation;
  338. q = GetNormalized( q );
  339. }
  340. }
  341. }
  342. int CClothProxyCompiler::GetOrCreateClothRootBone()
  343. {
  344. if ( m_nRootFxNode < 0 )
  345. {
  346. Assert( m_pAuthFx->FindNodeIndex( g_pDefaultClothRootBoneName ) < 0 );
  347. CAuthPhysFx::CBone root;
  348. root.m_Name = g_pDefaultClothRootBoneName;
  349. root.m_Transform = g_TransformIdentity;
  350. root.m_bSimulated = false;
  351. root.m_bFreeRotation = false;
  352. m_nRootFxNode = m_pAuthFx->m_Nodes.AddToTail( root );
  353. }
  354. return m_nRootFxNode;
  355. }
  356. CAuthPhysFx::CBone *CClothProxyCompiler::CMeshContext::GetClothBone( int nDmePos )
  357. {
  358. int nFxBone = m_DmePosToFxBone[ nDmePos ];
  359. return nFxBone < 0 ? NULL : &m_pAuthFx->m_Nodes[ nFxBone ];
  360. }
  361. CAuthPhysFx::CBone *CClothProxyCompiler::CMeshContext::GetOrCreateClothBone( int nDmePos, bool bSimulated )
  362. {
  363. return &m_pAuthFx->m_Nodes[ GetOrCreateClothBoneIndex( nDmePos, bSimulated ) ];
  364. }
  365. int CClothProxyCompiler::CMeshContext::GetClothBoneIndex( int nDmePos )
  366. {
  367. return m_DmePosToFxBone[ nDmePos ];
  368. }
  369. int CClothProxyCompiler::CMeshContext::GetOrCreateClothBoneIndex( int nDmePos, bool bSimulated )
  370. {
  371. int &refFxBone = m_DmePosToFxBone[ nDmePos ];
  372. if ( refFxBone < 0 )
  373. {
  374. CAuthPhysFx::CBone bone;
  375. bone.m_Name.Format( "$cloth_m%dp%d", m_nDmeMesh, nDmePos );
  376. bone.m_Transform.m_vPosition = VectorTransform( m_AttrPos.m_Data[ nDmePos ], m_MeshTransform );
  377. bone.m_Transform.m_orientation = quat_identity;
  378. bone.m_bSimulated = bSimulated; // by default, we don't want to make anything dynamic; only the nodes explicitly designated as dynamic should turn dynamic
  379. bone.m_bFreeRotation = bSimulated;
  380. bone.m_bVirtual = true; // all these nodes are virtual, they need a parent bone to drive them for animation attraction or rigid animation (or setting to animated pose) to work
  381. bone.m_bNeedNodeBase = bSimulated; // potentially, we need every simulated node to recompute the transform to drive vertex angents and normals. Unless we later find out this bone doesn't have any vertices bound, in which case we can reset it to false
  382. refFxBone = m_pAuthFx->m_Nodes.AddToTail( bone );
  383. }
  384. return refFxBone;
  385. }
  386. void CClothProxyCompiler::CreateClothBones( CMeshContext &context )
  387. {
  388. context.m_DmePosToFxBone.SetCount( context.m_AttrPos.m_Data.Count() );
  389. context.m_DmePosToFxBone.FillWithValue( -1 );
  390. CIndexedAttr< float > attrCloth( context.m_pBindState, CDmeVertexDataBase::FIELD_CLOTH_ENABLE );
  391. if ( attrCloth && attrCloth.GetElementCount() == context.m_AttrPos.GetElementCount() )
  392. {
  393. int nDataCount = context.m_AttrPos.GetDataCount();
  394. CVarBitVec dmePosEnable( nDataCount );
  395. for ( int nIndex = 0; nIndex < attrCloth.GetElementCount(); ++nIndex )
  396. {
  397. float flEnable = attrCloth[ nIndex ];
  398. int nDmePos = context.m_AttrPos.m_IndexData[ nIndex ];
  399. dmePosEnable.Set( nDmePos );
  400. if ( flEnable >= context.m_pModelContext->m_flClothEnableThreshold ) // only create dynamic nodes at this time, we may or may not need the static nodes
  401. {
  402. context.GetOrCreateClothBone( nDmePos, true );
  403. }
  404. }
  405. int nPosEnableCount = dmePosEnable.PopulationCount();
  406. if ( nPosEnableCount != nDataCount )
  407. {
  408. Warning( "Mesh %s has cloth_enable data on %d of %d vertices only. Delete history and reexport?\n", context.m_pDmeMesh->GetName(), nPosEnableCount, nDataCount );
  409. }
  410. }
  411. else
  412. {
  413. Warning( "Mesh %s has no cloth_enable attribute, pinning one vertex\n", context.m_pDmeMesh->GetName() );
  414. // in a proxy mesh, we use the whole thing. We might as well just go ahead and create the bones
  415. for ( int nPos = 0; nPos < context.m_AttrPos.m_Data.Count(); ++nPos )
  416. {
  417. // cloth_enable may or may not be present. If it's not present, we assume it's all enabled but a single vertex (so that it doesn't fall down immediately, but shows to the artist that s|he forgot to create cloth_enable map)
  418. context.GetOrCreateClothBone( nPos, true );
  419. }
  420. int nPin = 0;
  421. // find the top vertex and mark it as static
  422. for ( int nPos = 1; nPos < context.m_AttrPos.GetDataCount(); ++nPos )
  423. {
  424. if ( context.m_AttrPos.m_Data[ nPos ].z > context.m_AttrPos.m_Data[ nPin ].z )
  425. {
  426. nPin = nPos;
  427. }
  428. }
  429. context.GetOrCreateClothBone( nPin, false ); // pin one vertex for the artist to see a piece of cloth hanging to remind that cloth_enable needs to be done
  430. }
  431. }
  432. CClothProxyCompiler::CModelContext::CModelContext( CClothProxyCompiler *pCompiler, CDmeModel *pModel, float flClothEnableThreshold, const CVClothProxyMesh &proxy ) : m_Proxy( proxy ), m_pModel( pModel )
  433. {
  434. m_pAuthFx = pCompiler->GetFx();
  435. m_flClothEnableThreshold = flClothEnableThreshold;
  436. m_JointToBoneSubset.SetCount( pModel->GetJointCount() );
  437. int nModelJointCount = pModel->GetJointCount();
  438. m_JointToFxBone.SetCount( nModelJointCount );
  439. for ( int nJoint = 0; nJoint < nModelJointCount; ++nJoint )
  440. {
  441. const char *pJointName = pModel->GetJoint( nJoint )->GetName();
  442. m_JointToFxBone[ nJoint ] = m_pAuthFx->FindNodeIndex( pJointName );
  443. }
  444. for ( int nJoint = 0; nJoint < nModelJointCount; ++nJoint )
  445. {
  446. CDmeDag *pJoint = pModel->GetJoint( nJoint );
  447. UtlSymId_t &refSubset = m_JointToBoneSubset[ nJoint ];
  448. refSubset = pCompiler->m_BoneSubsets.Find( pJoint->GetName() );
  449. if ( refSubset == UTL_INVAL_SYMBOL )
  450. {
  451. refSubset = pCompiler->m_BoneSubsets.Insert( pJoint->GetName(), new CAuthFxBoneSubset( nJoint ) );
  452. }
  453. }
  454. }
  455. int CClothProxyCompiler::CModelContext::MapJointToFxBone( int nJoint, bool bSimulated )
  456. {
  457. if ( nJoint < 0 )
  458. return -1;
  459. int &refFxBoneIndex = m_JointToFxBone[ nJoint ];
  460. if ( refFxBoneIndex < 0 )
  461. {
  462. CDmeDag *pJoint = m_pModel->GetJoint( nJoint );
  463. //backSolvedJoints.Set( nJoint ); // we are back-solving this one, if only with one single dynamic simulated vertex so far
  464. const char *pJointName = pJoint->GetName();
  465. if ( IsDebug() && bSimulated && !V_stricmp( pJointName, "pelvis" ) )
  466. {
  467. ExecuteOnce( Warning( "Including pelvis into simulated cloth bones; this is probably wrong, as pelvis will tilt depending on cloth movement\n" ) );
  468. }
  469. refFxBoneIndex = m_pAuthFx->FindNodeIndex( pJointName );
  470. if ( refFxBoneIndex < 0 )
  471. {
  472. // make a driven node
  473. CAuthPhysFx::CBone fxBone;
  474. fxBone.m_Name = pJoint->GetName();
  475. fxBone.m_bSimulated = bSimulated;
  476. // dynamic nodes are naturally free rotating
  477. // static nodes are not, by default. Unless we want to back-solve something and make it into a static joint. That's not implemented yet, but may be in the future for some reason.
  478. // in that case, we need to make those static nodes free-rotating here
  479. fxBone.m_bFreeRotation = bSimulated;
  480. fxBone.m_bForceSimulated = bSimulated;
  481. matrix3x4a_t tm;
  482. pJoint->GetAbsTransform( tm );
  483. fxBone.m_Transform = MatrixTransform( tm );
  484. refFxBoneIndex = m_pAuthFx->m_Nodes.AddToTail( fxBone );
  485. }
  486. }
  487. return refFxBoneIndex;
  488. }
  489. int CClothProxyCompiler::CMeshContext::FindMostBoundJoint( int nDmePos, float flBonusForExisting )
  490. {
  491. int nBindCount = GetSkinningJointCount();
  492. if ( !nBindCount )
  493. return -1;
  494. // a static node. Find the joint that will drive it and add it as a static node
  495. const int *pIndices = m_pBindState->GetJointIndexData( nDmePos );
  496. const float *pWeight = m_pBindState->GetJointWeightData( nDmePos );
  497. int nBestIndex = -1;
  498. float flBestWeight = 0;
  499. for ( int i = 0; i < nBindCount; ++i )
  500. {
  501. float flWeight = pWeight[ i ];
  502. if ( m_pModelContext->m_JointToFxBone[ pIndices[ i ] ] >= 0 )
  503. {
  504. // the joint already exists, add the bonus points
  505. flWeight += flBonusForExisting;
  506. }
  507. if ( flWeight > flBestWeight )
  508. {
  509. nBestIndex = pIndices[ i ];
  510. flBestWeight = flWeight;
  511. }
  512. }
  513. return nBestIndex;
  514. }
  515. void CClothProxyCompiler::AddFitWeights( CMeshContext &context )
  516. {
  517. int nBindCount = context.GetSkinningJointCount();
  518. if ( !nBindCount )
  519. {
  520. // cannot backsolve joints if vertices aren't bound to them
  521. return;
  522. }
  523. float flWeightThreshold = context.m_pModelContext->m_Proxy.m_flBackSolveInfluenceThreshold;
  524. // first pass: just find the dynamic nodes that may contribute to back-solve
  525. // jointToFxBone will be non--1 only for those joints that have dynamic influences (and never locked)
  526. CVarBitVec lockedJoints( context.m_pModelContext->GetJointCount() );
  527. bool bBackSolveNonClothJoints = context.m_pModelContext->m_Proxy.m_bFlexClothBorders;
  528. if ( !bBackSolveNonClothJoints )
  529. {
  530. CIndexedAttr< float > attrCloth( context.m_pBindState, CDmeVertexDataBase::FIELD_CLOTH_ENABLE );
  531. // don't try to back-solve joints that have ANY static influences, so find those first
  532. if ( attrCloth )
  533. {
  534. for ( int nIndex = 0; nIndex < attrCloth.GetElementCount(); ++nIndex )
  535. {
  536. float flEnable = attrCloth[ nIndex ];
  537. if ( flEnable < context.m_pModelContext->m_flClothEnableThreshold ) // only create dynamic nodes at this time, we may or may not need the static nodes
  538. {
  539. int nDmePos = context.m_AttrPos.m_IndexData[ nIndex ];
  540. // static node, skip all attached joints
  541. // a static node. add to dynamic back-solve (no need to back-solve static-only nodes)
  542. const int *pIndices = context.m_pBindState->GetJointIndexData( nDmePos );
  543. const float *pWeight = context.m_pBindState->GetJointWeightData( nDmePos );
  544. for ( int nBinding = 0; nBinding < nBindCount; ++nBinding )
  545. {
  546. if ( pWeight[ nBinding ] >= flWeightThreshold )
  547. {
  548. lockedJoints.Set( pIndices[ nBinding ] );
  549. }
  550. }
  551. }
  552. }
  553. }
  554. }
  555. //CVarBitVec backSolvedJoints( nModelJointCount ); // those Dme Joints that will be back-solved (rotated and translated) by cloth movement
  556. for ( int nPos = 0; nPos < context.m_AttrPos.m_Data.Count(); ++nPos )
  557. {
  558. int nFxBone = context.m_DmePosToFxBone[ nPos ];
  559. if ( nFxBone < 0 )
  560. continue;
  561. CAuthPhysFx::CBone &bone = m_pAuthFx->m_Nodes[ nFxBone ]; // note: to find this as vertex in Maya, maya.xyz = valve.yzx; conversely, valve.xyz = maya.zxy
  562. if ( !bone.m_bSimulated )
  563. continue;
  564. // a simulated position. we may back-solve from it.
  565. const int *pIndices = context.m_pBindState->GetJointIndexData( nPos );
  566. const float *pWeight = context.m_pBindState->GetJointWeightData( nPos );
  567. for ( int nBinding = 0; nBinding < nBindCount; ++nBinding )
  568. {
  569. FeFitInfluence_t inf;
  570. inf.flWeight = pWeight[ nBinding ];
  571. inf.nVertexNode = nFxBone;
  572. if ( inf.flWeight >= flWeightThreshold )
  573. {
  574. // non-negligible influence, must add for back-solving
  575. int nJoint = pIndices[ nBinding ];
  576. if ( lockedJoints[ nJoint ] )
  577. continue; // just don't add any influences here, we aren't trying to affect this joint
  578. // we have a fxBone. add influence on it
  579. inf.nMatrixNode = context.m_pModelContext->MapJointToFxBone( nJoint, true );
  580. m_pAuthFx->m_FitInfluences.AddToTail( inf );
  581. }
  582. }
  583. }
  584. if ( bBackSolveNonClothJoints )
  585. {
  586. // add the static node influences for those joints that already have dynamic influences.
  587. // if a joint has no dynamic influences at all we should just ignore it
  588. CVarBitVec pinnedFxBones( Max( m_pAuthFx->GetBoneCount(), 1 ) );
  589. for ( int nPos = 0; nPos < context.m_AttrPos.m_Data.Count(); ++nPos )
  590. {
  591. CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nPos );
  592. if ( pFxBone && pFxBone->m_bSimulated )
  593. continue; // already went through dynamic nodes, skip all of them. We only need to look at the static nodes here
  594. // a static node. add to dynamic back-solve (no need to back-solve static-only nodes). We'll skip joints that don't get affected by any dynamic node
  595. const int *pIndices = context.m_pBindState->GetJointIndexData( nPos );
  596. const float *pWeight = context.m_pBindState->GetJointWeightData( nPos );
  597. for ( int nBinding = 0; nBinding < nBindCount; ++nBinding )
  598. {
  599. float flWeight = pWeight[ nBinding ];
  600. if ( flWeight < flWeightThreshold )
  601. continue;
  602. int nJoint = pIndices[ nBinding ];
  603. int nFxBoneIndex = context.m_pModelContext->m_JointToFxBone[ nJoint ];
  604. if ( nFxBoneIndex < 0 ) // is this Dme joint one of the Bones that have at least some dynamic cloth influence? if not, we don't want to build any influences on it
  605. continue;
  606. // ok , this STATIC vertex is bound to a bone that is also bound to some dynamic verts. It's useful to bind it to static verts, too, and let the solver decide how to fit the matrix to one set or the other
  607. FeFitInfluence_t inf;
  608. inf.flWeight = flWeight;
  609. int nVertexNode = context.GetOrCreateClothBoneIndex( nPos, false ); //
  610. // this is a static node vertex, otherwise we would skip it at the start
  611. AssertDbg( !m_pAuthFx->m_Nodes[ nVertexNode ].m_bSimulated );
  612. inf.nVertexNode = nVertexNode;
  613. inf.nMatrixNode = nFxBoneIndex;
  614. if ( 0 )
  615. {
  616. // we have a fxBone. add the static influence on it. One way to do it is to effectively pin it with this single vert: if a bone has ANY non-cloth-enabled verts, moving it will move those verts, which is not an expected result from an artist perspective
  617. // so we may pin it with itself - so that it rotates, but doesn't move from its animated position
  618. // .. don't add anything extra
  619. if ( !pinnedFxBones[ nFxBoneIndex ] )
  620. {
  621. pinnedFxBones.Set( nFxBoneIndex );
  622. CAuthPhysFx::CBone& fxBone = m_pAuthFx->m_Nodes[ nFxBoneIndex ];
  623. fxBone.m_bSimulated = false;
  624. fxBone.m_bForceSimulated = false;
  625. fxBone.m_bFreeRotation = true;
  626. inf.flWeight = 1.0f;
  627. inf.nVertexNode = nFxBoneIndex;
  628. m_pAuthFx->m_FitInfluences.AddToTail( inf );
  629. }
  630. }
  631. else
  632. {
  633. // an alternative is to just add all influences and let the FeModelBuilder deal with it
  634. m_pAuthFx->m_FitInfluences.AddToTail( inf ); // influence this semi-dynamic bone, because we don't want totally free movement of that joint
  635. }
  636. }
  637. }
  638. }
  639. // also, we have to take into account connected static nodes: if a bone moves a dynamic vertex, which is connected to a static vertex, that static vertex should be in the set to influence the bone
  640. // the FeModelBuilder may choose the 3 most appropriate static influences to compute center of mass and orientation
  641. }
  642. void CClothProxyCompiler::BindNodeOffsetParents( CMeshContext &context )
  643. {
  644. int nSkinningJointCount = context.GetSkinningJointCount() > 0;
  645. for ( int nDmePos = 0; nDmePos < context.m_AttrPos.m_Data.Count(); ++nDmePos )
  646. {
  647. CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nDmePos );
  648. if ( !pFxBone )
  649. continue;
  650. // to always have an option to turn on animation attraction for dynamic nodes, run this for dynamic nodes, too
  651. //if ( pFxBone->m_bSimulated )
  652. // continue;
  653. if ( pFxBone->m_nParent >= 0 )
  654. continue; // we already bound this node to a parent, makes no sense to override it now
  655. // bind this vertex node to a real bone
  656. if ( nSkinningJointCount )
  657. {
  658. int nParentJoint = context.FindMostBoundJoint( nDmePos, 0.05f );
  659. if ( nParentJoint < 0 )
  660. {
  661. Vector p = VectorTransform( context.m_AttrPos.m_Data[ nDmePos ], context.m_MeshTransform );
  662. Warning( "Cannot find most-bound-joint for position %d {%.2f,%.2f,%.2f} in mesh %s\n", nDmePos, p.x, p.y, p.z, context.m_pDmeMesh->GetName() );
  663. }
  664. else
  665. {
  666. pFxBone->m_nParent = context.m_pModelContext->MapJointToFxBone( nParentJoint, false );
  667. }
  668. }
  669. else
  670. {
  671. pFxBone->m_nParent = GetOrCreateClothRootBone();
  672. }
  673. }
  674. }
  675. int CClothProxyCompiler::CMeshContext::GetSkinningJointCount()
  676. {
  677. return this->m_pBindState->HasSkinningData() ? this->m_pBindState->JointCount() : 0;
  678. }
  679. void CClothProxyCompiler::CreateClothQuads( CMeshContext &context )
  680. {
  681. int nBindCount = context.GetSkinningJointCount();
  682. CClothProxyCompiler *pCompiler = this;
  683. int nSkippedQuads = 0;
  684. CVarBitVec dynamicDmePos( context.m_DmePosToFxBone.Count() );
  685. Assert( context.m_AttrPos.GetDataCount() == context.m_DmePosToFxBone.Count() );
  686. for ( int nDmePos = 0; nDmePos < context.m_DmePosToFxBone.Count(); ++nDmePos )
  687. {
  688. CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nDmePos );
  689. if ( pFxBone && pFxBone->m_bSimulated )
  690. {
  691. dynamicDmePos.Set( nDmePos );
  692. }
  693. }
  694. EnumerateFaces( context.m_pDmeMesh, context.m_pBindState, &dynamicDmePos,
  695. [ pCompiler, &context, nBindCount, &nSkippedQuads ]( int nPos[], int nCount )
  696. {
  697. Assert( nCount >= 3 && nCount <= 4 );
  698. CAuthPhysFx::CQuad quad;
  699. Vector v[ 4 ];
  700. int nDynamic = 0;
  701. for ( int j = 0; j < nCount; ++j )
  702. {
  703. int nPosVert = nPos[ j ];
  704. int nFxBone = context.GetOrCreateClothBoneIndex( nPosVert, false );
  705. if ( context.m_pAuthFx->m_Nodes[ nFxBone ].m_bSimulated )
  706. ++nDynamic;
  707. quad.m_nNodes[ j ] = nFxBone;
  708. v[ j ] = context.m_pAuthFx->GetBone( nFxBone )->m_Transform.m_vPosition;
  709. }
  710. Assert( nDynamic > 0 ); NOTE_UNUSED( nDynamic );
  711. for ( int j = nCount; j < 4; ++j )
  712. {
  713. quad.m_nNodes[ j ] = quad.m_nNodes[ nCount - 1 ];
  714. v[ j ] = v[ nCount - 1 ];
  715. }
  716. Vector vNormal = CrossProduct( v[ 2 ] - v[ 0 ], v[ 3 ] - v[ 1 ] );
  717. if ( vNormal.LengthSqr() < 1e-10f )
  718. {
  719. nSkippedQuads++; // this quad is too small, let the artist fix the content
  720. }
  721. else
  722. {
  723. int nQuad = context.m_pAuthFx->m_Quads.AddToTail( quad );
  724. CUtlSortVector< int > arrBones;
  725. for ( int j = 0; j < nCount; ++j )
  726. {
  727. if ( nBindCount > 0 )
  728. {
  729. const int *pIndices = context.m_pBindState->GetJointIndexData( nPos[j] );
  730. const float *pWeight = context.m_pBindState->GetJointWeightData( nPos[j] );
  731. // this vertex is bound to some bones, attach the quad there
  732. for ( int nBinding = 0; nBinding < nBindCount; ++nBinding )
  733. {
  734. if ( pWeight[ nBinding ] > FLT_EPSILON )
  735. {
  736. int nIndex = pIndices[ nBinding ];
  737. Assert( nIndex >= 0 && nIndex < context.m_pModelContext->m_JointToBoneSubset.Count() );
  738. arrBones.InsertIfNotFound( nIndex );
  739. }
  740. }
  741. }
  742. }
  743. if ( arrBones.IsEmpty() )
  744. {
  745. // this isn't bound to bones. Attach to the default list
  746. pCompiler->m_DefaultSubset.m_Quads.AddToTail( ProjItem_t( nQuad, context.m_pModelContext->m_Proxy.m_flEnvelope ) );
  747. }
  748. else
  749. {
  750. for ( int nIndex : arrBones )
  751. {
  752. UtlSymId_t nSymBone = context.m_pModelContext->m_JointToBoneSubset[ nIndex ];
  753. CAuthFxBoneSubset *pSubset = pCompiler->m_BoneSubsets[ nSymBone ];
  754. pSubset->m_Quads.AddToTail( ProjItem_t( nQuad, context.m_pModelContext->m_Proxy.m_flEnvelope ) );
  755. }
  756. }
  757. }
  758. } );
  759. if ( nSkippedQuads )
  760. {
  761. Warning( "Skipping %d degenerate quads, %s\n", nSkippedQuads, context.m_pDmeMesh->GetName() );
  762. }
  763. }
  764. void CClothProxyCompiler::ApplyClothBoneAttributes( CMeshContext &context )
  765. {
  766. CDmeVertexData *pBindState = context.m_pBindState;
  767. ClothAttributes < CIndexedAttr < float > > attr( [ pBindState ]( const char *pAttrName ) { return CIndexedAttr< float >( pBindState, pAttrName ); } );
  768. Assert( context.m_AttrPos.GetDataCount() == pBindState->GetPositionData().Count() );
  769. CVarBitVec walkedPos( context.m_AttrPos.GetDataCount() );
  770. for ( int nIndex = 0; nIndex < context.m_AttrPos.GetElementCount(); ++nIndex )
  771. {
  772. int nDmePos = context.m_AttrPos.m_IndexData[ nIndex ];
  773. CAuthPhysFx::CBone *pFxBone = context.GetClothBone( nDmePos );
  774. if ( pFxBone && !walkedPos[ nDmePos ] )
  775. {
  776. attr.Apply( nIndex, *pFxBone );
  777. walkedPos.Set( nDmePos );
  778. }
  779. }
  780. }
  781. CClothProxyCompiler::CMeshContext::CMeshContext( CClothProxyCompiler *pCompiler, CModelContext *pModelContext, CDmeMesh *pMesh, const matrix3x4_t &tm, int nDmeMesh )
  782. {
  783. m_pModelContext = pModelContext;
  784. m_nDmeMesh = nDmeMesh;
  785. m_pDmeMesh = pMesh;
  786. m_MeshTransform = tm;
  787. m_pCompiler = pCompiler;
  788. m_pAuthFx = pCompiler ? pCompiler->m_pAuthFx : NULL;
  789. m_pBindState = pMesh->GetBindBaseState();
  790. m_pBindState->Resolve(); // not sure what this does, but Get...Data functions seem to do this
  791. m_AttrPos.Init( m_pBindState, CDmeVertexData::FIELD_POSITION );
  792. m_AttrNormal.Init( m_pBindState, CDmeVertexData::FIELD_NORMAL );
  793. if ( m_AttrNormal && m_AttrNormal.GetElementCount() != m_AttrPos.GetElementCount() )
  794. {
  795. Warning( "Mesh %s unexpected normal element count %d, expected %d\n", pMesh->GetName(), m_AttrNormal.GetElementCount(), m_AttrPos.GetElementCount() );
  796. m_AttrNormal.Reset();
  797. }
  798. else
  799. {
  800. m_AttrTangent.Init( m_pBindState, CDmeVertexData::FIELD_TANGENT );
  801. if ( m_AttrTangent && m_AttrTangent.GetElementCount() != m_AttrPos.GetElementCount() )
  802. {
  803. Warning( "Mesh %s unexpected tangent element count %d, expected %d\n", pMesh->GetName(), m_AttrTangent.GetElementCount(), m_AttrPos.GetElementCount() );
  804. m_AttrTangent.Reset();
  805. }
  806. }
  807. }
  808. void CClothProxyCompiler::AppendMesh( CModelContext &modelContext, CDmeMesh *pMesh, const matrix3x4_t &tm )
  809. {
  810. CMeshContext context( this, &modelContext, pMesh, tm, m_nProxyMeshes++ );
  811. if ( !context.m_AttrPos )
  812. {
  813. Warning( "No position data found in mesh %s\n", pMesh->GetName() );
  814. return; // something's wrong if we have no positions
  815. }
  816. m_MeshNames.AddToTail( pMesh->GetName() );
  817. CreateClothBones( context );
  818. if ( modelContext.m_Proxy.m_bBackSolveJoints || m_Options.m_bDriveMeshesWithBacksolvedJointsOnly )
  819. {
  820. // back-solve joints from the created simulated bones
  821. AddFitWeights( context );
  822. }
  823. // this may create the last static nodes for those quads that connect static nodes to dynamic nodes
  824. CreateClothQuads( context );
  825. // apply attributes and orientations must be last, after all the Fx nodes have been created as necessary
  826. // they only make sense for skinned cloth, though
  827. BindNodeOffsetParents( context );
  828. // OrientClothBones( context ); <-- cloth bones that can be oriented, will be oriented according to easy computation with FeNodeBase
  829. ApplyClothBoneAttributes( context );
  830. }
  831. /*
  832. void CClothProxyCompiler::Bake( CAuthPhysFx *pFx )
  833. {
  834. // go through collected bones, find the used ones and add them and their corresponding polygons to AuthFx
  835. }
  836. void CClothProxyCompiler::CAuthFxSubset::Append( const CAuthFxSubset &other )
  837. {
  838. }
  839. */
  840. int CClothProxyCompiler::GetAuthFxBone( const char *pName )
  841. {
  842. return m_pAuthFx->FindNodeIndex( pName ); // TODO: maybe replace this with a faster lookup
  843. }
  844. bool CClothProxyCompiler::Project( const Vector &vPos, UtlSymId_t *pFindSubset, int nFindSubsetCount, CUtlVector<Binding_t> &outBindings, int nIslandFilter )
  845. {
  846. CUtlSortVector< QuadProjection_t > bestProj;
  847. CVarBitVec visitedQuads( m_pAuthFx->GetQuadCount() );
  848. for ( int nSubsetIndex = 0; nSubsetIndex < nFindSubsetCount; ++nSubsetIndex )
  849. {
  850. UtlSymId_t nFxBone = pFindSubset[ nSubsetIndex ];
  851. CAuthFxBoneSubset *pSubset = m_BoneSubsets[ nFxBone ];
  852. for ( int nPrIt = 0; nPrIt < pSubset->m_Quads.Count(); ++nPrIt )
  853. {
  854. ProjItem_t q = pSubset->m_Quads[ nPrIt ];
  855. if ( visitedQuads.IsBitSet( q.nIndex ) )
  856. continue;
  857. visitedQuads.Set( q.nIndex );
  858. ProjectAndAddToQueue( q, vPos, bestProj, nIslandFilter );
  859. }
  860. }
  861. for ( int nPrIt = 0; nPrIt < m_DefaultSubset.m_Quads.Count(); ++nPrIt )
  862. {
  863. ProjItem_t q = m_DefaultSubset.m_Quads[ nPrIt ];
  864. if ( visitedQuads.IsBitSet( q.nIndex ) )
  865. continue;
  866. visitedQuads.Set( q.nIndex );
  867. ProjectAndAddToQueue( q, vPos, bestProj, nIslandFilter );
  868. }
  869. if ( bestProj.Count() >= 2 && bestProj[ 0 ].m_flDistance < 0 && bestProj[ 1 ].m_flDistance < 0 && DotProduct( bestProj[ 0 ].m_vNormal, bestProj[ 1 ].m_vNormal ) < 0 )
  870. {
  871. // we're smack inside some volume
  872. bestProj.SetCountNonDestructively( 2 );
  873. }
  874. else if ( bestProj.Count() > 1 )
  875. {
  876. bestProj.SetCountNonDestructively( 1 );
  877. }
  878. int nAddedBindings = 0;
  879. for ( int i = 0; i < bestProj.Count(); ++i )
  880. {
  881. for ( int j = 0; j < bestProj[ i ].m_nBindings; ++j )
  882. {
  883. outBindings.AddToTail( bestProj[ i ].m_Binding[ j ] );
  884. ++nAddedBindings;
  885. }
  886. }
  887. return nAddedBindings > 0;
  888. }
  889. CClothProxyCompiler::QuadProjection_t CClothProxyCompiler::ProjectOnQuad( const Vector &vPos, const CAuthPhysFx::CQuad &quad )
  890. {
  891. if ( quad.m_nNodes[ 3 ] == quad.m_nNodes[ 2 ] )
  892. return ProjectOnTri( vPos, quad );
  893. QuadProjection_t out;
  894. Vector v[ 4 ], e[4];
  895. for ( int i = 0; i < 4; ++i )
  896. {
  897. v[ i ] = m_pAuthFx->GetBone( quad.m_nNodes[ i ] )->m_Transform.m_vPosition;
  898. }
  899. float flEdgeLen[ 4 ];
  900. for ( int i = 0; i < 4; ++i )
  901. {
  902. e[ i ] = v[ ( i + 1 ) % 4 ] - v[ i ];
  903. flEdgeLen[ i ] = e[ i ].Length();
  904. e[ i ] /= flEdgeLen[ i ];
  905. }
  906. Vector vNormal = CrossProduct( v[ 2 ] - v[ 0 ], v[ 3 ] - v[ 1 ] ).Normalized();
  907. float flSide[ 4 ];
  908. for ( int i = 0; i < 4; ++i )
  909. {
  910. flSide[ i ] = DotProduct( vPos - v[ i ], CrossProduct( vNormal, e[i] ).Normalized() );
  911. }
  912. Assert( !( flSide[ 0 ] < 0 && flSide[ 1 ] < 0 && flSide[ 2 ] < 0 && flSide[ 3 ] < 0 ) );
  913. if ( ( flSide[ 0 ] > 0 && flSide[ 1 ] > 0 && flSide[ 2 ] > 0 && flSide[ 3 ] > 0 ) )
  914. {
  915. // we project onto the interior of the quad, more or less. Form the approximate weights, find approximate distance
  916. float flEven = flSide[ 0 ] / ( flSide[ 0 ] + flSide[ 2 ] ), flOdd = flSide[ 1 ] / ( flSide[ 1 ] + flSide[ 3 ] );
  917. out.m_nBindings = 4;
  918. out.m_Binding[ 0 ].nAuthFxBone = quad.m_nNodes[ 0 ];
  919. out.m_Binding[ 0 ].flWeight = flOdd * ( 1 - flEven );
  920. out.m_Binding[ 1 ].nAuthFxBone = quad.m_nNodes[ 1 ];
  921. out.m_Binding[ 1 ].flWeight = ( 1 - flOdd ) * ( 1 - flEven );
  922. out.m_Binding[ 2 ].nAuthFxBone = quad.m_nNodes[ 2 ];
  923. out.m_Binding[ 2 ].flWeight = ( 1 - flOdd ) * flEven;
  924. out.m_Binding[ 3 ].nAuthFxBone = quad.m_nNodes[ 3 ];
  925. out.m_Binding[ 3 ].flWeight = flOdd * flEven;
  926. out.m_vNormal = vNormal;
  927. out.m_vContact = v[ 0 ] * out.m_Binding[ 0 ].flWeight + v[ 1 ] * out.m_Binding[ 1 ].flWeight + v[ 2 ] * out.m_Binding[ 2 ].flWeight + v[ 3 ] * out.m_Binding[ 3 ].flWeight;//vPos - vNormal * out.m_flDistance;
  928. out.m_flDistance = ( vPos - out.m_vContact ).Length();
  929. return out;
  930. }
  931. // project onto each edge interior. The closest one wins
  932. out.m_nBindings = 0;
  933. out.m_flDistance = FLT_MAX;
  934. for ( int i = 0; i < 4; ++i )
  935. {
  936. float flEdgeProj = DotProduct( vPos - v[ i ], e[ i ] );
  937. flEdgeProj = Clamp( flEdgeProj, 0.0f, flEdgeLen[ i ] );
  938. Vector vContact = v[ i ] + flEdgeProj * e[ i ];
  939. Vector vContactToPos = vPos - vContact;
  940. float flDistance = vContactToPos.Length();
  941. if ( !out.m_nBindings || flDistance < out.m_flDistance )
  942. {
  943. float w = flEdgeProj / flEdgeLen[ i ];
  944. out.m_flDistance = flDistance;
  945. out.m_vContact = vContact;
  946. out.m_vNormal = flDistance > FLT_EPSILON ? vContactToPos / flDistance : m_pAuthFx->GetBone(quad.m_nNodes[ i ] )->m_Transform.m_orientation.GetUp();
  947. out.m_nBindings = 0;
  948. if ( w < 0.999f )
  949. {
  950. out.AddBinding( quad.m_nNodes[ i ], 1.0f - w );
  951. }
  952. if ( w > 0.001f )
  953. {
  954. out.AddBinding( quad.m_nNodes[ ( i + 1 ) % 4 ], w );
  955. }
  956. }
  957. }
  958. return out;
  959. }
  960. CClothProxyCompiler::QuadProjection_t CClothProxyCompiler::ProjectOnTri( const Vector &vPos, const CAuthPhysFx::CQuad &quad )
  961. {
  962. Assert( quad.m_nNodes[ 3 ] == quad.m_nNodes[ 2 ] );
  963. QuadProjection_t out;
  964. Vector v[ 3 ], e[ 3 ];
  965. for ( int i = 0; i < 3; ++i )
  966. {
  967. v[ i ] = m_pAuthFx->GetBone( quad.m_nNodes[ i ] )->m_Transform.m_vPosition;
  968. }
  969. float flEdgeLen[ 3 ];
  970. for ( int i = 0; i < 3; ++i )
  971. {
  972. e[ i ] = v[ ( i + 1 ) % 3 ] - v[ i ];
  973. flEdgeLen[ i ] = e[ i ].Length();
  974. e[ i ] /= flEdgeLen[ i ];
  975. }
  976. Vector vNormal = CrossProduct( v[ 1 ] - v[ 0 ], v[ 2 ] - v[ 0 ] ).Normalized();
  977. float flSide[ 3 ], flOpposing[ 3 ];
  978. for ( int i = 0; i < 3; ++i )
  979. {
  980. Vector vInSide = CrossProduct( vNormal, e[ i ] ).Normalized();
  981. flSide[ i ] = DotProduct( vPos - v[ i ], vInSide );
  982. flOpposing[ i ] = DotProduct( v[ ( i + 2 ) % 3 ] - v[ i ], vInSide );
  983. }
  984. Assert( !( flSide[ 0 ] < 0 && flSide[ 1 ] < 0 && flSide[ 2 ] < 0 ) );
  985. if ( ( flSide[ 0 ] > 0 && flSide[ 1 ] > 0 && flSide[ 2 ] > 0 ) )
  986. {
  987. // we project onto the interior of the quad, more or less. Form the approximate weights, find approximate distance
  988. out.m_nBindings = 3;
  989. out.m_Binding[ 0 ].nAuthFxBone = quad.m_nNodes[ 0 ];
  990. out.m_Binding[ 0 ].flWeight = Clamp( flSide[ 1 ] / flOpposing[ 1 ], 0.0f, 1.0f );
  991. out.m_Binding[ 1 ].nAuthFxBone = quad.m_nNodes[ 1 ];
  992. out.m_Binding[ 1 ].flWeight = Clamp( flSide[ 2 ] / flOpposing[ 2 ], 0.0f, 1.0f );
  993. out.m_Binding[ 2 ].nAuthFxBone = quad.m_nNodes[ 2 ];
  994. out.m_Binding[ 2 ].flWeight = Clamp( flSide[ 0 ] / flOpposing[ 0 ], 0.0f, 1.0f );
  995. out.m_vNormal = vNormal;
  996. out.m_vContact = v[ 0 ] * out.m_Binding[ 0 ].flWeight + v[ 1 ] * out.m_Binding[ 1 ].flWeight + v[ 2 ] * out.m_Binding[ 2 ].flWeight;
  997. out.m_flDistance = ( vPos - out.m_vContact ).Length();
  998. return out;
  999. }
  1000. // project onto each edge interior. The closest one wins
  1001. out.m_nBindings = 0;
  1002. out.m_flDistance = FLT_MAX;
  1003. for ( int i = 0; i < 3; ++i )
  1004. {
  1005. float flEdgeProj = DotProduct( vPos - v[ i ], e[ i ] );
  1006. flEdgeProj = Clamp( flEdgeProj, 0.0f, flEdgeLen[ i ] );
  1007. Vector vContact = v[ i ] + flEdgeProj * e[ i ];
  1008. Vector vContactToPos = vPos - vContact;
  1009. float flDistance = vContactToPos.Length();
  1010. if ( flDistance < out.m_flDistance )
  1011. {
  1012. float w = flEdgeProj / flEdgeLen[ i ];
  1013. out.m_flDistance = flDistance;
  1014. out.m_vContact = vContact;
  1015. out.m_vNormal = flDistance > FLT_EPSILON ? vContactToPos / flDistance : vNormal;
  1016. out.m_nBindings = 0;
  1017. if ( w < 0.999f )
  1018. {
  1019. out.AddBinding( quad.m_nNodes[ i ], 1.0f - w );
  1020. }
  1021. if ( w > 0.001f )
  1022. {
  1023. out.AddBinding( quad.m_nNodes[ ( i + 1 ) % 3 ], w );
  1024. }
  1025. }
  1026. }
  1027. return out;
  1028. }
  1029. void CClothProxyCompiler::ProjectAndAddToQueue( const ProjItem_t &q, const Vector & vPos, CUtlSortVector< QuadProjection_t > &bestProj, int nIslandFilter )
  1030. {
  1031. CAuthPhysFx::CQuad &quad = m_pAuthFx->m_Quads[ q.nIndex ];
  1032. if ( nIslandFilter >= 0 && NodeToIsland( quad.m_nNodes[ 0 ] ) != nIslandFilter )
  1033. return;
  1034. // project onto this quad, find the best projection
  1035. QuadProjection_t proj = ProjectOnQuad( vPos, quad );
  1036. if ( !proj.IsEmpty() && proj.m_flDistance <= q.flEnvelope )
  1037. {
  1038. bestProj.Insert( proj );
  1039. if ( bestProj.Count() > 2 )
  1040. {
  1041. bestProj.SetCountNonDestructively( 2 ); // we only need to keep 2 entries
  1042. }
  1043. }
  1044. }
  1045. int CClothProxyCompiler::NodeToIsland( int nNode )
  1046. {
  1047. AssertDbg( nNode >= 0 && nNode < m_pAuthFx->GetBoneCount() );
  1048. if ( m_Options.m_flMatchProxiesToMeshes <= 0 )
  1049. {
  1050. if ( m_NodeToIslandMap.Count() != m_pAuthFx->GetBoneCount() )
  1051. {
  1052. m_nIslandCount = m_pAuthFx->BuildIslandMap( m_NodeToIslandMap );
  1053. }
  1054. return m_NodeToIslandMap[ nNode ];
  1055. }
  1056. else
  1057. {
  1058. return 0;
  1059. }
  1060. }
  1061. CLockedResource< PhysFeModelDesc_t > CClothProxyCompiler::Compile( CResourceStream *pStream )const
  1062. {
  1063. return m_pAuthFx->Compile( pStream, &m_Options );
  1064. }