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 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 ); } } }
void CalCoreBone::calculateState() { if(m_parentId == -1) { // no parent, this means absolute state == relative state m_translationAbsolute = m_translation; m_rotationAbsolute = m_rotation; } else { // get the parent bone CalCoreBone *pParent; pParent = m_pCoreSkeleton->getCoreBone(m_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 all child bones std::list<int>::iterator iteratorChildId; for(iteratorChildId = m_listChildId.begin(); iteratorChildId != m_listChildId.end(); ++iteratorChildId) { m_pCoreSkeleton->getCoreBone(*iteratorChildId)->calculateState(); } }
void CalCoreTrack::translationCompressibility( bool * transRequiredResult, bool * transDynamicResult, bool * highRangeRequiredResult, float threshold, float highRangeThreshold, CalCoreSkeleton * skel ) { * transRequiredResult = false; * transDynamicResult = false; * highRangeRequiredResult = false; unsigned int numFrames = m_keyframes.size(); CalCoreBone * cb = skel->getCoreBone( m_coreBoneId ); const CalVector & cbtrans = cb->getTranslation(); CalVector trans0; float t2 = threshold * threshold; unsigned int i; for( i = 0; i < numFrames; i++ ) { CalCoreKeyframe * keyframe = m_keyframes[ i ]; const CalVector & kftrans = keyframe->getTranslation(); if( fabsf( kftrans.x ) >= highRangeThreshold || fabsf( kftrans.y ) >= highRangeThreshold || fabsf( kftrans.z ) >= highRangeThreshold ) { * highRangeRequiredResult = true; } if( i == 0 ) { trans0 = keyframe->getTranslation(); } else { float d2 = DistanceSquared( trans0, kftrans ); if( d2 > t2 ) { * transDynamicResult = true; } } float d2 = DistanceSquared( cbtrans, kftrans ); if( d2 > t2 ) { * transRequiredResult = true; } } }
const std::list<int>& BoneBridgeCAL3D::GetListChildBoneID() const { CalBone* calBone = (CalBone*)GetCalBone(); CalCoreBone* coreBone = calBone->getCoreBone(); std::list<int>& listChildID = coreBone->getListChildId(); return listChildID; }
void BoneBridgeCAL3D::ComputeBoundingBox() { CalCoreBone* coreBone = mpCalBone->getCoreBone(); assert(coreBone); CalCoreModel* coreModel = mpCalModel->getCoreModel(); assert(coreModel); if (!coreBone->isBoundingBoxPrecomputed()) { coreBone->calculateBoundingBox(coreModel); assert(coreBone->isBoundingBoxPrecomputed()); } mpCalBone->calculateBoundingBox(); }
void CalCoreAnimation::fillInvalidTranslations( CalCoreSkeleton * skel ) { std::list<CalCoreTrack *>::iterator iteratorCoreTrack; for(iteratorCoreTrack = m_listCoreTrack.begin(); iteratorCoreTrack != m_listCoreTrack.end(); ++iteratorCoreTrack) { CalCoreTrack * tr = * iteratorCoreTrack; int boneId = tr->getCoreBoneId(); assert( boneId != -1 ); CalCoreBone * bo = skel->getCoreBone( boneId ); if( bo ) { CalVector trans = bo->getTranslation(); tr->fillInvalidTranslations( trans ); } } }
BoneBridgeCAL3D::BoneBridgeCAL3D(Skeleton& skeleton, CalBone* calBone, CalModel* calModel, int calBoneID) : mSkeleton(skeleton) , mpCalBone(calBone) , mpCalModel(calModel) , mCalBoneID(calBoneID) { // create box first { CalCoreBone* coreBone = mpCalBone->getCoreBone(); // start by computing our bounding box and our bounding box corners ComputeBoundingBox(); std::vector<Vec3f> corners = ComputeBoundingBoxCorners(coreBone->getBoundingBox()); Vec3f bbMin = FindMinBoundingBoxXYZ(corners); Vec3f bbMax = FindMaxBoundingBoxXYZ(corners); BoundingBox<3, float> bbox(bbMin, bbMax - bbMin); // don't allow any boxes of no area { Vec3f dimensions = bbox.GetDimensions(); const bool no_volume = dimensions[X] <= 0 || dimensions[Y] <= 0 || dimensions[Z] <= 0; if (no_volume) { static const float kThinnest = 0.01f; //0.01f; // enforce a volume! bbox = BoundingBox<3, float>(bbox.GetMinimum(), Vec3f( dimensions[X] > 0 ? dimensions[X] : kThinnest, dimensions[Y] > 0 ? dimensions[Y] : kThinnest, dimensions[Z] > 0 ? dimensions[Z] : kThinnest)); } } SetDimensions(bbox.GetDimensions()); } }
//------------------------------------------------------------------------------// // Export the skeleton from a Maxscript call --// //------------------------------------------------------------------------------// bool CMaxInterface::ExportSkeletonFromMaxscriptCall(const std::string& strFilename, bool bShowUI) { // build a skeleton candidate CSkeletonCandidate skeletonCandidate; if(!skeletonCandidate.CreateFromInterfaceFromMaxScriptCall()) return false; //Does the user wants to see the UI and select the bones himself ? if (bShowUI) { // show export wizard sheet CSkeletonExportSheet sheet(_T("Cal3D Skeleton Export"), GetMainWnd()); sheet.SetSkeletonCandidate(&skeletonCandidate); sheet.SetWizardMode(); if(sheet.DoModal() != ID_WIZFINISH) return true; } // build the selected ids of the bone candidates int selectedCount = skeletonCandidate.BuildSelectedId(); if(selectedCount == 0) { theExporter.SetLastError("No bones selected to export.", __FILE__, __LINE__); return false; } // create the core skeleton instance CalCoreSkeletonPtr coreSkeleton = new CalCoreSkeleton; // get bone candidate vector std::vector<CBoneCandidate *>& vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate(); // start the progress info StartProgressInfo("Exporting to skeleton file..."); size_t boneCandidateId; int selectedId; for(boneCandidateId = 0, selectedId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++) { // get the bone candidate CBoneCandidate *pBoneCandidate; pBoneCandidate = vectorBoneCandidate[boneCandidateId]; // only export selected bone candidates if(pBoneCandidate->IsSelected()) { // update the progress info SetProgressInfo(int(100.0f * (selectedId + 1) / selectedCount)); selectedId++; // allocate new core bone instance CalCoreBone *pCoreBone = new CalCoreBone(pBoneCandidate->GetNode()->GetName()); // get the parent id of the bone candidate int parentId; parentId = skeletonCandidate.GetParentSelectedId(boneCandidateId); // set the parentId pCoreBone->setParentId(parentId); // get the translation and the rotation of the bone candidate CalVector translation; CalQuaternion rotation; skeletonCandidate.GetTranslationAndRotation(boneCandidateId, -1.0f, translation, rotation); // set the translation and rotation pCoreBone->setTranslation(translation); pCoreBone->setRotation(rotation); // get the bone space translation and the rotation of the bone candidate CalVector translationBoneSpace; CalQuaternion rotationBoneSpace; skeletonCandidate.GetTranslationAndRotationBoneSpace(boneCandidateId, -1.0f, translationBoneSpace, rotationBoneSpace); // set the bone space translation and rotation pCoreBone->setTranslationBoneSpace(translationBoneSpace); pCoreBone->setRotationBoneSpace(rotationBoneSpace); // set the core skeleton of the core bone instance pCoreBone->setCoreSkeleton(coreSkeleton.get()); // add the core bone to the core skeleton instance int boneId; boneId = coreSkeleton->addCoreBone(pCoreBone); // adjust child list of parent bone if(parentId != -1) { // get parent core bone CalCoreBone *pParentCoreBone; pParentCoreBone = coreSkeleton->getCoreBone(parentId); if(pParentCoreBone == 0) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreBone; StopProgressInfo(); return false; } // add this core bone to the child list of the parent bone pParentCoreBone->addChildId(boneId); } } } // stop the progress info StopProgressInfo(); // save core skeleton to the file if(!CalSaver::saveCoreSkeleton(strFilename, coreSkeleton.get())) { theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); return false; } return true; }
void IKCharacter::setup( CalSkeleton* cal_skel, bool _auto_root_follow ) { skeleton = cal_skel; auto_root_follow = _auto_root_follow; // find leaf bones deque<int> current; vector<int> roots = cal_skel->getCoreSkeleton()->getVectorRootCoreBoneId(); current.insert( current.begin(), roots.begin(), roots.end() ); while( !current.empty() ) { CalCoreBone* check = skeleton->getCoreSkeleton()->getCoreBone( current.front() ); list<int> children = check->getListChildId(); if ( children.size()==0 ) { // this is a leaf leaf_bones.push_back( current.front() ); printf("found leaf: %s\n", skeleton->getCoreSkeleton()->getCoreBone( leaf_bones.back() )->getName().c_str() ); } else { // not a leaf current.insert( current.end(), children.begin(), children.end() ); } // store length // default non-zero bone_lengths[current.front()] = 0.0001f; if ( check->getParentId()!= -1 ) { CalCoreBone* parent = skeleton->getCoreSkeleton()->getCoreBone( check->getParentId() ); CalVector delta = check->getTranslationAbsolute() - parent->getTranslationAbsolute(); bone_lengths[check->getParentId()] = delta.length(); } // cached rotations debug_cached_rotations[current.front()] = CalQuaternion(); current.pop_front(); } // set all weights to default vector<CalCoreBone*> all_bones = skeleton->getCoreSkeleton()->getVectorCoreBone(); for( int i=0; i<all_bones.size() ;i++ ) { weight_centres[all_bones[i]->getId()] = 0.5f; } // release all leaves for ( int i=0; i<leaf_bones.size() ;i++ ) { weight_centres[leaf_bones[i]] = 0; } // pin all roots for ( int i=0; i<roots.size(); i++ ) { weight_centres[roots[i]] = 1; } // fetch world positions from Cal3D model pullWorldPositions(); // set targets /* for ( int i=0; i<leaf_bones.size(); i++ ) { CalVector p = world_positions[leaf_bones[i]]; setTarget( leaf_bones[i], ofxVec3f(p.x,p.y,p.z) ); }*/ // setupMagicIgnoringRotationOffsets(); }
int CMaxAnimationImport::DoImport( const TCHAR* name, ImpInterface* ii, Interface* i, BOOL suppressPrompts) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HWND window = i->GetMAXHWnd(); CFileDialog fileDialog(TRUE, "xsf", 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 0, CWnd::FromHandle(window)); if (fileDialog.DoModal() != IDOK) { return IMPEXP_CANCEL; } CString skeleton = fileDialog.GetPathName(); cal3d::RefPtr<CalCoreSkeleton> skel = CalLoader::loadCoreSkeleton(std::string(skeleton)); if (!skel) { MessageBox( window, "Loading skeleton file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } cal3d::RefPtr<CalCoreAnimation> anim = CalLoader::loadCoreAnimation(name); if (!anim) { MessageBox( window, "Loading animation file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } typedef std::list<CalCoreTrack*> CoreTrackList; CoreTrackList& trackList = anim->getListCoreTrack(); for (CoreTrackList::iterator itr = trackList.begin(); itr != trackList.end(); ++itr) { CalCoreTrack* track = *itr; int boneId = track->getCoreBoneId(); CalCoreBone* bone = skel->getCoreBone(boneId); if (!bone) continue; INode* node = i->GetINodeByName(bone->getName().c_str()); if (!node) continue; unsigned kfCount = track->getCoreKeyframeCount(); SuspendAnimate(); AnimateOn(); for (unsigned i = 0; i < kfCount; ++i) { CalCoreKeyframe* kf = track->getCoreKeyframe(i); CalQuaternion kf_q = kf->getRotation(); CalVector kf_v = kf->getTranslation(); TimeValue time = SecToTicks(kf->getTime()); Matrix3 tm; tm.IdentityMatrix(); Quat(kf_q.x, kf_q.y, kf_q.z, kf_q.w).MakeMatrix(tm); tm.SetTrans(Point3(kf_v.x, kf_v.y, kf_v.z)); INode* parent = node->GetParentNode(); if (parent) { tm *= parent->GetNodeTM(time); } node->SetNodeTM(time, tm); } ResumeAnimate(); /* typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); int mapsize = sizeof(keys); int size = keys.size(); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { Point3 p; CalCoreKeyframe* kf = mi->second; p.x = kf->getTranslation().x; p.y = kf->getTranslation().y; p.z = kf->getTranslation().z; pos->SetValue(SecToTicks(mi->first), &p); } */ /* IKeyControl* kc = GetKeyControlInterface(pos); if (!kc) continue; typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); kc->SetNumKeys(keys.size()); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { ITCBPoint3Key key; key.time = SecToTicks(mi->first); key.tens = 0; key.cont = 0; key.bias = 0; key.easeIn = 25.0; key.easeOut = 25.0; key.val.x = mi->second->getTranslation().x; key.val.y = mi->second->getTranslation().y; key.val.z = mi->second->getTranslation().z; kc->SetKey(idx++, &key); } kc->SortKeys(); */ } return IMPEXP_SUCCESS; }
int CMaxAnimationImport::DoImport( const TCHAR* name, ImpInterface* ii, Interface* i, BOOL suppressPrompts) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HWND window = i->GetMAXHWnd(); CFileDialog fileDialog(TRUE, "xsf", 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 0, CWnd::FromHandle(window)); if (fileDialog.DoModal() != IDOK) { return IMPEXP_CANCEL; } CString skeleton = fileDialog.GetPathName(); CalCoreSkeletonPtr skel = CalLoader::loadCoreSkeleton(std::string(skeleton)); if (!skel) { MessageBox( window, "Loading skeleton file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } CalCoreAnimationPtr anim = CalLoader::loadCoreAnimation(name); if (!anim) { MessageBox( window, "Loading animation file failed", "Import Cal3D Animation", MB_OK | MB_ICONERROR); return IMPEXP_FAIL; } // Get the pose information in the animation const std::vector<CalTransform>& poses = anim->getPoses(); unsigned int num_poses = poses.size() / anim->getTrackCount(); // Calculate the time_per_frame incorrectly since the duration for animations // is stored incorrectly. float time_per_frame = anim->getDuration() / num_poses; // Import each track for (unsigned track_id = 0; track_id < anim->getTrackCount(); ++track_id) { // Get the core bone mapped to the animation int bone_id = anim->getBoneAssignment(track_id); CalCoreBone* bone = skel->getCoreBone(bone_id); if (!bone) continue; // Get the max node for the bone INode* node = i->GetINodeByName(bone->getName().c_str()); if (!node) continue; SuspendAnimate(); AnimateOn(); // Add each pose keyframe in the track float keyframe_time = 0.0f; for (unsigned keyframe_index = 0; keyframe_index < num_poses; ++keyframe_index) { // Get the keyframe data const CalTransform& pose_coord_sys = poses[(keyframe_index * anim->getTrackCount()) + track_id]; const CalVector &kf_v = pose_coord_sys.getTranslation(); const CalQuaternion &kf_q = pose_coord_sys.getRotation(); TimeValue time = SecToTicks(keyframe_time); // Convert to Max math Matrix3 tm; tm.IdentityMatrix(); Quat(kf_q.x, kf_q.y, kf_q.z, kf_q.w).MakeMatrix(tm); tm.SetTrans(Point3(kf_v.x, kf_v.y, kf_v.z)); // Convert the transform to world space INode* parent = node->GetParentNode(); if (parent) { tm *= parent->GetNodeTM(time); } // Set the new transform on the node node->SetNodeTM(time, tm); keyframe_time += time_per_frame; } ResumeAnimate(); /* typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); int mapsize = sizeof(keys); int size = keys.size(); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { Point3 p; CalCoreKeyframe* kf = mi->second; p.x = kf->getTranslation().x; p.y = kf->getTranslation().y; p.z = kf->getTranslation().z; pos->SetValue(SecToTicks(mi->first), &p); } */ /* IKeyControl* kc = GetKeyControlInterface(pos); if (!kc) continue; typedef std::map<float, CalCoreKeyframe*> KeyMap; KeyMap& keys = track->getMapCoreKeyframe(); kc->SetNumKeys(keys.size()); int idx = 0; for (KeyMap::iterator mi = keys.begin(); mi != keys.end(); ++mi) { ITCBPoint3Key key; key.time = SecToTicks(mi->first); key.tens = 0; key.cont = 0; key.bias = 0; key.easeIn = 25.0; key.easeOut = 25.0; key.val.x = mi->second->getTranslation().x; key.val.y = mi->second->getTranslation().y; key.val.z = mi->second->getTranslation().z; kc->SetKey(idx++, &key); } kc->SortKeys(); */ } return IMPEXP_SUCCESS; }
bool CExporter::ExportSkeleton(const std::string& strFilename) { // check if a valid interface is set if(m_pInterface == 0) { SetLastError("Invalid handle.", __FILE__, __LINE__); return false; } // build a skeleton candidate CSkeletonCandidate skeletonCandidate; if(!skeletonCandidate.CreateFromInterface()) return false; // show export wizard sheet CSkeletonExportSheet sheet("Cal3D Skeleton Export", m_pInterface->GetMainWnd()); sheet.SetSkeletonCandidate(&skeletonCandidate); sheet.SetWizardMode(); if(sheet.DoModal() != ID_WIZFINISH) return true; // build the selected ids of the bone candidates int selectedCount = skeletonCandidate.BuildSelectedId(); if(selectedCount == 0) { SetLastError("No bones selected to export.", __FILE__, __LINE__); return false; } // create the core skeleton instance CalCoreSkeletonPtr coreSkeleton = new CalCoreSkeleton; // get bone candidate vector std::vector<CBoneCandidate *> vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate(); // start the progress info m_pInterface->StartProgressInfo("Exporting to skeleton file..."); size_t boneCandidateId; int selectedId; for(boneCandidateId = 0, selectedId = 0; boneCandidateId < vectorBoneCandidate.size(); boneCandidateId++) { // get the bone candidate CBoneCandidate *pBoneCandidate = vectorBoneCandidate[boneCandidateId]; // only export selected bone candidates if(pBoneCandidate->IsSelected()) { // update the progress info m_pInterface->SetProgressInfo(int(100.0f * (selectedId + 1) / selectedCount)); selectedId++; // allocate new core bone instance CalCoreBone *pCoreBone = new CalCoreBone(pBoneCandidate->GetNode()->GetName()); // get the parent id of the bone candidate int parentId = skeletonCandidate.GetParentSelectedId(boneCandidateId); // set the parentId pCoreBone->setParentId(parentId); // get the translation and the rotation of the bone candidate CalVector translation; CalQuaternion rotation; skeletonCandidate.GetTranslationAndRotation(boneCandidateId, -1.0f, translation, rotation); // set the translation and rotation pCoreBone->setTranslation(translation); pCoreBone->setRotation(rotation); // get the bone space translation and the rotation of the bone candidate CalVector translationBoneSpace; CalQuaternion rotationBoneSpace; skeletonCandidate.GetTranslationAndRotationBoneSpace(boneCandidateId, -1.0f, translationBoneSpace, rotationBoneSpace); // set the bone space translation and rotation pCoreBone->setTranslationBoneSpace(translationBoneSpace); pCoreBone->setRotationBoneSpace(rotationBoneSpace); // set the core skeleton of the core bone instance pCoreBone->setCoreSkeleton(coreSkeleton.get()); // add the core bone to the core skeleton instance int boneId; boneId = coreSkeleton->addCoreBone(pCoreBone); // adjust child list of parent bone if(parentId != -1) { // get parent core bone CalCoreBone *pParentCoreBone; pParentCoreBone = coreSkeleton->getCoreBone(parentId); if(pParentCoreBone == 0) { SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); delete pCoreBone; m_pInterface->StopProgressInfo(); return false; } // add this core bone to the child list of the parent bone pParentCoreBone->addChildId(boneId); } } } // stop the progress info m_pInterface->StopProgressInfo(); // save core skeleton to the file if(!CalSaver::saveCoreSkeleton(strFilename, coreSkeleton.get())) { SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__); return false; } HKEY hk; LONG lret=RegCreateKey(HKEY_CURRENT_USER, "Software\\Cal3D\\Exporter", &hk); if(lret==ERROR_SUCCESS && NULL!=hk) { lret=RegSetValueEx(hk,"skeleton",NULL,REG_SZ,(unsigned char *)strFilename.c_str() ,strFilename.length()); RegCloseKey(hk); } return true; }