Fixed server side setupbones

This commit is contained in:
Kamay Xutax 2024-08-22 23:55:21 +02:00
parent 259c05ac75
commit 1da7d763fe
9 changed files with 63 additions and 272 deletions

View file

@ -1972,8 +1972,10 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat
// debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 ); // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 );
// TODO_ENHANCED: Do that only for client side animations // TODO_ENHANCED: Do that only for client side animations
// if (m_bClientSideAnimation) if (m_bClientSideAnimation)
{
MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q ); MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q );
}
AccumulateLayers( boneSetup, pos, q, currentTime ); AccumulateLayers( boneSetup, pos, q, currentTime );
@ -2743,82 +2745,6 @@ void C_BaseAnimating::ThreadedBoneSetup()
g_PreviousBoneSetups.RemoveAll(); g_PreviousBoneSetups.RemoveAll();
} }
void C_BaseAnimating::BuildMatricesWithBoneMerge(
const CStudioHdr *pStudioHdr,
const QAngle& angles,
const Vector& origin,
const Vector pos[MAXSTUDIOBONES],
const Quaternion q[MAXSTUDIOBONES],
matrix3x4_t bonetoworld[MAXSTUDIOBONES],
C_BaseAnimating *pParent,
CBoneCache *pParentCache
)
{
CStudioHdr *fhdr = pParent->GetModelPtr();
mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
matrix3x4_t rotationmatrix; // model to world transformation
AngleMatrix( angles, origin, rotationmatrix);
for ( int i=0; i < pStudioHdr->numbones(); i++ )
{
// Now find the bone in the parent entity.
bool merged = false;
int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() );
if ( parentBoneIndex >= 0 )
{
matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex );
if ( pMat )
{
MatrixCopy( *pMat, bonetoworld[ i ] );
merged = true;
}
}
if ( !merged )
{
// If we get down here, then the bone wasn't merged.
matrix3x4_t bonematrix;
QuaternionMatrix( q[i], pos[i], bonematrix );
if (pbones[i].parent == -1)
{
ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
}
else
{
ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
}
}
}
}
void C_BaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime )
{
if(!pStudioHdr)
{
Assert(!"C_BaseAnimating::GetSkeleton() without a model");
return;
}
IBoneSetup boneSetup( pStudioHdr, boneMask, m_flPoseParameter );
boneSetup.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk );
if ( m_pIk )
{
CIKContext auto_ik;
auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), currentTime, 0, boneMask );
boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik );
}
else
{
boneSetup.CalcAutoplaySequences( pos, q, currentTime, NULL );
}
boneSetup.CalcBoneAdj( pos, q, m_flEncodedController );
}
bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{ {
VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );
@ -2972,8 +2898,10 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i
// NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated
if ( !IsModelScaled() ) if ( !IsModelScaled() )
{ {
// only allocate an ik block if the npc can use it // only allocate an ik block if the npc can use it
if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) ) // The flag is now completely ignored to match server bones!
// If it doesn't work well, blame models.
if ( !m_pIk && hdr->numikchains() > 0 /* && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) */ )
{ {
m_pIk = new CIKContext; m_pIk = new CIKContext;
} }

View file

@ -99,8 +99,8 @@ public:
enum enum
{ {
NUM_POSEPAREMETERS = 24, NUM_POSEPAREMETERS = MAXSTUDIOPOSEPARAM,
NUM_BONECTRLS = 4 NUM_BONECTRLS = MAXSTUDIOBONECTRLS
}; };
C_BaseAnimating(); C_BaseAnimating();
@ -144,11 +144,6 @@ public:
virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax );
// model specific // model specific
void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles,
const Vector& origin, const Vector pos[MAXSTUDIOBONES],
const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES],
CBaseAnimating *pParent, CBoneCache *pParentCache );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime );
virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
virtual void UpdateIKLocks( float currentTime ); virtual void UpdateIKLocks( float currentTime );
virtual void CalculateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime );

View file

@ -369,67 +369,4 @@ CStudioHdr *C_BaseAnimatingOverlay::OnNewModel()
} }
return hdr; return hdr;
}
void C_BaseAnimatingOverlay::GetSkeleton( CStudioHdr* pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime )
{
if(!pStudioHdr)
{
Assert(!"C_BaseAnimating::GetSkeleton() without a model");
return;
}
if (!pStudioHdr->SequencesAvailable())
{
return;
}
float poseparameters[MAXSTUDIOPOSEPARAM];
GetPoseParameters(pStudioHdr, poseparameters);
IBoneSetup boneSetup( pStudioHdr, boneMask, poseparameters );
boneSetup.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk );
// sort the layers
int layer[MAX_OVERLAYS] = {};
int i;
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
layer[i] = MAX_OVERLAYS;
}
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
CAnimationLayer &pLayer = m_AnimOverlay[i];
if( (pLayer.m_flWeight > 0) && pLayer.IsActive() && pLayer.m_nOrder >= 0 && pLayer.m_nOrder < m_AnimOverlay.Count())
{
layer[pLayer.m_nOrder] = i;
}
}
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
if (layer[i] >= 0 && layer[i] < m_AnimOverlay.Count())
{
CAnimationLayer &pLayer = m_AnimOverlay[layer[i]];
// UNDONE: Is it correct to use overlay weight for IK too?
boneSetup.AccumulatePose( pos, q, pLayer.m_nSequence, pLayer.m_flCycle, pLayer.m_flWeight, currentTime, m_pIk );
}
}
if ( m_pIk )
{
CIKContext auto_ik;
auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), currentTime, 0, boneMask );
boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik );
}
else
{
boneSetup.CalcAutoplaySequences(pos, q, currentTime, NULL);
}
float controllers[MAXSTUDIOBONECTRLS];
GetBoneControllers(controllers);
boneSetup.CalcBoneAdj( pos, q, controllers );
} }

View file

@ -38,7 +38,6 @@ public:
// model specific // model specific
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); virtual void DoAnimationEvents( CStudioHdr *pStudioHdr );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime );
enum enum
{ {

View file

@ -4293,12 +4293,13 @@ void C_BaseEntity::CalcAbsolutePosition( )
NormalizeAngles( m_angAbsRotation ); NormalizeAngles( m_angAbsRotation );
return; return;
} }
if ( IsEffectActive(EF_BONEMERGE) ) // TODO_ENHANCED: this should be safe to remove.
{ // if ( IsEffectActive(EF_BONEMERGE) )
MoveToAimEnt(); // {
return; // MoveToAimEnt();
} // return;
// }
// Construct the entity-to-world matrix // Construct the entity-to-world matrix
// Start with making an entity-to-parent matrix // Start with making an entity-to-parent matrix

View file

@ -202,9 +202,10 @@ C_CHostage::C_CHostage()
m_flDeadOrRescuedTime = 0.0; m_flDeadOrRescuedTime = 0.0;
m_flLastBodyYaw = 0; m_flLastBodyYaw = 0;
m_createdLowViolenceRagdoll = false; m_createdLowViolenceRagdoll = false;
// TODO: Get IK working on the steep slopes CS has, then enable it on characters. // TODO: Get IK working on the steep slopes CS has, then enable it on characters.
m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK; // Breaks server side setup bones !
// m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
// set the model so the PlayerAnimState uses the Hostage activities/sequences // set the model so the PlayerAnimState uses the Hostage activities/sequences
SetModelName( "models/Characters/Hostage_01.mdl" ); SetModelName( "models/Characters/Hostage_01.mdl" );

View file

@ -2601,100 +2601,9 @@ float C_CSPlayer::GetDeathCamInterpolationTime()
} }
ConVar cl_server_setup_bones("cl_server_setup_bones", "1");
bool C_CSPlayer::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) bool C_CSPlayer::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{ {
if (cl_server_setup_bones.GetBool()) return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
{
AUTO_LOCK( m_BoneSetupLock );
MDLCACHE_CRITICAL_SECTION();
Assert( GetModelPtr() );
CStudioHdr *pStudioHdr = GetModelPtr( );
if(!pStudioHdr)
{
Assert(!"C_BaseAnimating::GetSkeleton() without a model");
return false;
}
Assert( !IsEFlagSet( EFL_SETTING_UP_BONES ) );
AddEFlags( EFL_SETTING_UP_BONES );
Vector pos[MAXSTUDIOBONES];
Quaternion q[MAXSTUDIOBONES];
// adjust hit boxes based on IK driven offset
Vector adjOrigin = GetRenderOrigin();
if ( m_pIk )
{
// FIXME: pass this into Studio_BuildMatrices to skip transforms
CBoneBitList boneComputed;
m_iIKCounter++;
m_pIk->Init( pStudioHdr, GetRenderAngles(), adjOrigin, currentTime, m_iIKCounter, boneMask );
GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime );
m_pIk->UpdateTargets( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
CalculateIKLocks( currentTime );
m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
}
else
{
// Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime );
}
CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() );
if ( pParent )
{
// We're doing bone merging, so do special stuff here.
CBoneCache *pParentCache = pParent->GetBoneCache(pParent->GetModelPtr());
if ( pParentCache )
{
BuildMatricesWithBoneMerge(
pStudioHdr,
GetRenderAngles(),
adjOrigin,
pos,
q,
m_BoneAccessor.GetBoneArrayForWrite(),
pParent,
pParentCache );
RemoveEFlags( EFL_SETTING_UP_BONES );
return true;
}
}
Studio_BuildMatrices(
pStudioHdr,
GetRenderAngles(),
adjOrigin,
pos,
q,
-1,
GetModelScale(), // Scaling
m_BoneAccessor.GetBoneArrayForWrite(),
boneMask );
RemoveEFlags(EFL_SETTING_UP_BONES);
if ( pBoneToWorldOut )
{
memcpy( pBoneToWorldOut, m_BoneAccessor.GetBoneArrayForWrite(), sizeof( matrix3x4_t ) * MAXSTUDIOBONES );
}
return true;
}
else
{
return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
}
} }
//============================================================================= //=============================================================================

View file

@ -1800,31 +1800,46 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
// adjust hit boxes based on IK driven offset // adjust hit boxes based on IK driven offset
Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset ); Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset );
if ( CanSkipAnimation() ) // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated
if ( !IsModelScaled() )
{ {
IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() ); // only allocate an ik block if the npc can use it
boneSetup.InitPose( pos, q ); if ( !m_pIk && pStudioHdr->numikchains() > 0 )
// Msg( "%.03f : %s:%s not in pvs\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); {
m_pIk = new CIKContext;
}
} }
else else
{ {
// Reset the IK
if ( m_pIk ) if ( m_pIk )
{ {
// FIXME: pass this into Studio_BuildMatrices to skip transforms delete m_pIk;
CBoneBitList boneComputed; m_pIk = NULL;
m_iIKCounter++; }
m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); }
GetSkeleton( pStudioHdr, pos, q, boneMask );
m_pIk->UpdateTargets( pos, q, pBoneToWorld, boneComputed ); if ( m_pIk )
CalculateIKLocks( gpGlobals->curtime ); {
m_pIk->SolveDependencies( pos, q, pBoneToWorld, boneComputed ); m_pIk->Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask );
} }
else
{ if ( m_pIk )
// Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); {
GetSkeleton( pStudioHdr, pos, q, boneMask ); // FIXME: pass this into Studio_BuildMatrices to skip transforms
} CBoneBitList boneComputed;
m_iIKCounter++;
m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask );
GetSkeleton( pStudioHdr, pos, q, boneMask );
m_pIk->UpdateTargets( pos, q, pBoneToWorld, boneComputed );
CalculateIKLocks( gpGlobals->curtime );
m_pIk->SolveDependencies( pos, q, pBoneToWorld, boneComputed );
}
else
{
// Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
GetSkeleton( pStudioHdr, pos, q, boneMask );
} }
CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() ); CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() );

View file

@ -41,8 +41,8 @@ public:
enum enum
{ {
NUM_POSEPAREMETERS = 24, NUM_POSEPAREMETERS = MAXSTUDIOPOSEPARAM,
NUM_BONECTRLS = 4 NUM_BONECTRLS = MAXSTUDIOBONECTRLS
}; };
DECLARE_DATADESC(); DECLARE_DATADESC();
@ -161,6 +161,8 @@ public:
bool HasPoseParameter( int iSequence, int iParameter ); bool HasPoseParameter( int iSequence, int iParameter );
float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f );
inline bool IsModelScaled() const;
protected: protected:
// The modus operandi for pose parameters is that you should not use the const char * version of the functions // The modus operandi for pose parameters is that you should not use the const char * version of the functions
// in general code -- it causes many many string comparisons, which is slower than you think. Better is to // in general code -- it causes many many string comparisons, which is slower than you think. Better is to
@ -518,6 +520,10 @@ inline void CBaseAnimating::SetCycle( float flCycle )
m_flCycle = flCycle; m_flCycle = flCycle;
} }
inline bool CBaseAnimating::IsModelScaled() const
{
return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON );
}
EXTERN_SEND_TABLE(DT_BaseAnimating); EXTERN_SEND_TABLE(DT_BaseAnimating);