// *************************************************************************** bool CExportNel::getNELUnHeritFatherScale(INode &node) { // Default. bool ret= false; /* If my parent exist, and if my parent is a BipedNode, always suppose I must unherit scale. This is because Biped NodeTM always have a Scale 1,1,1. Hence Sons bones do not herit scale. */ INode *parentNode= node.GetParentNode(); if(parentNode && isBipedNode(*parentNode) ) { ret= true; } // Else, test the std way. else { // Get the TM controler Control *c; c = node.GetTMController(); // If a TM controler exist if (c) { // Get the inherit flags DWORD flags=c->GetInheritanceFlags(); // Unherit scale if all scale inherit flags are cleared ret= (flags&(INHERIT_SCL_X|INHERIT_SCL_Y|INHERIT_SCL_Z))!=0; } } return ret; }
// *************************************************************************** bool CExportNel::isBipedNode(INode &node) { bool ret= false; Control *c= node.GetTMController(); if( c && ( c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID || c->ClassID() == BIPBODY_CONTROL_CLASS_ID )) ret= true; return ret; }
void SkeletonExporter::export_camera(INode *node) { Control *c; int size_key; float camera_znear, camera_zfar; CameraState cs; // Interval valid = FOREVER; ObjectState os; CameraObject *cam; GenCamera *gencam; float roll0; Matrix3 mat; Point3 row; os = node->EvalWorldState(0); cam = (CameraObject *)os.obj; gencam = (GenCamera *)os.obj; if (gencam->Type() != TARGETED_CAMERA) { fprintf(fTXT, "Only targeted camera are supported!\n\n"); return; } fprintf(fTXT, "Targeted camera found\n"); write_chunk_header(fA3D, TARGETED_CAMERA_ID, node->GetName(), 40); if (makeRAY) write_chunk_header(fRAY, TARGETED_CAMERA_ID, node->GetName(), 40); INode* target = node->GetTarget(); fprintf(fTXT, "Name : %s\n", node->GetName()); cam->EvalCameraState(0, FOREVER, &cs); // ------------------ salviamo znear e zfar ---------------------- camera_znear=2; camera_zfar=2000; if (cs.manualClip) { camera_znear=cs.hither; camera_zfar=cs.yon; } fprintf(fTXT, "Znear = %f \n", camera_znear); fwrite(&camera_znear, sizeof(float), 1, fA3D); if (makeRAY) fwrite(&camera_znear, sizeof(float), 1, fRAY); fprintf(fTXT, "Zfar = %f \n", camera_zfar); fwrite(&camera_zfar, sizeof(float), 1, fA3D); if (makeRAY) fwrite(&camera_zfar, sizeof(float), 1, fRAY); // ----------------- salviamo l'angolo di FOV -------------------- fprintf(fTXT, "FOV (rad) = %f \n", cs.fov); fwrite(&cs.fov, sizeof(float), 1, fA3D); if (makeRAY) fwrite(&cs.fov, sizeof(float), 1, fRAY); // ------------------ salviamo l'angolo di roll ------------------ c=node->GetTMController()->GetRollController(); c->GetValue(0, &roll0, FOREVER); fprintf(fTXT, "Roll (rad) = %f \n", roll0); fwrite(&roll0, sizeof(float), 1, fA3D); if (makeRAY) fwrite(&roll0, sizeof(float), 1, fRAY); // salviamo la posizione nel mondo mat = node->GetNodeTM(0); row = mat.GetRow(3); fprintf(fTXT, "Camera world position : x=%f, y=%f, z=%f\n", row.x, row.y, row.z); write_point3(&row, fA3D); if (makeRAY) write_point3(&row, fRAY); // --------- salviamo la posizione del target nel mondo ---------- if (target) { mat = target->GetNodeTM(0); row = mat.GetRow(3); fprintf(fTXT, "Target world position : x=%f, y=%f, z=%f\n", row.x, row.y, row.z); write_point3(&row, fA3D); if (makeRAY) write_point3(&row, fRAY); } // esportiamo l'animazione della posizione della camera // se ci sono un numero di key > 0 c=node->GetTMController()->GetPositionController(); if ((c) && (c->NumKeys()>0)) { if (IsTCBControl(c)) size_key=36; else if (IsBezierControl(c)) size_key=40; else size_key=16; fprintf(fTXT, "Camera position track present."); write_chunk_header(fA3D, POSITION_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); export_point3_track(c, 1, fA3D); if (makeRAY) write_chunk_header(fRAY, POSITION_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); if (makeRAY) export_point3_track(c, 1, fRAY); } // ----- esportiamo l'animazione della posizione del target ------ if (target) { c=target->GetTMController()->GetPositionController(); if ((c) && (c->NumKeys()>0)) { if (IsTCBControl(c)) size_key=36; else if (IsBezierControl(c)) size_key=40; else size_key=16; fprintf(fTXT, "Target position track present."); write_chunk_header(fA3D, CAMERA_TARGET_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); export_point3_track(c, 1, fA3D); if (makeRAY) write_chunk_header(fRAY, CAMERA_TARGET_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); if (makeRAY) export_point3_track(c, 1, fRAY); } } // --------------- esportiamo le tracce di FOV ------------------- c=gencam->GetFOVControl(); if ((c) && (c->NumKeys()>0)) { if (IsTCBControl(c)) size_key=28; else if (IsBezierControl(c)) size_key=16; else size_key=8; fprintf(fTXT, "Camera FOV track present."); write_chunk_header(fA3D, CAMERA_FOV_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); export_float_track(c, 1, fA3D); // radianti if (makeRAY) write_chunk_header(fRAY, CAMERA_FOV_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); if (makeRAY) export_float_track(c, 1, fRAY); // radianti } // --------------- esportiamo le tracce di roll ------------------ c=node->GetTMController()->GetRollController(); if ((c) && (c->NumKeys()>0)) { if (IsTCBControl(c)) size_key=28; else if (IsBezierControl(c)) size_key=16; else size_key=8; fprintf(fTXT, "Camera roll track present."); write_chunk_header(fA3D, CAMERA_ROLL_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); export_float_track(c, 1, fA3D); // radianti if (makeRAY) write_chunk_header(fRAY, CAMERA_ROLL_TRACK_ID, node->GetName(), 1+2+4+c->NumKeys()*size_key); if (makeRAY) export_float_track(c, 1, fRAY); // radianti } fprintf(fTXT, "\n\n--------------------------------------------------\n"); }
void KeyTest() { int i, numKeys; INode * n; Control * c; Quat newQuat, prevQuat; IKeyControl* ikeys; ITCBPoint3Key tcbPosKey; ITCBRotKey tcbRotKey; ITCBScaleKey tcbScaleKey; IBezPoint3Key bezPosKey; IBezQuatKey bezRotKey; IBezScaleKey bezScaleKey; ILinPoint3Key linPosKey; ILinRotKey linRotKey; ILinScaleKey linScaleKey; // Get the first node in the selection set if (!CMaxEnv::singleton().m_pInterace->GetSelNodeCount()) return; n = CMaxEnv::singleton().m_pInterace->GetSelNode(0); // --- Process the position keys --- c = n->GetTMController()->GetPositionController(); ikeys = GetKeyControlInterface(c); if (!ikeys) { // No interface available to access the keys... // Just sample the controller to get the position // data at each key... SampleController(n, c); return; } numKeys = ikeys->GetNumKeys(); DebugPrint(_T("\nThere are %d position key(s)"), numKeys); if (c->ClassID() == Class_ID(TCBINTERP_POSITION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &tcbPosKey); //DebugPrint(_T("\nTCB Position Key: %d=(%.1f, %.1f, %.1f)"), // i, tcbPosKey.val.x, tcbPosKey.val.y, tcbPosKey.val.z); } } else if (c->ClassID() == Class_ID(HYBRIDINTERP_POSITION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &bezPosKey); //DebugPrint(_T("\nBezier Position Key: %d=(%.1f, %.1f, %.1f)"), // i, bezPosKey.val.x, bezPosKey.val.y, bezPosKey.val.z); } } else if (c->ClassID() == Class_ID(LININTERP_POSITION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &linPosKey); //DebugPrint(_T("\nLinear Position Key: %d=(%.1f, %.1f, %.1f)"), // i, linPosKey.val.x, linPosKey.val.y, linPosKey.val.z); } } // --- Process the rotation keys --- c = n->GetTMController()->GetRotationController(); ikeys = GetKeyControlInterface(c); if (!ikeys) return; numKeys = ikeys->GetNumKeys(); //DebugPrint(_T("\nThere are %d rotation key(s)"), numKeys); if (c->ClassID() == Class_ID(TCBINTERP_ROTATION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &tcbRotKey); newQuat = QFromAngAxis(tcbRotKey.val.angle, tcbRotKey.val.axis); if (i) newQuat = prevQuat * newQuat; prevQuat = newQuat; //DebugPrint(_T("\nTCB Rotation Key: %d=(%.1f, %.1f, %.1f, %.1f)"), // i, newQuat.x, newQuat.y, newQuat.z, newQuat.w); } } else if (c->ClassID() == Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &bezRotKey); newQuat = bezRotKey.val; if (i) newQuat = prevQuat * newQuat; prevQuat = newQuat; //DebugPrint(_T("\nBezier Rotation Key: %d=(%.1f, %.1f, %.1f, %.1f)"), // i, newQuat.x, newQuat.y, newQuat.z, newQuat.w); } } else if (c->ClassID() == Class_ID(LININTERP_ROTATION_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &linRotKey); newQuat = linRotKey.val; if (i) newQuat = prevQuat * newQuat; prevQuat = newQuat; //DebugPrint(_T("\nLinear Rotation Key: %d=(%.1f, %.1f, %.1f, %.1f)"), // i, newQuat.x, newQuat.y, newQuat.z, newQuat.w); } } // --- Process the scale keys --- c = n->GetTMController()->GetScaleController(); ikeys = GetKeyControlInterface(c); if (!ikeys) return; numKeys = ikeys->GetNumKeys(); //DebugPrint(_T("\nThere are %d scale key(s)"), numKeys); if (c->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &tcbScaleKey); //DebugPrint(_T("\nTCB Scale Key: %2d=(%.1f, %.1f, %.1f)"), // i, tcbScaleKey.val.s.x, tcbScaleKey.val.s.y, // tcbScaleKey.val.s.z); } } else if (c->ClassID() == Class_ID(HYBRIDINTERP_SCALE_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &bezScaleKey); //DebugPrint(_T("\nBezier Scale Key: %2d=(%.1f, %.1f, %.1f)"), // i, bezScaleKey.val.s.x, bezScaleKey.val.s.y, // bezScaleKey.val.s.z); } } else if (c->ClassID() == Class_ID(LININTERP_SCALE_CLASS_ID, 0)) { for (i = 0; i < numKeys; i++) { ikeys->GetKey(i, &linScaleKey); DebugPrint(_T("\nLinear Scale Key: %2d=(%.1f, %.1f, %.1f)"), i, linScaleKey.val.s.x, linScaleKey.val.s.y, linScaleKey.val.s.z); } } }
/** * @brief * Writes the scene node modifiers */ void PLSceneNode::WriteModifiers(XmlElement &cSceneElement, const String &sApplicationDrive, const String &sApplicationDir) { // Is there a 3ds Max node? (no 3ds Max node, no properties) INode *pMaxNode = GetMaxNode(); if (pMaxNode) { // Has this 3ds Max node a target? if (pMaxNode->GetTarget()) { // Write down the scene node modifier WriteTargetRotationModifier(cSceneElement, *pMaxNode->GetTarget(), false); } // Are there any position, rotation, scale keyframes? bool bPositionKeyframes = false; bool bRotationKeyframes = false; bool bScaleKeyframes = false; // Check 3ds Max node controllers Control *pTMController = pMaxNode->GetTMController(); if (pTMController) { // Position controller Control *pController = pTMController->GetPositionController(); if (pController) { // Are there any position keyframes? bPositionKeyframes = PLTools::HasKeyControlInterface(*pController); if (!bPositionKeyframes) { // Is there a path controller? IPathPosition *pPathController = GetIPathConstInterface(pController); if (pPathController && pPathController->GetNumTargets() > 0) { INode *pTarget = pPathController->GetNode(0); if (pTarget) { // Get path filename const String sPathFilename = PLTools::GetResourceFilename(PLTools::ResourcePath, String(pTarget->GetName()) + ".path"); // Get the percentage along the path float fPercentageAlongPath = 0.0f; { IParamBlock2 *pIParamBlock2 = pPathController->GetParamBlock(path_params); int nRefNum = pIParamBlock2 ? pIParamBlock2->GetControllerRefNum(path_percent) : -1; RefTargetHandle cRefTargetHandle = (nRefNum >= 0) ? pIParamBlock2->GetReference(nRefNum) : nullptr; if (cRefTargetHandle) fPercentageAlongPath = pIParamBlock2->GetFloat(path_percent, 0); } { // Add scene node modifier XmlElement *pModifierElement = new XmlElement("Modifier"); pModifierElement->SetAttribute("Class", "PLScene::SNMPositionPath"); pModifierElement->SetAttribute("Filename", sPathFilename); pModifierElement->SetAttribute("Progress", String::Format("%f", fPercentageAlongPath)); // [TODO] Any change to setup speed inside 3ds Max? static const float fSpeed = 0.03f; // Automatic animation playback? if (g_SEOptions.bAnimationPlayback) pModifierElement->SetAttribute("Speed", String::Format("%f", (pPathController->GetFlip() ? -fSpeed : fSpeed))); else pModifierElement->SetAttribute("Speed", "0.0"); // Link modifier element cSceneElement.LinkEndChild(*pModifierElement); } // Follow? if (pPathController->GetFollow()) { // Add scene node modifier XmlElement *pModifierElement = new XmlElement("Modifier"); pModifierElement->SetAttribute("Class", "PLScene::SNMRotationMoveDirection"); // Link modifier element cSceneElement.LinkEndChild(*pModifierElement); } } } } } // Rotation controller pController = pTMController->GetRotationController(); if (pController) { // Are there any rotation keyframes? bRotationKeyframes = PLTools::HasKeyControlInterface(*pController); if (!bRotationKeyframes) { // Is there a look at controller? ILookAtConstRotation *pLookAtController = GetILookAtConstInterface(pController); if (pLookAtController && pLookAtController->GetNumTargets() > 0) { INode *pTarget = pLookAtController->GetNode(0); if (pTarget) { // Check look at controller bool bFlip = (pLookAtController->GetTargetAxisFlip() != 0); // Write down the scene node modifier WriteTargetRotationModifier(cSceneElement, *pTarget, bFlip); } } } } // Scale controller pController = pTMController->GetScaleController(); if (pController) { // Are there any scale keyframes? bScaleKeyframes = PLTools::HasKeyControlInterface(*pController); } } // Export keyframes? if (bPositionKeyframes || bRotationKeyframes || bScaleKeyframes) { // Get timing Interval cInterval = GetCOREInterface()->GetAnimRange(); int nTicksPerFrame = GetTicksPerFrame(); int nFrameCount = (cInterval.End() - cInterval.Start()) / nTicksPerFrame + 1; // Used to detect whether or not something is animated Point3 vFirstPos, vFirstScale; Quat qFirstRot; bool bUsePosition = false, bUseScale = false, bUseRotation = false; // Prepare the position chunk Chunk cPositionChunk; cPositionChunk.SetSemantic(Chunk::Position); cPositionChunk.Allocate(Chunk::Float, 3, nFrameCount); float *pfPositionData = reinterpret_cast<float*>(cPositionChunk.GetData()); // Prepare the rotation chunk Chunk cRotationChunk; cRotationChunk.SetSemantic(Chunk::Rotation); cRotationChunk.Allocate(Chunk::Float, 4, nFrameCount); float *pfRotationData = reinterpret_cast<float*>(cRotationChunk.GetData()); // Prepare the scale chunk Chunk cScaleChunk; cScaleChunk.SetSemantic(Chunk::Scale); cScaleChunk.Allocate(Chunk::Float, 3, nFrameCount); float *pfScaleData = reinterpret_cast<float*>(cScaleChunk.GetData()); // Loop through all frames int nTime = cInterval.Start(); for (int nFrame=0; nFrame<nFrameCount; nFrame++, nTime+=nTicksPerFrame) { // Get the position, rotation and scale Point3 vPos, vScale; Quat qRot; GetPosRotScale(vPos, qRot, vScale, nTime); // First frame? if (!nFrame) { vFirstPos = vPos; vFirstScale = vScale; qFirstRot = qRot; } else { if (!vFirstPos.Equals(vPos)) bUsePosition = true; if (!vFirstScale.Equals(vScale)) bUseScale = true; if (!qFirstRot.Equals(qRot)) bUseRotation = true; } // Position if (bPositionKeyframes && pfPositionData) { // Currently ONLY the center of the container the node is in use used to make it relative const Point3 vParentWorldSpaceCenter = GetContainer() ? GetContainer()->GetWorldSpaceCenter() : Point3(0.0f, 0.0f, 0.0f); // Get the position const Point3 vFinalPos = (GetType() != TypeScene && GetType() != TypeCell) ? vPos-vParentWorldSpaceCenter : static_cast<const PLSceneContainer*>(this)->GetWorldSpaceCenter(); // x *pfPositionData = vFinalPos.x; pfPositionData++; // y *pfPositionData = vFinalPos.y; pfPositionData++; // z *pfPositionData = vFinalPos.z; pfPositionData++; } // Rotation if (bRotationKeyframes && pfRotationData) { // [TODO] Check this (why do we need it?) qRot.Invert(); // w *pfRotationData = qRot.w; pfRotationData++; // x *pfRotationData = qRot.x; pfRotationData++; // y *pfRotationData = qRot.y; pfRotationData++; // z *pfRotationData = qRot.z; pfRotationData++; } // Scale if (bScaleKeyframes && pfScaleData) { // x *pfScaleData = vScale.x; pfScaleData++; // y *pfScaleData = vScale.y; pfScaleData++; // z *pfScaleData = vScale.z; pfScaleData++; } } // Create keyframe animation scene node modifiers if (bPositionKeyframes && bUsePosition) { // [TODO] Better (and safer) filename // Save chunk const String sPositionKeys = PLTools::GetResourceFilename(PLTools::ResourceKeyframes, String::Format("%s_PositionKeyframes.chunk", GetName().GetASCII()).GetASCII()); if (SaveChunk(cPositionChunk, sApplicationDrive + sApplicationDir + sPositionKeys)) { // Add the modifier XmlElement *pModifierElement = new XmlElement("Modifier"); // Set class attribute pModifierElement->SetAttribute("Class", "PLScene::SNMPositionKeyframeAnimation"); // [TODO] Currently the frame rate is by default always 24 // Set frames per second attribute // pModifierElement->SetAttribute("FramesPerSecond", GetFrameRate()); // Automatic animation playback? pModifierElement->SetAttribute("Speed", g_SEOptions.bAnimationPlayback ? "1.0" : "0.0"); // Set keys attribute pModifierElement->SetAttribute("Keys", sPositionKeys); // Link modifier elements cSceneElement.LinkEndChild(*pModifierElement); } } if (bRotationKeyframes && bUseRotation) { // [TODO] Better (and safer) filename // Save chunk const String sRotationKeys = PLTools::GetResourceFilename(PLTools::ResourceKeyframes, String::Format("%s_RotationKeyframes.chunk", GetName().GetASCII()).GetASCII()); if (SaveChunk(cRotationChunk, sApplicationDrive + sApplicationDir + sRotationKeys)) { // Add the modifier XmlElement *pModifierElement = new XmlElement("Modifier"); // Set class attribute pModifierElement->SetAttribute("Class", "PLScene::SNMRotationKeyframeAnimation"); // [TODO] Currently the frame rate is by default always 24 // Set frames per second attribute // pModifierElement->SetAttribute("FramesPerSecond", GetFrameRate()); // Automatic animation playback? pModifierElement->SetAttribute("Speed", g_SEOptions.bAnimationPlayback ? "1.0" : "0.0"); // Set keys attribute pModifierElement->SetAttribute("Keys", sRotationKeys); // Link modifier elements cSceneElement.LinkEndChild(*pModifierElement); } } if (bScaleKeyframes && bUseScale) { // [TODO] Better (and safer) filename // Save chunk const String sScaleKeys = PLTools::GetResourceFilename(PLTools::ResourceKeyframes, String::Format("%s_ScaleKeyframes.chunk", GetName().GetASCII()).GetASCII()); if (SaveChunk(cScaleChunk, sApplicationDrive + sApplicationDir + sScaleKeys)) { // Add the modifier XmlElement *pModifierElement = new XmlElement("Modifier"); // Set class attribute pModifierElement->SetAttribute("Class", "PLScene::SNMScaleKeyframeAnimation"); // [TODO] Currently the frame rate is by default always 24 // Set frames per second attribute // pModifierElement->SetAttribute("FramesPerSecond", GetFrameRate()); // Automatic animation playback? pModifierElement->SetAttribute("Speed", g_SEOptions.bAnimationPlayback ? "1.0" : "0.0"); // Set keys attribute pModifierElement->SetAttribute("Keys", sScaleKeys); // Link modifier elements cSceneElement.LinkEndChild(*pModifierElement); } } } // Use modifiers? if (g_SEOptions.bUserPropModifiers) { // Check for modifiers MSTR sModifier; int nIndex = 1; TSTR s3dsMaxString; sModifier = _T("Mod"); while (pMaxNode->GetUserPropString(sModifier, s3dsMaxString)) { // Add scene node modifier XmlElement *pModifierElement = new XmlElement("Modifier"); // We really NEED a 'Class' attribute! bool bClassFound = false; // Get all expressions static RegEx cExpressionRegEx("\\s*((\\w*\\s*=\\s*\"[^\"]*\")|(\\w*\\s*=\\s*[\\w|]*))"); const String sString = s3dsMaxString; uint32 nExpressionParsePos = 0; while (cExpressionRegEx.Match(sString, nExpressionParsePos)) { // Get expression nExpressionParsePos = cExpressionRegEx.GetPosition(); const String sExpression = cExpressionRegEx.GetResult(0); // Process the found expression static RegEx cRegEx("\\s*(\\w*)\\s*=\\s*\"?\\s*([^\"]*)\\s*\"?"); if (cRegEx.Match(sExpression)) { // Get name and value const String sName = cRegEx.GetResult(0); const String sValue = cRegEx.GetResult(1); // Set attribute pModifierElement->SetAttribute(sName, sValue); // Class variable already found? if (!bClassFound && sName == "Class") bClassFound = true; } } // Link modifier element? if (bClassFound) cSceneElement.LinkEndChild(*pModifierElement); else delete pModifierElement; // Get next modifier sModifier.printf(_T("Mod%d"), nIndex); nIndex++; } } } }
// 2. 加载骨骼数据 void M2Importer::importBoneObject() { // Bone Group Header Node INode* groupHeadNode = createGroupHeaderNode(); groupHeadNode->SetGroupHead(TRUE); groupHeadNode->SetGroupMember(FALSE); if (m_modelHeader->nameLength > 1) { TCHAR* modelName = (TCHAR*)(m_m2FileData + m_modelHeader->nameOfs); TCHAR boneGroupName[256]; sprintf(boneGroupName, "%s_bone", modelName); groupHeadNode->SetName(boneGroupName); } else groupHeadNode->SetName("BoneGroup"); // Bone // 一个Bone构造一个Node, 并且加入到组中 ModelBoneDef* boneData = (ModelBoneDef*)(m_m2FileData + m_modelHeader->ofsBones); m_boneNodeList.reserve(m_modelHeader->nBones); for (unsigned int i = 0; i < m_modelHeader->nBones; ++i) { ModelBoneDef& boneDef = boneData[i]; // create bone node HelperObject* obj = (HelperObject*)CreateInstance(HELPER_CLASS_ID, Class_ID(BONE_CLASS_ID, 0)); ImpNode* node = m_impInterface->CreateNode(); TCHAR boneName[256]; sprintf(boneName, "bone_%02d", i); node->SetName(boneName); node->SetPivot(*(Point3*)&(boneDef.pivot)); node->Reference(obj); m_impInterface->AddNodeToScene(node); // 设置变换矩阵 Matrix3 tm; tm.IdentityMatrix(); tm.SetTrans(*(Point3*)&(boneDef.pivot)); node->SetTransform(0, tm); // 添加到组 INode* realINode = node->GetINode(); realINode->SetGroupHead(FALSE); realINode->SetGroupMember(TRUE); groupHeadNode->AttachChild(realINode); // 设置Bone父子关系 realINode->ShowBone(2); m_boneNodeList.push_back(realINode); if (boneDef.parent != -1) { INode* parentNode = m_boneNodeList[boneDef.parent]; parentNode->AttachChild(realINode); } realINode->EvalWorldState(0); } // 导入每根骨骼的关键桢数据 for (unsigned int i = 0; i < m_modelHeader->nBones; ++i) { ModelBoneDef& boneDef = boneData[i]; INode* realINode = m_boneNodeList[i]; Control* tmControl = realINode->GetTMController(); // Position if (boneDef.translation.nKeys) { // 设置动画控制器为线性控制器 Control* posControl = createPositionController(); tmControl->SetPositionController(posControl); unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.translation.ofsTimes); Point3* keyData = (Point3*)(m_m2FileData + boneDef.translation.ofsKeys); // 设置动画时间范围 bool animRangeChanged = false; Interval animRange = m_maxInterface->GetAnimRange(); for (unsigned int j = 0; j < boneDef.translation.nKeys; ++j) { if (timeData[j] < animRange.Start()) { animRange.SetStart(timeData[j]); animRangeChanged = true; } else if (timeData[j] > animRange.End()) { animRange.SetEnd(timeData[j]); animRangeChanged = true; } } if (animRangeChanged) m_maxInterface->SetAnimRange(animRange); // 设置动画关键桢数据 Control* xControl = posControl->GetXController(); IKeyControl* xKeyControl = GetKeyControlInterface(xControl); xKeyControl->SetNumKeys(boneDef.translation.nKeys); Control* yControl = posControl->GetYController(); IKeyControl* yKeyControl = GetKeyControlInterface(yControl); yKeyControl->SetNumKeys(boneDef.translation.nKeys); Control* zControl = posControl->GetZController(); IKeyControl* zKeyControl = GetKeyControlInterface(zControl); zKeyControl->SetNumKeys(boneDef.translation.nKeys); for (unsigned int j = 0; j < boneDef.translation.nKeys; ++j) { // X AnyKey bufX; ILinFloatKey* keyX = reinterpret_cast<ILinFloatKey*>((IKey*)bufX); keyX->time = timeData[j]; keyX->val = keyData[j].x; xKeyControl->AppendKey(keyX); // Y AnyKey bufY; ILinFloatKey* keyY = reinterpret_cast<ILinFloatKey*>((IKey*)bufY); keyY->time = timeData[j]; keyY->val = keyData[j].y; yKeyControl->AppendKey(keyY); // Z AnyKey bufZ; ILinFloatKey* keyZ = reinterpret_cast<ILinFloatKey*>((IKey*)bufZ); keyZ->time = timeData[j]; keyZ->val = keyData[j].z; zKeyControl->AppendKey(keyZ); } } /* // Rotation if (boneDef.rotation.nKeys) { Control* rotControl = createRotationController(); tmControl->SetRotationController(rotControl); unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.rotation.ofsTimes); Quat* keyData = (Quat*)(m_m2FileData + boneDef.rotation.ofsKeys); // 设置动画时间范围 bool animRangeChanged = false; Interval animRange = m_maxInterface->GetAnimRange(); for (unsigned int j = 0; j < boneDef.rotation.nKeys; ++j) { if (timeData[j] < animRange.Start()) { animRange.SetStart(timeData[j]); animRangeChanged = true; } else if (timeData[j] > animRange.End()) { animRange.SetEnd(timeData[j]); animRangeChanged = true; } } if (animRangeChanged) m_maxInterface->SetAnimRange(animRange); // 设置动画关键桢数据 IKeyControl* keyControl = GetKeyControlInterface(rotControl); keyControl->SetNumKeys(boneDef.rotation.nKeys); for (unsigned int j = 0; j < boneDef.rotation.nKeys; ++j) { AnyKey buf; ILinRotKey* key = reinterpret_cast<ILinRotKey*>((IKey*)buf); key->time = timeData[j]; key->val = keyData[j]; keyControl->AppendKey(key); } } */ // Scaling if (boneDef.scaling.nKeys) { Control* scaControl = createScaleController(); tmControl->SetScaleController(scaControl); unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.scaling.ofsTimes); Point3* keyData = (Point3*)(m_m2FileData + boneDef.scaling.ofsKeys); // 设置动画时间范围 bool animRangeChanged = false; Interval animRange = m_maxInterface->GetAnimRange(); for (unsigned int j = 0; j < boneDef.scaling.nKeys; ++j) { if (timeData[j] < animRange.Start()) { animRange.SetStart(timeData[j]); animRangeChanged = true; } else if (timeData[j] > animRange.End()) { animRange.SetEnd(timeData[j]); animRangeChanged = true; } } if (animRangeChanged) m_maxInterface->SetAnimRange(animRange); // 设置动画关键桢数据 IKeyControl* keyControl = GetKeyControlInterface(scaControl); keyControl->SetNumKeys(boneDef.scaling.nKeys); for (unsigned int j = 0; j < boneDef.scaling.nKeys; ++j) { AnyKey buf; ILinScaleKey* key = reinterpret_cast<ILinScaleKey*>((IKey*)buf); key->time = timeData[j]; key->val = ScaleValue(keyData[j]); keyControl->AppendKey(key); } } } }