//------------------------------ bool SceneGraphCreator::recursivelyCloneINode( ImpNode* parentImportNode, INode* nodeToClone ) { ImpNode* newImportNode = getMaxImportInterface()->CreateNode(); getMaxImportInterface()->AddNodeToScene(newImportNode); INode* newNode = newImportNode->GetINode(); Object* object = nodeToClone->GetObjectRef(); newImportNode->Reference(object); newNode->SetTMController(nodeToClone->GetTMController()); newImportNode->SetName(nodeToClone->GetName()); //used to assign material addClonedINodeOriginalINodePair(newNode, nodeToClone); INode* parentNode = parentImportNode->GetINode(); parentNode->AttachChild(newNode, TRUE); /* If the node to clone references an object, the cloned one must references the same object.*/ COLLADAFW::UniqueId id = getUniqueIdByObjectINode(nodeToClone); if ( id.isValid() ) { addUniqueIdObjectINodePair(id, newNode); addObjectINodeUniqueIdPair(newNode, id); } // Clone the children for ( int i = 0, count = nodeToClone->NumberOfChildren(); i < count; ++i) recursivelyCloneINode(newImportNode, nodeToClone->GetChildNode(i)); return true; }
//------------------------------ bool SceneGraphCreator::create() { if ( !mVisualScene ) return false; INode* rootNode = getMaxInterface()->GetRootNode(); //why does this not work: setting rotation on root node // Matrix3 maxTransformationMatrix; // Matrix4ToMaxMatrix3(maxTransformationMatrix, mUpAxisRotation); // rootNode->SetNodeTM(0, maxTransformationMatrix); // // Matrix3 x = rootNode->GetNodeTM(0); if( COLLADABU::Math::Matrix4::IDENTITY != mUpAxisRotation ) { ImpNode* upAxisCorrectionNode = getMaxImportInterface()->CreateNode(); Matrix3 maxTransformationMatrix; Matrix4ToMaxMatrix3( maxTransformationMatrix, mUpAxisRotation ); upAxisCorrectionNode->SetName(__T("upaxis")); upAxisCorrectionNode->SetTransform(0, maxTransformationMatrix); INode* iNode = upAxisCorrectionNode->GetINode(); upAxisCorrectionNode->Reference( getDummyObject() ); rootNode->AttachChild(iNode, FALSE); importNodes(mVisualScene->getRootNodes(), iNode); } else importNodes(mVisualScene->getRootNodes(), rootNode); return true; }
// PROCESSBIPNODERECURSE // When we find a Biped-controlled node in our hierarchy, we need to find one non-biped // child and promote it to the place of the biped node in the hierarchy. The siblings // of the promoted node will become its children, as will the original children from the // biped node. void ProcessBipedNodeRecurse(INode *bipNode, INode *parent, Interface *theInterface) { int numChildren = bipNode->NumberOfChildren(); char *bipName = bipNode ? bipNode->GetName() : nil; INode *replacement = nil; for (int i = 0; i < numChildren; i++) { INode *child = bipNode->GetChildNode(i); char *childName = child ? child->GetName() : nil; if( ! HasBipController(child) ) { replacement = child; // this child is going to be our replacement for this bipnode // sample the animation (into global space) plSampleVec *samples = SampleNodeMotion(replacement, bipNode, 1, theInterface); // detach from the parent (this blows away the animation) replacement->Detach(0); // attach the node to the biped's parent. parent->AttachChild(replacement); ReapplyAnimation(child, samples); FreeMotionSamples(samples); // we only need one replacement for the bip node break; } } if(replacement) { // reparent the siblings to the newly promoted replacement node numChildren = bipNode->NumberOfChildren(); for (int i = 0; i < numChildren; i++) { INode *child = bipNode->GetChildNode(i); if( HasBipController(child) ) { ProcessBipedNodeRecurse(child, replacement, theInterface); } else { child->Detach(0); // remove the (non-bip) child from the bip node replacement->AttachChild(child); // attach it to the non-bip parent ProcessNonBipedNodeRecurse(child, replacement, theInterface); } } } else { // this is an error condition: we've got a bip node that has no non-bip child for us to promote char buf[256]; sprintf(buf, "Couldn't find non-bip node to transfer motion to for bip node %s\n", bipNode->GetName()); hsStatusMessage(buf); } }
bool SceneGraphCreator::importInstances( const COLLADAFW::PointerArray<Instance>& instanceArray, ImpNode* parentImportNode ) { for ( size_t i = 0, count = instanceArray.getCount(); i < count; ++i) { Instance* instance = instanceArray[i]; ImpNode* newImportNode = getMaxImportInterface()->CreateNode(); INode* newNode = newImportNode->GetINode(); const COLLADAFW::UniqueId& uniqueId = instance->getInstanciatedObjectId(); Object* object = getObjectByUniqueId(uniqueId); if ( object ) { newImportNode->Reference(object); } else { newImportNode->Reference( getDummyObject() ); } const COLLADAFW::UniqueId& instanceUniqueId = instance->getInstanciatedObjectId(); // Store mapping between unique ids and nodes referencing the corresponding object. // Used to clone nodes addObjectINodeUniqueIdPair(newNode, instanceUniqueId); // Used to resolve instancing of objects addUniqueIdObjectINodePair(instanceUniqueId, newNode); INode* parentNode = parentImportNode->GetINode(); parentNode->AttachChild(newNode, FALSE); // post process the creation if ( postProcess ) (this->*postProcess)(newNode, instance); } return true; }
void WMOGroupImpl::buildMaxData() { // Group Header Node INode* groupHeadNode = createGroupHeaderNode(); groupHeadNode->SetGroupHead(TRUE); groupHeadNode->SetGroupMember(FALSE); // Geoset // 一个Render Batch构造一个Node, 并且加入到组中 for (int i = 0; i < m_batchCount; ++i) { WMORenderBatch& renderBatch = m_batchData[i]; m_wmoImporter->m_logStream << "Model Geoset " << i << " Vertex Info: " << renderBatch.vertexStart << " -- " << renderBatch.vertexEnd << endl; m_wmoImporter->m_logStream << "Model Geoset " << i << " Index Info: " << renderBatch.indexStart << " -- " << renderBatch.indexCount << endl; // Triangle Mesh Object // 基本的三角形模型对象 TriObject* triObject = CreateNewTriObject(); // 创建Node, 并且设为Group Header Node的子节点 ImpNode* tmpImpNode = m_wmoImporter->m_impInterface->CreateNode(); tmpImpNode->Reference(triObject); m_wmoImporter->m_impInterface->AddNodeToScene(tmpImpNode); INode* realINode = tmpImpNode->GetINode(); realINode->SetGroupHead(FALSE); realINode->SetGroupMember(TRUE); groupHeadNode->AttachChild(realINode); m_geosetNodeList.push_back(realINode); TCHAR nodeName[256]; sprintf(nodeName, "%s_part_%03d", m_groupName.c_str(), i); realINode->SetName(nodeName); // mesh unsigned short vertexCount = renderBatch.vertexEnd - renderBatch.vertexStart + 1; unsigned int trigangleCount = renderBatch.indexCount / 3; Mesh& mesh = triObject->GetMesh(); mesh.setNumVerts(vertexCount); mesh.setNumTVerts(vertexCount, TRUE); mesh.setNumFaces(trigangleCount); mesh.setNumTVFaces(trigangleCount); // 顶点坐标和UV for (int i = 0; i < vertexCount; ++i) { mesh.verts[i] = *(Point3*)(&(m_vertexData[renderBatch.vertexStart + i])); // UV坐标反转 mesh.tVerts[i].x = m_textureCoords[renderBatch.vertexStart + i].x; mesh.tVerts[i].y = 1.0f - m_textureCoords[renderBatch.vertexStart + i].y; } // 三角形 for (unsigned int i = 0; i < trigangleCount; ++i) { Face& face = mesh.faces[i]; int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart; int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart; int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart; face.setVerts(index1, index2, index3); face.Show(); face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS); TVFace& tface = mesh.tvFace[i]; tface.setTVerts(index1, index2, index3); } // 法线 mesh.SpecifyNormals(); MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals(); if (specNorms) { specNorms->ClearAndFree(); specNorms->SetNumFaces(trigangleCount); specNorms->SetNumNormals(vertexCount); Point3* norms = specNorms->GetNormalArray(); for (int i = 0; i < vertexCount; ++i) { norms[i] = *(Point3*)(&m_normalData[renderBatch.vertexStart + i]); } MeshNormalFace* pFaces = specNorms->GetFaceArray(); for (unsigned int i = 0; i < trigangleCount; ++i) { int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart; int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart; int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart; pFaces[i].SpecifyNormalID(0, index1); pFaces[i].SpecifyNormalID(1, index2); pFaces[i].SpecifyNormalID(2, index3); } specNorms->SetAllExplicit(true); specNorms->CheckNormals(); } // 删除重复的和无效的面 mesh.RemoveDegenerateFaces(); mesh.RemoveIllegalFaces(); realINode->SetMtl(m_wmoImporter->m_materialList[renderBatch.texture]); //realINode->BackCull(FALSE); // 取消背面裁减 不是所有的Node都要取消背面裁减 realINode->EvalWorldState(0); } }
int importAlembicScene(AbcArchiveCache *pArchiveCache, AbcObjectCache *pRootObjectCache, alembic_importoptions &options, std::string &file, progressUpdate &progress, std::map<std::string, bool> &nodeFullPaths) { std::vector<stackElement> sceneStack; sceneStack.reserve(200); for (size_t j = 0; j < pRootObjectCache->childIdentifiers.size(); j++) { sceneStack.push_back(stackElement( &(pArchiveCache->find(pRootObjectCache->childIdentifiers[j])->second))); } while (!sceneStack.empty()) { stackElement sElement = sceneStack.back(); sceneStack.pop_back(); Abc::IObject &iObj = sElement.pObjectCache->obj; INode *pParentMaxNode = sElement.pParentMaxNode; if (!iObj.valid()) { return alembic_failure; } const std::string fullname = iObj.getFullName(); const std::string pname = (pParentMaxNode) ? EC_MCHAR_to_UTF8(pParentMaxNode->GetName()) : std::string(""); const std::string name = iObj.getName(); ESS_LOG_INFO("Importing " << fullname); bool bCreateDummyNode = false; int mergedGeomNodeIndex = -1; AbcObjectCache *pMergedObjectCache = NULL; getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateDummyNode, mergedGeomNodeIndex, &pMergedObjectCache); INode *pMaxNode = NULL; // the newly create node, which may be a merged node INode *pExistingNode = NULL; int keepTM = 1; // I don't remember why this needed to be set in some // cases. bool bCreateNode = true; if (!nodeFullPaths.empty()) { if (mergedGeomNodeIndex != -1) { AbcG::IObject mergedGeomChild = pMergedObjectCache->obj; bCreateNode = nodeFullPaths.find(mergedGeomChild.getFullName()) != nodeFullPaths.end(); } else { bCreateNode = nodeFullPaths.find(fullname) != nodeFullPaths.end(); } } if (bCreateNode) { // if we are about to merge a camera with its parent transform, force it // to create a dummy node instead if the camera's // transform also has children. This is done to prevent the camera // correction matrix from being applied to the other children if (!bCreateDummyNode && pMergedObjectCache && sElement.pObjectCache->childIdentifiers.size() > 1 && AbcG::ICamera::matches(pMergedObjectCache->obj.getMetaData())) { bCreateDummyNode = true; mergedGeomNodeIndex = -1; } if (bCreateDummyNode) { std::string importName = removeXfoSuffix(iObj.getName()); pExistingNode = GetChildNodeFromName(importName, pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; // see if a controller already exists, and then delete it int ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options); if (ret != 0) { return ret; } } // only create node if either attachToExisting is false or it is true // and the object does not already exist else { int ret = AlembicImport_DummyNode(iObj, options, &pMaxNode, importName); if (ret != 0) { return ret; } ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options); if (ret != 0) { return ret; } } } else { if (mergedGeomNodeIndex != -1) { // we are merging, so look at the child geometry node AbcG::IObject mergedGeomChild = pMergedObjectCache->obj; std::string importName = removeXfoSuffix(iObj.getName()); // mergedGeomChild.getName()); pExistingNode = GetChildNodeFromName(importName, pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; } // only create node if either attachToExisting is false or it is // true and the object does not already exist int ret = createAlembicObject(mergedGeomChild, &pMaxNode, options, file); if (ret != 0) { return ret; } if (pMaxNode != NULL) { ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, &mergedGeomChild, file, options); if (ret != 0) { return ret; } } } else { // geometry node(s) under a dummy node (in pParentMaxNode) pExistingNode = GetChildNodeFromName(iObj.getName(), pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; } // only create node if either attachToExisting is false or it is // true and the object does not already exist int ret = createAlembicObject(iObj, &pMaxNode, options, file); if (ret != 0) { return ret; } // since the transform is the identity, should position relative to // parent keepTM = 0; if (AbcG::ICamera::matches(iObj.getMetaData())) { // apply camera adjustment matrix to the identity Matrix3 rotation(TRUE); rotation.RotateX(HALFPI); TimeValue zero(0); pMaxNode->SetNodeTM(zero, rotation); } // import identity matrix, since more than goemetry node share the // same transform // Should we just list MAX put a default position/scale/rotation // controller on? // int ret = AlembicImport_XForm(pMaxNode, *piParentObj, file, // options); } if (options.failOnUnsupported) { if (!pMaxNode) { return alembic_failure; } } } } if (pMaxNode && pParentMaxNode && !pExistingNode) { pParentMaxNode->AttachChild(pMaxNode, keepTM); } progress.increment(); progress.update(); if (pMaxNode) { for (size_t j = 0; j < sElement.pObjectCache->childIdentifiers.size(); j++) { AbcObjectCache *pChildObjectCache = &(pArchiveCache->find(sElement.pObjectCache->childIdentifiers[j]) ->second); if (NodeCategory::get(pChildObjectCache->obj) == NodeCategory::UNSUPPORTED) { continue; // skip over unsupported types } // I assume that geometry nodes are always leaf nodes. Thus, if we // merged a geometry node will its parent transform, we don't // need to push it to the stack. // A geometry node can't be combined with its transform node, the // transform node has other tranform nodes as children. These // nodes must be pushed. if (mergedGeomNodeIndex != j) { sceneStack.push_back(stackElement(pChildObjectCache, pMaxNode)); } } } } return alembic_success; }
void NifImporter::ImportBones(NiNodeRef node, bool recurse) { try { if (uncontrolledDummies) BuildControllerRefList(node, ctrlCount); string name = node->GetName(); vector<NiAVObjectRef> children = node->GetChildren(); vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); NiAVObject::CollisionType cType = node->GetCollisionMode(); if (children.empty() && name == "Bounding Box") return; // Do all node manipulations here NiNodeRef parent = node->GetParent(); string parentname = (parent ? parent->GetName() : ""); Matrix44 m4 = node->GetWorldTransform(); // Check for Prn strings and change parent if necessary if (supportPrnStrings) { list<NiStringExtraDataRef> strings = DynamicCast<NiStringExtraData>(node->GetExtraData()); for (list<NiStringExtraDataRef>::iterator itr = strings.begin(); itr != strings.end(); ++itr){ if (strmatch((*itr)->GetName(), "Prn")) { parentname = (*itr)->GetData(); if (INode *pn = gi->GetINodeByName(parentname.c_str())){ // Apparently Heads tend to need to be rotated 90 degrees on import for if (!rotate90Degrees.empty() && wildmatch(rotate90Degrees, parentname)) { m4 *= TOMATRIX4(RotateYMatrix(TORAD(90))); } m4 *= TOMATRIX4(pn->GetObjTMAfterWSM(0, NULL)); } } } } float len = node->GetLocalTranslation().Magnitude(); // Remove NonAccum nodes and merge into primary bone if (mergeNonAccum && wildmatch("* NonAccum", name) && parent) { string realname = name.substr(0, name.length() - 9); if (strmatch(realname, parent->GetName())) { Matrix44 tm = parent->GetLocalTransform() * node->GetLocalTransform(); name = realname; len += tm.GetTranslation().Magnitude(); parent = parent->GetParent(); } } PosRotScale prs = prsDefault; Vector3 pos; Matrix33 rot; float scale; m4.Decompose(pos, rot, scale); Matrix3 im = TOMATRIX3(m4); Point3 p = im.GetTrans(); Quat q(im); //q.Normalize(); Vector3 ppos; Point3 zAxis(0,0,0); bool hasChildren = !children.empty(); if (hasChildren) { float len = 0.0f; for (vector<NiAVObjectRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) { len += GetObjectLength(*itr); } len /= float(children.size()); ppos = pos + Vector3(len, 0.0f, 0.0f); // just really need magnitude as rotation will take care of positioning } else if (parent) { ppos = pos + Vector3(len/3.0f, 0.0f, 0.0f); } Point3 pp(ppos.x, ppos.y, ppos.z); Point3 qp = TORAD(TOEULER(im)); INode *bone = NULL; if (!doNotReuseExistingBones) // Games like BC3 reuse the same bone names { bone = FindNode(node); if (bone == NULL) bone = gi->GetINodeByName(name.c_str()); } if (bone) { // Is there a better way of "Affect Pivot Only" behaviors? INode *pinode = bone->GetParentNode(); if (pinode) bone->Detach(0,1); PosRotScaleNode(bone, p, q, scale, prs); if (pinode) pinode->AttachChild(bone, 1); } else { bool isDummy = ( (uncontrolledDummies && !HasControllerRef(ctrlCount, name)) || (!dummyNodeMatches.empty() && wildmatch(dummyNodeMatches, name)) || (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TYPE)) ); if (wildmatch("Camera*", name)) { if (enableCameras) { if (bone = CreateCamera(name)) { PosRotScaleNode(bone, p, q, scale, prs); bone->Hide(node->GetVisibility() ? FALSE : TRUE); } } }else if (isDummy && createNubsForBones) bone = CreateHelper(name, p); else if (bone = CreateBone(name, p, pp, zAxis)) { PosRotScaleNode(bone, p, q, scale, prs); bone->Hide(node->GetVisibility() ? FALSE : TRUE); } if (bone) { if (!parentname.empty()) { if (mergeNonAccum && wildmatch("* NonAccum", parentname)) { parentname = parentname.substr(0, parentname.length() - 9); } if (INode *pn = gi->GetINodeByName(parentname.c_str())) pn->AttachChild(bone, 1); } RegisterNode(node, bone); } } // Import UPB if (bone) ImportUPB(bone, node); // Import Havok Collision Data surrounding node, // unfortunately this causes double import of collision so I'm disabling it for now. if (enableCollision && node->GetParent()) { ImportCollision(node); } if (bone && recurse) { ImportBones(childNodes); } } catch( exception & e ) { e=e; } catch( ... ) { } }
// 1. 加载模型顶点数据 void M2Importer::importGeomObject() { // 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); groupHeadNode->SetName(modelName); m_logStream << "ModelName: " << modelName << endl; } else groupHeadNode->SetName("GeomGroup"); // Geoset // 一个Geoset构造一个Node, 并且加入到组中 unsigned short* verDataIndex = (unsigned short*)(m_m2FileData + m_modelView->ofsIndex); unsigned short* triData = (unsigned short*)(m_m2FileData + m_modelView->ofsTris); m_geosetNodeList.reserve(m_modelView->nSub); m_materialList.reserve(m_modelView->nSub); for (unsigned int i = 0; i < m_modelView->nSub; ++i) m_materialList.push_back(0); for (unsigned int i = 0; i < m_modelView->nSub; ++i) { ModelGeoset& geosetData = m_modelGeoset[i]; // Triangle Mesh Object // 基本的三角形模型对象 TriObject* triObject = CreateNewTriObject(); // 创建Node, 并且设为Group Header Node的子节点 ImpNode* tmpImpNode = m_impInterface->CreateNode(); tmpImpNode->Reference(triObject); //tmpImpNode->SetPivot(*(Point3*)&(geosetData.v)); m_impInterface->AddNodeToScene(tmpImpNode); INode* realINode = tmpImpNode->GetINode(); realINode->SetGroupHead(FALSE); realINode->SetGroupMember(TRUE); groupHeadNode->AttachChild(realINode); m_geosetNodeList.push_back(realINode); TCHAR nodeName[256]; sprintf(nodeName, "GeosetPart_%d", i); realINode->SetName(nodeName); // mesh Mesh& mesh = triObject->GetMesh(); mesh.setNumVerts(geosetData.vcount); mesh.setNumTVerts(geosetData.vcount, TRUE); unsigned int triangeCount = geosetData.icount / 3; mesh.setNumFaces(triangeCount); mesh.setNumTVFaces(triangeCount); m_logStream << "Model Geoset " << i << " Vertex Count: " << geosetData.vcount << endl; m_logStream << "Model Geoset " << i << " Index Count: " << triangeCount << endl; // 顶点坐标和UV for (unsigned int i = 0; i < geosetData.vcount; ++i) { ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ]; mesh.verts[i] = *(Point3*)(&vertexData.pos); // UV坐标反转 mesh.tVerts[i].x = vertexData.texcoords.x; mesh.tVerts[i].y = 1.0f - vertexData.texcoords.y; } // 三角形 for (unsigned int i = 0; i < triangeCount; ++i) { Face& face = mesh.faces[i]; face.setVerts(triData[geosetData.istart + i*3] - m_indexCount, triData[geosetData.istart + i*3+1] - m_indexCount, triData[geosetData.istart + i*3+2] - m_indexCount); face.Show(); face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS); TVFace& tface = mesh.tvFace[i]; tface.setTVerts(triData[geosetData.istart + i*3] - m_indexCount, triData[geosetData.istart + i*3+1] - m_indexCount, triData[geosetData.istart + i*3+2] - m_indexCount); } // 法线 mesh.SpecifyNormals(); MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals(); if (specNorms) { specNorms->ClearAndFree(); specNorms->SetNumFaces(triangeCount); specNorms->SetNumNormals(geosetData.vcount); Point3* norms = specNorms->GetNormalArray(); for (unsigned int i = 0; i < geosetData.vcount; ++i) { ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ]; norms[i] = *(Point3*)(&vertexData.normal); } MeshNormalFace* pFaces = specNorms->GetFaceArray(); for (unsigned int i = 0; i < triangeCount; ++i) { pFaces[i].SpecifyNormalID(0, triData[geosetData.istart + i*3] - m_indexCount); pFaces[i].SpecifyNormalID(1, triData[geosetData.istart + i*3+1] - m_indexCount); pFaces[i].SpecifyNormalID(2, triData[geosetData.istart + i*3+2] - m_indexCount); } specNorms->SetAllExplicit(true); specNorms->CheckNormals(); } // 删除重复的和无效的面 mesh.RemoveDegenerateFaces(); mesh.RemoveIllegalFaces(); //realINode->BackCull(FALSE); // 取消背面裁减 双面绘制与取消背面裁减一起设置 realINode->EvalWorldState(0); // 索引值修正 m_indexCount += geosetData.vcount; } // 加载材质 unsigned short* texLookupData = (unsigned short*)(m_m2FileData + m_modelHeader->ofsTexLookup); ModelTextureDef* texUnitDefData = (ModelTextureDef*)(m_m2FileData + m_modelHeader->ofsTextures); ModelTexUnit* texUnitData = (ModelTexUnit*)(m_m2FileData + m_modelView->ofsTex); for (unsigned int i = 0; i < m_modelView->nTex; ++i) { ModelTexUnit& texUnit = texUnitData[i]; unsigned short textureID = texLookupData[texUnit.textureid]; ModelTextureDef& texDef = texUnitDefData[textureID]; string textureName; if (texDef.type == 0) textureName = (LPCSTR)(m_m2FileData + texDef.nameOfs); else textureName = getReplacableTexture(texDef.type); StdMat2* material = m_materialList[texUnit.op]; if (!material) material = createMaterial(); // 根据混合属性决定加在第几层 material->SetSubTexmap(ID_DI, createTexture(textureName.c_str())); material->EnableMap(ID_DI, TRUE); //material->SetTwoSided(TRUE); // 双面 设置了此标志的才打开 m_maxInterface->GetMaterialLibrary().Add(material); m_geosetNodeList[texUnit.op]->SetMtl(material); } m_maxInterface->RedrawViews(m_maxInterface->GetTime()); }
// 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); } } } }