#include "stdafx.h" #include "CryModel.h" #include "CryModelState.h" #include "CVars.h" ///////////////////////////////////////////// physics stuff ///////////////////////////////////////////////// #define FULL_LOD_LEVEL 0 ////////////////////////////////////////////////////////////////////////// // finds the first physicalized parent of the given bone (bone given by index) int CryModelState::getBonePhysParentIndex(int iBoneIndex, int nLod) { int iPrevBoneIndex; do { iBoneIndex = getBoneParentIndex(iPrevBoneIndex = iBoneIndex); } while (iBoneIndex!=iPrevBoneIndex && !getBoneInfo(iBoneIndex)->m_PhysInfo[nLod].pPhysGeom); return iBoneIndex==iPrevBoneIndex ? -1 : iBoneIndex; } ////////////////////////////////////////////////////////////////////////// // finds the first physicalized child (or itself) of the given bone (bone given by index) // returns -1 if it's not physicalized int CryModelState::getBonePhysChildIndex (int iBoneIndex, int nLod) { CryBoneInfo* pBoneInfo = getBoneInfo (iBoneIndex); if (pBoneInfo->m_PhysInfo[nLod].pPhysGeom) return iBoneIndex; unsigned numChildren = pBoneInfo->numChildren(); unsigned nFirstChild = pBoneInfo->getFirstChildIndexOffset() + iBoneIndex; for (unsigned nChild = 0; nChild < numChildren; ++nChild) { int nResult = getBonePhysChildIndex(nFirstChild + nChild, nLod); if (nResult >= 0) return nResult; } return -1; } void CryModelState::BuildPhysicalEntity(IPhysicalEntity *pent,float mass,int surface_idx,float stiffness_scale, float scale,Vec3d offset, int nLod) { pe_type pentype = pent->GetType(); int i,j; pe_geomparams gp; pe_articgeomparams agp; pe_geomparams *pgp = pentype==PE_ARTICULATED ? &agp:&gp; pgp->flags = pentype==PE_LIVING ? 0:geom_collides|geom_floats; pgp->bRecalcBBox = 0; float volume; Matrix44 mtx; for (i=0, volume=0; i<(int)numBones(); ++i) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) volume += getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom->V; pgp->density = mass/volume; if (surface_idx>=0) pgp->surface_idx = surface_idx; pent->Action(&pe_action_remove_all_parts()); for(i=0;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) { mtx = getBoneMatrixGlobal(i); *(Vec3d*)mtx[3] *= scale; *(Vec3d*)mtx[3] += offset; pgp->pMtx4x4T = mtx[0]; pgp->flags = /*strstr(getBoneInfo(i)->getNameCStr(),"Hand") ? geom_no_raytrace :*/ geom_collides|geom_floats; agp.idbody = i; pent->AddGeometry(getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom,pgp,i); getBoneInfo(i)->m_fMass = pgp->density*getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom->V; } if (pentype==PE_ARTICULATED) { CryBone *pBone; CryBoneInfo* pBoneInfo; matrix3x3bf mtx0; for(i=0;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) { pe_params_joint pj; int iParts[8]; const char *ptr,*ptr1; pBone = &getBone(i); pBoneInfo = getBoneInfo(i); Matrix44& matBoneGlobal = getBoneMatrixGlobal(i); pj.pSelfCollidingParts = iParts; if ((pj.flags = pBoneInfo->m_PhysInfo[nLod].flags)!=-1) pj.flags |= angle0_auto_kd*7; else pj.flags = angle0_locked; pj.op[0] = getBonePhysParentIndex(i,nLod); pj.op[1] = i; pj.pivot = matBoneGlobal.GetTranslationOLD(); pj.pivot = (pj.pivot+offset)*scale; pj.nSelfCollidingParts = 0; if ((ptr=strstr(pBoneInfo->getNameCStr(),"Forearm"))) { for(j=0;j<(int)numBones();j++) if (getBoneInfo(j)->m_PhysInfo[nLod].pPhysGeom && (strstr(getBoneInfo(j)->getNameCStr(),"Pelvis") || strstr(getBoneInfo(j)->getNameCStr(),"Head") || strstr(getBoneInfo(j)->getNameCStr(),"Spine") || (ptr1=strstr(getBoneInfo(j)->getNameCStr(),"Thigh")) && ptr[-2]==ptr1[-2] || strstr(getBoneInfo(j)->getNameCStr(),"Forearm") && i>j)) pj.pSelfCollidingParts[pj.nSelfCollidingParts++] = j; } if (pBoneInfo->m_PhysInfo[nLod].flags!=-1) for(j=0;j<3;j++) { pj.limits[0][j] = pBoneInfo->m_PhysInfo[nLod].min[j]; pj.limits[1][j] = pBoneInfo->m_PhysInfo[nLod].max[j]; pj.bounciness[j] = 0; pj.ks[j] = pBoneInfo->m_PhysInfo[nLod].spring_tension[j]*stiffness_scale; pj.kd[j] = pBoneInfo->m_PhysInfo[nLod].damping[j]; if (fabsf(pj.limits[0][j])<3) { pj.qdashpot[j] = 0.2f; pj.kdashpot[j] = 40.0f; } else pj.qdashpot[j] = pj.kdashpot[j] = 0; } else for(j=0;j<3;j++) { pj.limits[0][j]=-1E10f; pj.limits[1][j]=1E10f; pj.bounciness[j]=0; pj.ks[j]=0; pj.kd[j]=stiffness_scale; } pj.pMtx0 = pj.pMtx0T = 0; if (pBoneInfo->m_PhysInfo[nLod].framemtx[0][0]<10 && pBoneInfo->m_PhysInfo[nLod].flags!=-1) pj.pMtx0 = pBoneInfo->m_PhysInfo[nLod].framemtx[0]; pent->SetParams(&pj); } } //m_vOffset = offset; //m_fScale = scale; m_fMass = mass; m_iSurfaceIdx = surface_idx; } IPhysicalEntity *CryModelState::CreateCharacterPhysics(IPhysicalEntity *pHost, float mass,int surface_idx,float stiffness_scale, float scale,Vec3d offset, int nLod) { if (m_pCharPhysics) { GetPhysicalWorld()->DestroyPhysicalEntity(m_pCharPhysics); m_pCharPhysics = 0; } if (m_bHasPhysics) { pe_params_pos pp; pp.iSimClass = 4; m_pCharPhysics = GetPhysicalWorld()->CreatePhysicalEntity(PE_ARTICULATED,5.0f,&pp,0); pe_params_articulated_body pab; pab.bGrounded = 1; pab.scaleBounceResponse = 0.6f; pab.bAwake = 0; pab.pivot = vectorf(getBoneMatrixGlobal(getBonePhysChildIndex(0))[3])*scale; m_pCharPhysics->SetParams(&pab); BuildPhysicalEntity(m_pCharPhysics, mass,surface_idx,stiffness_scale, scale,vectorf(zero), 0); if (pHost) { pe_params_foreign_data pfd; pHost->GetParams(&pfd); MARK_UNUSED pfd.iForeignFlags; m_pCharPhysics->SetParams(&pfd); pe_params_articulated_body pab1; pab1.pivot.zero(); pab1.pHost = pHost; pab1.posHostPivot = vectorf(getBoneMatrixGlobal(getBonePhysChildIndex(0))[3])*scale+offset; m_pCharPhysics->SetParams(&pab1); } pe_params_joint pj; pj.op[0] = -1; pj.op[1] = getBonePhysChildIndex(0); pj.flags = all_angles_locked | joint_no_gravity | joint_isolated_accelerations; m_pCharPhysics->SetParams(&pj); } m_vOffset = offset; m_fScale = scale; m_fMass = mass; m_iSurfaceIdx = surface_idx; return m_pCharPhysics; } int CryModelState::CreateAuxilaryPhysics(IPhysicalEntity *pHost, float scale,Vec3d offset, int nLod) { int i,j,k; char strbuf[256],*pspace; // Delete aux physics for(i=0;iDestroyPhysicalEntity(m_auxPhys[i].pPhysEnt); delete[] m_auxPhys[i].pauxBoneInfo; } m_nAuxPhys=0; for (i = 0; i<(int)numBones(); i++) { CryBoneInfo* pBoneInfo = getBoneInfo(i); const char* szBoneName = pBoneInfo->getNameCStr(); #if defined(LINUX) if (!strnicmp(szBoneName,"rope",4)) #else if (!_strnicoll(szBoneName,"rope",4)) #endif { strcpy(strbuf,szBoneName); if (pspace = strchr(strbuf,' ')) { *pspace = 0; pBoneInfo->setName(strbuf); } for(j = 0; j < m_nAuxPhys && strcmp(m_auxPhys[j].strName,szBoneName); ++j) continue; if (j == m_nAuxPhys) { if (m_nAuxPhys==SIZEOF_ARRAY(m_auxPhys)) break; m_auxPhys[m_nAuxPhys].pPhysEnt = GetPhysicalWorld()->CreatePhysicalEntity(PE_ROPE); m_auxPhys[m_nAuxPhys++].strName = szBoneName; } pBoneInfo->m_nLimbId = 100+j; } } for (j = 0; j < m_nAuxPhys; ++j) { pe_status_pos sp; sp.pos.zero(); sp.q.SetIdentity(); if (pHost) pHost->GetStatus(&sp); pe_params_rope pr; int iLastBone = 0; pr.nSegments = 0; for(i=0;i<(int)numBones();i++) if (!strcmp(m_auxPhys[j].strName,getBoneInfo(i)->getNameCStr())) pr.nSegments++; pr.pPoints = new vectorf[pr.nSegments+1]; m_auxPhys[j].pauxBoneInfo = new aux_bone_info[m_auxPhys[j].nBones = pr.nSegments]; pr.length = 0; for(i=k=0;i<(int)numBones();i++) if (!strcmp(m_auxPhys[j].strName,getBoneInfo(i)->getNameCStr())) { if (k==0 && getBonePhysParentIndex(i,nLod)>=0) pr.idPartTiedTo[0] = getBonePhysParentIndex(i,nLod); pr.pPoints[k] = *(Vec3d*)getBoneMatrixGlobal(i)[3]*scale + offset; pr.pPoints[k+1] = *(Vec3d*)getBoneMatrixGlobal(getBoneChildIndex(i,0))[3]*scale + offset; m_auxPhys[j].pauxBoneInfo[k].iBone = i; m_auxPhys[j].pauxBoneInfo[k].dir0 = pr.pPoints[k+1]-pr.pPoints[k]; if (m_auxPhys[j].pauxBoneInfo[k].dir0.len2()>0) m_auxPhys[j].pauxBoneInfo[k].dir0 *= (m_auxPhys[j].pauxBoneInfo[k].rlen0 = 1.0f/m_auxPhys[j].pauxBoneInfo[k].dir0.len()); else { m_auxPhys[j].pauxBoneInfo[k].dir0(0,0,1); m_auxPhys[j].pauxBoneInfo[k].rlen0 = 1.0f; } m_auxPhys[j].pauxBoneInfo[k].quat0 = quaternionf(*(const matrix3x3in4x4Tf*)&getBoneMatrixGlobal(i)); pr.pPoints[k] = sp.q*pr.pPoints[k]+sp.pos; pr.pPoints[k+1] = sp.q*pr.pPoints[k+1]+sp.pos; pr.length += (pr.pPoints[k+1]-pr.pPoints[k]).len(); iLastBone = ++k; } if (!is_unused(pr.idPartTiedTo[0])) { pr.pEntTiedTo[0] = pHost; pr.ptTiedTo[0] = pr.pPoints[0]; } if ((i = getBonePhysChildIndex(iLastBone))>=0) { pr.pEntTiedTo[1] = pHost; pr.idPartTiedTo[1] = i; pr.ptTiedTo[1] = pr.pPoints[pr.nSegments]; } m_auxPhys[j].pPhysEnt->SetParams(&pr); delete[] pr.pPoints; } m_vOffset = offset; m_fScale = scale; return m_nAuxPhys; } ////////////////////////////////////////////////////////////////////////// // Replaces each bone global matrix with the relative matrix. // The root matrix is relative to the world, which is its parent, so it's // obviously both the global and relative (they coincide), so it doesn't change // // ASSUMES: the matrices are unitary and orthogonal, so that Transponse(M) == Inverse(M) // ASSUMES: in each bone global matrix, upon entry, there's the actual global matrix // RETURNS: in each m_matRelativeToParent matrix, there's a matrix relative to the parent void CryModelState::ConvertBoneGlobalToRelativeMatrices() { unsigned i, numBones = this->numBones(); // scan through all bones from the bottom up (from children to parents), // excluding the root (i>0) for (i = numBones-1; i > 0; --i) { Matrix44 &Mtxrel = getBone(i).m_matRelativeToParent; Matrix44 &mtxBoneGlobal = getBoneMatrixGlobal (i); Matrix44 &mtxParentGlobal = getBoneMatrixGlobal (getBoneParentIndex(i)); matrix3x3in4x4Tf &mtxrel((matrix3x3in4x4Tf&)Mtxrel), &mtxparent ((matrix3x3in4x4Tf&)mtxParentGlobal), &mtxchild ((matrix3x3in4x4Tf&)mtxBoneGlobal); vectorf dx = mtxBoneGlobal.GetTranslationOLD()-mtxParentGlobal.GetTranslationOLD(); (mtxrel = mtxparent.T()) *= mtxchild; Mtxrel.SetTranslationOLD(dx*mtxparent); Mtxrel[0][3] = Mtxrel[1][3] = Mtxrel[2][3] = 0.0f; Mtxrel[3][3] = 1.0f; } } ////////////////////////////////////////////////////////////////////////// // Multiplies each bone global matrix with the parent global matrix, // and calculates the relative-to-default-pos matrix. This is essentially // the process opposite to conversion of global matrices to relative form // performed by ConvertBoneGlobalToRelativeMatrices() // NOTE: // The root matrix is relative to the world, which is its parent, so it's // obviously both the global and relative (they coincide), so it doesn't change // // PARAMETERS: // bNonphysicalOnly - if set to true, only those bones that have no physical geometry are affected // // ASSUMES: in each m_matRelativeToParent matrix, upon entry, there's a matrix relative to the parent // RETURNS: in each bone global matrix, there's the actual global matrix void CryModelState::UnconvertBoneGlobalFromRelativeForm(bool bNonphysicalOnlyArg, int nLod) { unsigned numBones = this->numBones(); bool bNonphysicalOnly = true; // start from 1, since we don't affect the root, which is #0 for (unsigned i = 1; i < numBones; ++i) { CryBoneInfo* pBoneInfo = getBoneInfo(i); bool bPhysical = pBoneInfo->getPhysInfo(nLod).pPhysGeom || pBoneInfo->getLimbId()>=100; if (!bNonphysicalOnly || !bPhysical) { assert (pBoneInfo->hasParent()); Matrix44& matBoneGlobal = getBoneMatrixGlobal(i); matBoneGlobal = getBone(i).m_matRelativeToParent*getBoneMatrixGlobal(getBoneParentIndex(i)); } if (bPhysical) // don't update the 1st physical bone (pelvis) even if bNonphysicalOnlyArg is false bNonphysicalOnly = bNonphysicalOnlyArg; } } void CryModelState::ResetNonphysicalBoneRotations(int nLod, float fBlend) { // set non-physical bones to their default position wrt parent for LODs>0 // do it for every bone except the root, parents first unsigned numBones = this->numBones(); for (unsigned nBone = 1; nBone < numBones; ++nBone) { CryBoneInfo* pInfo = getBoneInfo(nBone); if (!pInfo->getPhysInfo(nLod).pPhysGeom) { CryBone* pBone = &getBone(nBone); Matrix44& matBoneGlobal = getBoneMatrixGlobal(nBone); if (fBlend>=1.0f) pInfo->getDefRelTransform().buildMatrix(pBone->m_matRelativeToParent); else { IController::PQLog pq; pq.blendPQ(pBone->m_pqTransform, pInfo->getDefRelTransform(), fBlend); pq.buildMatrix(pBone->m_matRelativeToParent); } } } } void CryModelState::SynchronizeWithPhysicalEntity(IPhysicalEntity *pent, const Vec3& posMaster,const Quat& qMaster, Vec3 offset, int iDir) { if (pent && (iDir==0 || iDir<0 && pent->GetType()!=PE_ARTICULATED && pent->GetType()!=PE_RIGID)) { // copy state _to_ physical entity //m_vOffset = offset; //m_fScale = scale; if (!m_bHasPhysics) return; pe_params_part partpos; int i,j; for(i=j=0;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[0].pPhysGeom) j=i; if (pent->GetType()==PE_ARTICULATED) offset = -*(Vec3*)getBoneMatrixGlobal(getBonePhysChildIndex(0))[3];//*scale; for(i=0;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[0].pPhysGeom) { partpos.partid = i; partpos.bRecalcBBox = i==j; Matrix44 mtx = getBoneMatrixGlobal(i); //*(vectorf*)mtx[3] *= scale; *(Vec3d*)mtx[3] += offset; partpos.pMtx4x4T = (float*)&mtx; if (!pent->SetParams(&partpos)) break; } } else { // copy state _from_ physical entity if (!pent && !m_nAuxPhys) return; int i,j,nLod = min(m_pCharPhysics!=pent?1:0,(int)numLODs()-1); float rScale = 1.0f;///scale; pe_status_pos sp; pe_status_joint sj; m_bPhysicsAwake = 0; if (pent) m_bPhysicsAwake = pent->GetStatus(&pe_status_awake()); for(j=0;jGetStatus(&pe_status_awake()); if (!m_bPhysicsAwake && !m_bPhysicsWasAwake) return; if (!m_bPhysicsAwake) m_fPhysBlendTime = m_fPhysBlendMaxTime+0.1f; ResetNonphysicalBoneRotations(nLod, m_fPhysBlendTime*m_frPhysBlendMaxTime); if (pent) { pe_status_pos partpos; partpos.flags = status_local; for(i=0;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) { partpos.partid = i; getBoneMatrixGlobal(i).SetIdentity(); partpos.pMtx4x4T = (float*)&getBoneMatrixGlobal(i); pent->GetStatus(&partpos); getBoneMatrixGlobal(i).SetTranslationOLD((getBoneMatrixGlobal(i).GetTranslationOLD()-offset)*rScale); if (m_fPhysBlendTime < m_fPhysBlendMaxTime) break; // if in blending stage, do it only for the root } //Matrix33 mtxRel; for(;i<(int)numBones();i++) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) { //mtxRel.SetIdentity33(); // build the physparent->immediate parent matrix //for(j=getBoneParentIndex(i); j>0 && !getBoneInfo(j)->getPhysInfo(nLod).pPhysGeom; j=getBoneParentIndex(j)) // mtxRel = (matrix3x3in4x4Tf&)getBone(j).m_matRelativeToParent * mtxRel; sj.idChildBody = i; pent->GetStatus(&sj); //(matrix3x3in4x4Tf&)getBone(i).m_matRelativeToParent = mtxRel.T()*Matrix33(sj.quat0*GetRotationXYZ(sj.q+sj.qext)); (matrix3x3in4x4Tf&)getBone(i).m_matRelativeToParent = Matrix33(getBoneInfo(i)->getqRelPhysParent(nLod) * sj.quat0 * GetRotationXYZ(sj.q+sj.qext)); getBone(i).m_matRelativeToParent.SetTranslationOLD(getBoneInfo(i)->getDefRelTransform().vPos); } pent->GetStatus(&sp); } else { sp.pos = posMaster; sp.q = qMaster; } // additionally copy state from all ropes present in this character pe_params_rope pr; for(j=0;jGetParams(&pr); for(i=0;i1E-4f) { int nBone = m_auxPhys[j].pauxBoneInfo[i].iBone; CryBone &bone = getBone(nBone); Matrix44& matBoneGlobal = getBoneMatrixGlobal(nBone); //(quaternionf(m_auxPhys[j].pauxBoneInfo[i].dir0, dir/len)*m_auxPhys[j].pauxBoneInfo[i].quat0). // getmatrix(matrix3x3in4x4Tf(matBoneGlobal[0])) *= len*m_auxPhys[j].pauxBoneInfo[i].rlen0; //Q2M_IVO //(GetRotationV0V1(m_auxPhys[j].pauxBoneInfo[i].dir0, dir/len)*m_auxPhys[j].pauxBoneInfo[i].quat0). //getmatrix((matrix3x3in4x4Tf&)matBoneGlobal) *= len*m_auxPhys[j].pauxBoneInfo[i].rlen0; *(matrix3x3in4x4Tf*)&matBoneGlobal = ( matrix3x3f( GetRotationV0V1(m_auxPhys[j].pauxBoneInfo[i].dir0, dir/len) * m_auxPhys[j].pauxBoneInfo[i].quat0 ) * len*m_auxPhys[j].pauxBoneInfo[i].rlen0 ); matBoneGlobal.SetTranslationOLD(((pt0-sp.pos)*sp.q-offset)*rScale); } } } UnconvertBoneGlobalFromRelativeForm(m_fPhysBlendTime>=m_fPhysBlendMaxTime, nLod); if(m_bPhysicsAwake) ForceReskin(); m_bPhysicsWasAwake = m_bPhysicsAwake; } } IPhysicalEntity *CryModelState::RelinquishCharacterPhysics() { if (m_bHasPhysics) { int i, nLod=min(numLODs()-1,1), iRoot=getBonePhysChildIndex(0,0); DestroyCharacterPhysics(); ConvertBoneGlobalToRelativeMatrices(); // takes into accout all post-animation layers // store death pose (current) matRelative orientation in bone's m_pqTransform for(i=0;i<(int)numBones();i++) { // '-' since pqTransform.buildMatrix assumes flipped quaternion getBone(i).m_pqTransform.vRotLog = -log(CryQuat((matrix3x3in4x4Tf&)getBone(i).m_matRelativeToParent)).v; //Vec3 vb4 = getBone(i).m_pqTransform.vRotLog; AdjustLogRotationTo(getBoneInfo(i)->getDefRelTransform().vRotLog, getBone(i).m_pqTransform.vRotLog); /*Vec3 vaft = getBone(i).m_pqTransform.vRotLog; if (fabsf(exp(CryQuat(0,vb4.x,vb4.y,vb4.z))|exp(CryQuat(0,vaft.x,vaft.y,vaft.z)))<0.98f) getBone(i).m_pqTransform.vRotLog=vb4;*/ getBone(i).m_pqTransform.vPos = getBoneInfo(i)->getDefRelTransform().vPos; } ResetNonphysicalBoneRotations(nLod,1.0f); // reset nonphysical bones matRel to default pose matRel UnconvertBoneGlobalFromRelativeForm(false,nLod); // build matGlobals from matRelativeToParents pe_params_articulated_body pab; pab.bGrounded = 0; pab.scaleBounceResponse = 1; pab.bCheckCollisions = 1; pab.bCollisionResp = 1; IPhysicalEntity *res = GetPhysicalWorld()->CreatePhysicalEntity(PE_ARTICULATED,&pab);//,&pp,0); BuildPhysicalEntity(res, m_fMass,m_iSurfaceIdx,0, m_fScale,m_vOffset, nLod); pe_params_joint pj; pj.bNoUpdate = 1; iRoot = getBonePhysChildIndex(0,nLod); for(i=0;i<3;i++) { pj.ks[i]=0; pj.kd[i]=0.2f; } for(i=numBones()-1;i>=0;i--) if (getBoneInfo(i)->m_PhysInfo[nLod].pPhysGeom) { pj.op[0] = getBonePhysParentIndex(i,nLod); pj.op[1] = i; pj.flags = getBoneInfo(i)->m_PhysInfo[nLod].flags & (all_angles_locked | angle0_limit_reached*7); if (i==iRoot) pj.flags = 0; res->SetParams(&pj); } m_fPhysBlendTime = 0.0f; m_fPhysBlendMaxTime = g_GetCVars()->ca_DeathBlendTime(); if (m_fPhysBlendMaxTime>0.001f) m_frPhysBlendMaxTime = 1.0f/m_fPhysBlendMaxTime; else { m_fPhysBlendMaxTime = 0.0f; m_frPhysBlendMaxTime = 1.0f; } ResetNonphysicalBoneRotations(nLod,0.0f); // restore death pose matRel from m_pqTransform UnconvertBoneGlobalFromRelativeForm(false,nLod); // build matGlobals from matRelativeToParents pe_simulation_params sp; sp.gravity.Set(0,0,-7.5f); sp.maxTimeStep = 0.025f; sp.damping = 0.3f; sp.iSimClass = 2; res->SetParams(&sp); m_vOffset.zero(); m_bPhysicsAwake=m_bPhysicsWasAwake = 1; m_uFlags |= nFlagsNeedReskinAllLODs; // in order to force skinning update during the first death sequence frame return res; } return 0; } bool CryModelState::AddImpact(const int partid,vectorf point,vectorf impact,float scale) { if (m_pCharPhysics) { if ((unsigned int)partid>=(unsigned int)numBones()) { //GetLog()->LogToFile("*ERROR* CryModelState::AddImpact: part id %u is out of range [0..%u]", partid, numBones()); // sometimes out of range value (like -1) is passed to indicate that no impulse should be added to character return false; } int i; CryBone* pImpactBone = &getBone(partid); const char* szImpactBoneName = getBoneInfo(partid)->getNameCStr(); for(i=0; i<4 && !(m_pIKEffectors[i] && m_pIKEffectors[i]->AffectsBone(partid)); i++); const char *ptr = strstr(szImpactBoneName,"Spine"); if (i<4 || strstr(szImpactBoneName,"Pelvis") || ptr && !ptr[5]) { if (i<4) { pe_params_articulated_body pab; m_pCharPhysics->GetParams(&pab); if (!pab.pHost) return false; //pe_action_impulse crouch_impulse; //crouch_impulse.impulse(0,0,-impact.len()*10.0f); //pab.pHost->Action(&crouch_impulse); } return false; // don't add impulse to spine and pelvis } if (strstr(szImpactBoneName,"UpperArm") || strstr(szImpactBoneName,"Forearm")) impact *= 0.35f; else if (strstr(szImpactBoneName,"Hand")) impact *= 0.2f; else if (strstr(szImpactBoneName,"Spine1")) impact *= 0.2f; pe_action_impulse impulse; impulse.partid = partid; impulse.impulse = impact; impulse.point = point; m_pCharPhysics->Action(&impulse); return true; } else { pe_action_impulse impulse; impulse.impulse = impact; impulse.point = point; for(int i=0;iAction(&impulse); } return false; } int CryModelState::TranslatePartIdToDeadBody(int partid) { if ((unsigned int)partid>=(unsigned int)numBones()) return -1; int nLod = min(numLODs()-1,1); if (getBoneInfo(partid)->m_PhysInfo[nLod].pPhysGeom) return partid; return getBonePhysParentIndex(partid,nLod); } void CryModelState::SetLimbIKGoal(int limbid, float scale, vectorf ptgoal, int ik_flags, float addlen, vectorf goal_normal) { if (ptgoal.x==1E10) { if (m_pIKEffectors[limbid]) { delete m_pIKEffectors[limbid]; m_pIKEffectors[limbid] = 0; } return; } int i; if (!m_pIKEffectors[limbid]) { for(i=0;i<(int)numBones() && getBoneInfo(i)->m_nLimbId!=limbid;i++); if (i==numBones()) return; m_pIKEffectors[limbid] = new CCryModEffIKSolver(this); m_pIKEffectors[limbid]->SetPrimaryBone(i); } for(i=0;i<3;i++) if (ptgoal[i]!=IK_NOT_USED) ptgoal[i]/=scale; if (limbid==LIMB_LEFT_LEG || limbid==LIMB_RIGHT_LEG) ptgoal.z += m_IKpos0[limbid].z; m_pIKEffectors[limbid]->SetGoal(ptgoal,ik_flags,addlen,goal_normal,m_IKpos0[limbid].z); } vectorf CryModelState::GetLimbEndPos(int limbid, float scale) { int i; for(i=0;i<(int)numBones() && getBoneInfo(i)->m_nLimbId!=limbid;i++); if (i==numBones()) return vectorf(zero); int limbend = getBoneGrandChildIndex(i,0,0); vectorf res = *(vectorf*)getBoneMatrixGlobal(limbend)[3]*scale; if (limbid==LIMB_LEFT_LEG || limbid==LIMB_RIGHT_LEG) res.z -= m_IKpos0[limbid].z; return res; } void CryModelState::ProcessPhysics(float fDeltaTimePhys, int nNeff) { if(g_GetCVars()->ca_NoPhys()) return; m_uFlags |= nFlagsNeedReskinAllLODs; pe_params_joint pj; pe_status_joint sj; pj.bNoUpdate = 1; if (fDeltaTimePhys>0) pj.ranimationTimeStep = 1.0f/(pj.animationTimeStep = fDeltaTimePhys); int i,j,iParent,iRoot; if (nNeff>=0) for(i=0;i<4;i++) if (m_pIKEffectors[i]) m_pIKEffectors[i]->Tick (fDeltaTimePhys); if (m_pCharPhysics && (m_bPhysicsAwake = m_pCharPhysics->GetStatus(&pe_status_awake()))) { if (nNeff==0) { // if there's no animation atm, just read the state from physics verbatim SynchronizeWithPhysicalEntity(m_pCharPhysics, Vec3(0,0,0),Quat(1,0,0,0),m_vOffset); } else { matrix3x3bf mtxid; mtxid.SetIdentity(); // read angles deltas from physics and set current angles from animation as qext to physics for(i=0; i<(int)numBones(); i++) if (getBoneInfo(i)->getPhysInfo(0).pPhysGeom && (iParent=getBonePhysParentIndex(i)) >= 0) { for (j = 0; j < 4 && !(m_pIKEffectors[j] && m_pIKEffectors[j]->AffectsBone(i)); ++j); if (j<4) continue; sj.idChildBody = i; if (!m_pCharPhysics->GetStatus(&sj)) continue; matrix3x3in4x4Tf &matrel((matrix3x3in4x4Tf&)getBone(i).m_matRelativeToParent); matrix3x3f matparent,mtx; matparent.SetIdentity(); for(int nCurParent=getBoneParentIndex(i); nCurParent != iParent; nCurParent=getBoneParentIndex(nCurParent)) matparent.T() *= ((matrix3x3in4x4Tf&)getBone(nCurParent).m_matRelativeToParent).T(); matrix3x3f &mtx0(getBoneInfo(i)->getPhysInfo(0).framemtx[0][0]<10 ? (matrix3x3RMf&)*(&getBoneInfo(i)->getPhysInfo(0).framemtx[0][0]) : mtxid); //EULER_IVO //(((mtx=mtx0.T())*=matparent)*=matrel).GetEulerAngles_XYZ(sj.qext); mtx=mtx0.T(); mtx*=matparent; mtx*=matrel; sj.qext=Ang3::GetAnglesXYZ(mtx); //quaternionf(sj.q+sj.qext).getmatrix(matrel); //Q2M_IVO //GetRotationXYZ(sj.q+sj.qext).getmatrix(matrel); matrel=matrix3x3f(GetRotationXYZ(sj.q+sj.qext)); (matrel.T() *= mtx0.T()) *= matparent; pj.op[0] = iParent; pj.op[1] = i; pj.qext = sj.qext; m_pCharPhysics->SetParams(&pj); } UnconvertBoneGlobalFromRelativeForm(false); } } if (nNeff>=0) for(int i=0;i<4;i++) if (m_pIKEffectors[i]) m_pIKEffectors[i]->ApplyToBone (nNeff++); if (m_pCharPhysics) { iRoot = getBonePhysChildIndex(0); if (m_bPhysicsAwake) { matrix3x3bf matrel; pj.q.zero(); for(i=0; i<(int)numBones(); i++) if (getBoneInfo(i)->m_PhysInfo[0].pPhysGeom && (iParent=getBonePhysParentIndex(i))>=0) { // now force positions of IK-controlled bones to physics for(j=0; j<4 && !(m_pIKEffectors[j] && m_pIKEffectors[j]->AffectsBone(i)); j++); if (j==4) continue; (matrel = ((matrix3x3in4x4Tf&)getBoneMatrixGlobal(iParent)).T()) *= (matrix3x3in4x4Tf&)getBoneMatrixGlobal(i); if (getBoneInfo(i)->m_PhysInfo[0].framemtx[0][0]<10) matrel.T() *= (matrix3x3RMf&)*(&getBoneInfo(i)->m_PhysInfo[0].framemtx[0][0]); //EULER_IVO //matrel.GetEulerAngles_XYZ(pj.qext); pj.qext = Ang3::GetAnglesXYZ(matrel); pj.op[0] = iParent; pj.op[1] = i; m_pCharPhysics->SetParams(&pj); } //EULER_IVO //((matrix3x3in4x4Tf&)getBoneMatrixGlobal(iRoot)).GetEulerAngles_XYZ(pj.qext); pj.qext = Ang3::GetAnglesXYZ( (matrix3x3in4x4Tf&)getBoneMatrixGlobal(iRoot) ); pj.op[0] = -1; pj.op[1] = iRoot; m_pCharPhysics->SetParams(&pj); } else SynchronizeWithPhysicalEntity(m_pCharPhysics, Vec3(zero),Quat(1,0,0,0),Vec3(zero), 0); pe_params_articulated_body pab; pab.pivot.zero(); pab.posHostPivot = m_vOffset+vectorf(getBoneMatrixGlobal(iRoot)[3])*m_fScale; pab.bRecalcJoints = m_bPhysicsAwake; m_pCharPhysics->SetParams(&pab); } for(i=0;iGetStatus(&pe_status_awake()); if (m_bPhysicsAwake) m_uFlags |= nFlagsNeedReskinAllLODs; m_bPhysicsWasAwake = m_bPhysicsAwake; } IPhysicalEntity *CryModelState::GetCharacterPhysics(const char *pRootBoneName) { if (!pRootBoneName) return m_pCharPhysics; for(int i=0;i=m_nAuxPhys) return 0; return m_auxPhys[iAuxPhys].pPhysEnt; } void CryModelState::DestroyCharacterPhysics(int iMode) { if (m_pCharPhysics) GetPhysicalWorld()->DestroyPhysicalEntity(m_pCharPhysics,iMode); if (iMode==0) m_pCharPhysics = 0; int i; for(i=0;iDestroyPhysicalEntity(m_auxPhys[i].pPhysEnt,iMode); if (iMode==0) delete[] m_auxPhys[i].pauxBoneInfo; } if (iMode==0) m_nAuxPhys = 0; }