////////////////////////////////////////////////////////////////////// // // Articulated Entity // // File: articulatedentity.cpp // Description : ArticulatedEntity class implementation // // History: // -:Created by Anton Knyazev // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "bvtree.h" #include "geometry.h" #include "singleboxtree.h" #include "cylindergeom.h" #include "rigidbody.h" #include "physicalplaceholder.h" #include "physicalentity.h" #include "geoman.h" #include "physicalworld.h" #include "rigidentity.h" #include "articulatedentity.h" int __ae_step=0; // for debugging CArticulatedEntity::CArticulatedEntity(CPhysicalWorld *pWorld) : CRigidEntity(pWorld) { m_nJoints = 0; m_bGrounded = 0; m_acc.Set(0,0,0); m_wacc.Set(0,0,0); m_joints = new ae_joint[m_nJointsAlloc=4]; m_nJoints = 0; m_nContactsAlloc = 0; m_offsPivot.Set(0,0,0); m_bAwake = 0; m_simTime = 0; m_simTimeAux = 10.0f; m_scaleBounceResponse = 1; m_posPivot.Set(0,0,0); m_bIaReady = 0; m_nPartsAlloc = 4; m_parts = new geom[m_nPartsAlloc]; m_infos = new ae_part_info[m_nPartsAlloc]; m_bCheckCollisions = 0; m_bCollisionResp = 0; m_maxAllowedStep = 0.02f; m_bInheritVel = 0; m_pHost = 0; m_posHostPivot.Set(0,0,0); m_bPartPosForced = 0; m_bExertImpulse = 0; m_Ya_vec[0].Set(0,0,0); m_Ya_vec[0].Set(0,0,0); m_nContacts = m_nDynContacts = m_bInGroup = 0; m_nCollLyingMode = 5; m_gravityLyingMode.Set(0,0,-5.0f); m_dampingLyingMode = 1.0f; m_EminLyingMode = 0.04f; m_maxPenetrationCur = 0; m_iSimType = 0; m_iSimTypeLyingMode = 1; m_iSimTypeCur = 0; m_iSimTypeOverride = 0; m_bFastLimbs = 0; m_bExpandHinges = 0; m_bUsingUnproj = 0; m_softness[0] = 0.01f; m_softness[1] = 0.05f; m_softness[2] = 0.001f; m_softness[3] = 0.01f; m_bUpdateBodies = 1; m_bCanSweep = 0; } CArticulatedEntity::~CArticulatedEntity() { if (m_joints) delete[] m_joints; if (m_infos) delete[] m_infos; } void CArticulatedEntity::AlertNeighbourhoodND() { if (m_pHost) m_pHost->Release(); m_pHost = 0; CRigidEntity::AlertNeighbourhoodND(); } int CArticulatedEntity::AddGeometry(phys_geometry *pgeom, pe_geomparams* _params,int id) { if (_params->type!=pe_articgeomparams::type_id) { pe_articgeomparams params = *(pe_geomparams*)_params; return AddGeometry(pgeom,¶ms,id); } pe_articgeomparams *params = (pe_articgeomparams*)_params; int res,i,nPartsAlloc=m_nPartsAlloc,nParts=m_nParts,idx; if ((res = CPhysicalEntity::AddGeometry(pgeom,params,id))<0 || m_nParts==nParts && params->flags & geom_proxy) return res; idx = m_nParts-1; float V=pgeom->V*cube(params->scale), M=params->mass ? params->mass : params->density*V; vectorf bodypos = m_pos+m_qrot*(params->pos+params->q*pgeom->origin); quaternionf bodyq = m_qrot*params->q*pgeom->q; if (M<=0) M=0.1f; m_parts[idx].mass = M; if (nPartsAlloc < m_nPartsAlloc) { ae_part_info *pInfos = m_infos; memcpy(m_infos = new ae_part_info[m_nPartsAlloc], pInfos, sizeof(ae_part_info)*nPartsAlloc); if (pInfos) delete[] pInfos; } for(i=0;iidbody;i++); if (i==m_nJoints) { if (m_nJoints==m_nJointsAlloc) { ae_joint *pJoints = m_joints; memcpy(m_joints=new ae_joint[m_nJointsAlloc+=4], pJoints, sizeof(ae_joint)*m_nJoints); if (pJoints) delete[] pJoints; } m_joints[m_nJoints].iStartPart = idx; m_joints[m_nJoints].nParts = 0; m_joints[m_nJoints++].idbody = params->idbody; } if (m_joints[i].iStartPart+m_joints[i].nPartsm_joints[i].iStartPart+m_joints[i].nParts; idx--) { m_parts[idx] = m_parts[idx-1]; m_infos[idx] = m_infos[idx-1]; } m_parts[idx] = tmppart; } m_joints[i].nParts++; if (M>0) { // pivot positions are not recalculated if (m_body.M==0) m_body.Create(bodypos,pgeom->Ibody*sqr(params->scale)*cube(params->scale),bodyq, V,M, m_qrot,m_pos); else m_body.Add(bodypos,pgeom->Ibody*sqr(params->scale)*cube(params->scale),bodyq,V,M); if (m_joints[i].body.M==0) { m_joints[i].body.Create(bodypos,pgeom->Ibody*sqr(params->scale)*cube(params->scale),bodyq, V,M, m_qrot*params->q,bodypos); m_joints[i].body.pOwner = this; m_joints[i].body.softness[0] = m_softness[0]; m_joints[i].body.softness[1] = m_softness[1]; } else m_joints[i].body.Add(bodypos,pgeom->Ibody*sqr(params->scale)*cube(params->scale),bodyq,V,M); } m_infos[idx].iJoint = i; m_infos[idx].idbody = params->idbody; m_joints[i].quat = m_joints[i].body.q*m_joints[i].body.qfb; m_infos[idx].q0 = !m_joints[i].quat*(m_qrot*m_parts[idx].q); m_infos[idx].pos0 = (m_pos+m_qrot*m_parts[idx].pos-m_joints[i].body.pos)*m_joints[i].quat; return res; } void CArticulatedEntity::RemoveGeometry(int id) { int i,j; for(i=0;i0) { vectorf bodypos = m_pos + m_qrot*(m_parts[i].pos+pgeom->origin); quaternionf bodyq = m_qrot*m_parts[i].q*pgeom->q; m_body.Add(bodypos,-pgeom->Ibody,bodyq,-pgeom->V,-m_parts[i].mass); m_joints[m_infos[i].iJoint].body.Add(bodypos,-pgeom->Ibody,bodyq,-pgeom->V,-m_parts[i].mass); if (m_body.M<1E-8) m_body.M = 0; if (m_joints[m_infos[i].iJoint].body.M<1E-8) m_joints[m_infos[i].iJoint].body.M = 0; m_joints[m_infos[i].iJoint].nParts--; for(j=0;ji) m_joints[j].iStartPart--; } CPhysicalEntity::RemoveGeometry(id); } void CArticulatedEntity::RecomputeMassDistribution(int ipart,int bMassChanged) { int i,iStart,iEnd; float V; vectorf bodypos; quaternionf bodyq; if (ipart>=0) { if (!bMassChanged) return; i = m_infos[ipart].iJoint; m_joints[i].body.zero(); iStart = m_joints[i].iStartPart; iEnd = m_joints[i].iStartPart+m_joints[i].nParts-1; } else { m_body.zero(); for(i=0;iV*cube(m_parts[i].scale); bodypos = m_pos + m_qrot*(m_parts[i].pos+m_parts[i].q*m_parts[i].pPhysGeom->origin); bodyq = m_qrot*m_parts[i].q*m_parts[i].pPhysGeom->q; if (m_parts[i].mass>0) { if (ipart<0) { if (m_body.M==0) m_body.Create(bodypos,m_parts[i].pPhysGeom->Ibody*sqr(m_parts[i].scale)*cube(m_parts[i].scale),bodyq, V,m_parts[i].mass, m_qrot,m_pos); else m_body.Add(bodypos,m_parts[i].pPhysGeom->Ibody*sqr(m_parts[i].scale)*cube(m_parts[i].scale),bodyq, V,m_parts[i].mass); } if (m_joints[m_infos[i].iJoint].body.M==0) { m_joints[m_infos[i].iJoint].body.Create(bodypos,m_parts[i].pPhysGeom->Ibody*sqr(m_parts[i].scale)*cube(m_parts[i].scale),bodyq, V,m_parts[i].mass, m_qrot,m_pos); m_joints[i].body.pOwner = this; m_joints[i].body.softness[0] = m_softness[0]; m_joints[i].body.softness[1] = m_softness[1]; } else m_joints[m_infos[i].iJoint].body.Add(bodypos,m_parts[i].pPhysGeom->Ibody*sqr(m_parts[i].scale)*cube(m_parts[i].scale),bodyq, V,m_parts[i].mass); } } } int CArticulatedEntity::SetParams(pe_params *_params) { vectorf prevpos = m_pos; quaternionf prevq = m_qrot; if (CRigidEntity::SetParams(_params)) { if (_params->type==pe_params_pos::type_id) { pe_params_pos *params = (pe_params_pos*)_params; int i=-1; if ((prevq.v-m_qrot.v).len2()>0) { if (m_nJoints>0) { /*if (m_bGrounded) { if ((m_joints[0].flags & all_angles_locked)!=all_angles_locked) { vectorf dangle; int j; quaternionf qalpha(m_joints[0].q+m_joints[0].qext); (!m_qrot*m_joints[0].quat0*qalpha).get_Euler_angles_xyz(dangle); for(j=0;j<3;j++) if (!(m_joints[0].flags & angle0_locked<0) { m_posPivot = m_pos + m_offsPivot; i = 0; } if (i>=0 && params->bRecalcBounds) for(;itype==pe_params_part::type_id) m_bPartPosForced = 1; return 1; } if (_params->type==pe_params_joint::type_id) { pe_params_joint *params = (pe_params_joint*)_params; m_bPartPosForced = 0; int i,j,op[2]={-1,-1},nChanges=0; for(i=0;iop[0]) op[0]=i; if (m_joints[i].idbody==params->op[1]) op[1]=i; } if (op[0]<0 && params->op[0]>=0 || op[1]<0) return 0; quaternionf qparent, qchild = m_joints[op[1]].body.q*m_joints[op[1]].body.qfb; vectorf posparent, poschild = m_joints[op[1]].body.pos; if (op[0]>=0) { qparent = m_joints[op[0]].body.q*m_joints[op[0]].body.qfb; posparent = m_joints[op[0]].body.pos; } else { qparent.SetIdentity(); posparent = m_posPivot; } if (!is_unused(params->pivot)) { vectorf pivot = m_qrot*params->pivot + m_pos; if (params->op[0]!=-1) m_joints[op[1]].pivot[0] = (pivot-posparent)*qparent; else m_joints[op[1]].pivot[0].Set(0,0,0); if (m_bGrounded || params->op[0]!=-1) m_joints[op[1]].pivot[1] = (pivot-poschild)*qchild; else m_joints[op[1]].pivot[1].Set(0,0,0); } if (!is_unused(params->flags)) { m_joints[op[1]].flags = params->flags | m_joints[op[1]].flags & params->flags & (angle0_limit_reached|angle0_gimbal_locked)*7; for(i=0;i<3;i++) if (params->flags & angle0_locked<nSelfCollidingParts)) { for(i=0;inSelfCollidingParts;j++) if (m_parts[i].id==params->pSelfCollidingParts[j]) m_joints[op[1]].selfCollMask |= getmask(i); } float rdt = !is_unused(params->ranimationTimeStep) ? params->ranimationTimeStep : 1.0f/params->animationTimeStep; for(i=0;i<3;i++) { if (!is_unused(params->limits[0][i])) m_joints[op[1]].limits[0][i] = params->limits[0][i]; if (!is_unused(params->limits[1][i])) m_joints[op[1]].limits[1][i] = params->limits[1][i]; if (!is_unused(params->bounciness[i])) m_joints[op[1]].bounciness[i] = params->bounciness[i]; if (!is_unused(params->ks[i])) m_joints[op[1]].ks[i] = params->ks[i]; if (!is_unused(params->kd[i])) m_joints[op[1]].kd[i] = ((m_joints[op[1]].flags & angle0_auto_kd<kd[i]; if (!is_unused(params->qdashpot[i])) m_joints[op[1]].qdashpot[i] = params->qdashpot[i]; if (!is_unused(params->kdashpot[i])) m_joints[op[1]].kdashpot[i] = params->kdashpot[i]; if (!is_unused(params->q[i])) m_joints[op[1]].q[i] = params->q[i]; if (!is_unused(params->qext[i])) { m_joints[op[1]].dqext[i] = (params->qext[i]-m_joints[op[1]].qext[i])*rdt; m_joints[op[1]].qext[i] = params->qext[i]; nChanges++; if (!(m_joints[op[1]].flags & angle0_locked<pMtx0T) params->q0 = quaternionf((matrix3x3Tf&)(*params->pMtx0T)/((matrix3x3Tf&)(*params->pMtx0T)).GetRow(0).len()); if (params->pMtx0) params->q0 = quaternionf((matrix3x3f&)(*params->pMtx0)/((matrix3x3f&)(*params->pMtx0)).GetRow(0).len()); if (!is_unused(params->q0)) { m_joints[op[1]].quat0 = params->q0; m_joints[op[1]].bQuat0Changed = 0; nChanges++; } ENTITY_VALIDATE("CArticulatedEntity:SetParams(params_joint)",params); if (m_joints[op[1]].iParent!=op[0]) { if (!is_unused(params->qext[0])) { //(!(qparent*m_joints[op[1]].quat0)*qchild).GetEulerAngles_XYZ(m_joints[op[1]].q); //EULER_IVO m_joints[op[1]].q = Ang3::GetAnglesXYZ( matrix3x3f(!(qparent*m_joints[op[1]].quat0)*qchild) ); m_joints[op[1]].q -= m_joints[op[1]].qext; } else //(!(qparent*m_joints[op[1]].quat0)*qchild).GetEulerAngles_XYZ(m_joints[op[1]].qext); //EULER_IVO m_joints[op[1]].qext = Ang3::GetAnglesXYZ( matrix3x3f(!(qparent*m_joints[op[1]].quat0)*qchild) ); if (op[1]!=op[0]+1) { int nChildren; for(nChildren=m_joints[op[1]].nChildren+1,i=1; i1 ? new ae_joint[nChildren] : &jbuf; memcpy(pjbuf, m_joints+op[1], nChildren*sizeof(ae_joint)); if (op[1]op[1] && m_joints[i].iParent<=op[0]) m_joints[i].iParent -= nChildren; memmove(m_joints+op[1], m_joints+op[1]+nChildren, (op[0]-op[1]-nChildren+1)*sizeof(ae_joint)); op[0] -= nChildren; } else { for(i=1;iop[0]) m_joints[i].iParent += nChildren; memmove(m_joints+op[0]+1+nChildren, m_joints+op[0]+1, (op[1]-op[0]-1)*sizeof(ae_joint)); } memcpy(m_joints+op[0]+1, pjbuf, nChildren*sizeof(ae_joint)); if (pjbuf!=&jbuf) delete[] pjbuf; JointListUpdated(); } op[1] = op[0]+1; m_joints[op[1]].iParent = op[0]; m_joints[op[1]].q0 = m_joints[op[1]].q; if (op[0]>=0) { m_joints[op[0]].nChildren++; m_joints[op[0]+1].iLevel = m_joints[op[0]].iLevel+1; } else m_joints[op[0]+1].iLevel = 0; for(i=op[0]; i>=0; i=m_joints[i].iParent) m_joints[i].nChildrenTree += m_joints[op[0]+1].nChildrenTree+1; if (params->op[0]==-1 && !m_bGrounded) { m_posPivot = m_joints[op[1]].body.pos; m_offsPivot = m_posPivot-m_pos; } (m_joints[op[1]].flags &= ~joint_expand_hinge) |= joint_expand_hinge & -m_bExpandHinges; MARK_UNUSED(m_joints[op[1]].hingePivot[0]); nChanges++; } else { for(i=0;i<3;i++) if (!is_unused(params->q[i])) { m_joints[op[1]].q[i] = params->q[i]; nChanges++; } if (nChanges) { m_joints[op[1]].q0 = m_joints[op[1]].q; if (!params->bNoUpdate) for(i=op[1];i<=op[1]+m_joints[op[1]].nChildrenTree;i++) SyncBodyWithJoint(i); } } m_bUpdateBodies = 1; return 1; } if (_params->type==pe_params_articulated_body::type_id) { pe_params_articulated_body *params = (pe_params_articulated_body*)_params; if (!is_unused(params->pivot)) { vectorf offs = m_posPivot; m_offsPivot = params->pivot; m_posPivot = m_pos+m_offsPivot; offs = m_posPivot-offs; for(int i=0;ibGrounded)) { m_bGrounded = params->bGrounded; if (m_nJoints>0 && m_joints[0].iParent==-1) { quaternionf qroot = m_joints[0].body.q*m_joints[0].body.qfb; if (m_bGrounded) { if (!is_unused(params->pivot)) { m_joints[0].pivot[1] = params->pivot-m_joints[0].body.pos; m_offsPivot -= m_joints[0].pivot[1]; m_posPivot += m_joints[0].pivot[1]; m_joints[0].pivot[1] = m_joints[0].pivot[1]*qroot; } } else { m_joints[0].pivot[1] = qroot*m_joints[0].pivot[1]; m_offsPivot -= m_joints[0].pivot[1]; m_posPivot -= m_joints[0].pivot[1]; m_joints[0].pivot[1].Set(0,0,0); m_joints[0].flags &= ~all_angles_locked; m_joints[0].limits[0].Set(-1E15,-1E15,-1E15); m_joints[0].limits[1].Set(1E15,1E15,1E15); m_joints[0].ks.Set(0,0,0); m_joints[0].kd.Set(0,0,0); m_acc.Set(0,0,0); m_body.w.Set(0,0,0); m_wacc.Set(0,0,0); } } m_bIaReady = 0; m_simTime = 0; m_bAwake = 1; } if (!is_unused(params->v) && (params->v-m_body.v).len2()>0) { m_body.v = params->v; m_simTime = 0; m_bAwake = 1; } if (!is_unused(params->a) && (params->a-m_acc).len2()>0) { m_acc = params->a; m_simTime = 0; m_bAwake = 1; } if (!is_unused(params->w) && (params->w-m_body.w).len2()>0) { if (m_bGrounded) m_body.w = params->w; else if (m_bIaReady) { matrix3x3f basis_inv = (matrix3x3RMf&)m_joints[0].rotaxes[0]; //m_joints[0].dq = basis_inv.invert()*m_body.w; basis_inv.Invert(); m_joints[0].dq = basis_inv*m_body.w; } m_simTime = 0; m_bAwake = 1; } if (!is_unused(params->wa) && (params->wa-m_wacc).len2()>0) { m_wacc = params->wa; m_simTime = 0; } if (!is_unused(params->scaleBounceResponse)) m_scaleBounceResponse = params->scaleBounceResponse; if (params->bApply_dqext) { for(int i=0;ibAwake)) if (!(m_bAwake = params->bAwake)) m_simTime = 10.0f; int bRecalcPos = 0; if (!is_unused(params->pHost)) { if (m_pHost) { m_pHost->Release(); m_pHost = 0; } if (params->pHost) { (m_pHost = ((CPhysicalPlaceholder*)params->pHost)->GetEntity())->AddRef(); bRecalcPos = 1; } } if (!is_unused(params->bInheritVel)) { m_bInheritVel = params->bInheritVel; bRecalcPos = 1; } if (!is_unused(params->posHostPivot)) { m_posHostPivot = params->posHostPivot; bRecalcPos = 1; } if (bRecalcPos) SyncWithHost(params->bRecalcJoints,0); if (!is_unused(params->bCheckCollisions)) m_bCheckCollisions = params->bCheckCollisions; if (!is_unused(params->bCollisionResp)) m_bCollisionResp = params->bCollisionResp; if (!is_unused(params->nCollLyingMode)) m_nCollLyingMode = params->nCollLyingMode; if (!is_unused(params->gravityLyingMode)) m_gravityLyingMode = params->gravityLyingMode; if (!is_unused(params->dampingLyingMode)) m_dampingLyingMode = params->dampingLyingMode; if (!is_unused(params->minEnergyLyingMode)) m_EminLyingMode = params->minEnergyLyingMode; if (!is_unused(params->iSimType)) m_iSimType = params->iSimType; if (!is_unused(params->iSimTypeLyingMode)) m_iSimTypeLyingMode = params->iSimTypeLyingMode; if (!is_unused(params->bExpandHinges)) m_bExpandHinges = params->bExpandHinges; return 1; } return 0; } int CArticulatedEntity::GetParams(pe_params *_params) { int res = CRigidEntity::GetParams(_params); if (res) return res; if (_params->type==pe_params_joint::type_id) { pe_params_joint *params = (pe_params_joint*)_params; int i; for(i=0;iop[1];i++); if (i>=m_nJoints) return 0; params->flags = m_joints[i].flags; params->pivot = (m_joints[i].body.pos + (m_joints[i].body.q*m_joints[i].body.qfb)*m_joints[i].pivot[1] - m_pos)*m_qrot; params->q0 = m_joints[i].quat0; //if (params->pMtx0) m_joints[i].quat0.getmatrix( (matrix3x3f&)*params->pMtx0 ); //Q2M_IVO if (params->pMtx0) ((matrix3x3f&)*params->pMtx0) = matrix3x3f(m_joints[i].quat0); //if (params->pMtx0T) m_joints[i].quat0.getmatrix((matrix3x3Tf&)*params->pMtx0T); //Q2M_IVO if (params->pMtx0T) ((matrix3x3Tf&)*params->pMtx0T) = matrix3x3f(m_joints[i].quat0); params->limits[0] = m_joints[i].limits[0]; params->limits[1] = m_joints[i].limits[1]; params->bounciness = m_joints[i].bounciness; params->ks = m_joints[i].ks; params->kd = m_joints[i].kd; params->q = m_joints[i].q; params->qext = m_joints[i].qext; params->op[0] = m_joints[i].iParent>=0 ? m_joints[m_joints[i].iParent].idbody : -1; return 1; } if (_params->type==pe_params_articulated_body::type_id) { pe_params_articulated_body *params = (pe_params_articulated_body*)_params; params->bGrounded = m_bGrounded; params->pivot = m_offsPivot; params->a = m_acc; params->wa = m_wacc; params->w = m_body.w; params->v = m_body.v; params->scaleBounceResponse = m_scaleBounceResponse; params->pHost = m_pHost; params->bInheritVel = m_bInheritVel; params->posHostPivot = m_posHostPivot; params->bCheckCollisions = m_bCheckCollisions; params->bCollisionResp = m_bCollisionResp; params->nCollLyingMode = m_nCollLyingMode; params->gravityLyingMode = m_gravityLyingMode; params->dampingLyingMode = m_dampingLyingMode; params->minEnergyLyingMode = m_EminLyingMode; params->iSimType = m_iSimType; params->iSimTypeLyingMode = m_iSimTypeLyingMode; params->bExpandHinges = m_bExpandHinges; return 1; } return 0; } int CArticulatedEntity::GetStatus(pe_status* _status) { if (_status->type==pe_status_joint::type_id) { pe_status_joint *status = (pe_status_joint*)_status; int i; for(i=0;iidChildBody;i++); if (i>=m_nJoints) return 0; status->flags = m_joints[i].flags; status->q = m_joints[i].q; status->qext = m_joints[i].qext; status->dq = m_joints[i].dq; status->quat0 = m_joints[i].quat0; return 1; } if (_status->type==pe_status_dynamics::type_id) { int i; pe_status_dynamics *status = (pe_status_dynamics*)_status; if (!is_unused(status->partid)) for(i=0; ipartid; i++); else i = status->ipart; if ((unsigned int)i>=(unsigned int)m_nParts) { m_body.pos.Set(0,0,0); m_body.M = 0; for(i=0;iv = pbody->v; status->w = pbody->w; status->a = m_gravity + pbody->Fcollision*pbody->Minv; status->wa = pbody->Iinv*(pbody->Tcollision - (pbody->w^pbody->L)); status->centerOfMass = pbody->pos; status->submergedFraction = m_submergedFraction; status->mass = pbody->M; return 1; } int res = CRigidEntity::GetStatus(_status); if (res && _status->type==pe_status_caps::type_id) { pe_status_caps *status = (pe_status_caps*)_status; status->bCanAlterOrientation = 1; } return res; } int CArticulatedEntity::Action(pe_action *_action) { if (_action->type==pe_action_impulse::type_id) { pe_action_impulse *action = (pe_action_impulse*)_action; int i,j; if (m_bCollisionResp && action->impulse.len2()iSource==0) return 1; if (is_unused(action->ipart)) for(i=0; ipartid; i++); else i = action->ipart; ENTITY_VALIDATE("CArticulatedEntity:Action(action_impulse)",action); if (m_flags&pef_monitor_impulses && action->iSource==0 && m_pWorld->m_pEventClient) if (!m_pWorld->m_pEventClient->OnImpulse(this,m_pForeignData,m_iForeignData, action)) return 1; box bbox; vectorf posloc; if ((unsigned int)i>=(unsigned int)m_nParts) { if (is_unused(action->point)) return 0; for(i=0;ipGeom->GetBBox(&bbox); posloc = (m_qrot*m_parts[i].q)*bbox.center + m_qrot*m_parts[i].pos + m_pos; posloc = bbox.Basis*((action->point-posloc)*(m_qrot*m_parts[i].q)); for(j=0;j<3 && posloc[j]=(unsigned int)m_nParts) return 0; } j = m_infos[i].iJoint; vectorf P(zero),L(zero); if (!is_unused(action->impulse)) P += action->impulse; if (!is_unused(action->momentum)) L += action->momentum; else if (!is_unused(action->point)) { // make sure that the point is not too far from the part's bounding box m_parts[i].pPhysGeomProxy->pGeom->GetBBox(&bbox); posloc = (m_qrot*m_parts[i].q)*bbox.center + m_qrot*m_parts[i].pos + m_pos; posloc = bbox.Basis*((action->point-posloc)*(m_qrot*m_parts[i].q)); if (posloc.xpoint-bodypos ^ action->impulse; } } m_joints[j].Pimpact += P; m_joints[j].Limpact += L; if (action->iSource!=1) { m_bAwake = 1; m_simTime = 0; for(i=0;iRepositionEntity(this, 2); } } return 1; } if (_action->type==pe_action_reset::type_id) { for(int idx=0;idxRepositionEntity(this,1); m_body.v.Set(0,0,0); m_body.w.Set(0,0,0); m_body.P.Set(0,0,0); m_body.L.Set(0,0,0); return CRigidEntity::Action(_action); } if (_action->type==pe_action_register_coll_event::type_id) { pe_action_register_coll_event *action = (pe_action_register_coll_event*)_action; m_iCollHistory = m_iCollHistory+1 & sizeof(m_CollHistory)/sizeof(m_CollHistory[0])-1; m_CollHistory[m_iCollHistory].pt = action->pt; m_CollHistory[m_iCollHistory].n = action->n; int i; for(i=0;ipartid[0];i++); RigidBody *pbody = &m_joints[m_infos[i].iJoint].body; m_CollHistory[m_iCollHistory].v[0] = pbody->v+(pbody->w^pbody->pos-action->pt); m_CollHistory[m_iCollHistory].v[1] = action->v; m_CollHistory[m_iCollHistory].mass[0] = pbody->M; m_CollHistory[m_iCollHistory].mass[1] = action->collMass; m_CollHistory[m_iCollHistory].idCollider = m_pWorld->GetPhysicalEntityId(action->pCollider); m_CollHistory[m_iCollHistory].partid[0] = action->partid[0]; m_CollHistory[m_iCollHistory].partid[1] = action->partid[1]; m_CollHistory[m_iCollHistory].idmat[0] = action->idmat[0]; m_CollHistory[m_iCollHistory].idmat[1] = action->idmat[1]; m_CollHistory[m_iCollHistory].age = 0; return 1; } if (_action->type==pe_action_set_velocity::type_id) { pe_action_set_velocity *action = (pe_action_set_velocity*)_action; if (m_nJoints<=0) return 0; if (!is_unused(action->v)) { pe_status_dynamics sd; GetStatus(&sd); pe_action_impulse ai; ai.ipart = m_joints[0].iStartPart; ai.point = sd.centerOfMass; ai.impulse = action->v*m_body.M; Action(&ai); } return 1; } return CRigidEntity::Action(_action); } int CArticulatedEntity::GetPotentialColliders(CPhysicalEntity **&pentlist) { pentlist = m_pCollEntList; return m_nCollEnts; } int CArticulatedEntity::CheckSelfCollision(int ipart0,int ipart1) { return m_joints[m_infos[ipart0].iJoint].selfCollMask & getmask(ipart1); } RigidBody *CArticulatedEntity::GetRigidBody(int ipart) { return (unsigned int)ipart<(unsigned int)m_nParts ? &m_joints[m_infos[ipart].iJoint].body : &m_body; } void CArticulatedEntity::SyncWithHost(int bRecalcJoints, float time_interval) { if (m_pHost) { if (m_pHost->m_iSimClass==7) { m_pHost = 0; return; } pe_status_pos sp; m_pHost->GetStatus(&sp); m_posPivot = sp.q*m_posHostPivot + sp.pos; m_pos = m_posPivot - m_offsPivot; pe_params_pos pp; pp.q = m_pHost->m_qrot; pp.bRecalcBounds = 0; SetParams(&pp); if (m_bInheritVel && time_interval>0) { pe_status_dynamics sd; m_pHost->GetStatus(&sd); float rdt = 1.0f/time_interval; m_acc = (sd.v-m_body.v)*rdt; m_wacc = (sd.w-m_body.w)*rdt; m_body.v = sd.v; m_body.w = sd.w; } if (bRecalcJoints) for(int i=0;iRepositionEntity(this,1); } } void CArticulatedEntity::UpdateJointRotationAxes(int idx) { quaternionf q_parent = m_joints[idx].iParent>=0 ? m_joints[m_joints[idx].iParent].quat : m_qrot; //(q_parent*m_joints[idx].quat0).getmatrix((matrix3x3CMf&)m_joints[idx].rotaxes[0]); //Q2M_IVO ((matrix3x3CMf&)m_joints[idx].rotaxes[0]) = matrix3x3f(q_parent*m_joints[idx].quat0); float angle,cosa,sina; angle = m_joints[idx].q[1]+m_joints[idx].qext[1]; cosa = cos_tpl(angle); sina = sin_tpl(angle); m_joints[idx].rotaxes[0] = m_joints[idx].rotaxes[0].rotated(m_joints[idx].rotaxes[1], cosa,sina); // rot x around y - pitch angle = m_joints[idx].q[2]+m_joints[idx].qext[2]; cosa = cos_tpl(angle); sina = sin_tpl(angle); m_joints[idx].rotaxes[0] = m_joints[idx].rotaxes[0].rotated(m_joints[idx].rotaxes[2], cosa,sina); // rot x around z - yaw m_joints[idx].rotaxes[1] = m_joints[idx].rotaxes[1].rotated(m_joints[idx].rotaxes[2], cosa,sina); // rot y around z } void CArticulatedEntity::CheckForGimbalLock(int idx) { int i; m_joints[idx].flags &= ~(angle0_gimbal_locked*7); if (!(m_joints[idx].flags & angle0_locked*5) && sqr(m_joints[idx].rotaxes[0]*m_joints[idx].rotaxes[2])>0.999f*0.999f) { if (!(m_joints[idx].flags & angle0_locked*7) && cry_fabsf(m_joints[idx].limits[1][0]-m_joints[idx].limits[0][0])>10 && fabsf(m_joints[idx].limits[1][1]-m_joints[idx].limits[0][1])>10 && fabsf(m_joints[idx].limits[1][2]-m_joints[idx].limits[0][2])>10) { // if joint is 3dof w/o limits, just rotate its quat0 to avoid gimbal lock //m_joints[idx].quat0 *= quaternionf(pi/6,m_joints[idx].rotaxes[1]); m_joints[idx].quat0 *= GetRotationAA((float)pi/6,vectorf(0,1,0));//(m_joints[idx].rotaxes[0]+m_joints[idx].rotaxes[1])*(1.0f/sqrt2)); m_joints[idx].bQuat0Changed = 1; SyncJointWithBody(idx,3); } else { i = iszero((int)m_joints[idx].flags & angle0_limit_reached) << 1; // gimbal lock angle that already reached its limit, if this is the case m_joints[idx].flags |= angle0_gimbal_locked<=0) { q_parent = m_joints[m_joints[idx].iParent].quat; pos_parent = m_joints[m_joints[idx].iParent].body.pos; pivot = pos_parent + q_parent*m_joints[idx].pivot[0]; } else { q_parent = m_qrot; pos_parent = pivot = m_posPivot; } if (flags & 1) { // sync geometry UpdateJointRotationAxes(idx); // m_joints[idx].quat = q_parent*m_joints[idx].quat0*quaternionf(m_joints[idx].q+m_joints[idx].qext); m_joints[idx].quat = q_parent*m_joints[idx].quat0*Quat::GetRotationXYZ(m_joints[idx].q+m_joints[idx].qext); m_joints[idx].body.q = m_joints[idx].quat*!m_joints[idx].body.qfb; m_joints[idx].body.pos = pos_parent + q_parent*m_joints[idx].pivot[0] - m_joints[idx].quat*m_joints[idx].pivot[1]; //m_joints[idx].body.q.getmatrix(R); //Q2M_IVO R = matrix3x3f(m_joints[idx].body.q); m_joints[idx].body.Iinv = R*m_joints[idx].body.Ibody_inv*R.T(); m_joints[idx].I = R*m_joints[idx].body.Ibody*R.T(); //((m_joints[idx].body.Iinv=R)*=m_joints[idx].body.Ibody_inv)*=R.T(); //((I=R)*=m_joints[idx].body.Ibody)*=R.T(); for(i=m_joints[idx].iStartPart; i=0) { m_joints[idx].body.w = m_joints[m_joints[idx].iParent].body.w; m_joints[idx].body.v = m_joints[m_joints[idx].iParent].body.v + (m_joints[m_joints[idx].iParent].body.w^m_joints[idx].body.pos-m_joints[m_joints[idx].iParent].body.pos); } else { m_joints[idx].body.v = m_body.v; if (m_bGrounded) { m_joints[idx].body.w = m_body.w; m_joints[idx].body.v += m_body.w^m_joints[idx].body.pos-m_posPivot; } else m_joints[idx].body.w.Set(0,0,0); } for(i=0,wpivot.Set(0,0,0); i<3; i++) wpivot += m_joints[idx].rotaxes[i]*m_joints[idx].dq[i]; m_joints[idx].body.v += wpivot^m_joints[idx].body.pos-pivot; m_joints[idx].body.w += wpivot; m_joints[idx].body.P = m_joints[idx].body.v*m_joints[idx].body.M; m_joints[idx].body.L = m_joints[idx].I*m_joints[idx].body.w; } } void CArticulatedEntity::SyncJointWithBody(int idx, int flags) { if (flags & 1) { // sync angles quaternionf qparent = m_joints[idx].iParent>=0 ? m_joints[m_joints[idx].iParent].quat : m_qrot; m_joints[idx].quat = m_joints[idx].body.q*m_joints[idx].body.qfb; //(!(qparent*m_joints[idx].quat0)*m_joints[idx].quat).GetEulerAngles_XYZ(m_joints[idx].q); //EULER_IVO m_joints[idx].q = Ang3::GetAnglesXYZ( matrix3x3f(!(qparent*m_joints[idx].quat0)*m_joints[idx].quat) ); m_joints[idx].q -= m_joints[idx].qext; UpdateJointRotationAxes(idx); CheckForGimbalLock(idx); } if (flags & 2) { // sync velocities vectorf wrel = m_joints[idx].iParent>=0 ? m_joints[m_joints[idx].iParent].body.w : m_body.w; wrel = m_joints[idx].body.w - wrel; if (!(m_joints[idx].flags & (angle0_locked|angle0_gimbal_locked)*7)) { matrix3x3f Basis_inv = (matrix3x3RMf&)m_joints[idx].rotaxes[0]; //m_joints[idx].dq = wrel*Basis_inv.invert(); // IVO Basis_inv.Invert(); m_joints[idx].dq = wrel*Basis_inv; } else { int i,j,iAxes[3]; for(i=j=0;i<3;i++) if (!(m_joints[idx].flags & (angle0_locked|angle0_gimbal_locked)<m_vars.maxVel)*2; int i,j; vectorf v; for(i=0; i0) for(j=0; jMinv==0 && m_pContacts[j].pent[1]->m_iSimClass>1) { RigidBody *pbody = m_pContacts[j].pbody[1]; vmax = max(vmax,(pbody->v + (pbody->w^pbody->pos-m_pContacts[j].pt[1])).len2()); Emax = m_body.M*sqr(10.0f)*2; // since will allow some extra energy, make sure we restrict the upper limit } } E += m_joints[i].body.M*(m_joints[i].body.v+v).len2() + m_joints[i].body.L*m_joints[i].body.w; } if (time_interval>0) { masktype constraint_mask; v.Set(0,0,0); for(i=0,constraint_mask=0; iMinv==0 && m_pConstraints[i].pent[1]->m_iSimClass>1) { RigidBody *pbody = m_pConstraints[i].pbody[1]; vmax = max(vmax,(pbody->v + (pbody->w^pbody->pos-m_pConstraints[i].pt[1])).len2()); } } E += m_body.M*(v.len2()+vmax); return min_safe(E,Emax); } return E; } float CArticulatedEntity::GetDamping(float time_interval) { float damping = CRigidEntity::GetDamping(time_interval); if (m_nContacts>=m_nCollLyingMode) damping = min(1.0f-m_dampingLyingMode*time_interval, damping); return damping; } int CArticulatedEntity::IsAwake(int ipart) { return (unsigned int)ipart<(unsigned int)m_nParts ? m_joints[m_infos[ipart].iJoint].bAwake : m_bAwake; } int CArticulatedEntity::GetUnprojAxis(int idx, vectorf &axis) { axis.Set(0,0,0); if (!(m_joints[idx].flags & (angle0_limit_reached|angle0_locked|angle0_gimbal_locked)*6)) // y and z axes are not locked return 1; else { int i; for(i=2; i>=0 && m_joints[idx].flags & (angle0_limit_reached|angle0_locked|angle0_gimbal_locked)<=0) { axis = m_joints[idx].rotaxes[i]; // free axis from list: z y x return 1; } } return 0; } inline masktype getContactMask(int iContact) { return iContact>=0 ? getmask(iContact) : 0; } int CArticulatedEntity::StepJoint(int idx, float time_interval,masktype &contact_mask,int &bBounced,int bFlying) { int i,j,idxpivot,ncont,itmax,curidx,sgq,bSelfColl; float qlim[2],dq,curq,e,diff[2],tdiff, minEnergy = m_nContacts>=m_nCollLyingMode ? m_EminLyingMode : m_Emin; vectorf q,n,ptsrc,ptdst,axis,axis0,pivot,prevpt; quaternionf qrot; matrix3x3f R; geom_contact *pcontacts; geom_world_data gwd; intersection_params ip; box bbox; m_joints[idx].prev_q = m_joints[idx].q; m_joints[idx].prev_dq = m_joints[idx].dq; m_joints[idx].prev_pos = m_joints[idx].body.pos; m_joints[idx].prev_qrot = m_joints[idx].body.q; m_joints[idx].prev_v = m_joints[idx].body.v; m_joints[idx].prev_w = m_joints[idx].body.w; m_joints[idx].bHasExtContacts = 0; if (m_iSimTypeCur && m_bCollisionResp) { e = (m_joints[idx].body.v.len2() + (m_joints[idx].body.L*m_joints[idx].body.w)*m_joints[idx].body.Minv)*0.5f + m_joints[idx].body.Eunproj; m_bAwake += (m_joints[idx].bAwake = isneg(minEnergy-e)); m_joints[idx].bAwake |= m_bFloating|m_bUsingUnproj; if (!m_joints[idx].bAwake) { for(i=m_joints[idx].iParent; i>=0; i=m_joints[i].iParent) m_joints[idx].bAwake |= m_joints[i].bAwake; } if (m_joints[idx].bAwake) { m_joints[idx].body.Step(time_interval); SyncJointWithBody(idx,3); } //m_joints[idx].body.q.getmatrix(R); //Q2M_IVO R = matrix3x3f(m_joints[idx].body.q); m_joints[idx].I = R*m_joints[idx].body.Ibody*R.T(); m_joints[idx].dv_body.Set(0,0,0); m_joints[idx].dw_body.Set(0,0,0); m_joints[idx].flags &= ~(angle0_limit_reached*7); q = m_joints[idx].q + m_joints[idx].qext; for(i=0;i<3;i++) if (!(m_joints[idx].flags & (angle0_locked|angle0_gimbal_locked)< m_joints[idx].limits[1][i]) { sgq = sgn(m_joints[idx].q[i]+m_joints[idx].qext[i]); qlim[sgq+1>>1] += (sgq<<1)*pi; } dq = m_joints[idx].dq[i]*time_interval; sgq = sgn(dq); curq = m_joints[idx].q[i]+m_joints[idx].qext[i]; if ((curq + dq - qlim[sgq+1>>1])*sgq > 0) { // we'll breach the limit that lies ahead along movement (ignore the other one) dq = qlim[sgq+1>>1]-curq+sgq*0.01f; dq = sgnnz(dq)*min(fabsf(dq),0.1f+(m_bCollisionResp^1)); // limit angle snapping in full simulation mode m_joints[idx].dq_limit[i] = m_joints[idx].dq[i]; m_joints[idx].flags |= angle0_limit_reached<pi) m_joints[idx].q[i]-=2*pi; //while(m_joints[idx].q[i]<-pi) m_joints[idx].q[i]+=2*pi; } else m_joints[idx].dq[i] = 0; m_joints[idx].body.Step(time_interval); m_joints[idx].dv_body = m_joints[idx].body.v; m_joints[idx].dw_body = m_joints[idx].body.w; SyncBodyWithJoint(idx); m_joints[idx].dv_body = m_joints[idx].body.v-m_joints[idx].dv_body; m_joints[idx].dw_body = m_joints[idx].body.w-m_joints[idx].dw_body; m_joints[idx].ddq.Set(0,0,0); e = (m_joints[idx].body.v.len2() + (m_joints[idx].body.L*m_joints[idx].body.w)*m_joints[idx].body.Minv)*0.5f; m_bAwake += (m_joints[idx].bAwake = isneg(minEnergy-e)); m_joints[idx].bAwake |= m_bFloating; if (!m_joints[idx].bAwake && m_bCollisionResp) { for(i=m_joints[idx].iParent; i>=0; i=m_joints[i].iParent) m_joints[idx].bAwake |= m_joints[i].bAwake; if (!m_joints[idx].bAwake) { m_joints[idx].q = m_joints[idx].prev_q; m_joints[idx].dq.Set(0,0,0); SyncBodyWithJoint(idx); m_joints[idx].body.P.Set(0,0,0); m_joints[idx].body.L.Set(0,0,0); m_joints[idx].body.v.Set(0,0,0); m_joints[idx].body.w.Set(0,0,0); if (idx==0) { m_pos = m_prev_pos; m_posPivot = m_pos+m_offsPivot; m_body.v.zero(); } } } CheckForGimbalLock(idx); } // force persistant contacts to lie in contact plane pivot = m_joints[idx].iParent<0 ? m_posPivot : m_joints[m_joints[idx].iParent].body.pos + m_joints[m_joints[idx].iParent].quat*m_joints[idx].pivot[0]; /*if (m_joints[idx].iContacts) { for(i=0; !(m_joints[idx].iContacts & getmask(i)); i++); n = m_pContacts[i].pbody[m_pContacts[i].iNormal]->q*m_pContacts[i].nloc; e = m_pWorld->m_vars.maxContactGap*0.5f; ptsrc = m_pContacts[i].pbody[0]->q*m_pContacts[i].ptloc[0] + m_pContacts[i].pbody[0]->pos; ptdst = m_pContacts[i].pbody[1]->q*m_pContacts[i].ptloc[1] + m_pContacts[i].pbody[1]->pos + n*e; if (idx==0) m_posPivot += n*(n*(ptdst-ptsrc)+e); else { axis = ptsrc-pivot ^ n*(n*(ptdst-ptsrc)); for(i=0;i<3;i++) if (m_joints[idx].flags & (angle0_limit_reached|angle0_locked|angle0_gimbal_locked)<sqr(6) || m_joints[idx].body.v.len2()>sqr(4)) && m_joints[idx].body.Minv>m_body.Minv*10.0f) { ip.iUnprojectionMode = 1; ip.centerOfRotation = pivot; ip.time_interval = 0.6f; if (!GetUnprojAxis(idx,ip.axisOfRotation)) { ip.iUnprojectionMode = 0; ip.vrel_min = 1E10; } } else { ip.iUnprojectionMode = 0; ip.vrel_min = 1E10; ip.bNoAreaContacts = true; } idxpivot = idx; itmax = -1; ip.bStopAtFirstTri = /*m_timeStepFull>m_maxAllowedStep ||*/ m_joints[idx].body.M0; //if (m_joints[idx].iParent>=0) ip.ptOutsidePivot[0] = m_joints[idx].iParent>=0 ? pivot : m_joints[idx].body.pos; ncont = CheckForNewContacts(&gwd,&ip, itmax, m_joints[idx].iStartPart,m_joints[idx].nParts); pcontacts = ip.pGlobalContacts; /*if (ncont>0 && itmax<0 && ip.iUnprojectionMode==1) { // find parent that has good free axes axis0 = (pcontacts[0].center-ip.centerOfRotation^pcontacts[0].dir).normalized(); for(i=3,idxpivot=m_joints[idxpivot].iParent; i>0 && idxpivot>0; i--,idxpivot=m_joints[idxpivot].iParent) { for(i=0,axis=axis0;i<3;i++) if (m_joints[idxpivot].flags & (angle0_limit_reached|angle0_locked|angle0_gimbal_locked)<0.5f*0.5f) { ip.centerOfRotation = m_joints[idxpivot].body.pos + m_joints[idxpivot].quat*m_joints[idxpivot].pivot[1]; ip.axisOfRotation = GetUnprojAxis(idxpivot); break; } } if (i*idxpivot>0) ncont = CheckForNewContacts(&gwd,&ip, itmax, m_joints[idx].iStartPart,m_joints[idx].nParts); }*/ if (itmax>=0) { if (pcontacts[itmax].iUnprojMode) { //qrot = quaternionf(pcontacts[itmax].t, pcontacts[itmax].dir); qrot.SetRotationAA(pcontacts[itmax].t, pcontacts[itmax].dir); for(i=idxpivot;i<=idx;i++) { // note: update of parent will possibly invalidate its registered contacts, is it crucial? m_joints[i].body.q = qrot*m_joints[i].body.q; m_joints[i].body.pos = ip.centerOfRotation + qrot*(m_joints[i].body.pos-ip.centerOfRotation); SyncJointWithBody(i,3); } if (!m_bCollisionResp) { for(i=0;i<3;i++) if (!(m_joints[idxpivot].flags & (angle0_locked|angle0_gimbal_locked|angle0_limit_reached)<pGeom->GetBBox(&bbox); if (m_nParts>3) m_parts[j].minContactDist = max(max(bbox.size.x,bbox.size.y),bbox.size.z)*m_parts[j].scale*0.4f; for(i=0;i0) for(;j0*/) // register border center only for penetration contacts in marginal joints contact_mask |= m_joints[idx].iContacts |= getContactMask(RegisterContactPoint(contact_mask,i, pcontacts[i].center, pcontacts, pcontacts[i].iPrim[0],pcontacts[i].iFeature[0], pcontacts[i].iPrim[1],pcontacts[i].iFeature[1], contact_new, pcontacts[i].t)); else { //m_parts[m_joints[idx].iStartPart].pPhysGeomProxy->pGeom->GetBBox(&bbox); //e = sqr(max(max(bbox.size.x,bbox.size.y),bbox.size.z)*0.2f); for(j=0,prevpt.zero(); je) { contact_mask |= m_joints[idx].iContacts |= getContactMask(RegisterContactPoint(contact_mask,i, pcontacts[i].ptborder[j], pcontacts, pcontacts[i].iPrim[0],pcontacts[i].iFeature[0], pcontacts[i].iPrim[1],pcontacts[i].iFeature[1], contact_new, pcontacts[i].t)); prevpt = pcontacts[i].ptborder[j]; } } if (!bSelfColl) m_maxPenetrationCur = max(m_maxPenetrationCur,(float)pcontacts[i].t); } else if (pcontacts[i].parea) { // register only points that are sufficiently far away from each other m_parts[m_joints[idx].iStartPart].pPhysGeomProxy->pGeom->GetBBox(&bbox); e = sqr(max(max(bbox.size.x,bbox.size.y),bbox.size.z)*0.8f*(iszero(idx)^1)); prevpt.zero(); for(j=0;jnpt;j++) if ((pcontacts[i].parea->pt[j]-prevpt).len2()>e) { contact_mask |= m_joints[idx].iContacts |= getContactMask(RegisterContactPoint(contact_mask,i, pcontacts[i].parea->pt[j], pcontacts, pcontacts[i].parea->piPrim[0][j], pcontacts[i].parea->piFeature[0][j], pcontacts[i].parea->piPrim[1][j],pcontacts[i].parea->piFeature[1][j])); prevpt = pcontacts[i].parea->pt[j]; } } else contact_mask |= m_joints[idx].iContacts |= getContactMask(RegisterContactPoint(contact_mask,i, pcontacts[i].pt, pcontacts, pcontacts[i].iPrim[0],pcontacts[i].iFeature[0], pcontacts[i].iPrim[1],pcontacts[i].iFeature[1])); } } // iterate children for(i=0,curidx=idx+1; i=m_nCollLyingMode) { gravity = m_gravityLyingMode; m_iSimTypeCur = m_iSimTypeLyingMode; } else { gravity = m_nContacts ? m_gravity : m_gravityFreefall; m_iSimTypeCur = m_iSimType | m_bFloating; } for(i=m_nColliders-1;i>=0;i--) { if (m_pColliders[i]->m_iSimClass==7) RemoveCollider(m_pColliders[i]); else contact_mask |= m_pColliderContacts[i]; } if (m_pHost && m_pHost->m_iSimClass==7) m_pHost = 0; if (m_bUpdateBodies & m_iSimTypeCur) for(i=0;i m_timeStepFull-0.001f) return 1; m_timeStepPerformed += time_interval; for(i=0;i szmax) szmax = m_body.v.len()*time_interval; sz.Set(szmax,szmax,szmax); m_nCollEnts = m_pWorld->GetEntitiesAround(m_BBox[0]-sz,m_BBox[1]+sz, m_pCollEntList, ent_terrain|ent_static|ent_sleeping_rigid|ent_rigid|ent_living|ent_independent|ent_sort_by_mass|ent_triggers, this); for(i=0;im_iSimClass>2 && m_pCollEntList[i]->GetType()!=PE_ARTICULATED) m_pCollEntList[i]->Awake(); if (m_iSimClass<=2) { for(i=j=0;im_iSimClass<=2 && (m_pCollEntList[i]->m_iGroup==m_iGroup && m_pCollEntList[i]->m_bMoved || !m_pCollEntList[i]->IsAwake() || m_pWorld->m_pGroupNums[m_pCollEntList[i]->m_iGroup]m_pGroupNums[m_iGroup])) m_pCollEntList[j++] = m_pCollEntList[i]; m_nCollEnts = j; } else m_nCollEnts = 0; } else m_nCollEnts = 0; for(i=m_bFastLimbs=0; ipGeom->GetBBox(&bbox); r = sqr(max(max(bbox.size.x,bbox.size.y),bbox.size.z)*m_parts[m_joints[i].iStartPart].scale); m_bFastLimbs |= isneg(r-(m_joints[i].body.v.len2()+m_joints[i].body.w.len2()*r)*sqr(time_interval)); }*/ m_iSimTypeCur &= m_bFastLimbs^1; m_iSimTypeCur |= m_iSimTypeOverride; m_qrot.SetIdentity(); m_bPartPosForced = 0; m_prev_pos = m_pos; m_prev_vel = m_body.v; if (!m_bGrounded) if (m_iSimTypeCur==0) m_posPivot += m_body.v*time_interval; else m_posPivot = m_joints[0].body.pos; m_pos = m_posPivot - m_offsPivot; m_bAwake = isneg(m_simTime-2.5f) | (iszero(m_nContacts) & (m_bGrounded^1) & (m_bFloating^1)); m_simTime += time_interval; m_simTimeAux += time_interval; m_maxPenetrationCur = 0; StepJoint(0, time_interval, contact_mask,bBounced, iszero(m_nContacts)); m_bAwake = isneg(-m_bAwake); m_nContacts = m_nDynContacts = 0; if (m_bCollisionResp) { contact_mask = VerifyExistingContacts(m_pWorld->m_vars.maxContactGap); ApplyBuoyancy(time_interval,gravity); for(i=0;i0 || m_joints[i].Limpact.len2()>0) { m_joints[i].body.P += m_joints[i].Pimpact; m_joints[i].body.L += m_joints[i].Limpact; m_joints[i].body.v = m_joints[i].body.P*m_joints[i].body.Minv; m_joints[i].body.w = m_joints[i].body.Iinv*m_joints[i].body.L; m_joints[i].Pimpact.zero(); m_joints[i].Limpact.zero(); } m_joints[i].iContacts &= contact_mask; for(j=0;jRepositionEntity(this,1); m_bAwake = bWasAwake; m_bSteppedBack = 0; // do not request step back if we were in deep penetration state initially i = m_iSimTypeCur | isneg(m_maxPenetrationCur-0.07f) | isneg(0.07f-maxPenetrationPrev); if (!i) m_simTimeAux = 0; return i | isneg(3-m_nStepBackCount); } if (!m_joints[0].fs) for(i=0;iQ.zero(); m_joints[i].fs->Ya_vec[0].zero(); m_joints[i].fs->Ya_vec[1].zero(); #if defined(LINUX) ((matrix3x3RMf&)(*reinterpret_cast(&(m_joints[i].fs->qinv)))).SetIdentity(); #else ((matrix3x3RMf&)m_joints[i].fs->qinv).SetIdentity(); #endif } if (bBounced && m_bIaReady) { // apply bounce impulses at joints that reached their limits bBounced=0; CollectPendingImpulses(0,bBounced); if (bBounced) { PropagateImpulses(dv = m_M0inv*-m_Ya_vec[0]); if (!m_bGrounded) m_body.v += dv; } } if (m_simTime>10) { for(i=0;iGetSpatialContactMatrix(m_posPivot, -1, Ihost_inv); M0host = (matrix3x3in6x6f&)Ihost_inv[3][0]; } if (M0host.IsZero()) m_M0inv.SetZero(); else { //(m_M0inv += M0host.invert()).invert(); M0host.Invert(); (m_M0inv+=M0host).Invert(); } } else m_M0inv.Invert(); m_bIaReady = 1; Za.zero(); CalcBodyZa(0, time_interval,Za); CalcBodiesIinv(m_bCollisionResp); for(i=0;iAction(&ai); } ComputeBBox(); m_pWorld->RepositionEntity(this,1); return isneg(m_timeStepFull-m_timeStepPerformed-0.001f); } void CArticulatedEntity::StepBack(float time_interval) { if (m_simTime>0) { matrix3x3f R; m_pos = m_prev_pos; m_posPivot = m_pos+m_offsPivot; m_body.P = (m_body.v=m_prev_vel)*m_body.M; for(int i=0;i=0 ? m_joints[m_joints[i].iParent].iLevel+1 : 0; } int CArticulatedEntity::GetStateSnapshot(CStream &stm,float time_back,int flags) { stm.WriteNumberInBits(SNAPSHOT_VERSION,4); stm.Write((unsigned char)m_nJoints); stm.Write(m_pos); stm.Write(m_body.v); stm.Write(m_bAwake!=0); int i = m_iSimClass-1; stm.WriteNumberInBits(i,2); #ifdef DEBUG_BONES_SYNC stm.WriteBits((BYTE*)&m_qrot,sizeof(m_qrot)*8); for(i=0;i0) { stm.Write(true); stm.Write(m_joints[i].body.P); stm.Write(m_joints[i].body.L); } else stm.Write(false); WritePacked(stm,m_joints[i].iContacts); } WriteContacts(stm,flags); return 1; } int CArticulatedEntity::SetStateFromSnapshot(CStream &stm, int flags) { int i=0,j,ver=0; bool bnz; matrix3x3f R; unsigned char nJoints; stm.ReadNumberInBits(ver,4); if (ver!=SNAPSHOT_VERSION) return 0; stm.Read(nJoints); if (nJoints!=m_nJoints) return 0; if (!(flags & ssf_no_update)) { stm.Read(m_pos); stm.Read(m_body.v); stm.Read(bnz); m_bAwake = bnz ? 1:0; stm.ReadNumberInBits(i, 2); m_iSimClass=i+1; #ifdef DEBUG_BONES_SYNC stm.ReadBits((BYTE*)&m_qrot,sizeof(m_qrot)*8); for(i=0;iRepositionEntity(this); } else { masktype dummy; stm.Seek(stm.GetReadPos()+2*sizeof(vectorf)*8+3); #ifdef DEBUG_BONES_SYNC stm.Seek(stm.GetReadPos()+sizeof(quaternionf)*8+m_nParts*(sizeof(quaternionf)+sizeof(vectorf))*8); #else for(i=0;iQ),Qtmp(3,qbuf); vectorf d,r,pos_parent,Qscale; quaternionf q_parent; vectorf Za_vec[2]; vectornf Za(6,Za_vec[0]); if (m_joints[idx].iParent>=0) { pos_parent = m_joints[m_joints[idx].iParent].body.pos; q_parent = m_joints[m_joints[idx].iParent].quat; } else { pos_parent = m_posPivot; q_parent = m_qrot; } d = m_joints[idx].body.pos - (pos_parent + q_parent*m_joints[idx].pivot[0]); r = m_joints[idx].body.pos - pos_parent; if (m_joints[idx].flags & joint_no_gravity) Za_vec[0].zero(); else Za_vec[0] = m_gravity*-m_joints[idx].body.M*time_interval; Za_vec[1].zero() = (m_joints[idx].body.w^m_joints[idx].I*m_joints[idx].body.w)*time_interval; Za_vec[0] += m_joints[idx].dv_body*m_joints[idx].body.M; Za_vec[1] += m_joints[idx].I*m_joints[idx].dw_body; m_joints[idx].fs->Q.zero(); m_joints[idx].ddq.zero(); if (!(m_joints[idx].flags & joint_isolated_accelerations)) for(j=0;jqinv[j*(m_joints[idx].nPotentialAngles+1)]; else Qscale.Set(1.0f,1.0f,1.0f); // calculate torque vector and spatial joint axes for(j=0;jaxidx2qidx[j]; kd = fabsf(m_joints[idx].dq[i])>15.0f ? 0 : m_joints[idx].kd[i]; k = time_interval*Qscale[j]; Q[j] = (m_joints[idx].ks[i]*m_joints[idx].q[i] + kd*m_joints[idx].dq[i])*-k; // if the joint is approaching limit (but haven't breached it yet) and is in dashpot area, damp the velocity if (fabsf(m_joints[idx].dq[i])>0.5f) { idir = isneg(m_joints[idx].dq[i])^1; tlim = m_joints[idx].q[i]-m_joints[idx].limits[idir][i]; if (tlim<-pi) tlim += 2*pi; if (tlim>pi) tlim -= 2*pi; tlim *= idir*2-1; qdashpot = m_joints[idx].qdashpot[i]; dq_dashpot = min(fabsf(m_joints[idx].dq[i])*Qscale[j], (qdashpot-tlim)*m_joints[idx].kdashpot[i]*isneg(fabsf(tlim-2*qdashpot)-qdashpot)*k); Q[j] += dq_dashpot*(1-idir*2); } } if (!(m_joints[idx].flags & (angle0_locked|angle0_gimbal_locked)*5)) { // take into accout that x and z axes influence one another Q[m_joints[idx].fs->qidx2axidx[0]] += Q[m_joints[idx].fs->qidx2axidx[2]]*(m_joints[idx].rotaxes[0]*m_joints[idx].rotaxes[2]); Q[m_joints[idx].fs->qidx2axidx[2]] += Q[m_joints[idx].fs->qidx2axidx[0]]*(m_joints[idx].rotaxes[0]*m_joints[idx].rotaxes[2]); } if (m_joints[idx].flags & joint_isolated_accelerations) m_joints[idx].ddq = m_joints[idx].fs->Q; vectorf Za_child_vec[2]; vectornf Za_child(6,Za_child_vec[0]); // iterate all children, accumulate Za for(i=0,curidx=idx+1; i0) { matrixf sT(Q.len = m_joints[idx].nActiveAngles,6,0, m_joints[idx].fs->s_vec[0][0]); matrixf qinv_down(m_joints[idx].nActiveAngles,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->qinv_down); matrixf Ia_s(6,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->Ia_s); if (!(m_joints[idx].flags & joint_isolated_accelerations)) ddq = qinv_down*((Qtmp=Q)-=sT*Za); Za_change += Ia_s*ddq; } if (m_joints[idx].nActiveAngless_vec[0][0]); matrixf qinv(m_joints[idx].nPotentialAngles,m_joints[idx].nPotentialAngles,0, m_joints[idx].fs->qinv); matrixf qinv_sT(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT[0]); ddq = qinv*((Qtmp=Q)-=sT*Za); } return curidx; } int CArticulatedEntity::CalcBodyIa(int idx, matrixf& Ia_change) { int i,j,curidx,nextidx; vectorf d,r,pos_parent; quaternionf q_parent; if (m_joints[idx].iParent>=0) { pos_parent = m_joints[m_joints[idx].iParent].body.pos; q_parent = m_joints[m_joints[idx].iParent].quat; } else { pos_parent = m_posPivot; q_parent = m_qrot; } d = m_joints[idx].body.pos - (pos_parent + q_parent*m_joints[idx].pivot[0]); r = m_joints[idx].body.pos - pos_parent; // fill initial Ia matrixf Ia(6,6,0,m_joints[idx].fs->Ia[0]); Ia.zero(); (matrix3x3in6x6f&)m_joints[idx].fs->Ia[0][3] = vectorf(m_joints[idx].body.M,m_joints[idx].body.M,m_joints[idx].body.M); (matrix3x3in6x6f&)m_joints[idx].fs->Ia[3][0] = m_joints[idx].I; // sort axes so that active angles' axes come first for (i=j=0;i<3;i++) if (!(m_joints[idx].flags & (angle0_locked|angle0_limit_reached|angle0_gimbal_locked)<qidx2axidx[i] = j; m_joints[idx].fs->axidx2qidx[j++] = i; } m_joints[idx].nActiveAngles = j; for (i=0;i<3;i++) if ((m_joints[idx].flags & (angle0_locked|angle0_limit_reached)<qidx2axidx[i] = j; m_joints[idx].fs->axidx2qidx[j++] = i; } m_joints[idx].nPotentialAngles = j; for(j=0;jaxidx2qidx[j]; m_joints[idx].fs->s_vec[j][0] = m_joints[idx].rotaxes[i]^d; m_joints[idx].fs->s_vec[j][1] = m_joints[idx].rotaxes[i]; } float buf[39]; matrixf Ia_child(6,6,0,_align16(buf)); // iterate all children, accumulate Ia for(i=0,curidx=idx+1; is_vec[0][0]); matrixf s(6,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->s); matrixf Ia_s_qinv_sT(6,6,0, m_joints[idx].fs->Ia_s_qinv_sT[0]); matrixf qinv(m_joints[idx].nActiveAngles,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->qinv); if (m_joints[idx].nActiveAngles>0) { SpatialTranspose(sT, s); matrixf Ia_s(6,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->Ia_s); matrixf qinv_down(m_joints[idx].nActiveAngles,m_joints[idx].nActiveAngles,0, m_joints[idx].fs->qinv_down); matrixf Ia_s_qinv(6,m_joints[idx].nActiveAngles,0, buf); Ia_s = Ia*s; qinv = (qinv_down = sT*Ia_s).invert(); Ia_s_qinv_sT = (Ia_s_qinv = Ia_s*qinv)*sT; Ia_change -= Ia_s_qinv_sT*Ia; Ia_s_qinv_sT *= -1.0f; } else Ia_s_qinv_sT.zero(); for(i=0;i<6;i++) m_joints[idx].fs->Ia_s_qinv_sT[i][i] += 1; r = m_joints[idx].body.pos - pos_parent; LeftOffsetSpatialMatrix(Ia_s_qinv_sT, r); if (m_joints[idx].nPotentialAngles>0) { // precalculate matrices for velocity propagation up - use limited angles also matrixf qinv_sT(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT[0]); matrixf qinv_sT_Ia(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT_Ia[0]); matrixf sT_Ia(m_joints[idx].nPotentialAngles,6,0, buf); if (m_joints[idx].nActiveAngles < m_joints[idx].nPotentialAngles) { sT.nRows = m_joints[idx].nPotentialAngles; SpatialTranspose(sT, s); (qinv = (sT_Ia = sT*Ia)*s).invert(); } (qinv_sT = qinv*sT)*=-1.0f; qinv_sT_Ia = qinv_sT*Ia; //matrixf(6,6,0,m_joints[idx].s_qinv_sT_Ia[0]) = s*qinv_sT_Ia; } return curidx; } int CArticulatedEntity::CollectPendingImpulses(int idx,int &bNotZero) { int i,j,curidx,newidx,bChildNotZero; bNotZero = 0; for(i=0;i<3;i++) if (!is_unused(m_joints[idx].dq_req[i])) { // note that articulation matrices from the previous frame are used, while rotaxes are already new; this introduces slight inconsistency //matrix3x3bf K; GetJointTorqueResponseMatrix(idx, K); //float resp = m_joints[idx].rotaxes[i]*K*m_joints[idx].rotaxes[i]; float buf[39],buf1[39]; matrixf Mresp(6,6,0,_align16(buf)),MrespLoc(6,6,0,_align16(buf1)); MrespLoc = matrixf(6,6,0,m_joints[idx].fs->Ia_s_qinv_sT[0]); for(j=0;j<6;j++) MrespLoc[j][j] -= 1.0f; Mresp = matrixf(6,6,0,m_joints[m_joints[idx].iParent].fs->Iinv[0])*MrespLoc; LeftOffsetSpatialMatrix(Mresp,m_joints[m_joints[idx].iParent].body.pos-m_joints[idx].body.pos); j = m_joints[idx].fs->qidx2axidx[i]; vectorf axis = m_joints[idx].rotaxes[i], dw = (matrix3x3in6x6f&)Mresp[0][3]*axis, dv = (matrix3x3in6x6f&)Mresp[3][3]*axis; float resp = -(vectorf(m_joints[idx].fs->qinv_sT[j]+3)*axis); resp -= vectorf(m_joints[idx].fs->qinv_sT_Ia[j])*dw + vectorf(m_joints[idx].fs->qinv_sT_Ia[j]+3)*dv; if (resp>0.1f*m_body.Minv) { resp = (m_joints[idx].dq_req[i]-m_joints[idx].dq[i])/resp*m_scaleBounceResponse; m_joints[idx].fs->Ya_vec[1] -= m_joints[idx].rotaxes[i]*resp; if (m_joints[idx].iParent>=0) m_joints[m_joints[idx].iParent].fs->Ya_vec[1] += m_joints[idx].rotaxes[i]*resp; bNotZero++; } } if (bNotZero += isneg(1E-6-m_joints[idx].Pext.len2()-m_joints[idx].Lext.len2())) { m_joints[idx].fs->Ya_vec[0] -= m_joints[idx].Pext; m_joints[idx].Pext.zero(); m_joints[idx].fs->Ya_vec[1] -= m_joints[idx].Lext; m_joints[idx].Lext.zero(); } for(i=0,curidx=idx+1; iIa_s_qinv_sT[0]); vectornf Ya(6,m_joints[idx].fs->Ya_vec[0]); vectornf Ya_child(6,m_joints[curidx].fs->Ya_vec[0]); Ya += Ia_s_qinv_sT*Ya_child; bNotZero += bChildNotZero; } curidx = newidx; } if (idx==0) { #if defined(LINUX) vectornf(6,(float*)(m_Ya_vec[0])) = ::operator*((const matrix_tpl &)matrixf(6,6,0,m_joints[0].fs->Ia_s_qinv_sT[0]), (const vectorn_tpl&)vectornf(6,m_joints[0].fs->Ya_vec[0])); #else vectornf(6,m_Ya_vec[0]) = matrixf(6,6,0,m_joints[0].fs->Ia_s_qinv_sT[0])*vectornf(6,m_joints[0].fs->Ya_vec[0]); #endif } return curidx; } void CArticulatedEntity::PropagateImpulses(const vectorf &dv, int bLockLimits) { int idx,i,j,bHitsLimit; vectorf pos_parent; for(idx=0; idxdv_vec[0]); if (m_joints[idx].iParent>=0) { m_joints[idx].fs->dv_vec[0] = m_joints[m_joints[idx].iParent].fs->dv_vec[0]; m_joints[idx].fs->dv_vec[1] = m_joints[m_joints[idx].iParent].fs->dv_vec[1]; pos_parent = m_joints[m_joints[idx].iParent].body.pos; } else { m_joints[idx].fs->dv_vec[0].zero(); m_joints[idx].fs->dv_vec[1] = dv; pos_parent = m_posPivot; } m_joints[idx].fs->dv_vec[1] += m_joints[idx].fs->dv_vec[0] ^ m_joints[idx].body.pos-pos_parent; if (m_joints[idx].nPotentialAngles>0) { vectornf ddq(m_joints[idx].nPotentialAngles, m_joints[idx].ddq); matrixf qinv_sT_Ia(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT_Ia[0]); matrixf qinv_sT(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT[0]); vectornf Ya(6,m_joints[idx].fs->Ya_vec[0]); matrixf s(6,m_joints[idx].nPotentialAngles,0, m_joints[idx].fs->s); ddq = qinv_sT_Ia*dv_spat; ddq += qinv_sT*Ya; for(i=0; iaxidx2qidx[i]; if (!is_unused(m_joints[idx].dq_req[j])) { m_joints[idx].ddq[i] = m_joints[idx].dq_req[j]-m_joints[idx].dq[j]; MARK_UNUSED m_joints[idx].dq_req[j]; } else if (m_joints[idx].flags & angle0_limit_reached<Ya_vec[0].zero(); m_joints[idx].fs->Ya_vec[1].zero(); } } void CArticulatedEntity::CalcVelocityChanges(float time_interval, const vectorf &dv,const vectorf &dw) { int idx,i,j; vectorf pos_parent; for(idx=0; idxdv_vec[0]); if (m_joints[idx].iParent>=0) { m_joints[idx].fs->dv_vec[0] = m_joints[m_joints[idx].iParent].fs->dv_vec[0]; m_joints[idx].fs->dv_vec[1] = m_joints[m_joints[idx].iParent].fs->dv_vec[1]; pos_parent = m_joints[m_joints[idx].iParent].body.pos; } else { m_joints[idx].fs->dv_vec[0] = dw; m_joints[idx].fs->dv_vec[1] = dv; pos_parent = m_posPivot; } m_joints[idx].fs->dv_vec[1] += m_joints[idx].fs->dv_vec[0] ^ m_joints[idx].body.pos-pos_parent; if (m_joints[idx].nPotentialAngles>0) { vectornf ddq(m_joints[idx].nPotentialAngles, m_joints[idx].ddq); matrixf qinv_sT(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT[0]); vectornf Ya(6,m_joints[idx].fs->Ya_vec[0]); matrixf qinv_sT_Ia(m_joints[idx].nPotentialAngles,6,0, m_joints[idx].fs->qinv_sT_Ia[0]); matrixf s(6,m_joints[idx].nPotentialAngles,0, m_joints[idx].fs->s); ddq += qinv_sT_Ia*dv_spat; ddq += qinv_sT*Ya; for(i=0; iaxidx2qidx[i]; if (m_joints[idx].flags & angle0_limit_reached<0) m_joints[idx].ddq[i] = 0; // do not accelerate angle that reached its limit m_joints[idx].dq[j] += m_joints[idx].ddq[i]; } dv_spat += s*ddq; } m_joints[idx].fs->Ya_vec[0].zero(); m_joints[idx].fs->Ya_vec[1].zero(); } } int CArticulatedEntity::OnRegisterContact(entity_contact *pcontact, int iop) { if (pcontact->pent[iop^1]!=this) { m_nContacts++; m_nDynContacts -= -pcontact->pent[iop^1]->m_iSimClass >> 31; m_joints[m_infos[pcontact->ipart[iop]].iJoint].bHasExtContacts = 1; } // force simtype 1 in case of character-vehicle interaction //m_iSimTypeOverride |= inrange(pcontact->pbody[iop^1]->Minv,1E-8f,m_body.Minv*0.1f); return 1; } void CArticulatedEntity::CalcBodiesIinv(int bLockLimits) { int idx,i,nAngles; float Iinv_buf[39],aux_buf[39],Mright_buf[39],s_buf[18],qinv_sT_buf[18]; vectorf r,pos_parent; matrixf Iinv_parent(6,6,0,_align16(Iinv_buf)),Iaux(6,6,0,_align16(aux_buf)); memset(Iinv_buf,0,sizeof(Iinv_buf)); ((matrix3x3in6x6f&)Iinv_parent.data[18] = m_M0inv) *=- 1.0f; for(idx=0; idx=0) { Iinv_parent.data = m_joints[m_joints[idx].iParent].fs->Iinv[0]; pos_parent = m_joints[m_joints[idx].iParent].body.pos; } else { Iinv_parent.data = _align16(Iinv_buf); pos_parent = m_posPivot; } matrixf Iinv(6,6,0,m_joints[idx].fs->Iinv[0]); matrixf s_qinv_sT_Ia(6,6,0, m_joints[idx].fs->s_qinv_sT_Ia[0]); r = m_joints[idx].body.pos-pos_parent; nAngles = bLockLimits ? m_joints[idx].nActiveAngles : m_joints[idx].nPotentialAngles; if (nAngles>0) { matrixf Mright(6,6,0,_align16(Mright_buf)),s(6,nAngles,0,m_joints[idx].fs->s); matrixf Ia(6,6,0, m_joints[idx].fs->Ia[0]); matrixf s_qinv_sT(6,6,0,m_joints[idx].fs->s_qinv_sT[0]); matrixf qinv_sT(nAngles,6,0,m_joints[idx].fs->qinv_sT[0]); if (nAngles!=m_joints[idx].nPotentialAngles) { matrixf sT(6,nAngles,0, m_joints[idx].fs->s_vec[0][0]); s.data = s_buf; SpatialTranspose(sT,s); qinv_sT.data = qinv_sT_buf; qinv_sT = matrixf(nAngles,nAngles,0,m_joints[idx].fs->qinv_down)*sT; } s_qinv_sT = s*qinv_sT; // already with '-' sign Iinv = s_qinv_sT*Ia; for(i=0;i<6;i++) Iinv.data[i*7] += 1.0f; RightOffsetSpatialMatrix(Iinv, -r); s_qinv_sT_Ia = Iinv; //Mright = Iinv_parent; //LeftOffsetSpatialMatrix(Mright, -r); //RightOffsetSpatialMatrix(Mright, r); Iinv = (Iaux=Iinv)*Iinv_parent; //Mright; if (nAngles == m_joints[idx].nActiveAngles) Iinv = (Iaux=Iinv)*matrixf(6,6,0,m_joints[idx].fs->Ia_s_qinv_sT[0]); else { Mright = Ia*s_qinv_sT; for(i=0;i<6;i++) Mright.data[i*7] += 1.0f; LeftOffsetSpatialMatrix(Mright, r); Iinv = (Iaux=Iinv)*Mright; } Iinv += s_qinv_sT; } else { Iinv = Iinv_parent; LeftOffsetSpatialMatrix(Iinv, -r); RightOffsetSpatialMatrix(Iinv, r); s_qinv_sT_Ia.identity(); RightOffsetSpatialMatrix(s_qinv_sT_Ia, -r); } } } void CArticulatedEntity::GetContactMatrix(const vectorf &pt, int ipart, matrix3x3f &K) { m_joints[m_infos[ipart].iJoint].body.GetContactMatrix(pt-m_joints[m_infos[ipart].iJoint].body.pos,K); } void CArticulatedEntity::GetJointTorqueResponseMatrix(int idx, matrix3x3f &K) { matrix3x3in6x6f& Lw((matrix3x3in6x6f&)m_joints[idx].fs->Iinv[0][3]); (K = Lw) *=- 1.0; if (m_joints[idx].iParent>=0) { matrix3x3in6x6f &ww_up((matrix3x3in6x6f&)*(matrix3x3in6x6f*)m_joints[idx].fs->s_qinv_sT_Ia[0]), &vw_up((matrix3x3in6x6f&)m_joints[idx].fs->s_qinv_sT_Ia[0][3]), &LL_down((matrix3x3in6x6f&)m_joints[idx].fs->Ia_s_qinv_sT[3][3]), &LP_down((matrix3x3in6x6f&)m_joints[idx].fs->Ia_s_qinv_sT[0][3]), &Lv_parent((matrix3x3in6x6f&)m_joints[m_joints[idx].iParent].fs->Iinv[3][3]), &Lw_parent((matrix3x3in6x6f&)m_joints[m_joints[idx].iParent].fs->Iinv[0][3]), &Pw_parent((matrix3x3in6x6f&)m_joints[m_joints[idx].iParent].fs->Iinv[0][0]); //matrix3x3bf rmtx; //(m_joints[idx].body.pos-m_joints[m_joints[idx].iParent].body.pos).crossproduct_matrix(rmtx); K += vw_up*Lv_parent;//-rmtx*Lw_parent); K += ww_up*Lw_parent; K += Pw_parent*LP_down; K += Lw_parent*LL_down; K -= Lw_parent; } } entity_contact *CArticulatedEntity::CreateConstraintContact(int idx) { entity_contact *pcontact = (entity_contact*)AllocSolverTmpBuf(sizeof(entity_contact)); if (!pcontact) return 0; pcontact->flags = 0; pcontact->pent[0] = this; pcontact->pbody[0] = &m_joints[idx].body; pcontact->ipart[0] = m_joints[idx].iStartPart; if (m_joints[idx].iParent>=0) { pcontact->pent[1] = this; pcontact->pbody[1] = &m_joints[m_joints[idx].iParent].body; pcontact->ipart[1] = m_joints[m_joints[idx].iParent].iStartPart; } else { pcontact->pent[1] = &g_StaticPhysicalEntity; pcontact->pbody[1] = &g_StaticRigidBody; pcontact->ipart[1] = 0; } pcontact->friction = 0; pcontact->vreq.zero(); pcontact->pt[0] = pcontact->pt[1] = m_joints[idx].body.pos + m_joints[idx].quat*m_joints[idx].pivot[1]; pcontact->K.SetZero(); return pcontact; } int CArticulatedEntity::RegisterContacts(float time_interval,int nMaxPlaneContacts) { int idx,i,j,iAxes[3]; masktype contacts_mask,constraints_mask; entity_contact *pcontact; __ae_step++; UpdateConstraints(); for(i=0,contacts_mask=constraints_mask=0;im_joints[idx].iContacts) // register only the last contact in history ArchiveContact(i); } for(i=0;i=0) { vectorf pivot[2],axisDrift(zero); if (!(pcontact = CreateConstraintContact(idx))) break; pcontact->flags = contact_constraint_3dof; GetContactMatrix(pcontact->pt[0], pcontact->ipart[0], pcontact->K); if (m_joints[idx].iParent>=0) { GetContactMatrix(pcontact->pt[0], pcontact->ipart[1], pcontact->K); pivot[0] = m_joints[m_joints[idx].iParent].body.pos + m_joints[m_joints[idx].iParent].quat*m_joints[idx].pivot[0]; } else pivot[0] = m_posPivot; pivot[1] = m_joints[idx].body.pos + m_joints[idx].quat*m_joints[idx].pivot[1]; if (m_iSimTypeCur && (pivot[0]-pivot[1]).len2()>sqr(0.003f)) { pcontact->vreq = (pivot[0]-pivot[1])*10.0f; pcontact->n = pcontact->vreq.normalized(); if (pcontact->vreq.len2()>sqr(10.0f)) pcontact->vreq = pcontact->n*10.0f; pcontact->pt[1] = pivot[0]; } else pcontact->n.Set(0,0,1); RegisterContact(pcontact); for(i=j=0;i<3;i++) if (!(m_joints[idx].flags & (angle0_locked|angle0_gimbal_locked)<pGeom->GetBBox(&bbox); cyl.axis = m_joints[idx].rotaxes[iAxes[0]]; cyl.center.zero(); cyl.r = (bbox.size.x+bbox.size.y+bbox.size.z)*m_parts[i].scale*0.05f; cyl.hh = cyl.r*0.2f; cylgeom.CreateCylinder(&cyl); gwd[0].offset = m_pos + m_qrot*m_parts[i].pos; //(m_qrot*m_parts[i].q).getmatrix(gwd[0].R); //Q2M_IVO gwd[0].R = matrix3x3f(m_qrot*m_parts[i].q); gwd[0].scale = m_parts[i].scale; gwd[1].offset = pcontact->pt[0]; gwd[1].v = -m_joints[idx].rotaxes[iAxes[0]]; ip.iUnprojectionMode = 0; ip.time_interval = 1E10; if (m_parts[i].pPhysGeomProxy->pGeom->Intersect(&cylgeom, gwd+1,gwd, &ip, punproj)) { punproj->t -= cyl.hh; m_joints[idx].hingePivot[1] = m_joints[idx].pivot[1] + (m_joints[idx].rotaxes[iAxes[0]]*m_joints[idx].quat)*punproj->t; m_joints[idx].hingePivot[0] = m_joints[idx].iParent>=0 ? m_joints[idx].pivot[0] + (m_joints[idx].rotaxes[iAxes[0]]*m_joints[m_joints[idx].iParent].quat)*punproj->t : m_posPivot + m_joints[idx].rotaxes[iAxes[0]]*punproj->t; } else m_joints[idx].flags &= ~joint_expand_hinge; } if (m_joints[idx].flags & joint_expand_hinge) { pcontact->flags = contact_constraint_3dof; pcontact->pt[0] = m_joints[idx].body.pos + m_joints[idx].quat*m_joints[idx].hingePivot[1]; GetContactMatrix(pcontact->pt[0], pcontact->ipart[0], pcontact->K); if (m_joints[idx].iParent>=0) { GetContactMatrix(pcontact->pt[0], pcontact->ipart[1], pcontact->K); pcontact->pt[1] = m_joints[m_joints[idx].iParent].body.pos + m_joints[m_joints[idx].iParent].quat*m_joints[idx].hingePivot[0]; } else pcontact->pt[1] = m_joints[idx].hingePivot[0]; if ((pcontact->pt[0]-pcontact->pt[1]).len2()>sqr(0.003f)) { pcontact->vreq = (pivot[0]-pivot[1])*10.0f; pcontact->n = pcontact->vreq.normalized(); if (pcontact->vreq.len2()>sqr(10.0f)) pcontact->vreq = pcontact->n*10.0f; } else pcontact->n.Set(0,0,1); } } pcontact->K = m_joints[idx].body.Iinv; if (m_joints[idx].iParent>=0) pcontact->K += m_joints[m_joints[idx].iParent].body.Iinv; if (j==2) { // 2 free axes, 1 axis locked pcontact->flags = contact_constraint_2dof | contact_angular; pcontact->n = (m_joints[idx].rotaxes[iAxes[0]]^m_joints[idx].rotaxes[iAxes[1]]).normalized(); pcontact->vreq = pcontact->n*min(5.0f,(axisDrift*pcontact->n)*6.0f); } else { // 1 free axis, 2 axes locked pcontact->flags = contact_constraint_1dof | contact_angular; pcontact->n = m_joints[idx].rotaxes[iAxes[0]]; pcontact->vreq = (axisDrift-pcontact->n*(pcontact->n*axisDrift))*6.0f; if (pcontact->vreq.len2()>sqr(5.0f)) pcontact->vreq.normalize() *= 5.0f; } RegisterContact(pcontact); } for(i=0;i<3;i++) if (m_joints[idx].flags & angle0_limit_reached<K = m_joints[idx].body.Iinv; if (m_joints[idx].iParent>=0) pcontact->K += m_joints[m_joints[idx].iParent].body.Iinv; pcontact->flags = contact_angular; pcontact->n = m_joints[idx].rotaxes[i]*-sgnnz(m_joints[idx].dq_limit[i]); if (m_iSimTypeCur) pcontact->vreq = pcontact->n*min(5.0f,fabsf(m_joints[idx].dq_limit[i])*4.0f); //pcontact->vsep = -0.01f; RegisterContact(pcontact); } } } return 0; } float __maxdiff = 0; int CArticulatedEntity::Update(float time_interval, float damping) { int i,j,nCollJoints=0; float e,minEnergy = m_nContacts>=m_nCollLyingMode ? m_EminLyingMode : m_Emin; m_bAwake = (iszero(m_nContacts) & (m_bFloating^1)) | isneg(m_simTimeAux-0.5f); m_bUsingUnproj = 0; m_nStepBackCount = (m_nStepBackCount&-m_bSteppedBack)+m_bSteppedBack; for(i=0;i=0; j=m_joints[j].iParent) m_joints[i].bAwake |= m_joints[j].bAwake; nCollJoints += m_joints[i].bHasExtContacts; if (m_iSimTypeCur && m_joints[i].body.Eunproj>0) { SyncJointWithBody(i,3); for(j=m_joints[i].iStartPart; j=0) { vectorf pivot[2],dpivot,dvel; int j = m_joints[i].iParent; pivot[0] = m_joints[j].body.pos + m_joints[j].quat*m_joints[i].pivot[0]; pivot[1] = m_joints[i].body.pos + m_joints[i].quat*m_joints[i].pivot[1]; dpivot = pivot[0]-pivot[1]; dvel = m_joints[i].body.v + (m_joints[i].body.w^pivot[1]-m_joints[i].body.pos) - m_joints[j].body.v - (m_joints[j].body.w^pivot[0]-m_joints[j].body.pos); float diff1 = (dvel-dpivot*10.0f).len(); pivot[0].zero(); } #endif /*for(j=iPersistentContacts=0; jv+(pbody->w ^ m_pContacts[j].pt-pbody->pos); pbody = m_pContacts[j].pbody[1]; vrel -= pbody->v+(pbody->w ^ m_pContacts[j].pt-pbody->pos); if (vrel*m_pContacts[j].nm_vars.minSeparationSpeed && m_pContacts[j].penetration==0) iPersistentContacts |= getmask(j); } m_joints[i].iContacts = iPersistentContacts;*/ } if (m_iSimClass-1!=m_bAwake) { m_iSimTypeOverride &= m_bAwake; m_iSimClass = 1+m_bAwake; m_pWorld->RepositionEntity(this,2); } if (!m_bAwake) { for(i=0;iAddObject(this, sizeof(CArticulatedEntity)); pSizer->AddObject(m_joints, m_nJointsAlloc*sizeof(m_joints[0])); pSizer->AddObject(m_infos, m_nPartsAlloc*sizeof(m_infos[0])); }