void IKCharacter::pullWorldPositions( int root_id, int leaf_id ) { CalVector root_pos; if ( auto_root_follow ) { // get root pos int skel_root_id = skeleton->getCoreSkeleton()->getVectorRootCoreBoneId()[0]; root_pos = skeleton->getBone(skel_root_id)->getTranslationAbsolute(); } // work from the leaves down to the root deque<int> queue; if ( leaf_id == -1 ) queue.insert( queue.begin(), leaf_bones.begin(), leaf_bones.end() ); else queue.push_back( leaf_id ); while ( !queue.empty() ) { int id = queue.front(); queue.pop_front(); CalBone* bone = skeleton->getBone(id); world_positions[id] = bone->getTranslationAbsolute() - root_pos; int parent_id = bone->getCoreBone()->getParentId(); if ( parent_id != -1 && id != root_id ) queue.push_back( parent_id ); } }
/// calculate a rotation to bring the current direction vector between parent and bone /// to the given new direction vector (non-normalized) ofxQuaternion IKCharacter::getRotationForParentBone( int bone_id, CalVector new_parent_to_bone_direction ) { CalCoreSkeleton* core_skel = skeleton->getCoreSkeleton(); CalBone* bone = skeleton->getBone( bone_id ); int parent_id = core_skel->getCoreBone( bone_id )->getParentId(); CalBone* parent_bone = skeleton->getBone( parent_id ); int parent_parent_id = parent_bone->getCoreBone()->getParentId(); // don't rotate the base state if ( parent_parent_id == -1 ) return ofxQuaternion(); // new_parent_to_bone_direction is currently in world-space // we need to bring it into the space of the parent bone CalQuaternion bone_space_rot = bone->getRotationBoneSpace(); bone_space_rot.invert(); new_parent_to_bone_direction *= bone_space_rot; CalVector old_dir = bone->getTranslation(); CalVector new_dir = new_parent_to_bone_direction; old_dir.normalize(); new_dir.normalize(); // rotate from one to the other ofxQuaternion rot; ofxVec3f od( old_dir.x, old_dir.y, old_dir.z ); ofxVec3f nd( new_dir.x, new_dir.y, new_dir.z ); rot.makeRotate( od, nd ); // return return rot.inverse(); }
int CalSkeleton::getBoneLinesStatic(float *pLines) { int nrLines; nrLines = 0; rde::vector<CalBone *>::iterator iteratorBone; for(iteratorBone = m_vectorBone.begin(); iteratorBone != m_vectorBone.end(); ++iteratorBone) { int parentId; parentId = (*iteratorBone)->getCoreBone()->getParentId(); if(parentId != -1) { CalBone *pParent; pParent = m_vectorBone[parentId]; const CalVector& translation = (*iteratorBone)->getCoreBone()->getTranslationAbsolute(); const CalVector& translationParent = pParent->getCoreBone()->getTranslationAbsolute(); *pLines++ = translationParent[0]; *pLines++ = translationParent[1]; *pLines++ = translationParent[2]; *pLines++ = translation[0]; *pLines++ = translation[1]; *pLines++ = translation[2]; nrLines++; } } return nrLines; }
void CalMixer::applyBoneAdjustments() { CalSkeleton * pSkeleton = m_pModel->getSkeleton(); std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone(); unsigned int i; for( i = 0; i < m_numBoneAdjustments; i++ ) { CalMixerBoneAdjustmentAndBoneId * ba = & m_boneAdjustmentAndBoneIdArray[ i ]; CalBone * bo = vectorBone[ ba->boneId_ ]; CalCoreBone * cbo = bo->getCoreBone(); if( ba->boneAdjustment_.flags_ & CalMixerBoneAdjustmentFlagMeshScale ) { bo->setMeshScaleAbsolute( ba->boneAdjustment_.meshScaleAbsolute_ ); } if( ba->boneAdjustment_.flags_ & CalMixerBoneAdjustmentFlagPosRot ) { const CalVector & localPos = cbo->getTranslation(); CalVector adjustedLocalPos = localPos; CalQuaternion adjustedLocalOri = ba->boneAdjustment_.localOri_; static float const scale = 1.0f; float rampValue = ba->boneAdjustment_.rampValue_; static bool const replace = true; static float const unrampedWeight = 1.0f; bo->blendState( unrampedWeight, adjustedLocalPos, adjustedLocalOri, scale, replace, rampValue ); } } }
const std::list<int>& BoneBridgeCAL3D::GetListChildBoneID() const { CalBone* calBone = (CalBone*)GetCalBone(); CalCoreBone* coreBone = calBone->getCoreBone(); std::list<int>& listChildID = coreBone->getListChildId(); return listChildID; }
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 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(); m_translationBoneSpace *= m_rotationAbsolute; m_translationBoneSpace += m_translationAbsolute; m_rotationBoneSpace = m_pCoreBone->getRotationBoneSpace(); m_rotationBoneSpace *= m_rotationAbsolute; // Generate the vertex transform. If I ever add support for bone-scaling // to Cal3D, this step will become significantly more complex. m_transformMatrix = m_rotationBoneSpace; // calculate all child bones std::list<int>::iterator iteratorChildId; for(iteratorChildId = m_pCoreBone->getListChildId().begin(); iteratorChildId != m_pCoreBone->getListChildId().end(); ++iteratorChildId) { m_pSkeleton->getBone(*iteratorChildId)->calculateState(); } }
///////////////////////////////////// // Purpose: get the translation // to bring a point into the // bone instance space // of given boneID // Output: pLoc set // Return: none ///////////////////////////////////// void IgfxObject::BoneGetTransBoneSpace(s32 boneID, Vec3D *pLoc) { if(m_pCalModel) { CalSkeleton *pSkel = m_pCalModel->getSkeleton(); CalBone *pBone = pSkel->getBone(boneID); CalVector cVec = pBone->getTranslationBoneSpace(); pLoc->x = cVec.x; pLoc->y = cVec.y; pLoc->z = cVec.z; } }
///////////////////////////////////// // Purpose: get the given bone's // bone space transformation // Output: pMtx filled // Return: none ///////////////////////////////////// void IgfxObject::BoneGetTransformMtx(s32 boneID, Matrix *pMtx) { if(m_pCalModel) { CalSkeleton *pSkel = m_pCalModel->getSkeleton(); CalBone *pBone = pSkel->getBone(boneID); CalMatrix cMtx = pBone->getTransformMatrix(); pMtx->_11 = cMtx.dxdx; pMtx->_21 = cMtx.dydx; pMtx->_31 = cMtx.dzdx; pMtx->_41 = 0; pMtx->_12 = cMtx.dxdy; pMtx->_22 = cMtx.dydy; pMtx->_32 = cMtx.dzdy; pMtx->_42 = 0; pMtx->_13 = cMtx.dxdz; pMtx->_23 = cMtx.dydz; pMtx->_33 = cMtx.dzdz; pMtx->_43 = 0; pMtx->_14 = 0; pMtx->_24 = 0; pMtx->_34 = 0; pMtx->_44 = 1; } }
///////////////////////////////////// // Purpose: get the rotation // to bring a point into the // bone instance space // Output: pQ set // Return: none ///////////////////////////////////// void IgfxObject::BoneGetRotateBoneSpace(s32 boneID, Quaternion *pQ) { if(m_pCalModel) { CalSkeleton *pSkel = m_pCalModel->getSkeleton(); CalBone *pBone = pSkel->getBone(boneID); CalQuaternion cQuat = pBone->getRotationBoneSpace(); pQ->x = cQuat.x; pQ->y = cQuat.y; pQ->z = cQuat.z; pQ->w = cQuat.w; } }
bool CalSkeleton::create(CalCoreSkeleton *pCoreSkeleton) { if(pCoreSkeleton == 0) { CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__); return false; } m_pCoreSkeleton = pCoreSkeleton; // clone the skeleton structure of the core skeleton rde::vector<CalCoreBone *>& vectorCoreBone = pCoreSkeleton->getVectorCoreBone(); // get the number of bones int boneCount; boneCount = vectorCoreBone.size(); // reserve space in the bone vector m_vectorBone.reserve(boneCount); // clone every core bone int boneId; for(boneId = 0; boneId < boneCount; boneId++) { CalBone *pBone; pBone = new CalBone(); if(pBone == 0) { CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__); return false; } // create a bone for every core bone if(!pBone->create(vectorCoreBone[boneId])) { delete pBone; return false; } // set skeleton in the bone instance pBone->setSkeleton(this); // insert bone into bone vector m_vectorBone.push_back(pBone); } return true; }
///////////////////////////////////// // Purpose: set the relative translation // of the given bone // Output: bone moved // Return: none ///////////////////////////////////// void IgfxObject::BoneSetTrans(s32 boneID, const Vec3D & loc) { if(m_pCalModel) { Vec3D trans; BoneGetTrans(boneID, &trans); CalSkeleton *pSkel = m_pCalModel->getSkeleton(); CalBone *pBone = pSkel->getBone(boneID); if(pBone) { pBone->setTranslation(CalVector(trans.x+loc.x, trans.y+loc.y, trans.z+loc.z)); pBone->calculateState(); } } }
///////////////////////////////////// // Purpose: set the relative rotation // of the given bone // Output: bone rotated // Return: none ///////////////////////////////////// void IgfxObject::BoneSetRotate(s32 boneID, const Quaternion & q) { if(m_pCalModel) { Quaternion quat; BoneGetRotate(boneID, &quat); quat *= q; CalSkeleton *pSkel = m_pCalModel->getSkeleton(); CalBone *pBone = pSkel->getBone(boneID); if(pBone) { pBone->setRotation(CalQuaternion(quat.x, quat.y, quat.z, quat.w)); pBone->calculateState(); } } }
core::matrix4 CCal3DSceneNode::getBoneMatrix( s32 boneId ) const { if ( calModel == 0 ) return core::matrix4(); CalSkeleton* skeleton = calModel->getSkeleton(); CalBone* bone = skeleton->getBone(boneId); CalQuaternion rot = bone->getRotationAbsolute(); CalVector pos = bone->getTranslationAbsolute(); // Note: Swap Y and Z to convert to Irrlicht coordinates core::quaternion quat = core::quaternion( rot.x, rot.y, rot.z, rot.w ); core::vector3df v = core::vector3df( pos.x, pos.y, pos.z ); core::matrix4 mat = quat.getMatrix(); mat.setTranslation(v); return mat; }
void IKCharacter::pullWorldPositions( int root_id, int leaf_id ) { deque<int> queue; if ( leaf_id == -1 ) queue.insert( queue.begin(), leaf_bones.begin(), leaf_bones.end() ); else queue.push_back( leaf_id ); // work backwards up the tree while ( !queue.empty() ) { int id = queue.front(); queue.pop_front(); CalBone* bone = skeleton->getBone(id); world_positions[id] = bone->getTranslationAbsolute(); int parent_id = bone->getCoreBone()->getParentId(); if ( parent_id != -1 && id != root_id ) queue.push_back( parent_id ); } }
int CalPhysique::calculateVerticesNormalsAndTexCoords(CalSubmesh *pSubmesh, float *pVertexBuffer, int NumTexCoords) const { // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // get vertex vector of the core submesh std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pSubmesh->getCoreSubmesh()->getVectorVertex(); // get the texture coordinate vector vector std::vector<std::vector<CalCoreSubmesh::TextureCoordinate> >& vectorvectorTextureCoordinate = pSubmesh->getCoreSubmesh()->getVectorVectorTextureCoordinate(); int TextureCoordinateCount=(int)vectorvectorTextureCoordinate.size(); // check if the map id is valid if(((NumTexCoords < 0) || (NumTexCoords > TextureCoordinateCount))) { if(TextureCoordinateCount!=0) { CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__); return -1; } } // get physical property vector of the core submesh std::vector<CalCoreSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty(); // get the number of vertices int vertexCount; vertexCount = pSubmesh->getVertexCount(); // get the sub morph target vector from the core sub mesh std::vector<CalCoreSubMorphTarget*>& vectorSubMorphTarget = pSubmesh->getCoreSubmesh()->getVectorCoreSubMorphTarget(); // get the number of morph targets int morphTargetCount = pSubmesh->getMorphTargetWeightCount(); // Check for spring case bool hasSpringsAndInternalData = (pSubmesh->getCoreSubmesh()->getSpringCount() > 0) && pSubmesh->hasInternalData(); // calculate all submesh vertices int vertexId; for(vertexId = 0; vertexId < vertexCount; ++vertexId) { // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // blend the morph targets CalVector position=vertex.position; CalVector normal=vertex.normal; { int morphTargetId; for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId) { CalCoreSubMorphTarget::BlendVertex const * blendVertex = vectorSubMorphTarget[morphTargetId]->getBlendVertex(vertexId); float currentWeight = pSubmesh->getMorphTargetWeight(morphTargetId); if( currentWeight != 0 ) { if( blendVertex ) { position.x += currentWeight*blendVertex->position.x; position.y += currentWeight*blendVertex->position.y; position.z += currentWeight*blendVertex->position.z; normal.x += currentWeight*blendVertex->normal.x; normal.y += currentWeight*blendVertex->normal.y; normal.z += currentWeight*blendVertex->normal.z; } } } } // initialize vertex float x, y, z; x = 0.0f; y = 0.0f; z = 0.0f; // initialize normal float nx, ny, nz; nx = 0.0f; ny = 0.0f; nz = 0.0f; // blend together all vertex influences int influenceId; int influenceCount=(int)vertex.vectorInfluence.size(); if(influenceCount == 0) { x = position.x; y = position.y; z = position.z; nx = normal.x; ny = normal.y; nz = normal.z; } else { for(influenceId = 0; influenceId < influenceCount; ++influenceId) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform vertex with current state of the bone CalVector v(position); v *= pBone->getTransformMatrix(); v += pBone->getTranslationBoneSpace(); x += influence.weight * v.x; y += influence.weight * v.y; z += influence.weight * v.z; // transform normal with current state of the bone CalVector n(normal); n *= pBone->getTransformMatrix(); nx += influence.weight * n.x; ny += influence.weight * n.y; nz += influence.weight * n.z; } } // save vertex position if(hasSpringsAndInternalData) { // get the pgysical property of the vertex CalCoreSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId]; // assign new vertex position if there is no vertex weight if(physicalProperty.weight == 0.0f) { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } } else { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } // re-normalize normal if necessary if (m_Normalize) { nx/= m_axisFactorX; ny/= m_axisFactorY; nz/= m_axisFactorZ; float scale; scale = (float) (1.0f / sqrt(nx * nx + ny * ny + nz * nz)); pVertexBuffer[3] = nx * scale; pVertexBuffer[4] = ny * scale; pVertexBuffer[5] = nz * scale; } else { pVertexBuffer[3] = nx; pVertexBuffer[4] = ny; pVertexBuffer[5] = nz; } pVertexBuffer += 6; if(TextureCoordinateCount==0) { pVertexBuffer+=NumTexCoords*2; } else { for(int mapId=0; mapId < NumTexCoords; ++mapId) { pVertexBuffer[0] = vectorvectorTextureCoordinate[mapId][vertexId].u; pVertexBuffer[1] = vectorvectorTextureCoordinate[mapId][vertexId].v; pVertexBuffer += 2; } } } return vertexCount; }
int CalPhysique::calculateVertices(CalSubmesh *pSubmesh, float *pVertexBuffer, int stride) const { if(stride <= 0) { stride = 3*sizeof(float); } // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // get vertex vector of the core submesh std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pSubmesh->getCoreSubmesh()->getVectorVertex(); // get physical property vector of the core submesh std::vector<CalCoreSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty(); // get the number of vertices int vertexCount; vertexCount = pSubmesh->getVertexCount(); // get the sub morph target vector from the core sub mesh std::vector<CalCoreSubMorphTarget*>& vectorSubMorphTarget = pSubmesh->getCoreSubmesh()->getVectorCoreSubMorphTarget(); // Get the number of morph targets and cache the weights in an array // that can be indexed quickly inside the vertex inner loop. int morphTargetCount = pSubmesh->getMorphTargetWeightCount(); static int const morphTargetCountMax = 100; // Arbitrary. if( morphTargetCount > morphTargetCountMax ) { morphTargetCount = morphTargetCountMax; } static float morphTargetScaleArray[ morphTargetCountMax ]; for(int i = 0; i < morphTargetCount; i++ ) { morphTargetScaleArray[ i ] = pSubmesh->getMorphTargetWeight( i ); } // Check for spring case bool hasSpringsAndInternalData = (pSubmesh->getCoreSubmesh()->getSpringCount() > 0) && pSubmesh->hasInternalData(); // calculate all submesh vertices int vertexId; for(vertexId = 0; vertexId < vertexCount; ++vertexId) { // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // blend the morph targets CalVector position=vertex.position; { int morphTargetId; for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId) { CalCoreSubMorphTarget::BlendVertex const * blendVertex = vectorSubMorphTarget[morphTargetId]->getBlendVertex(vertexId); float morphScale = morphTargetScaleArray[ morphTargetId ]; if( blendVertex ) { position.x += morphScale * blendVertex->position.x; position.y += morphScale * blendVertex->position.y; position.z += morphScale * blendVertex->position.z; } } } // initialize vertex float x, y, z; x = 0.0f; y = 0.0f; z = 0.0f; // blend together all vertex influences size_t influenceCount=vertex.vectorInfluence.size(); if(influenceCount == 0) { x = position.x; y = position.y; z = position.z; } else { for(size_t influenceId = 0; influenceId < influenceCount; ++influenceId) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform vertex with current state of the bone CalVector v(position); v *= pBone->getTransformMatrix(); v += pBone->getTranslationBoneSpace(); x += influence.weight * v.x; y += influence.weight * v.y; z += influence.weight * v.z; } } // save vertex position if(hasSpringsAndInternalData) { // get the physical property of the vertex CalCoreSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId]; // assign new vertex position if there is no vertex weight if(physicalProperty.weight == 0.0f) { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } } else { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } // next vertex position in buffer pVertexBuffer = (float *)(((char *)pVertexBuffer) + stride) ; } return vertexCount; }
int CalPhysique::calculateVerticesAndNormals(CalSubmesh *pSubmesh, float *pVertexBuffer, int stride) const { if(stride <= 0) { stride = 6*sizeof(float); } // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // CalBone ** vectorBonePtr = &vectorBone[0]; // get vertex vector of the core submesh CalCoreSubmesh::Vertex* vectorVertex = &pSubmesh->getCoreSubmesh()->getVectorVertex()[0]; // get physical property vector of the core submesh std::vector<CalCoreSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty(); // get the number of vertices int vertexCount = pSubmesh->getVertexCount(); // get the sub morph target vector from the core sub mesh std::vector<CalCoreSubMorphTarget*>& vectorSubMorphTarget = pSubmesh->getCoreSubmesh()->getVectorCoreSubMorphTarget(); // get the number of morph targets int morphTargetCount = pSubmesh->getMorphTargetWeightCount(); EnlargeMiawCacheAsNecessary( morphTargetCount ); unsigned int numMiaws; pSubmesh->getMorphIdAndWeightArray( MiawCache, & numMiaws, ( unsigned int ) morphTargetCount ); // Check for spring case bool hasSpringsAndInternalData = (pSubmesh->getCoreSubmesh()->getSpringCount() > 0) && pSubmesh->hasInternalData(); // calculate all submesh vertices int vertexId; //CalCoreSubMorphTarget::BlendVertex blendVertex; for(vertexId = 0; vertexId < vertexCount; ++vertexId) { // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // Off unless normalizing set to on and either there are morph targets or multiple influences. bool mustNormalize = false; // blend the morph targets CalVector position=vertex.position; CalVector normal=vertex.normal; { mustNormalize = true; // Morph targets can skew normals. unsigned int i; for( i = 0; i < numMiaws; i++ ) { MorphIdAndWeight * miaw = & MiawCache[ i ]; int morphTargetId = miaw->morphId_; CalCoreSubMorphTarget::BlendVertex const * blendVertex = vectorSubMorphTarget[morphTargetId]->getBlendVertex(vertexId); float currentWeight = miaw->weight_; if( blendVertex ) { position.x += currentWeight*blendVertex->position.x; position.y += currentWeight*blendVertex->position.y; position.z += currentWeight*blendVertex->position.z; normal.x += currentWeight*blendVertex->normal.x; normal.y += currentWeight*blendVertex->normal.y; normal.z += currentWeight*blendVertex->normal.z; } } } // initialize vertex float x, y, z; x = 0.0f; y = 0.0f; z = 0.0f; // initialize normal float nx, ny, nz; nx = 0.0f; ny = 0.0f; nz = 0.0f; // blend together all vertex influences int influenceId; int influenceCount=(int)vertex.vectorInfluence.size(); if(influenceCount > 1) { mustNormalize = true; // If multiple influences, normalize the normals! } for(influenceId = 0; influenceId < influenceCount; ++influenceId) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform vertex with current state of the bone CalVector v(position); v *= pBone->getTransformMatrix(); v += pBone->getTranslationBoneSpace(); x += influence.weight * v.x; y += influence.weight * v.y; z += influence.weight * v.z; // transform normal with current state of the bone CalVector n(normal); n *= pBone->getTransformMatrix(); nx += influence.weight * n.x; ny += influence.weight * n.y; nz += influence.weight * n.z; } // save vertex position if(hasSpringsAndInternalData) { mustNormalize = true; // get the physical property of the vertex CalCoreSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId]; // assign new vertex position if there is no vertex weight if(physicalProperty.weight == 0.0f) { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } } else { pVertexBuffer[0] = x * m_axisFactorX; pVertexBuffer[1] = y * m_axisFactorY; pVertexBuffer[2] = z * m_axisFactorZ; } // re-normalize normal if necessary if (m_Normalize && mustNormalize) { nx/= m_axisFactorX; ny/= m_axisFactorY; nz/= m_axisFactorZ; float scale; scale = (float)( 1.0f / sqrt(nx * nx + ny * ny + nz * nz)); pVertexBuffer[3] = nx * scale; pVertexBuffer[4] = ny * scale; pVertexBuffer[5] = nz * scale; } else { pVertexBuffer[3] = nx; pVertexBuffer[4] = ny; pVertexBuffer[5] = nz; } // next vertex position in buffer pVertexBuffer = (float *)(((char *)pVertexBuffer) + stride) ; } return vertexCount; }
int CalPhysique::calculateNormals(CalSubmesh *pSubmesh, float *pNormalBuffer, int stride) const { if(stride <= 0) { stride = 3*sizeof(float); } // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // get vertex vector of the submesh std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pSubmesh->getCoreSubmesh()->getVectorVertex(); // get the number of vertices int vertexCount; vertexCount = pSubmesh->getVertexCount(); // get the sub morph target vector from the core sub mesh std::vector<CalCoreSubMorphTarget*>& vectorSubMorphTarget = pSubmesh->getCoreSubmesh()->getVectorCoreSubMorphTarget(); // get the number of morph targets int morphTargetCount = pSubmesh->getMorphTargetWeightCount(); // calculate normal for all submesh vertices int vertexId; for(vertexId = 0; vertexId < vertexCount; ++vertexId) { // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // blend the morph targets CalVector normal=vertex.normal; { int morphTargetId; for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId) { CalCoreSubMorphTarget::BlendVertex const * blendVertex = vectorSubMorphTarget[morphTargetId]->getBlendVertex(vertexId); float currentWeight = pSubmesh->getMorphTargetWeight(morphTargetId); if( blendVertex ) { normal.x += currentWeight*blendVertex->normal.x; normal.y += currentWeight*blendVertex->normal.y; normal.z += currentWeight*blendVertex->normal.z; } } } // initialize normal float nx, ny, nz; nx = 0.0f; ny = 0.0f; nz = 0.0f; // blend together all vertex influences int influenceId; int influenceCount=(int)vertex.vectorInfluence.size(); if(influenceCount == 0) { nx = normal.x; ny = normal.y; nz = normal.z; } else { for(influenceId = 0; influenceId < influenceCount; ++influenceId) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform normal with current state of the bone CalVector v(normal); v *= pBone->getTransformMatrix(); nx += influence.weight * v.x; ny += influence.weight * v.y; nz += influence.weight * v.z; } } // re-normalize normal if necessary if (m_Normalize) { nx/= m_axisFactorX; ny/= m_axisFactorY; nz/= m_axisFactorZ; float scale; scale = (float)( 1.0f / sqrt(nx * nx + ny * ny + nz * nz)); pNormalBuffer[0] = nx * scale; pNormalBuffer[1] = ny * scale; pNormalBuffer[2] = nz * scale; } else { pNormalBuffer[0] = nx; pNormalBuffer[1] = ny; pNormalBuffer[2] = nz; } // next vertex position in buffer pNormalBuffer = (float *)(((char *)pNormalBuffer) + stride) ; } return vertexCount; }
int CalPhysique::calculateTangentSpaces(CalSubmesh *pSubmesh, int mapId, float *pTangentSpaceBuffer, int stride) const { if((mapId < 0) || (mapId >= (int)pSubmesh->getCoreSubmesh()->getVectorVectorTangentSpace().size())) return false; if(stride <= 0) { stride = 4*sizeof(float); } // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // get vertex vector of the submesh std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pSubmesh->getCoreSubmesh()->getVectorVertex(); // get tangent space vector of the submesh std::vector<CalCoreSubmesh::TangentSpace>& vectorTangentSpace = pSubmesh->getCoreSubmesh()->getVectorVectorTangentSpace()[mapId]; // get the number of vertices int vertexCount; vertexCount = pSubmesh->getVertexCount(); // calculate normal for all submesh vertices int vertexId; for(vertexId = 0; vertexId < vertexCount; vertexId++) { CalCoreSubmesh::TangentSpace& tangentSpace = vectorTangentSpace[vertexId]; // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // initialize tangent float tx, ty, tz; tx = 0.0f; ty = 0.0f; tz = 0.0f; // blend together all vertex influences int influenceId; int influenceCount=(int)vertex.vectorInfluence.size(); for(influenceId = 0; influenceId < influenceCount; influenceId++) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform normal with current state of the bone CalVector v(tangentSpace.tangent); v *= pBone->getTransformMatrix(); tx += influence.weight * v.x; ty += influence.weight * v.y; tz += influence.weight * v.z; } // re-normalize tangent if necessary if (m_Normalize) { float scale; tx/= m_axisFactorX; ty/= m_axisFactorY; tz/= m_axisFactorZ; scale = (float)( 1.0f / sqrt(tx * tx + ty * ty + tz * tz)); pTangentSpaceBuffer[0] = tx * scale; pTangentSpaceBuffer[1] = ty * scale; pTangentSpaceBuffer[2] = tz * scale; } else { pTangentSpaceBuffer[0] = tx; pTangentSpaceBuffer[1] = ty; pTangentSpaceBuffer[2] = tz; } pTangentSpaceBuffer[3] = tangentSpace.crossFactor; // next vertex position in buffer pTangentSpaceBuffer = (float *)(((char *)pTangentSpaceBuffer) + stride) ; } return vertexCount; }
CalVector CalPhysique::calculateVertex(CalSubmesh *pSubmesh, int vertexId) { // get bone vector of the skeleton std::vector<CalBone *>& vectorBone = m_pModel->getSkeleton()->getVectorBone(); // get vertex of the core submesh std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pSubmesh->getCoreSubmesh()->getVectorVertex(); // get physical property vector of the core submesh //std::vector<CalCoreSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty(); // get the sub morph target vector from the core sub mesh std::vector<CalCoreSubMorphTarget*>& vectorSubMorphTarget = pSubmesh->getCoreSubmesh()->getVectorCoreSubMorphTarget(); // get the number of morph targets int morphTargetCount = pSubmesh->getMorphTargetWeightCount(); // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // blend the morph targets CalVector position=vertex.position; { int morphTargetId; for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId) { CalCoreSubMorphTarget::BlendVertex blendVertex; vectorSubMorphTarget[morphTargetId]->getBlendVertex(vertexId, blendVertex); float currentWeight = pSubmesh->getMorphTargetWeight(morphTargetId); position.x += currentWeight*blendVertex.position.x; position.y += currentWeight*blendVertex.position.y; position.z += currentWeight*blendVertex.position.z; } } // initialize vertex float x, y, z; x = 0.0f; y = 0.0f; z = 0.0f; // blend together all vertex influences int influenceId; int influenceCount=(int)vertex.vectorInfluence.size(); if(influenceCount == 0) { x = position.x; y = position.y; z = position.z; } else { for(influenceId = 0; influenceId < influenceCount; ++influenceId) { // get the influence CalCoreSubmesh::Influence& influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone *pBone; pBone = vectorBone[influence.boneId]; // transform vertex with current state of the bone CalVector v(position); v *= pBone->getTransformMatrix(); v += pBone->getTranslationBoneSpace(); x += influence.weight * v.x; y += influence.weight * v.y; z += influence.weight * v.z; } } /* // save vertex position if(pSubmesh->getCoreSubmesh()->getSpringCount() > 0 && pSubmesh->hasInternalData()) { // get the pgysical property of the vertex CalCoreSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId]; // assign new vertex position if there is no vertex weight if(physicalProperty.weight == 0.0f) { pVertexBuffer[0] = x; pVertexBuffer[1] = y; pVertexBuffer[2] = z; } } else { pVertexBuffer[0] = x; pVertexBuffer[1] = y; pVertexBuffer[2] = z; } */ // return the vertex //return CalVector(x, y, z); return CalVector(x*m_axisFactorX,y*m_axisFactorY,z*m_axisFactorZ); }
void IKCharacter::solve( int iterations, int root_id, int leaf_id ) { while ( iterations>0 ) { // start at leaf nodes deque<int> queue; // push leaf bones to target positions for ( int i=0; i<leaf_bones.size(); i++ ) { // if we have a leaf id to use, skip all other leaves if ( leaf_id != -1 && leaf_id != leaf_bones[i] ) continue; // if we have a target for this one if ( leaf_targets.find(leaf_bones[i]) != leaf_targets.end() ) { // set it world_positions[leaf_bones[i]] = leaf_targets[leaf_bones[i]].second; } int parent_id = skeleton->getCoreSkeleton()->getCoreBone( leaf_bones[i] )->getParentId(); if ( parent_id != -1 ) queue.push_back( parent_id ); } // queue to handle branching deque< int > branch_queue; while ( !queue.empty() || !branch_queue.empty() ) { // if main queue is empty then we are ready to deal with branches if ( queue.empty() ) { queue.push_back( branch_queue.front() ); branch_queue.pop_front(); continue; } int next_id = queue.front(); queue.pop_front(); // bail out if we should if ( root_id != -1 && next_id == root_id ) continue; CalBone* bone = skeleton->getBone( next_id ); list<int>& children = bone->getCoreBone()->getListChildId(); // is this a branch? if ( children.size()>1 ) { // still other children to process -- push to branch queue if ( !queue.empty() ) { branch_queue.push_back( next_id ); continue; } // otherwise, process branch here // if we're here, then all the children of this branch have been processed already int parent_id = bone->getCoreBone()->getParentId(); if ( parent_id != -1 ) { //printf("averaging %lu positions for %s wc %f: ", children.size(), bone->getCoreBone()->getName().c_str(), getWeightCentre( next_id ) ); // fetch all child positions vector<CalVector> results; results.insert( results.begin(), children.size(), world_positions[next_id] ); int count=0; for ( list<int>::iterator it = children.begin(); it != children.end(); ++it,++count ) { // child_pos CalVector& b_c = world_positions[*it]; // current pos CalVector& b_p = results[count]; // now, the bone is the wrong length. correct its length to fulfil size constraint. CalVector delta = b_c - b_p; float length = delta.length(); length = max( 0.00001f, length ); // pointing from parent to child CalVector direction = delta/length; CalCoreBone* child_bone = skeleton->getCoreSkeleton()->getCoreBone( *it ); CalVector rest_delta = bone->getCoreBone()->getTranslationAbsolute() - child_bone->getTranslationAbsolute(); float desired_length = rest_delta.length(); float delta_length = desired_length - length; // balance according to weight_centre float weight_centre = getWeightCentre(next_id); // move b_c += weight_centre * delta_length * direction; b_p -= (1.0f-weight_centre) * delta_length * direction; //printf("%s %f (%f %f %f), ", child_bone->getName().c_str(), delta_length, b_p.x, b_p.y, b_p.z ); } //printf("\n"); // now average CalVector average; for ( int i=0; i<results.size(); i++ ) { average += results[i]; } average /= results.size(); // store world_positions[next_id] = average; // add parent queue.push_back( parent_id ); } } else { // children.size() is exactly 1 assert( children.size()==1 ); int child_id = children.front(); // child_pos CalVector& b_c = world_positions[child_id]; // current pos CalVector& b_p = world_positions[next_id]; // now, the bone is the wrong length. correct its length to fulfil size constraint. float desired_length = getBoneLength(next_id); CalVector delta = b_c - b_p; float length = delta.length(); length = max( 0.00001f, length ); length = min( desired_length*1.5f, length ); // pointing from parent to child CalVector direction = delta/length; float delta_length = desired_length - length; // balance according to weight_centre float weight_centre = getWeightCentre(next_id); // move b_c += weight_centre * delta_length * direction; b_p -= (1.0f-weight_centre) * delta_length * direction; // add parent int parent_id = bone->getCoreBone()->getParentId(); if ( parent_id != -1 ) queue.push_back( parent_id ); } } iterations--; } }
void CalMixer::updateSkeleton() { // get the skeleton we need to update CalSkeleton *pSkeleton; pSkeleton = m_pModel->getSkeleton(); if(pSkeleton == 0) return; // clear the skeleton state pSkeleton->clearState(); // get the bone vector of the skeleton std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone(); // loop through all animation actions std::list<CalAnimationAction *>::iterator iteratorAnimationAction; for(iteratorAnimationAction = m_listAnimationAction.begin(); iteratorAnimationAction != m_listAnimationAction.end(); ++iteratorAnimationAction) { // get the core animation instance CalCoreAnimation *pCoreAnimation; pCoreAnimation = (*iteratorAnimationAction)->getCoreAnimation(); // Ask the animation for the pose at the given time std::vector<CalTransform> pose; pose.resize(pCoreAnimation->getTrackCount()); pCoreAnimation->getPose((*iteratorAnimationAction)->getTime(), pose); // Blend the pose into the current bone states for (unsigned bone_id = 0; bone_id < pSkeleton->getCoreSkeleton()->getVectorCoreBone().size(); ++bone_id) { int track_number = pCoreAnimation->getTrackAssignment(bone_id); // Skip this bone if the bone does not have a track assigned in the animation if (track_number == -1) { continue; } // Blend the animation pose with the skeleton CalBone* pBone = vectorBone[bone_id]; pBone->blendState((*iteratorAnimationAction)->getWeight(), pose[track_number].getTranslation(), pose[track_number].getRotation()); } } // lock the skeleton state pSkeleton->lockState(); // loop through all animation cycles std::list<CalAnimationCycle *>::iterator iteratorAnimationCycle; for(iteratorAnimationCycle = m_listAnimationCycle.begin(); iteratorAnimationCycle != m_listAnimationCycle.end(); ++iteratorAnimationCycle) { // get the core animation instance CalCoreAnimation *pCoreAnimation; pCoreAnimation = (*iteratorAnimationCycle)->getCoreAnimation(); // calculate adjusted time float animationTime; if((*iteratorAnimationCycle)->getState() == CalAnimation::STATE_SYNC) { if(m_animationDuration == 0.0f) { animationTime = 0.0f; } else { animationTime = m_animationTime * pCoreAnimation->getDuration() / m_animationDuration; } } else { animationTime = (*iteratorAnimationCycle)->getTime(); } // Ask the animation for the pose at the given time std::vector<CalTransform> pose; pose.resize(pCoreAnimation->getTrackCount()); pCoreAnimation->getPose(animationTime, pose); // Blend the pose into the current bone states for (unsigned index = 0; index < pose.size(); ++index) { int track_number = pCoreAnimation->getTrackAssignment(index); // Skip this bone if the bone does not have a track assigned in the animation if (track_number == -1) { continue; } CalBone* pBone = vectorBone[index]; pBone->blendState((*iteratorAnimationCycle)->getWeight(), pose[track_number].getTranslation(), pose[track_number].getRotation()); } } // lock the skeleton state pSkeleton->lockState(); // let the skeleton calculate its final state pSkeleton->calculateState(); }
void CalMixer::updateSkeleton() { // get the skeleton we need to update CalSkeleton *pSkeleton; pSkeleton = m_pModel->getSkeleton(); if(pSkeleton == 0) return; // clear the skeleton state pSkeleton->clearState(); // get the bone vector of the skeleton std::vector<CalBone *>& vectorBone = pSkeleton->getVectorBone(); // The bone adjustments are "replace" so they have to go first, giving them // highest priority and full influence. Subsequent animations affecting the same bones, // including subsequent replace animations, will have their incluence attenuated appropriately. applyBoneAdjustments(); // loop through all animation actions std::list<CalAnimationAction *>::iterator itaa; for( itaa = m_listAnimationAction.begin(); itaa != m_listAnimationAction.end(); itaa++ ) { // get the core animation instance CalAnimationAction * aa = * itaa; // Manual animations can be on or off. If they are off, they do not apply // to the bone. if( aa->on() ) { CalCoreAnimation * pCoreAnimation = aa->getCoreAnimation(); // get the list of core tracks of above core animation std::list<CalCoreTrack *>& listCoreTrack = pCoreAnimation->getListCoreTrack(); // loop through all core tracks of the core animation std::list<CalCoreTrack *>::iterator itct; for( itct = listCoreTrack.begin(); itct != listCoreTrack.end(); itct++ ) { // get the appropriate bone of the track CalCoreTrack * ct = * itct; if( ct->getCoreBoneId() >= int(vectorBone.size()) ) { continue; } CalBone * pBone = vectorBone[ ct->getCoreBoneId() ]; // get the current translation and rotation CalVector translation; CalQuaternion rotation; ct->getState( aa->getTime(), translation, rotation); // Replace and CrossFade both blend with the replace function. bool replace = aa->getCompositionFunction() != CalAnimation::CompositionFunctionAverage; float scale = aa->getScale(); pBone->blendState( aa->getWeight(), translation, rotation, scale, replace, aa->getRampValue() ); } } } // === What does lockState() mean? Why do we need it at all? It seems only to allow us // to blend all the animation actions together into a temporary sum, and then // blend all the animation cycles together into a different sum, and then blend // the two sums together according to their relative weight sums. I believe this is mathematically // equivalent of blending all the animation actions and cycles together into a single sum, // according to their relative weights. pSkeleton->lockState(); // let the skeleton calculate its final state pSkeleton->calculateState(); }
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(); } }
void CCal3DSceneNode::render() { if ( bInitialized ) { irr::video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setTransform( irr::video::ETS_WORLD, AbsoluteTransformation ); irr::video::S3DVertex tmp; irr::scene::SMeshBuffer mb; unsigned char meshColor[4]; // r g b a // get the renderer of the model CalRenderer* pCalRenderer; pCalRenderer = m_calModel->getRenderer(); pCalRenderer->setNormalization( true ); if ( this->DebugDataVisible ) { irr::video::SMaterial mat; mat.Wireframe = false; mat.Lighting = false; driver->setMaterial( mat ); driver->draw3DBox( Box ); CalSkeleton* pCalSkeleton = m_calModel->getSkeleton(); pCalSkeleton->calculateBoundingBoxes(); std::vector<CalBone*>& vectorCoreBone = pCalSkeleton->getVectorBone(); irr::core::aabbox3df b; CalVector p[8]; Vector3 v[8]; for ( size_t boneId = 0; boneId < vectorCoreBone.size(); ++boneId ) { CalBone* bone = vectorCoreBone[boneId]; CalBoundingBox& calBoundingBox = bone->getBoundingBox(); calBoundingBox.computePoints( p ); for ( int i = 0; i < 8; ++i ) { v[i].set( p[i].x, p[i].y, p[i].z ); } driver->setMaterial( mat ); // draw the box driver->draw3DLine( v[0], v[1], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[0], v[2], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[1], v[3], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[2], v[3], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[4], v[5], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[4], v[6], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[5], v[7], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[6], v[7], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[0], v[4], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[1], v[5], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[2], v[6], irr::video::SColor( 255, 0, 0, 255 ) ); driver->draw3DLine( v[3], v[7], irr::video::SColor( 255, 0, 0, 255 ) ); //printf("F: %f\n", v[0].X); } } // begin the rendering loop if ( pCalRenderer->beginRendering() ) { // get the number of meshes int meshCount; meshCount = pCalRenderer->getMeshCount(); // render all meshes of the model int meshId; for ( meshId = 0; meshId < meshCount; meshId++ ) { // get the number of submeshes int submeshCount; submeshCount = pCalRenderer->getSubmeshCount( meshId ); // render all submeshes of the mesh int submeshId; for ( submeshId = 0; submeshId < submeshCount; submeshId++ ) { // select mesh and submesh for further data access if ( pCalRenderer->selectMeshSubmesh( meshId, submeshId ) ) { // set the material ambient color pCalRenderer->getAmbientColor( &meshColor[0] ); material.AmbientColor.set( meshColor[3], meshColor[0], meshColor[1], meshColor[2] ); // set the material diffuse color pCalRenderer->getDiffuseColor( &meshColor[0] ); material.DiffuseColor.set( meshColor[3], meshColor[0], meshColor[1], meshColor[2] ); // set the material specular color pCalRenderer->getSpecularColor( &meshColor[0] ); material.SpecularColor.set( meshColor[3], meshColor[0], meshColor[1], meshColor[2] ); // set the material shininess factor material.Shininess = pCalRenderer->getShininess(); // get the transformed vertices of the submesh static float meshVertices[3000][3]; int vertexCount = 0; // TODO: //if (KERNEL.GetTicks() % 3 == 0) //- make lod dependent? vertexCount = pCalRenderer->getVertices( &meshVertices[0][0] ); // get the transformed normals of the submesh static float meshNormals[3000][3]; int normalsCount = 0; // if (KERNEL.GetTicks() % 3 == 0) normalsCount = pCalRenderer->getNormals( &meshNormals[0][0] ); // get the texture coordinates of the submesh static float meshTextureCoordinates[3000][2]; int textureCoordinateCount = 0; textureCoordinateCount = pCalRenderer->getTextureCoordinates( 0, &meshTextureCoordinates[0][0] ); // get the faces of the submesh static CalIndex meshFaces[5000][3]; int faceCount = 0; //if (KERNEL.GetTicks() % 12 == 0) faceCount = pCalRenderer->getFaces( &meshFaces[0][0] ); if ( ( pCalRenderer->getMapCount() > 0 ) && ( textureCoordinateCount > 0 ) ) { irr::video::ITexture* t = static_cast<irr::video::ITexture*>( pCalRenderer->getMapUserData( 0 ) ); material.Texture1 = t; } static S3DVertex vs[5000]; for ( int i = 0; i < vertexCount; i++ ) { vs[i].Pos.set( meshVertices[i][0], meshVertices[i][1], meshVertices[i][2] ); vs[i].Normal.set( meshNormals[i][0], meshNormals[i][1], meshNormals[i][2] ); vs[i].TCoords.set( meshTextureCoordinates[i][0], meshTextureCoordinates[i][1] ); vs[i].Color = irr::video::SColor( 255, 255, 255, 255 ); } static u16 is[5000]; for ( int i = 0; i < faceCount; i += 1 ) { is[i * 3 + 0] = meshFaces[i][0]; is[i * 3 + 1] = meshFaces[i][1]; is[i * 3 + 2] = meshFaces[i][2]; } //mb.Vertices.clear(); //mb.Vertices.reallocate(vertexCount); //for(int i=0;i<vertexCount;i++) //{ // tmp.Pos.set(meshVertices[i][0],meshVertices[i][1],meshVertices[i][2]); // tmp.Normal.set(meshNormals[i][0],meshNormals[i][1],meshNormals[i][2]); // tmp.TCoords.set(meshTextureCoordinates[i][0],meshTextureCoordinates[i][1]); // tmp.Color=irr::video::SColor(255,255,255,255); // mb.Vertices.push_back(tmp); //} //mb.Indices.clear(); //mb.Indices.reallocate(faceCount); //for(int i=0; i<faceCount; ++i) //{ // mb.Indices.push_back(meshFaces[i][0]); // mb.Indices.push_back(meshFaces[i][1]); // mb.Indices.push_back(meshFaces[i][2]); //} // draw driver->setMaterial( material ); //driver->drawIndexedTriangleList(mb.Vertices.const_pointer(),mb.Vertices.size(),mb.Indices.const_pointer(),faceCount); driver->drawIndexedTriangleList( vs, vertexCount, is, faceCount ); //driver->drawMeshBuffer(&mb); //CONSOLE.addx("#Verts %d #Norm %d #Tex %d #Faces %d #Map %d", // vertexCount,normalsCount,textureCoordinateCount,faceCount, pCalRenderer->getMapCount()); } } } // end the rendering pCalRenderer->endRendering(); } } }
void IKCharacter::draw( int bone_id, float scale, bool additional_drawing ) { CalBone* bone = skeleton->getBone( bone_id ); int parent_id = bone->getCoreBone()->getParentId(); if ( parent_id != -1 ) { // current CalBone* parent = skeleton->getBone( parent_id ); glBegin( GL_LINES ); CalVector v = parent->getTranslationAbsolute(); v*=scale; CalVector c = v; glVertex3f( v.x, v.y, v.z ); v = bone->getTranslationAbsolute(); v*=scale; c += v; c /= 2.0f; glVertex3f( v.x, v.y, v.z ); glEnd(); // world glPushAttrib( GL_CURRENT_BIT ); glColor3f( 0.1f, 0.8f, 0.1f ); glBegin( GL_LINES ); v = world_positions[parent_id]; v*=scale; glVertex3f( v.x, v.y, v.z ); v = world_positions[bone_id]; v*=scale; glVertex3f( v.x, v.y, v.z ); glEnd(); glPopAttrib(); if ( additional_drawing ) { glPushAttrib( GL_CURRENT_BIT ); glBegin( GL_LINES ); // core glColor3f( (parent_id==debug_bone)?1.0f:0.3f, 0.3f, 0.5f ); v = parent->getCoreBone()->getTranslationAbsolute(); v*=scale; glVertex3f( v.x, v.y, v.z ); v = bone->getCoreBone()->getTranslationAbsolute(); v*=scale; glVertex3f( v.x, v.y, v.z ); glEnd(); // draw rotation glPushMatrix(); CalVector root = bone->getCoreBone()->getTranslationAbsolute(); glTranslatef( root.x, root.y, root.z ); CalVector rot; rot.set( 0, 0.1f*scale, 0 ); rot *= bone->getCoreBone()->getRotationAbsolute(); ofEnableAlphaBlending(); glColor4f( 0.2f, 0.2f, 0.8f, 0.2f ); glBegin( GL_TRIANGLES ); //glVertex3f( 0,0,0 ); glVertex3f( rot.x, rot.y, rot.z ); rot *= debug_cached_rotations[bone_id]; glVertex3f( rot.x, rot.y, rot.z ); glEnd(); glColor4f( 0.2f, 0.2f, 0.8f, 0.8f ); rot.set( 0, 0.1f*scale, 0 ); rot *= bone->getCoreBone()->getRotationAbsolute(); glBegin( GL_LINES ); glVertex3f( 0,0,0 ); glVertex3f( rot.x, rot.y, rot.z ); rot *= debug_cached_rotations[bone_id]; glVertex3f( 0,0,0 ); glVertex3f( rot.x, rot.y, rot.z ); glEnd(); ofDisableAlphaBlending(); glPopMatrix(); CalVector u( 0, 0.1f*scale, 0); u *= bone->getRotationAbsolute(); CalVector r( 0.1f*scale, 0, 0 ); r *= bone->getRotationAbsolute(); CalVector f( 0, 0, 0.1f*scale ); f *= bone->getRotationAbsolute(); // right blue glPushMatrix(); root = bone->getTranslationAbsolute(); glTranslatef( root.x, root.y, root.z ); glBegin( GL_LINES ); glColor3f( 0, 0, 1 ); glVertex3f( 0,0,0 ); glVertex3f( r.x, r.y, r.z ); // up red glColor3f( 1, 0, 0 ); glVertex3f( 0,0,0 ); glVertex3f( u.x, u.y, u.z ); // forward green glColor3f( 0, 1, 0 ); glVertex3f( 0,0,0 ); glVertex3f( f.x, f.y, f.z ); glEnd(); glPopMatrix(); // right blue glPushMatrix(); root = world_positions[bone_id]; glTranslatef( root.x, root.y, root.z ); glBegin( GL_LINES ); glColor3f( 0, 0, 1 ); glVertex3f( 0,0,0 ); glVertex3f( r.x, r.y, r.z ); // up red glColor3f( 1, 0, 0 ); glVertex3f( 0,0,0 ); glVertex3f( u.x, u.y, u.z ); // forward green glColor3f( 0, 1, 0 ); glVertex3f( 0,0,0 ); glVertex3f( f.x, f.y, f.z ); glEnd(); glPopMatrix(); glPopAttrib(); } } list<int> children = bone->getCoreBone()->getListChildId(); for ( list<int>::iterator it = children.begin(); it != children.end(); ++it ) { draw( *it, scale, additional_drawing ); } }