private static void ExtractStandardMeshes(List <MayaM2Mesh> meshList, Dictionary <string, MayaM2Bone> jointMap, List <MayaM2Vertex> globalVertexList) { for (var meshIter = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kMesh); !meshIter.isDone; meshIter.next()) { var meshPath = new MDagPath(); meshIter.getPath(meshPath); var meshFn = new MFnMesh(meshPath); // only want non-history items if (meshFn.isIntermediateObject) { continue; } var name = meshFn.name; if (name == "Collision") { continue; //TODO use custom attribute } var mesh = new MayaM2Mesh(); ExtractMeshGeometry(mesh, meshPath, jointMap, globalVertexList); ExtractMeshShaders(mesh, meshPath); meshList.Add(mesh); } }
/// <summary> /// Return true if node descendant hierarchy has any exportable Mesh, Camera, Light or Locator /// </summary> private bool isNodeRelevantToExportRec(MDagPath mDagPathRoot) { var mIteratorType = new MIteratorType(); MIntArray listOfFilters = new MIntArray(); listOfFilters.Add((int)MFn.Type.kMesh); listOfFilters.Add((int)MFn.Type.kCamera); listOfFilters.Add((int)MFn.Type.kLight); listOfFilters.Add((int)MFn.Type.kLocator); mIteratorType.setFilterList(listOfFilters); var dagIterator = new MItDag(mIteratorType, MItDag.TraversalType.kDepthFirst); dagIterator.reset(mDagPathRoot); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); // Check direct descendants if (getApiTypeOfDirectDescendants(mDagPath) != MFn.Type.kUnknown) { return(true); } dagIterator.next(); } // No relevant node found among descendants return(false); }
/// <summary> /// /// </summary> /// <param name="isFull">If true all nodes are printed, otherwise only relevant ones</param> private void PrintDAG(bool isFull, MObject root = null) { var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst); if (root != null) { dagIterator.reset(root); } RaiseMessage("DAG: " + (isFull ? "full" : "relevant")); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); if (isFull || isNodeRelevantToExportRec(mDagPath) || mDagPath.apiType == MFn.Type.kMesh || mDagPath.apiType == MFn.Type.kCamera || mDagPath.hasFn(MFn.Type.kLight) || mDagPath.apiType == MFn.Type.kLocator) { RaiseMessage("name=" + mDagPath.partialPathName + "\t type=" + mDagPath.apiType, (int)dagIterator.depth + 1); } else { dagIterator.prune(); } dagIterator.next(); } }
/// <summary> /// Extract the vertices, normals and triangles of a mesh into the M2 collision data fields. /// </summary> /// <param name="wowModel"></param> private static void InjectCollisionMesh(M2 wowModel) { var collisionFound = false; for (var meshIter = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kMesh); !meshIter.isDone; meshIter.next()) { var meshPath = new MDagPath(); meshIter.getPath(meshPath); var meshFn = new MFnMesh(meshPath); // only want non-history items if (meshFn.isIntermediateObject) { continue; } var name = meshFn.name; if (name != "Collision") { continue; //TODO use custom attribute } if (collisionFound) { throw new Exception("More than one collision box has been found. One supported."); } MGlobal.displayInfo("\t Collision mesh detected."); wowModel.CollisionBox = new CAaBox(AxisInvert(meshFn.boundingBox.min), AxisInvert(meshFn.boundingBox.max)); wowModel.CollisionSphereRadius = (float)Math.Max(meshFn.boundingBox.depth / 2, meshFn.boundingBox.width / 2); //TODO fixme better iterate through faces var collisionPoints = new MFloatPointArray(); meshFn.getPoints(collisionPoints, MSpace.Space.kWorld); var collisionNormals = new MFloatVectorArray(); meshFn.getNormals(collisionNormals, MSpace.Space.kWorld); var collisionTriangles = new MIntArray(); meshFn.getTriangles(new MIntArray(), collisionTriangles); for (var i = 0; i < collisionPoints.Count; i++) { wowModel.CollisionVertices.Add(AxisInvert(collisionPoints[i])); wowModel.CollisionNormals.Add(AxisInvert(collisionNormals[i])); } foreach (var vertIndex in collisionTriangles) { wowModel.CollisionTriangles.Add((ushort)vertIndex); } collisionFound = true; } }
public void Create() { MItDag jointIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kJoint); //Create Joints and collect their DAG Paths short jointID = 0; for (; !jointIterator.isDone; jointIterator.next()) { MFnIkJoint ikJoint = new MFnIkJoint(); MDagPath jointDagPath = new MDagPath(); jointIterator.getPath(jointDagPath); this.JointDagPaths.Add(jointDagPath); ikJoint.setObject(jointDagPath); MTransformationMatrix local = new MTransformationMatrix(ikJoint.transformationMatrix); MTransformationMatrix inverseGlobal = new MTransformationMatrix(jointDagPath.inclusiveMatrixInverse); this.Joints.Add(new SKLJoint(jointID, ikJoint.name, local, inverseGlobal)); this.JointIndices.Add(ELF.Hash(ikJoint.name), jointID); jointID++; } //Set Joint parents for (int i = 0; i < this.Joints.Count; i++) { MFnIkJoint ikJoint = new MFnIkJoint(this.JointDagPaths[i]); if (ikJoint.parentCount == 1 && ikJoint.parent(0).apiType == MFn.Type.kJoint) { MFnIkJoint parentJoint = new MFnIkJoint(ikJoint.parent(0)); MDagPath parentDagPath = new MDagPath(); parentJoint.getPath(parentDagPath); //Find index of parent for (int j = 0; j < this.JointDagPaths.Count; j++) { if (parentDagPath.equalEqual(this.JointDagPaths[j])) { this.Joints[i].ParentID = (short)j; } } } else { this.Joints[i].ParentID = -1; } } MGlobal.displayInfo("SKLFile:Create - Created SKL File"); }
private void buildXformTree() { // Get the very root of the Maya DAG. MItDag rootIt = new MItDag(); rootXform.isRoot = true; rootXform.name = "root"; MFnDagNode rootDagNode = new MFnDagNode(rootIt.root()); rootDagNode.getPath(rootXform.mayaObjectPath); // Process all children transforms of the root. processXform(rootXform); }
/// <summary> /// Init the dictionary of the skin. This dictionary represents the skeleton. It contains the node names and their index. /// And add it to skinDictionary /// </summary> /// <param name="skin">the skin cluster</param> /// <returns> /// The dictionary that represents the skin skeleton /// </returns> private Dictionary <string, int> GetIndexByFullPathNameDictionary(MFnSkinCluster skin) { if (skinDictionary.ContainsKey(skin.name)) { return(skinDictionary[skin.name]); } Dictionary <string, int> indexByFullPathName = new Dictionary <string, int>(); List <MObject> revelantNodes = GetRevelantNodes(skin); // get the root node MObject rootNode = GetRootNode(skin); // Travel the DAG MItDag dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst); dagIterator.reset(rootNode); int index = 0; while (!dagIterator.isDone) { // current node MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); MObject currentNode = mDagPath.node; try { if (revelantNodes.Count(node => Equals(node, currentNode)) > 0) { MFnTransform currentNodeTransform = new MFnTransform(currentNode); string currentFullPathName = currentNodeTransform.fullPathName; indexByFullPathName.Add(currentFullPathName, index); index++; } } catch // When it's not a kTransform or kJoint node. For exemple a kLocator, kNurbsCurve. { RaiseError($"{currentNode.apiType} is not supported. It will not be exported: {mDagPath.fullPathName}", 3); return(null); } dagIterator.next(); } skinDictionary.Add(skin.name, indexByFullPathName); return(indexByFullPathName); }
public List<string> getMayaNodesByType(MFnType t) { List<string> lMayaNodes = new List<string>(); MItDag itdagn = new MItDag(MItDag.TraversalType.kBreadthFirst, (MFn.Type)t); MFnDagNode dagn; while (!itdagn.isDone) { dagn = new MFnDagNode(itdagn.item()); if(!dagn.isIntermediateObject) lMayaNodes.Add(dagn.partialPathName); itdagn.next(); } return lMayaNodes; }
/* * static Action m_update= delegate { }; * public void SubscribeEvent() * { * IEvents subscriber = OperationContext.Current.GetCallbackChannel<IEvents>(); * m_update += subscriber.hasUpdated; * } * * public static void SendUpdateEvent() * { * m_update(); * } * * public void UpdateEvent() * { * ServiceImplementation.SendUpdateEvent(); * } */ public List <string> getMayaNodesByType(MFnType t) { var lMayaNodes = new List <string>(); var itdagn = new MItDag(MItDag.TraversalType.kBreadthFirst, (MFn.Type)t); MFnDagNode dagn; while (!itdagn.isDone) { dagn = new MFnDagNode(itdagn.item()); if (!dagn.isIntermediateObject) { lMayaNodes.Add(dagn.partialPathName); } itdagn.next(); } return(lMayaNodes); }
protected void initTests(MPx3dModelView view) { MGlobal.displayInfo("exampleCameraSetViewCmd::initTests"); clearResults(view); // Add every camera into the scene. Don't change the main camera, // it is OK that it gets reused. // MFnCameraSet cstFn = new MFnCameraSet(); MObject cstObj = cstFn.create(); MDagPath cameraPath = null; MItDag dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kCamera); for (; !dagIterator.isDone; dagIterator.next()) { cameraPath = new MDagPath(); MFnCamera camera; try { dagIterator.getPath(cameraPath); camera = new MFnCamera(cameraPath); } catch (Exception) { continue; } fCameraList.append(cameraPath); cstFn.appendLayer(cameraPath, MObject.kNullObj); MGlobal.displayInfo(camera.fullPathName()); } view.setCameraSet(cstObj); view.refresh(); }
private void parseArgs( MArgList args,ref MItDag.TraversalType traversalType, MFn.Type filter, ref bool quiet) { string arg = ""; const string breadthFlag = "-b"; const string breadthFlagLong = "-breadthFirst"; const string depthFlag = "-d"; const string depthFlagLong = "-depthFirst"; const string cameraFlag = "-c"; const string cameraFlagLong = "-cameras"; const string lightFlag = "-l"; const string lightFlagLong = "-lights"; const string nurbsSurfaceFlag = "-n"; const string nurbsSurfaceFlagLong = "-nurbsSurfaces"; const string quietFlag = "-q"; const string quietFlagLong = "-quiet"; for (uint i = 0; i < args.length; i++) { arg = args.asString(i); if ( arg == breadthFlag || arg == breadthFlagLong ) traversalType = MItDag.TraversalType.kBreadthFirst; else if ( arg == depthFlag || arg == depthFlagLong ) traversalType = MItDag.TraversalType.kDepthFirst; else if ( arg == cameraFlag || arg == cameraFlagLong ) filter = MFn.Type.kCamera; else if ( arg == lightFlag || arg == lightFlagLong ) filter = MFn.Type.kLight; else if ( arg == nurbsSurfaceFlag || arg == nurbsSurfaceFlagLong ) filter = MFn.Type.kNurbsSurface; else if ( arg == quietFlag || arg == quietFlagLong ) quiet = true; else { arg += ": unknown argument"; throw new ArgumentException(arg, "args"); } } }
public void Export(string outputDirectory, string outputFileName, string outputFormat, bool generateManifest, bool onlySelected, bool autoSaveMayaFile, bool exportHiddenObjects, bool copyTexturesToOutput, bool optimizeVertices, bool exportTangents, string scaleFactor, bool exportSkin) { // Chekc if the animation is running MGlobal.executeCommand("play -q - state", out int isPlayed); if (isPlayed == 1) { RaiseError("Stop the animation before exporting."); return; } // Check input text is valid var scaleFactorFloat = 1.0f; try { scaleFactor = scaleFactor.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactor = scaleFactor.Replace(",", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactorFloat = float.Parse(scaleFactor); } catch { RaiseError("Scale factor is not a valid number."); return; } RaiseMessage("Exportation started", Color.Blue); var progression = 0.0f; ReportProgressChanged(progression); // Store export options _onlySelected = onlySelected; _exportHiddenObjects = exportHiddenObjects; _optimizeVertices = optimizeVertices; _exportTangents = exportTangents; CopyTexturesToOutput = copyTexturesToOutput; isBabylonExported = outputFormat == "babylon" || outputFormat == "binary babylon"; _exportSkin = exportSkin; // Check directory exists if (!Directory.Exists(outputDirectory)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); var outputBabylonDirectory = outputDirectory; var babylonScene = new BabylonScene(outputBabylonDirectory); // Save scene if (autoSaveMayaFile) { RaiseMessage("Saving Maya file"); // Query expand file name string fileName = MGlobal.executeCommandStringResult($@"file -q -exn;"); // If scene has already been saved previously if (fileName.EndsWith(".ma") || fileName.EndsWith(".mb")) { // Name is already specified and this line will not fail MFileIO.save(); } else { // Open SaveAs dialog window MGlobal.executeCommand($@"fileDialog2;"); } } // Force output file extension to be babylon outputFileName = Path.ChangeExtension(outputFileName, "babylon"); // Store selected nodes MSelectionList selectedNodes = new MSelectionList(); MGlobal.getActiveSelectionList(selectedNodes); selectedNodeFullPaths = new List <string>(); MItSelectionList mItSelectionList = new MItSelectionList(selectedNodes); while (!mItSelectionList.isDone) { MDagPath mDagPath = new MDagPath(); try { mItSelectionList.getDagPath(mDagPath); selectedNodeFullPaths.Add(mDagPath.fullPathName); } catch { // selected object is not a DAG object // fail silently } mItSelectionList.next(); } if (selectedNodeFullPaths.Count > 0) { RaiseMessage("Selected nodes full path"); foreach (string selectedNodeFullPath in selectedNodeFullPaths) { RaiseMessage(selectedNodeFullPath, 1); } } // Producer babylonScene.producer = new BabylonProducer { name = "Maya", version = "2018", exporter_version = exporterVersion, file = outputFileName }; // Global babylonScene.autoClear = true; // TODO - Retreive colors from Maya //babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); //babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); // TODO - Add custom properties _exportQuaternionsInsteadOfEulers = true; PrintDAG(true); PrintDAG(false); // -------------------- // ------ Nodes ------- // -------------------- RaiseMessage("Exporting nodes"); // Clear materials referencedMaterials.Clear(); multiMaterials.Clear(); // Get all nodes var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kTransform); List <MDagPath> nodes = new List <MDagPath>(); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); // Check if one of its descendant (direct or not) is a mesh/camera/light/locator if (isNodeRelevantToExportRec(mDagPath) // Ensure it's not one of the default cameras used as viewports in Maya && defaultCameraNames.Contains(mDagPath.partialPathName) == false) { nodes.Add(mDagPath); } else { // Skip descendants dagIterator.prune(); } dagIterator.next(); } // Export all nodes var progressionStep = 100.0f / nodes.Count; foreach (MDagPath mDagPath in nodes) { BabylonNode babylonNode = null; switch (getApiTypeOfDirectDescendants(mDagPath)) { case MFn.Type.kMesh: babylonNode = ExportMesh(mDagPath, babylonScene); break; case MFn.Type.kCamera: babylonNode = ExportCamera(mDagPath, babylonScene); break; case MFn.Type.kLight: // Lights api type are actually kPointLight, kSpotLight... babylonNode = ExportLight(mDagPath, babylonScene); break; case MFn.Type.kLocator: // Camera target babylonNode = ExportDummy(mDagPath, babylonScene); break; } // If node is not exported successfully if (babylonNode == null) { // Create a dummy (empty mesh) babylonNode = ExportDummy(mDagPath, babylonScene); } ; // Update progress bar progression += progressionStep; ReportProgressChanged(progression); CheckCancelled(); } RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // if nothing is enlightened, exclude all meshes foreach (BabylonLight light in babylonScene.LightsList) { if (light.includedOnlyMeshesIds.Length == 0) { light.excludedMeshesIds = babylonScene.MeshesList.Select(m => m.id).ToArray(); } } /* * Switch coordinate system at global level * * Add a root node with negative scaling * Pros - It's safer to use a root node * Cons - It's cleaner to switch at object level (as it is done now) * Use root node method when you want to be 100% sure of the output * Don't forget to also inverse winding order of mesh indices */ //// Switch from right to left handed coordinate system //MUuid mUuid = new MUuid(); //mUuid.generate(); //var rootNode = new BabylonMesh //{ // name = "root", // id = mUuid.asString(), // scaling = new float[] { 1, 1, -1 } //}; //foreach(var babylonMesh in babylonScene.MeshesList) //{ // // Add root meshes as child to root node // if (babylonMesh.parentId == null) // { // babylonMesh.parentId = rootNode.id; // } //} //babylonScene.MeshesList.Add(rootNode); // Main camera BabylonCamera babylonMainCamera = null; if (babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light if (babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default ambient light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } if (scaleFactorFloat != 1.0f) { RaiseMessage("A root node is added for scaling", 1); // Create root node for scaling BabylonMesh rootNode = new BabylonMesh { name = "root", id = Tools.GenerateUUID() }; rootNode.isDummy = true; float rootNodeScale = 1.0f / scaleFactorFloat; rootNode.scaling = new float[3] { rootNodeScale, rootNodeScale, rootNodeScale }; // Update all top nodes var babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode babylonNode in babylonNodes) { if (babylonNode.parentId == null) { babylonNode.parentId = rootNode.id; } } // Store root node babylonScene.MeshesList.Add(rootNode); } // -------------------- // ----- Materials ---- // -------------------- RaiseMessage("Exporting materials"); GenerateMaterialDuplicationDatas(babylonScene); foreach (var mat in referencedMaterials) { ExportMaterial(mat, babylonScene); CheckCancelled(); } foreach (var mat in multiMaterials) { ExportMultiMaterial(mat.Key, mat.Value, babylonScene); CheckCancelled(); } UpdateMeshesMaterialId(babylonScene); RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Export skeletons if (_exportSkin && skins.Count > 0) { progressSkin = 0; progressSkinStep = 100 / skins.Count; ReportProgressChanged(progressSkin); RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // Output babylonScene.Prepare(false, false); if (isBabylonExported) { Write(babylonScene, outputBabylonDirectory, outputFileName, outputFormat, generateManifest); } ReportProgressChanged(100); // Export glTF if (outputFormat == "gltf" || outputFormat == "glb") { bool generateBinary = outputFormat == "glb"; ExportGltf(babylonScene, outputDirectory, outputFileName, generateBinary); } watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
/// <summary> /// Export to file /// </summary> /// <param name="outputDirectory">The directory to store the generated files</param> /// <param name="outputFileName">The filename to use for the generated files</param> /// <param name="outputFormat">The format to use for the generated files</param> /// <param name="generateManifest">Specifies if a manifest file should be generated</param> /// <param name="onlySelected">Specifies if only the selected objects should be exported</param> /// <param name="autoSaveMayaFile">Specifies if the Maya scene should be auto-saved</param> /// <param name="exportHiddenObjects">Specifies if hidden objects should be exported</param> /// <param name="copyTexturesToOutput">Specifies if textures should be copied to the output directory</param> /// <param name="optimizeVertices">Specifies if vertices should be optimized on export</param> /// <param name="exportTangents">Specifies if tangents should be exported</param> /// <param name="scaleFactor">Scales the scene by this factor</param> /// <param name="exportSkin">Specifies if skins should be exported</param> /// <param name="quality">The texture quality</param> /// <param name="dracoCompression">Specifies if draco compression should be used</param> /// <param name="exportMorphNormal">Specifies if normals should be exported for morph targets</param> /// <param name="exportMorphTangent">Specifies if tangents should be exported for morph targets</param> /// <param name="exportKHRLightsPunctual">Specifies if the KHR_lights_punctual extension should be enabled</param> /// <param name="exportKHRTextureTransform">Specifies if the KHR_texture_transform extension should be enabled</param> /// <param name="bakeAnimationFrames">Specifies if animations should be exporting keyframes directly or should manually bake out animations frame by frame</param> public void Export(ExportParameters exportParameters) { this.exportParameters = exportParameters; // Check if the animation is running MGlobal.executeCommand("play -q - state", out int isPlayed); if (isPlayed == 1) { RaiseError("Stop the animation before exporting."); return; } RaiseMessage("Export started", Color.Blue); var progression = 0.0f; ReportProgressChanged(progression); // Store export options this.isBabylonExported = exportParameters.outputFormat == "babylon" || exportParameters.outputFormat == "binary babylon"; var outputBabylonDirectory = Path.GetDirectoryName(exportParameters.outputPath); // Check directory exists if (!Directory.Exists(outputBabylonDirectory)) { RaiseError("Export stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); var babylonScene = new BabylonScene(outputBabylonDirectory); // Save scene if (exportParameters.autoSaveSceneFile) { RaiseMessage("Saving Maya file"); // Query expand file name string fileName = MGlobal.executeCommandStringResult($@"file -q -exn;"); // If scene has already been saved previously if (fileName.EndsWith(".ma") || fileName.EndsWith(".mb")) { // Name is already specified and this line will not fail MFileIO.save(); } else { // Open SaveAs dialog window MGlobal.executeCommand($@"fileDialog2;"); } } // Force output file extension to be babylon var outputFileName = Path.ChangeExtension(Path.GetFileName(exportParameters.outputPath), "babylon"); // Store selected nodes MSelectionList selectedNodes = new MSelectionList(); MGlobal.getActiveSelectionList(selectedNodes); selectedNodeFullPaths = new List <string>(); MItSelectionList mItSelectionList = new MItSelectionList(selectedNodes); while (!mItSelectionList.isDone) { MDagPath mDagPath = new MDagPath(); try { mItSelectionList.getDagPath(mDagPath); selectedNodeFullPaths.Add(mDagPath.fullPathName); } catch { // selected object is not a DAG object // fail silently } mItSelectionList.next(); } if (selectedNodeFullPaths.Count > 0) { RaiseMessage("Selected nodes full path"); foreach (string selectedNodeFullPath in selectedNodeFullPaths) { RaiseMessage(selectedNodeFullPath, 1); } } // Producer babylonScene.producer = new BabylonProducer { name = "Maya", version = "2018", exporter_version = exporterVersion, file = outputFileName }; // Global babylonScene.autoClear = true; // TODO - Retreive colors from Maya //babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); //babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); babylonScene.TimelineStartFrame = Loader.GetMinTime(); babylonScene.TimelineEndFrame = Loader.GetMaxTime(); babylonScene.TimelineFramesPerSecond = Loader.GetFPS(); // TODO - Add custom properties _exportQuaternionsInsteadOfEulers = true; PrintDAG(true); PrintDAG(false); // Store the current frame. It can be change to find a proper one for the node/bone export double currentTime = Loader.GetCurrentTime(); // -------------------- // ------ Nodes ------- // -------------------- RaiseMessage("Exporting nodes"); // It makes each morph target manager export starts from id = 0. BabylonMorphTargetManager.Reset(); // Clear materials referencedMaterials.Clear(); multiMaterials.Clear(); // Get all nodes var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kTransform); List <MDagPath> nodes = new List <MDagPath>(); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); // Check if one of its descendant (direct or not) is a mesh/camera/light/locator if (isNodeRelevantToExportRec(mDagPath) // Ensure it's not one of the default cameras used as viewports in Maya && defaultCameraNames.Contains(mDagPath.partialPathName) == false) { nodes.Add(mDagPath); } else { // Skip descendants dagIterator.prune(); } dagIterator.next(); } // Export all nodes var progressionStep = 100.0f / nodes.Count; foreach (MDagPath mDagPath in nodes) { BabylonNode babylonNode = null; try { switch (getApiTypeOfDirectDescendants(mDagPath)) { case MFn.Type.kMesh: babylonNode = ExportMesh(mDagPath, babylonScene); break; case MFn.Type.kCamera: babylonNode = ExportCamera(mDagPath, babylonScene); break; case MFn.Type.kLight: // Lights api type are actually kPointLight, kSpotLight... babylonNode = ExportLight(mDagPath, babylonScene); break; case MFn.Type.kLocator: // Camera target babylonNode = ExportDummy(mDagPath, babylonScene); break; } } catch (Exception e) { this.RaiseWarning(String.Format("Exception raised during export. Node will be exported as dummy node. \r\nMessage: \r\n{0} \r\n{1}", e.Message, e.InnerException), 2); } // If node is not exported successfully if (babylonNode == null) { // Create a dummy (empty mesh) babylonNode = ExportDummy(mDagPath, babylonScene); } ; // Update progress bar progression += progressionStep; ReportProgressChanged(progression); CheckCancelled(); } RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // if nothing is enlightened, exclude all meshes foreach (BabylonLight light in babylonScene.LightsList) { if (light.includedOnlyMeshesIds.Length == 0) { light.excludedMeshesIds = babylonScene.MeshesList.Select(m => m.id).ToArray(); } } /* * Switch coordinate system at global level * * Add a root node with negative scaling * Pros - It's safer to use a root node * Cons - It's cleaner to switch at object level (as it is done now) * Use root node method when you want to be 100% sure of the output * Don't forget to also inverse winding order of mesh indices */ //// Switch from right to left handed coordinate system //MUuid mUuid = new MUuid(); //mUuid.generate(); //var rootNode = new BabylonMesh //{ // name = "root", // id = mUuid.asString(), // scaling = new float[] { 1, 1, -1 } //}; //foreach(var babylonMesh in babylonScene.MeshesList) //{ // // Add root meshes as child to root node // if (babylonMesh.parentId == null) // { // babylonMesh.parentId = rootNode.id; // } //} //babylonScene.MeshesList.Add(rootNode); // Main camera BabylonCamera babylonMainCamera = null; if (babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light if (!exportParameters.pbrNoLight && babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default ambient light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } var sceneScaleFactor = exportParameters.scaleFactor; if (exportParameters.scaleFactor != 1.0f) { RaiseMessage(String.Format("A root node is added to globally scale the scene by {0}", sceneScaleFactor), 1); // Create root node for scaling BabylonMesh rootNode = new BabylonMesh { name = "root", id = Tools.GenerateUUID() }; rootNode.isDummy = true; float rootNodeScale = sceneScaleFactor; rootNode.scaling = new float[3] { rootNodeScale, rootNodeScale, rootNodeScale }; if (ExportQuaternionsInsteadOfEulers) { rootNode.rotationQuaternion = new float[] { 0, 0, 0, 1 }; } else { rootNode.rotation = new float[] { 0, 0, 0 }; } // Update all top nodes var babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode babylonNode in babylonNodes) { if (babylonNode.parentId == null) { babylonNode.parentId = rootNode.id; } } // Store root node babylonScene.MeshesList.Add(rootNode); } // -------------------- // ----- Materials ---- // -------------------- RaiseMessage("Exporting materials"); GenerateMaterialDuplicationDatas(babylonScene); foreach (var mat in referencedMaterials) { ExportMaterial(mat, babylonScene, exportParameters.pbrFull); CheckCancelled(); } foreach (var mat in multiMaterials) { ExportMultiMaterial(mat.Key, mat.Value, babylonScene, exportParameters.pbrFull); CheckCancelled(); } UpdateMeshesMaterialId(babylonScene); RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Export skeletons if (exportParameters.exportSkins && skins.Count > 0) { progressSkin = 0; progressSkinStep = 100 / skins.Count; ReportProgressChanged(progressSkin); RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // set back the frame Loader.SetCurrentTime(currentTime); // ---------------------------- // ----- Animation groups ----- // ---------------------------- RaiseMessage("Export animation groups"); // add animation groups to the scene babylonScene.animationGroups = ExportAnimationGroups(babylonScene); if (isBabylonExported) { // if we are exporting to .Babylon then remove then remove animations from nodes if there are animation groups. if (babylonScene.animationGroups.Count > 0) { // add animations of each nodes in the animGroup List <BabylonNode> babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode node in babylonNodes) { node.animations = null; } foreach (BabylonSkeleton skel in babylonScene.SkeletonsList) { foreach (BabylonBone bone in skel.bones) { bone.animation = null; } } } // setup a default skybox for the scene for .Babylon export. var sourcePath = exportParameters.pbrEnvironment; if (!string.IsNullOrEmpty(sourcePath)) { babylonScene.createDefaultSkybox = exportParameters.createDefaultSkybox; var fileName = Path.GetFileName(sourcePath); // Allow only dds file format if (!fileName.EndsWith(".dds")) { RaiseWarning("Failed to export defauenvironment texture: only .dds format is supported."); } else { RaiseMessage($"texture id = Max_Babylon_Default_Environment"); babylonScene.environmentTexture = fileName; if (exportParameters.writeTextures) { try { var destPath = Path.Combine(babylonScene.OutputPath, fileName); if (File.Exists(sourcePath) && sourcePath != destPath) { File.Copy(sourcePath, destPath, true); } } catch { // silently fails RaiseMessage($"Fail to export the default env texture", 3); } } } } } // Output babylonScene.Prepare(false, false); if (isBabylonExported) { Write(babylonScene, outputBabylonDirectory, outputFileName, exportParameters.outputFormat, exportParameters.generateManifest); } ReportProgressChanged(100); // Export glTF if (exportParameters.outputFormat == "gltf" || exportParameters.outputFormat == "glb") { bool generateBinary = exportParameters.outputFormat == "glb"; GLTFExporter gltfExporter = new GLTFExporter(); gltfExporter.ExportGltf(this.exportParameters, babylonScene, outputBabylonDirectory, outputFileName, generateBinary, this); } watch.Stop(); RaiseMessage(string.Format("Export done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
public void Export(string outputDirectory, string outputFileName, string outputFormat, bool generateManifest, bool onlySelected, bool autoSaveMayaFile, bool exportHiddenObjects, bool copyTexturesToOutput) { RaiseMessage("Exportation started", Color.Blue); var progression = 0.0f; ReportProgressChanged(progression); // Store export options _onlySelected = onlySelected; _exportHiddenObjects = exportHiddenObjects; isBabylonExported = outputFormat == "babylon" || outputFormat == "binary babylon"; // Check directory exists if (!Directory.Exists(outputDirectory)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); var outputBabylonDirectory = outputDirectory; var babylonScene = new BabylonScene(outputBabylonDirectory); // Save scene if (autoSaveMayaFile) { RaiseMessage("Saving Maya file"); // TODO //MFileIO.save(); } // Force output file extension to be babylon outputFileName = Path.ChangeExtension(outputFileName, "babylon"); // Producer babylonScene.producer = new BabylonProducer { name = "Maya", version = "2018", exporter_version = "1.0", file = outputFileName }; // Global babylonScene.autoClear = true; // TODO - Retreive colors from Maya //babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); //babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); // TODO - Add custom properties _exportQuaternionsInsteadOfEulers = true; // -------------------- // ------ Meshes ------ // -------------------- RaiseMessage("Exporting meshes"); // Get all meshes var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kMesh); List <MObject> mObjects = new List <MObject>(); while (!dagIterator.isDone) { var mObject = dagIterator.currentItem(); mObjects.Add(mObject); dagIterator.next(); } // Export all meshes var progressionStep = 100.0f / mObjects.Count; foreach (MObject mObject in mObjects) { ExportMesh(mObject, babylonScene); // Update progress bar progression += progressionStep; ReportProgressChanged(progression); } RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kMesh); // Switch from right to left handed coordinate system MUuid mUuid = new MUuid(); mUuid.generate(); var rootNode = new BabylonMesh { name = "root", id = mUuid.asString(), scaling = new float[] { 1, 1, -1 } }; foreach (var babylonMesh in babylonScene.MeshesList) { // Add root meshes as child to root node if (babylonMesh.parentId == null) { babylonMesh.parentId = rootNode.id; } } babylonScene.MeshesList.Add(rootNode); // -------------------- // ----- Materials ---- // -------------------- // TODO - Materials // Output babylonScene.Prepare(false, false); if (isBabylonExported) { Write(babylonScene, outputBabylonDirectory, outputFileName, outputFormat, generateManifest); } // TODO - Export glTF watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
protected void writeReferenceNodes(FileStream f) { // // We don't write out createNode commands for reference nodes, but // we do write out parenting between them and non-reference nodes, // as well as attributes added and attribute values changed after the // referenced file was loaded // writeRefNodeParenting(f); // // Output the commands for DAG nodes first. // MItDag dagIter = new MItDag(); for (dagIter.next(); !dagIter.isDone; dagIter.next()) { MObject node = dagIter.item(); MFnDependencyNode nodeFn = new MFnDependencyNode(node); if (nodeFn.isFromReferencedFile && !nodeFn.isFlagSet(fAttrFlag)) { writeNodeAttrs(f, node, false); // // Make note of any connections to this node which have been // broken by the main scene. // MFileIO.getReferenceConnectionsBroken( node, fBrokenConnSrcs, fBrokenConnDests, true, true ); nodeFn.setFlag(fAttrFlag, true); } } // // Now do the remaining, non-DAG nodes. // MItDependencyNodes nodeIter = new MItDependencyNodes(); for (; !nodeIter.isDone; nodeIter.next()) { MObject node = nodeIter.item; MFnDependencyNode nodeFn = new MFnDependencyNode(node); if (nodeFn.isFromReferencedFile && !nodeFn.isFlagSet(fAttrFlag)) { writeNodeAttrs(f, node, false); // // Make note of any connections to this node which have been // broken by the main scene. // MFileIO.getReferenceConnectionsBroken( node, fBrokenConnSrcs, fBrokenConnDests, true, true ); nodeFn.setFlag(fAttrFlag, true); } } }
// // Write out all of the connections in the scene. // protected void writeConnections(FileStream f) { // // If the scene has broken any connections which were made in referenced // files, handle those first so that the attributes are free for any new // connections which may come along. // writeBrokenRefConnections(f); // // We're about to write out the scene's connections in three parts: DAG // nodes, non-DAG non-default nodes, then default nodes. // // It's really not necessary that we group them like this and would in // fact be more efficient to do them all in one MItDependencyNodes // traversal. However, this is the order in which the normal MayaAscii // translator does them, so this makes it easier to compare the output // of this translator to Maya's output. // // // Write out connections for the DAG nodes first. // MItDag dagIter = new MItDag(); dagIter.traverseUnderWorld(true); for (dagIter.next(); !dagIter.isDone; dagIter.next()) { MObject node = dagIter.item(); MFnDagNode dagNodeFn = new MFnDagNode(node); if (!dagNodeFn.isFlagSet(fConnectionFlag) && dagNodeFn.canBeWritten && !dagNodeFn.isDefaultNode) { writeNodeConnections(f, dagIter.item()); dagNodeFn.setFlag(fConnectionFlag, true); } } // // Now do the non-DAG, non-default nodes. // MItDependencyNodes nodeIter = new MItDependencyNodes(); for (; !nodeIter.isDone; nodeIter.next()) { MFnDependencyNode nodeFn = new MFnDependencyNode(nodeIter.item); if (!nodeFn.isFlagSet(fConnectionFlag) && nodeFn.canBeWritten && !nodeFn.isDefaultNode) { writeNodeConnections(f, nodeIter.item); nodeFn.setFlag(fConnectionFlag, true); } } // // And finish up with the default nodes. // uint numNodes = fDefaultNodes.length; int i; for (i = 0; i < numNodes; i++) { MFnDependencyNode nodeFn = new MFnDependencyNode(fDefaultNodes[i]); if (!nodeFn.isFlagSet(fConnectionFlag) && nodeFn.canBeWritten && nodeFn.isDefaultNode) { writeNodeConnections(f, fDefaultNodes[i]); nodeFn.setFlag(fConnectionFlag, true); } } }
public void ResetLights() { //<AmbientLight Color="White" /> //<DirectionalLight Color="White" Direction="-1,-1,-1" /> //<PointLight Color="White" ConstantAttenuation="1" LinearAttenuation="1" Position="0,0,0" QuadraticAttenuation="1" Range="0" /> //<SpotLight Color="White" ConstantAttenuation="1" Direction="-1,-1,-1" InnerConeAngle="10" LinearAttenuation="1" OuterConeAngle="10" Position="0,0,0" QuadraticAttenuation="1" Range="0" /> lights.Children.Clear () ; MItDag dagIterator =new MItDag (MItDag.TraversalType.kDepthFirst, MFn.Type.kLight) ; for ( ; !dagIterator.isDone ; dagIterator.next () ) { MDagPath lightPath =new MDagPath () ; dagIterator.getPath (lightPath) ; MFnLight light =new MFnLight (lightPath) ; bool isAmbient =light.lightAmbient ; MColor mcolor =light.color ; Color color =Color.FromScRgb (1.0f, mcolor.r, mcolor.g, mcolor.b) ; if ( isAmbient ) { AmbientLight ambient =new AmbientLight (color) ; lights.Children.Add (ambient) ; continue ; } MFloatVector lightDirection =light.lightDirection (0, MSpace.Space.kWorld) ; Vector3D direction =new Vector3D (lightDirection.x, lightDirection.y, lightDirection.z) ; bool isDiffuse =light.lightDiffuse ; try { MFnDirectionalLight dirLight =new MFnDirectionalLight (lightPath) ; DirectionalLight directional =new DirectionalLight (color, direction) ; lights.Children.Add (directional) ; continue ; } catch { } MObject transformNode =lightPath.transform ; MFnDagNode transform =new MFnDagNode (transformNode) ; MTransformationMatrix matrix =new MTransformationMatrix (transform.transformationMatrix) ; double [] threeDoubles =new double [3] ; int rOrder =0 ; //MTransformationMatrix.RotationOrder rOrder ; matrix.getRotation (threeDoubles, out rOrder, MSpace.Space.kWorld) ; matrix.getScale (threeDoubles, MSpace.Space.kWorld) ; MVector pos =matrix.getTranslation (MSpace.Space.kWorld) ; Point3D position =new Point3D (pos.x, pos.y, pos.z) ; try { MFnPointLight pointLight =new MFnPointLight (lightPath) ; PointLight point =new PointLight (color, position) ; //point.ConstantAttenuation =pointLight. ; // LinearAttenuation / QuadraticAttenuation //point.Range =pointLight.rayDepthLimit ; lights.Children.Add (point) ; continue ; } catch { } try { MFnSpotLight spotLight =new MFnSpotLight (lightPath) ; MAngle InnerConeAngle =new MAngle (spotLight.coneAngle) ; MAngle OuterConeAngle =new MAngle (spotLight.penumbraAngle) ; SpotLight spot =new SpotLight (color, position, direction, OuterConeAngle.asDegrees, InnerConeAngle.asDegrees) ; spot.ConstantAttenuation =spotLight.dropOff ; // LinearAttenuation / QuadraticAttenuation //spot.Range =spotLight.rayDepthLimit ; lights.Children.Add (spot) ; continue ; } catch { } } }
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); }
public void ResetLights() { //<AmbientLight Color="White" /> //<DirectionalLight Color="White" Direction="-1,-1,-1" /> //<PointLight Color="White" ConstantAttenuation="1" LinearAttenuation="1" Position="0,0,0" QuadraticAttenuation="1" Range="0" /> //<SpotLight Color="White" ConstantAttenuation="1" Direction="-1,-1,-1" InnerConeAngle="10" LinearAttenuation="1" OuterConeAngle="10" Position="0,0,0" QuadraticAttenuation="1" Range="0" /> lights.Children.Clear(); MItDag dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kLight); for ( ; !dagIterator.isDone; dagIterator.next()) { MDagPath lightPath = new MDagPath(); dagIterator.getPath(lightPath); MFnLight light = new MFnLight(lightPath); bool isAmbient = light.lightAmbient; MColor mcolor = light.color; Color color = Color.FromScRgb(1.0f, mcolor.r, mcolor.g, mcolor.b); if (isAmbient) { AmbientLight ambient = new AmbientLight(color); lights.Children.Add(ambient); continue; } MFloatVector lightDirection = light.lightDirection(0, MSpace.Space.kWorld); Vector3D direction = new Vector3D(lightDirection.x, lightDirection.y, lightDirection.z); bool isDiffuse = light.lightDiffuse; try { MFnDirectionalLight dirLight = new MFnDirectionalLight(lightPath); DirectionalLight directional = new DirectionalLight(color, direction); lights.Children.Add(directional); continue; } catch { } MObject transformNode = lightPath.transform; MFnDagNode transform = new MFnDagNode(transformNode); MTransformationMatrix matrix = new MTransformationMatrix(transform.transformationMatrix); double [] threeDoubles = new double [3]; int rOrder = 0; //MTransformationMatrix.RotationOrder rOrder ; matrix.getRotation(threeDoubles, out rOrder, MSpace.Space.kWorld); matrix.getScale(threeDoubles, MSpace.Space.kWorld); MVector pos = matrix.getTranslation(MSpace.Space.kWorld); Point3D position = new Point3D(pos.x, pos.y, pos.z); try { MFnPointLight pointLight = new MFnPointLight(lightPath); PointLight point = new PointLight(color, position); //point.ConstantAttenuation =pointLight. ; // LinearAttenuation / QuadraticAttenuation //point.Range =pointLight.rayDepthLimit ; lights.Children.Add(point); continue; } catch { } try { MFnSpotLight spotLight = new MFnSpotLight(lightPath); MAngle InnerConeAngle = new MAngle(spotLight.coneAngle); MAngle OuterConeAngle = new MAngle(spotLight.penumbraAngle); SpotLight spot = new SpotLight(color, position, direction, OuterConeAngle.asDegrees, InnerConeAngle.asDegrees); spot.ConstantAttenuation = spotLight.dropOff; // LinearAttenuation / QuadraticAttenuation //spot.Range =spotLight.rayDepthLimit ; lights.Children.Add(spot); continue; } catch { } } }
private void doScan(MItDag.TraversalType traversalType, MFn.Type filter, bool quiet) { MItDag dagIterator = new MItDag(traversalType, filter); // Scan the entire DAG and output the name and depth of each node if (traversalType == MItDag.TraversalType.kBreadthFirst) if (!quiet) MGlobal.displayInfo(Environment.NewLine + "Starting Breadth First scan of the Dag"); else if (!quiet) MGlobal.displayInfo(Environment.NewLine + "Starting Depth First scan of the Dag"); switch (filter) { case MFn.Type.kCamera: if (!quiet) MGlobal.displayInfo( ": Filtering for Cameras\n"); break; case MFn.Type.kLight: if (!quiet) MGlobal.displayInfo(": Filtering for Lights\n"); break; case MFn.Type.kNurbsSurface: if (!quiet) MGlobal.displayInfo(": Filtering for Nurbs Surfaces\n"); break; default: MGlobal.displayInfo(Environment.NewLine); break; } int objectCount = 0; for ( ; !dagIterator.isDone; dagIterator.next() ) { MDagPath dagPath = new MDagPath(); try { dagIterator.getPath(dagPath); } catch (System.Exception ) { continue; } MFnDagNode dagNode = null; try { dagNode = new MFnDagNode(dagPath); } catch (System.Exception ) { continue; } if (!quiet) MGlobal.displayInfo(dagNode.name + ": " + dagNode.typeName + Environment.NewLine); if (!quiet) MGlobal.displayInfo( " dagPath: " + dagPath.fullPathName + Environment.NewLine); objectCount += 1; if (dagPath.hasFn(MFn.Type.kCamera)) { MFnCamera camera = null; try { camera = new MFnCamera(dagPath); } catch (System.Exception) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Camera data // if (!quiet) { MGlobal.displayInfo(" eyePoint: " + MPointToString(camera.eyePoint(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" upDirection: " + MVectorToString( camera.upDirection(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" viewDirection: " + MVectorToString( camera.viewDirection(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" aspectRatio: " + Convert.ToString( camera.aspectRatio ) + Environment.NewLine); MGlobal.displayInfo(" horizontalFilmAperture: " + Convert.ToString(camera.horizontalFilmAperture ) + Environment.NewLine); MGlobal.displayInfo(" verticalFilmAperture: " + Convert.ToString(camera.verticalFilmAperture ) + Environment.NewLine); } } else if (dagPath.hasFn(MFn.Type.kLight)) { MFnLight light = null; try { light = new MFnLight(dagPath); } catch (System.Exception) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Light data // MColor color = light.color; if (!quiet) { MGlobal.displayInfo(string.Format(" color: [%f, %f, %f]\n", color.r, color.g, color.b)); } color = light.shadowColor; if (!quiet) { MGlobal.displayInfo(string.Format(" shadowColor: [%f, %f, %f]\n", color.r, color.g, color.b)); MGlobal.displayInfo(" intensity: "+Convert.ToString(light.intensity) + Environment.NewLine); } } else if (dagPath.hasFn(MFn.Type.kNurbsSurface)) { MFnNurbsSurface surface= null; try { surface = new MFnNurbsSurface(dagPath); } catch (System.Exception ) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Surface data // if (!quiet) { MGlobal.displayInfo(string.Format(" numCVs: %d * %s", surface.numCVsInU, surface.numCVsInV) + Environment.NewLine); MGlobal.displayInfo(string.Format(" numKnots: %d * %s\n", surface.numKnotsInU, surface.numKnotsInV) + Environment.NewLine); MGlobal.displayInfo(string.Format(" numSpans: %d * %s\n", surface.numSpansInU, surface.numSpansInV) + Environment.NewLine); } } else { // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); } } setResult(objectCount); }
private void doScan(MItDag.TraversalType traversalType, MFn.Type filter, bool quiet) { MItDag dagIterator = new MItDag(traversalType, filter); // Scan the entire DAG and output the name and depth of each node if (traversalType == MItDag.TraversalType.kBreadthFirst) { if (!quiet) { MGlobal.displayInfo(Environment.NewLine + "Starting Breadth First scan of the Dag"); } else if (!quiet) { MGlobal.displayInfo(Environment.NewLine + "Starting Depth First scan of the Dag"); } } switch (filter) { case MFn.Type.kCamera: if (!quiet) { MGlobal.displayInfo(": Filtering for Cameras\n"); } break; case MFn.Type.kLight: if (!quiet) { MGlobal.displayInfo(": Filtering for Lights\n"); } break; case MFn.Type.kNurbsSurface: if (!quiet) { MGlobal.displayInfo(": Filtering for Nurbs Surfaces\n"); } break; default: MGlobal.displayInfo(Environment.NewLine); break; } int objectCount = 0; for ( ; !dagIterator.isDone; dagIterator.next()) { MDagPath dagPath = new MDagPath(); try { dagIterator.getPath(dagPath); } catch (System.Exception) { continue; } MFnDagNode dagNode = null; try { dagNode = new MFnDagNode(dagPath); } catch (System.Exception) { continue; } if (!quiet) { MGlobal.displayInfo(dagNode.name + ": " + dagNode.typeName + Environment.NewLine); } if (!quiet) { MGlobal.displayInfo(" dagPath: " + dagPath.fullPathName + Environment.NewLine); } objectCount += 1; if (dagPath.hasFn(MFn.Type.kCamera)) { MFnCamera camera = null; try { camera = new MFnCamera(dagPath); } catch (System.Exception) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Camera data // if (!quiet) { MGlobal.displayInfo(" eyePoint: " + MPointToString(camera.eyePoint(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" upDirection: " + MVectorToString(camera.upDirection(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" viewDirection: " + MVectorToString(camera.viewDirection(MSpace.Space.kWorld)) + Environment.NewLine); MGlobal.displayInfo(" aspectRatio: " + Convert.ToString(camera.aspectRatio) + Environment.NewLine); MGlobal.displayInfo(" horizontalFilmAperture: " + Convert.ToString(camera.horizontalFilmAperture) + Environment.NewLine); MGlobal.displayInfo(" verticalFilmAperture: " + Convert.ToString(camera.verticalFilmAperture) + Environment.NewLine); } } else if (dagPath.hasFn(MFn.Type.kLight)) { MFnLight light = null; try { light = new MFnLight(dagPath); } catch (System.Exception) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Light data // MColor color = light.color; if (!quiet) { MGlobal.displayInfo(string.Format(" color: [%f, %f, %f]\n", color.r, color.g, color.b)); } color = light.shadowColor; if (!quiet) { MGlobal.displayInfo(string.Format(" shadowColor: [%f, %f, %f]\n", color.r, color.g, color.b)); MGlobal.displayInfo(" intensity: " + Convert.ToString(light.intensity) + Environment.NewLine); } } else if (dagPath.hasFn(MFn.Type.kNurbsSurface)) { MFnNurbsSurface surface = null; try { surface = new MFnNurbsSurface(dagPath); } catch (System.Exception) { continue; } // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); // Extract some interesting Surface data // if (!quiet) { MGlobal.displayInfo(string.Format(" numCVs: %d * %s", surface.numCVsInU, surface.numCVsInV) + Environment.NewLine); MGlobal.displayInfo(string.Format(" numKnots: %d * %s\n", surface.numKnotsInU, surface.numKnotsInV) + Environment.NewLine); MGlobal.displayInfo(string.Format(" numSpans: %d * %s\n", surface.numSpansInU, surface.numSpansInV) + Environment.NewLine); } } else { // Get the translation/rotation/scale data // printTransformData(dagPath, quiet); } } setResult(objectCount); }
private static Dictionary <string, MayaM2Bone> ExtractJoints(List <MayaM2Sequence> seqList) { var jointMap = new Dictionary <string, MayaM2Bone>(); //Goal of iteration : Extract raw joint data and store it in intermediate object, MayaM2Bone var processedJoints = new HashSet <string>(); for (var jointIter = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kJoint); !jointIter.isDone; jointIter.next()) { var jointPath = new MDagPath(); jointIter.getPath(jointPath); if (processedJoints.Contains(jointPath.fullPathName)) { continue; } MGlobal.displayInfo("Extracting raw data of " + jointPath.fullPathName); var joint = new MFnIkJoint(jointPath); var mayaBone = new MayaM2Bone(); jointMap[jointPath.fullPathName] = mayaBone; // Hierarchy var isRoot = joint.parentCount == 0 || !joint.parent(0).hasFn(MFn.Type.kJoint); if (!isRoot) { var parentPath = new MDagPath(); MDagPath.getAPathTo(joint.parent(0), parentPath); if (!jointMap.ContainsKey(parentPath.fullPathName)) { MGlobal.displayError("\tParent is not referenced. Crash incoming. Path : " + parentPath.fullPathName); } jointMap[jointPath.fullPathName].Parent = jointMap[parentPath.fullPathName]; } //Note : M2Bone.submesh_id is wrong in the wiki. Do not try to compute it. // Label jointMap[jointPath.fullPathName].Type = MGlobal.executeCommandStringResult("getAttr -asString " + joint.fullPathName + ".type"); jointMap[jointPath.fullPathName].OtherType = MGlobal.executeCommandStringResult("getAttr -asString " + joint.fullPathName + ".otherType"); jointMap[jointPath.fullPathName].Side = MGlobal.executeCommandStringResult("getAttr -asString " + joint.fullPathName + ".side"); // Base translation is used to compute position MAnimControl.currentTime = 0; jointMap[jointPath.fullPathName].BaseTranslation = joint.getTranslation(MSpace.Space.kTransform); foreach (var seq in seqList) { var transData = new List <Tuple <uint, MVector> >(); var rotData = new List <Tuple <uint, MQuaternion> >(); var scaleData = new List <Tuple <uint, MVector> >(); for (var i = seq.Start; i < seq.End; i += 33) //TODO FIXME What if not multiple of 33 ? { //Get data for this joint for this frame MAnimControl.currentTime = new MTime(i, MTime.Unit.kMilliseconds); var translation = joint.getTranslation(MSpace.Space.kTransform); var rotation = new MQuaternion(); joint.getRotation(rotation, MSpace.Space.kTransform); var scaleArray = new double[3]; joint.getScale(scaleArray); var scale = new MVector(scaleArray); if (!translation.isEquivalent(MVector.zero, Epsilon)) { var previousIsTheSame = transData.Count > 0 && transData.Last().Item2.isEquivalent(translation, Epsilon); if (!previousIsTheSame) { transData.Add(new Tuple <uint, MVector>((uint)(i - seq.Start), translation)); } } if (!rotation.isEquivalent(MQuaternion.identity, Epsilon)) { var previousIsTheSame = rotData.Count > 0 && rotData.Last().Item2.isEquivalent(rotation, Epsilon); if (!previousIsTheSame) { rotData.Add(new Tuple <uint, MQuaternion>((uint)(i - seq.Start), rotation)); } } if (!scale.isEquivalent(MVector.one, Epsilon)) { var previousIsTheSame = scaleData.Count > 0 && scaleData.Last().Item2.isEquivalent(scale, Epsilon); if (!previousIsTheSame) { scaleData.Add(new Tuple <uint, MVector>((uint)(i - seq.Start), scale)); } } } if (transData.Count > 0) { jointMap[joint.fullPathName].Translation.Add(transData); } if (rotData.Count > 0) { jointMap[joint.fullPathName].Rotation.Add(rotData); } if (scaleData.Count > 0) { jointMap[joint.fullPathName].Scale.Add(scaleData); } } processedJoints.Add(jointPath.fullPathName); } //Goal of iteration : apply transformations to joint data & their children processedJoints.Clear(); for (var jointIter = new MItDag(MItDag.TraversalType.kBreadthFirst, MFn.Type.kJoint); !jointIter.isDone; jointIter.next()) { var jointPath = new MDagPath(); jointIter.getPath(jointPath); if (processedJoints.Contains(jointPath.fullPathName)) { continue; } MGlobal.displayInfo("Applying joint orient of " + jointPath.fullPathName); var joint = new MFnIkJoint(jointPath); var jointOrient = new MQuaternion(); joint.getOrientation(jointOrient); for (uint i = 0; i < joint.childCount; i++) { if (!joint.child(i).hasFn(MFn.Type.kJoint)) { continue; } var childFn = new MFnIkJoint(joint.child(i)); MGlobal.displayInfo("\tto " + childFn.fullPathName + ";"); jointMap[childFn.fullPathName].RotateTranslation(jointOrient); } processedJoints.Add(jointPath.fullPathName); } return(jointMap); }