Matrix4x4f BoneBridgeCAL3D::CalculateBoneSpaceTransform() const { Matrix4x4f boneSpaceTransform = Matrix4x4f::Identity(); // set up bone space geometry transform { // transform forward by half the box length const Vec3f& dimensions = GetDimensions(); boneSpaceTransform.SetTranslation(Vec3f(dimensions[Y] / 2.0f, 0.0f, 0.0f)); // set rotational offset (the inversion of the core bone absolute rotation) { CalCoreBone* coreBone = mpCalBone->getCoreBone(); CalQuaternion calRotAbsolute = coreBone->getRotationAbsolute(); calRotAbsolute.invert(); Quaternionf kernelRot = ConvertCAL3DtoKernel(calRotAbsolute); boneSpaceTransform.SetRotate(kernelRot); } } return boneSpaceTransform; }
void CalCoreBone::initBoundingBox() { CalQuaternion rot; rot=m_rotationBoneSpace; rot.invert(); CalVector dir = CalVector(1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[0].setNormal(dir); dir = CalVector(-1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[1].setNormal(dir); dir = CalVector(0.0f,1.0f,0.0f); dir*=rot; m_boundingBox.plane[2].setNormal(dir); dir = CalVector(0.0f,-1.0f,0.0f); dir*=rot; m_boundingBox.plane[3].setNormal(dir); dir = CalVector(0.0f,0.0f,1.0f); dir*=rot; m_boundingBox.plane[4].setNormal(dir); dir = CalVector(0.0f,0.0f,-1.0f); dir*=rot; m_boundingBox.plane[5].setNormal(dir); }
float DistanceDegrees( CalQuaternion const & p1, CalQuaternion const & p2 ) { // To determine the angular distance between the oris, multiply one by the inverse // of the other, which should leave us with an identity ori if they are equal. If // they are not equal, then the angular magnitude of the rotation in degrees is the // difference between the oris. CalQuaternion odist = p1; odist.invert(); odist *= p2; float w = odist.w; if( w > 1 ) w = 1; if( w < -1 ) w = -1; float distrads = 2 * acos( w ); // Non-negative. float distdegrees = distrads * 180.0f / 3.141592654f; // Non-negative. if( distdegrees > 180.0 ) distdegrees -= 360.0; return fabsf( distdegrees ); }
void CalCoreBone::calculateBoundingBox(CalCoreModel * pCoreModel) { int boneId = m_pCoreSkeleton->getCoreBoneId(m_strName); bool bBoundsComputed=false; int planeId; CalQuaternion rot; rot=m_rotationBoneSpace; rot.invert(); CalVector dir = CalVector(1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[0].setNormal(dir); dir = CalVector(-1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[1].setNormal(dir); dir = CalVector(0.0f,1.0f,0.0f); dir*=rot; m_boundingBox.plane[2].setNormal(dir); dir = CalVector(0.0f,-1.0f,0.0f); dir*=rot; m_boundingBox.plane[3].setNormal(dir); dir = CalVector(0.0f,0.0f,1.0f); dir*=rot; m_boundingBox.plane[4].setNormal(dir); dir = CalVector(0.0f,0.0f,-1.0f); dir*=rot; m_boundingBox.plane[5].setNormal(dir); int meshId; for(meshId=0; meshId < pCoreModel->getCoreMeshCount(); ++meshId) { CalCoreMesh * pCoreMesh = pCoreModel->getCoreMesh(meshId); int submeshId; for(submeshId=0;submeshId<pCoreMesh->getCoreSubmeshCount();submeshId++) { CalCoreSubmesh *pCoreSubmesh = pCoreMesh->getCoreSubmesh(submeshId); if(pCoreSubmesh->getSpringCount()==0) { std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex(); for(size_t vertexId=0;vertexId <vectorVertex.size(); ++vertexId) { for(size_t influenceId=0;influenceId<vectorVertex[vertexId].vectorInfluence.size();++influenceId) { if(vectorVertex[vertexId].vectorInfluence[influenceId].boneId == boneId && vectorVertex[vertexId].vectorInfluence[influenceId].weight > 0.5f) { for(planeId = 0; planeId < 6; ++planeId) { if(m_boundingBox.plane[planeId].eval(vectorVertex[vertexId].position) < 0.0f) { m_boundingBox.plane[planeId].setPosition(vectorVertex[vertexId].position); m_boundingPosition[planeId]=vectorVertex[vertexId].position; bBoundsComputed=true; } } } } } } } } // To handle bones with no vertices assigned if(!bBoundsComputed) { for(planeId = 0; planeId < 6; ++planeId) { m_boundingBox.plane[planeId].setPosition(m_translation); m_boundingPosition[planeId] = m_translation; } } m_boundingBoxPrecomputed = true; }
void CalBone::calculateState() { // check if the bone was not touched by any active animation if(m_accumulatedWeight == 0.0f) { // set the bone to the initial skeleton state m_translation = m_pCoreBone->getTranslation(); m_rotation = m_pCoreBone->getRotation(); } // get parent bone id int parentId; parentId = m_pCoreBone->getParentId(); if(parentId == -1) { // no parent, this means absolute state == relative state m_translationAbsolute = m_translation; m_rotationAbsolute = m_rotation; } else { // get the parent bone const CalBone *pParent; pParent = m_pSkeleton->getBone(parentId); // transform relative state with the absolute state of the parent m_translationAbsolute = m_translation; m_translationAbsolute *= pParent->getRotationAbsolute(); m_translationAbsolute += pParent->getTranslationAbsolute(); m_rotationAbsolute = m_rotation; m_rotationAbsolute *= pParent->getRotationAbsolute(); } // calculate the bone space transformation m_translationBoneSpace = m_pCoreBone->getTranslationBoneSpace(); // Must go before the *= m_rotationAbsolute. bool meshScalingOn; if( m_meshScaleAbsolute.x != 1 || m_meshScaleAbsolute.y != 1 || m_meshScaleAbsolute.z != 1 ) { meshScalingOn = true; CalVector scalevec; // The mesh transformation is intended to apply to the vector from the // bone node to the vert, relative to the model's global coordinate system. // For example, even though the head node's X axis aims up, the model's // global coordinate system has X to stage right, Z up, and Y stage back. // // The standard vert transformation is: // v1 = vmesh - boneAbsPosInJpose // v2 = v1 * boneAbsRotInAnimPose // v3 = v2 + boneAbsPosInAnimPose // // Cal3d does the calculation by: // u1 = umesh * transformMatrix // u2 = u1 + translationBoneSpace // // where translationBoneSpace = // "coreBoneTranslationBoneSpace" // * boneAbsRotInAnimPose // + boneAbsPosInAnimPose // // and where transformMatrix = // "coreBoneRotBoneSpace" // * boneAbsRotInAnimPose // // I don't know what "coreBoneRotBoneSpace" and "coreBoneTranslationBoneSpace" actually are, // but to add scale to the scandard vert transformation, I simply do: // // v3' = vmesh * scalevec * boneAbsRotInAnimPose // - boneAbsPosInJpose * scalevec * boneAbsRotInAnimPose // + boneAbsPosInAnimPose // // Essentially, the boneAbsPosInJpose is just an extra vector added to // each vertex that we want to subtract out. We must transform the extra // vector in exactly the same way we transform the vmesh. Therefore if we scale the mesh, we // must also scale the boneAbsPosInJpose. // // Expanding out the u2 equation, we have: // // u2 = umesh * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // + "coreBoneTranslationBoneSpace" * boneAbsRotInAnimPose // + boneAbsPosInAnimPose // // We assume that "coreBoneTranslationBoneSpace" = vectorThatMustBeSubtractedFromUmesh * "coreBoneRotBoneSpace": // // u2 = umesh * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // + vectorThatMustBeSubtractedFromUmesh * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // + boneAbsPosInAnimPose // // We assume that scale should be applied to umesh, not umesh * "coreBoneRotBoneSpace": // // u2 = umesh * scaleVec * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // + "coreBoneTranslationBoneSpace" * "coreBoneRotBoneSpaceInverse" * scaleVec * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // + boneAbsPosInAnimPose // // which yields, // // transformMatrix' = scaleVec * "coreBoneRotBoneSpace" * boneAbsRotInAnimPose // // and, // // translationBoneSpace' = // coreBoneTranslationBoneSpace * "coreBoneRotBoneSpaceInverse" * scaleVec * "coreBoneRotBoneSpace" // * boneAbsRotInAnimPose // + boneAbsPosInAnimPose CalQuaternion coreBoneRotBoneSpaceInverse = m_pCoreBone->getRotationBoneSpace(); coreBoneRotBoneSpaceInverse.invert(); m_translationBoneSpace *= coreBoneRotBoneSpaceInverse; m_translationBoneSpace.x *= m_meshScaleAbsolute.x; m_translationBoneSpace.y *= m_meshScaleAbsolute.y; m_translationBoneSpace.z *= m_meshScaleAbsolute.z; m_translationBoneSpace *= m_pCoreBone->getRotationBoneSpace(); } else { meshScalingOn = false; } m_translationBoneSpace *= m_rotationAbsolute; m_translationBoneSpace += m_translationAbsolute; m_rotationBoneSpace = m_pCoreBone->getRotationBoneSpace(); m_rotationBoneSpace *= m_rotationAbsolute; m_transformMatrix = m_pCoreBone->getRotationBoneSpace(); if( meshScalingOn ) { // By applying each scale component to the row, instead of the column, we // are effectively making the scale apply prior to the rotationBoneSpace. m_transformMatrix.dxdx *= m_meshScaleAbsolute.x; m_transformMatrix.dydx *= m_meshScaleAbsolute.x; m_transformMatrix.dzdx *= m_meshScaleAbsolute.x; m_transformMatrix.dxdy *= m_meshScaleAbsolute.y; m_transformMatrix.dydy *= m_meshScaleAbsolute.y; m_transformMatrix.dzdy *= m_meshScaleAbsolute.y; m_transformMatrix.dxdz *= m_meshScaleAbsolute.z; m_transformMatrix.dydz *= m_meshScaleAbsolute.z; m_transformMatrix.dzdz *= m_meshScaleAbsolute.z; } m_transformMatrix *= m_rotationAbsolute; // calculate all child bones std::list<int>::iterator iteratorChildId; int i = 0; for(iteratorChildId = m_pCoreBone->getListChildId().begin(); iteratorChildId != m_pCoreBone->getListChildId().end(); ++iteratorChildId, i++ ) { CalBone * bo = m_pSkeleton->getBone(*iteratorChildId); bo->calculateState(); } }