/// <summary> /// Return the bones to export. /// </summary> /// <param name="skin">the skin to export</param> /// <returns>Array of BabylonBone to export</returns> private BabylonBone[] ExportBones(MFnSkinCluster skin) { int logRank = 1; int skinIndex = GetSkeletonIndex(skin); List <BabylonBone> bones = new List <BabylonBone>(); Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin); List <MObject> revelantNodes = GetRevelantNodes(skin); progressBoneStep = progressSkinStep / revelantNodes.Count; foreach (MObject node in revelantNodes) { MFnDagNode dagNode = new MFnDagNode(node); MFnTransform currentNodeTransform = new MFnTransform(node); string currentFullPathName = dagNode.fullPathName; int index = indexByFullPathName[currentFullPathName]; int parentIndex = -1; string parentId = null; // find the parent node to get its index if (!dagNode.parent(0).hasFn(MFn.Type.kWorld)) { MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0)); parentId = firstParentTransform.uuid().asString(); parentIndex = indexByFullPathName[firstParentTransform.fullPathName]; } string boneId = currentNodeTransform.uuid().asString(); // create the bone BabylonBone bone = new BabylonBone() { id = (!isBabylonExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs parentNodeId = parentId, name = dagNode.name, index = indexByFullPathName[currentFullPathName], parentBoneIndex = parentIndex, matrix = GetBabylonMatrix(currentNodeTransform, frameBySkeletonID[skinIndex]).m, animation = GetAnimationsFrameByFrameMatrix(currentNodeTransform) }; bones.Add(bone); RaiseVerbose($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1); // Progress bar progressSkin += progressBoneStep; ReportProgressChanged(progressSkin); CheckCancelled(); } // sort List <BabylonBone> sorted = new List <BabylonBone>(); sorted = bones.OrderBy(bone => bone.index).ToList(); bones = sorted; RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1); return(bones.ToArray()); }
/// <summary> /// Return the bones to export. /// </summary> /// <param name="skin">the skin to export</param> /// <returns>Array of BabylonBone to export</returns> private BabylonBone[] ExportBones(MFnSkinCluster skin) { int logRank = 1; int skinIndex = GetSkeletonIndex(skin); List <BabylonBone> bones = new List <BabylonBone>(); Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin); List <MObject> revelantNodes = GetRevelantNodes(skin); progressBoneStep = progressSkinStep / revelantNodes.Count; foreach (MObject node in revelantNodes) { MFnDagNode dagNode = new MFnDagNode(node); MFnTransform currentNodeTransform = new MFnTransform(node); string currentFullPathName = dagNode.fullPathName; int index = indexByFullPathName[currentFullPathName]; int parentIndex = -1; // find the parent node to get its index if (!dagNode.parent(0).hasFn(MFn.Type.kWorld)) { MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0)); parentIndex = indexByFullPathName[firstParentTransform.fullPathName]; } // create the bone BabylonBone bone = new BabylonBone() { name = currentFullPathName, index = indexByFullPathName[currentFullPathName], parentBoneIndex = parentIndex, matrix = ConvertMayaToBabylonMatrix(currentNodeTransform.transformationMatrix).m.ToArray(), animation = GetAnimationsFrameByFrameMatrix(currentNodeTransform) }; bones.Add(bone); RaiseMessage($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1); // Progress bar progressSkin += progressBoneStep; ReportProgressChanged(progressSkin); CheckCancelled(); } // sort List <BabylonBone> sorted = new List <BabylonBone>(); sorted = bones.OrderBy(bone => bone.index).ToList(); bones = sorted; RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1); return(bones.ToArray()); }
/// <summary> /// Find a bone in the skin cluster connections. /// From this bone travel the Dag up to the root node. /// </summary> /// <param name="skin">The skin cluster</param> /// <returns> /// The root node of the skeleton. /// </returns> private MObject GetRootNode(MFnSkinCluster skin) { MObject rootJoint = null; if (rootBySkin.ContainsKey(skin)) { return(rootBySkin[skin]); } // Get a joint of the skin rootJoint = GetInfluentNodes(skin)[0]; // Check the joint parent until it's a kWorld MFnDagNode mFnDagNode = new MFnDagNode(rootJoint); MObject firstParent = mFnDagNode.parent(0); MFnDependencyNode node = new MFnDependencyNode(firstParent); while (!firstParent.apiType.Equals(MFn.Type.kWorld)) { rootJoint = firstParent; mFnDagNode = new MFnDagNode(rootJoint); firstParent = mFnDagNode.parent(0); node = new MFnDependencyNode(firstParent); } rootBySkin.Add(skin, rootJoint); return(rootJoint); }
/// <summary> /// Init the two list influentNodesBySkin and revelantNodesBySkin of a skin cluster. /// By getting the parents of the influent nodes. /// </summary> /// <param name="skin">the skin cluster</param> /// <returns> /// The list of nodes that form the skeleton /// </returns> private List <MObject> GetRevelantNodes(MFnSkinCluster skin) { if (revelantNodesBySkin.ContainsKey(skin)) { return(revelantNodesBySkin[skin]); } List <MObject> influentNodes = GetInfluentNodes(skin); List <MObject> revelantNodes = new List <MObject>(); // Add parents until it's a kWorld foreach (MObject node in influentNodes) { MObject currentNode = node; //MObject parent = findValidParent(node); // A node can have several parents. Which one is the right one ? It seems that the first one is most likely a transform while (!currentNode.apiType.Equals(MFn.Type.kWorld)) { MFnDagNode dagNode = new MFnDagNode(currentNode); if (revelantNodes.Count(revelantNode => Equals(revelantNode, currentNode)) == 0) { revelantNodes.Add(currentNode); } // iter MObject firstParent = dagNode.parent(0); currentNode = firstParent; } } revelantNodesBySkin.Add(skin, revelantNodes); return(revelantNodes); }
private void buildMeshNodes() { MItDependencyNodes it = new MItDependencyNodes(MFn.Type.kMesh); while (!it.isDone) { // Get the dag node of the mesh. MFnDagNode dagNode = new MFnDagNode(it.thisNode); // Create a new mesh. MayaMesh meshNode = new MayaMesh(); // Add the mesh to the all meshes list. allMeshes.Add(meshNode); // Configure the mesh node meshNode.name = dagNode.fullPathName; dagNode.getPath(meshNode.mayaObjectPath); meshNode.id = allMeshes.Count - 1; // The first parent of a mesh is the source transform, even with instances. meshNode.sourceXForm = pathXformMap[(new MFnDagNode(dagNode.parent(0))).fullPathName]; // Set the source Xform to know it's a source for an instance (its mesh). meshNode.sourceXForm.isSourceXform = true; // If the mesh has more than one parent, it has been instanced. We need to know this for computing local positions. meshNode.isInstanced = dagNode.isInstanced(); // Add the map to the dictionary to search by name. pathMeshMap[meshNode.name] = meshNode; it.next(); } }
private void ExportNode(BabylonAbstractMesh babylonAbstractMesh, MFnDagNode mFnDagNode, BabylonScene babylonScene) { if (mFnDagNode.parentCount != 0) { MObject parentMObject = mFnDagNode.parent(0); MFnDagNode mFnDagNodeParent = new MFnDagNode(parentMObject); // Position / rotation / scaling ExportTransform(babylonAbstractMesh, mFnDagNodeParent); // TODO - Hierarchy //babylonAbstractMesh.parentId = mFnDagNodeParent.uuid().asString(); } }
// // If a DAG node is instanced (i.e. has multiple parents), this method // will put it under its remaining parents. It will already have been put // under its first parent when it was created. // protected void writeInstances(FileStream f) { uint numInstancedNodes = fInstanceChildren.length; int i; for (i = 0; i < numInstancedNodes; i++) { MFnDagNode nodeFn = new MFnDagNode(fInstanceChildren[i]); uint numParents = nodeFn.parentCount; uint p; for (p = 0; p < numParents; p++) { // // We don't want to issue a 'parent' command for the node's // existing parent. // try { if (nodeFn.parent((uint)i).notEqual(fInstanceParents[i].node)) { MObject parent = nodeFn.parent((uint)i); MFnDagNode parentFn = new MFnDagNode(parent); if (!parentFn.isFromReferencedFile) { // // Get the first path to the parent node. // MDagPath parentPath = new MDagPath(); MDagPath.getAPathTo(parentFn.objectProperty, parentPath); writeParent(f, parentPath, fInstanceChildren[i], true); } } } catch (Exception) { continue; } } } // // We don't need this any more, so free up the space. // fInstanceChildren.clear(); fInstanceParents.clear(); }
protected void writeDagNodes(FileStream f) { fParentingRequired.clear(); MItDag dagIter = new MItDag(); dagIter.traverseUnderWorld(true); MDagPath worldPath = new MDagPath(); dagIter.getPath(worldPath); // // We step over the world node before starting the loop, because it // doesn't get written out. // for (dagIter.next(); !dagIter.isDone; dagIter.next()) { MDagPath path = new MDagPath(); dagIter.getPath(path); // // If the node has already been written, then all of its descendants // must have been written, or at least checked, as well, so prune // this branch of the tree from the iteration. // MFnDagNode dagNodeFn = new MFnDagNode(path); if (dagNodeFn.isFlagSet(fCreateFlag)) { dagIter.prune(); continue; } // // If this is a default node, it will be written out later, so skip // it. // if (dagNodeFn.isDefaultNode) continue; // // If this node is not writable, and is not a shared node, then mark // it as having been written, and skip it. // if (!dagNodeFn.canBeWritten && !dagNodeFn.isShared) { dagNodeFn.setFlag(fCreateFlag, true); continue; } uint numParents = dagNodeFn.parentCount; if (dagNodeFn.isFromReferencedFile) { // // We don't issue 'creatNode' commands for nodes from referenced // files, but if the node has any parents which are not from // referenced files, other than the world, then make a note that // we'll need to issue extra 'parent' commands for it later on. // uint i; for (i = 0; i < numParents; i++) { MObject altParent = dagNodeFn.parent(i); MFnDagNode altParentFn = new MFnDagNode(altParent); if (!altParentFn.isFromReferencedFile && (altParentFn.objectProperty.notEqual(worldPath.node))) { fParentingRequired.append(path); break; } } } else { // // Find the node's parent. // MDagPath parentPath = new MDagPath(worldPath); if (path.length > 1) { // // Get the parent's path. // parentPath.assign(path); parentPath.pop(); // // If the parent is in the underworld, then find the closest // ancestor which is not. // if (parentPath.pathCount > 1) { // // The first segment of the path contains whatever // portion of the path exists in the world. So the closest // worldly ancestor is simply the one at the end of that // first path segment. // path.getPath(parentPath, 0); } } MFnDagNode parentNodeFn = new MFnDagNode(parentPath); if (parentNodeFn.isFromReferencedFile) { // // We prefer to parent to a non-referenced node. So if this // node has any other parents, which are not from referenced // files and have not already been processed, then we'll // skip this instance and wait for an instance through one // of those parents. // uint i; for (i = 0; i < numParents; i++) { if (dagNodeFn.parent(i).notEqual(parentNodeFn.objectProperty)) { MObject altParent = dagNodeFn.parent(i); MFnDagNode altParentFn = new MFnDagNode(altParent); if (!altParentFn.isFromReferencedFile && !altParentFn.isFlagSet(fCreateFlag)) { break; } } } if (i < numParents) continue; // // This node only has parents within referenced files, so // create it without a parent and note that we need to issue // 'parent' commands for it later on. // writeCreateNode(f, path, worldPath); fParentingRequired.append(path); } else { writeCreateNode(f, path, parentPath); // // Let's see if this node has any parents from referenced // files, or any parents other than this one which are not // from referenced files. // uint i; bool hasRefParents = false; bool hasOtherNonRefParents = false; for (i = 0; i < numParents; i++) { if (dagNodeFn.parent(i).notEqual(parentNodeFn.objectProperty)) { MObject altParent = dagNodeFn.parent(i); MFnDagNode altParentFn = new MFnDagNode(altParent); if (altParentFn.isFromReferencedFile) hasRefParents = true; else hasOtherNonRefParents = true; // // If we've already got positives for both tests, // then there's no need in continuing. // if (hasRefParents && hasOtherNonRefParents) break; } } // // If this node has parents from referenced files, then // make note that we will have to issue 'parent' commands // later on. // if (hasRefParents) fParentingRequired.append(path); // // If this node has parents other than this one which are // not from referenced files, then make note that the // parenting for the other instances still has to be done. // if (hasOtherNonRefParents) { fInstanceChildren.append(path); fInstanceParents.append(parentPath); } } // // Write out the node's 'addAttr', 'setAttr' and 'lockNode' // commands. // writeNodeAttrs(f, path.node, true); writeLockNode(f, path.node); } // // Mark the node as having been written. // dagNodeFn.setFlag(fCreateFlag, true); } // // Write out the parenting for instances. // writeInstances(f); }
// // Deal with nodes whose parenting is between referenced and non-referenced // nodes. // protected void writeRefNodeParenting(FileStream f) { uint numNodes = fParentingRequired.length; int i; for (i = 0; i < numNodes; i++) { MFnDagNode nodeFn = new MFnDagNode(fParentingRequired[i]); // // Find out if this node has any parents from referenced or // non-referenced files. // bool hasRefParents = false; bool hasNonRefParents = false; uint numParents = nodeFn.parentCount; uint p; for (p = 0; p < numParents; p++) { MObject parent = nodeFn.parent(p); MFnDagNode parentFn = new MFnDagNode(parent); if (parentFn.isFromReferencedFile) hasRefParents = true; else hasNonRefParents = true; if (hasRefParents && hasNonRefParents) break; } // // If this node is from a referenced file and it has parents which // are also from a referenced file, then it already has its first // parent and all others are added instances. // // Similarly if the node is not from a referenced file and has // parents which are also not from referenced files. // bool alreadyHasFirstParent = (nodeFn.isFromReferencedFile ? hasRefParents : hasNonRefParents); // // Now run through the parents again and output any parenting // which involves a non-referenced node, either as parent or child. // for (p = 0; p < numParents; p++) { MObject parent = nodeFn.parent(p); MFnDagNode parentFn = new MFnDagNode(parent); if (parentFn.isFromReferencedFile != nodeFn.isFromReferencedFile) { // // Get the first path to the parent. // MDagPath parentPath = new MDagPath(); MDagPath.getAPathTo(parentFn.objectProperty, parentPath); writeParent( f, parentPath, fParentingRequired[i], alreadyHasFirstParent ); // // If it didn't have its first parent before, it does now. // alreadyHasFirstParent = true; } } } }
private void buildMeshNodes() { MItDependencyNodes it = new MItDependencyNodes(MFn.Type.kMesh); while( !it.isDone ) { // Get the dag node of the mesh. MFnDagNode dagNode = new MFnDagNode(it.thisNode); // Create a new mesh. MayaMesh meshNode = new MayaMesh(); // Add the mesh to the all meshes list. allMeshes.Add(meshNode); // Configure the mesh node meshNode.name = dagNode.fullPathName; dagNode.getPath(meshNode.mayaObjectPath); meshNode.id = allMeshes.Count - 1; // The first parent of a mesh is the source transform, even with instances. meshNode.sourceXForm = pathXformMap[(new MFnDagNode(dagNode.parent(0))).fullPathName]; // Set the source Xform to know it's a source for an instance (its mesh). meshNode.sourceXForm.isSourceXform = true; // If the mesh has more than one parent, it has been instanced. We need to know this for computing local positions. meshNode.isInstanced = dagNode.isInstanced(); // Add the map to the dictionary to search by name. pathMeshMap[meshNode.name] = meshNode; it.next(); } }
private void buildLightNodes() { MItDependencyNodes it = new MItDependencyNodes(MFn.Type.kLight); while( !it.isDone ) { MObject mayaObj = it.thisNode; if( shouldPruneLight(mayaObj) ) { it.next(); continue; } // Create a new light and add it to the all lights list. MayaLight light = new MayaLight(); allLights.Add(light); light.id = allLights.Count - 1; // Get the dag node of the light for its name and parent. MFnDagNode dagNode = new MFnDagNode(mayaObj); dagNode.getPath(light.mayaObjectPath); light.name = dagNode.fullPathName; // First parent is the source transform node. light.sourceXform = pathXformMap[(new MFnDagNode(dagNode.parent(0))).fullPathName]; // Add the light to the dictionary to search by name. pathLightMap[light.name] = light; // // NOTE: Parent transforms of light sources in Maya can NOT be frozen, // so accessing them is guaranteed to not be frozen. // if( mayaObj.hasFn(MFn.Type.kAmbientLight) ) { MFnAmbientLight mayaLight = new MFnAmbientLight(mayaObj); light.type = MayaLight.Type.kAmbient; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; } else if( mayaObj.hasFn(MFn.Type.kDirectionalLight) ) { MFnDirectionalLight mayaLight = new MFnDirectionalLight(mayaObj); light.type = MayaLight.Type.kDirectional; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; } else if( mayaObj.hasFn(MFn.Type.kPointLight) ) { MFnPointLight mayaLight = new MFnPointLight(mayaObj); light.type = MayaLight.Type.kPoint; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; light.range = (float)mayaLight.centerOfIllumination; } else if( mayaObj.hasFn(MFn.Type.kSpotLight) ) { MFnSpotLight mayaLight = new MFnSpotLight(mayaObj); light.type = MayaLight.Type.kSpot; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; light.range = (float)mayaLight.centerOfIllumination; float mayaConeAngle = (float)(mayaLight.coneAngle * 0.5); light.coneInnerAngle = 57.29578f * mayaConeAngle; light.coneOuterAngle = 57.29578f * (mayaConeAngle + Math.Abs((float)mayaLight.penumbraAngle)); } it.next(); } }
private void buildLightNodes() { MItDependencyNodes it = new MItDependencyNodes(MFn.Type.kLight); while (!it.isDone) { MObject mayaObj = it.thisNode; if (shouldPruneLight(mayaObj)) { it.next(); continue; } // Create a new light and add it to the all lights list. MayaLight light = new MayaLight(); allLights.Add(light); light.id = allLights.Count - 1; // Get the dag node of the light for its name and parent. MFnDagNode dagNode = new MFnDagNode(mayaObj); dagNode.getPath(light.mayaObjectPath); light.name = dagNode.fullPathName; // First parent is the source transform node. light.sourceXform = pathXformMap[(new MFnDagNode(dagNode.parent(0))).fullPathName]; // Add the light to the dictionary to search by name. pathLightMap[light.name] = light; // // NOTE: Parent transforms of light sources in Maya can NOT be frozen, // so accessing them is guaranteed to not be frozen. // if (mayaObj.hasFn(MFn.Type.kAmbientLight)) { MFnAmbientLight mayaLight = new MFnAmbientLight(mayaObj); light.type = MayaLight.Type.kAmbient; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; } else if (mayaObj.hasFn(MFn.Type.kDirectionalLight)) { MFnDirectionalLight mayaLight = new MFnDirectionalLight(mayaObj); light.type = MayaLight.Type.kDirectional; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; } else if (mayaObj.hasFn(MFn.Type.kPointLight)) { MFnPointLight mayaLight = new MFnPointLight(mayaObj); light.type = MayaLight.Type.kPoint; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; light.range = (float)mayaLight.centerOfIllumination; } else if (mayaObj.hasFn(MFn.Type.kSpotLight)) { MFnSpotLight mayaLight = new MFnSpotLight(mayaObj); light.type = MayaLight.Type.kSpot; light.color = new Color(mayaLight.color.r, mayaLight.color.g, mayaLight.color.b, mayaLight.color.a); light.intensity = mayaLight.intensity; light.range = (float)mayaLight.centerOfIllumination; float mayaConeAngle = (float)(mayaLight.coneAngle * 0.5); light.coneInnerAngle = 57.29578f * mayaConeAngle; light.coneOuterAngle = 57.29578f * (mayaConeAngle + Math.Abs((float)mayaLight.penumbraAngle)); } it.next(); } }