/// <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> /// /// </summary> /// <param name="mDagPath">DAG path to the transform</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportDummy(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); MFnTransform mFnTransform = new MFnTransform(mDagPath); var babylonMesh = new BabylonMesh { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; babylonMesh.isDummy = true; // Position / rotation / scaling / hierarchy ExportNode(babylonMesh, mFnTransform, babylonScene); // TODO - Animations //exportAnimation(babylonMesh, meshNode); babylonScene.MeshesList.Add(babylonMesh); return(babylonMesh); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above mesh</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above mesh MFnTransform mFnTransform = new MFnTransform(mDagPath); // Mesh direct child of the transform MFnMesh mFnMesh = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.apiType == MFn.Type.kMesh) { var _mFnMesh = new MFnMesh(childObject); if (!_mFnMesh.isIntermediateObject) { mFnMesh = _mFnMesh; } } } if (mFnMesh == null) { RaiseError("No mesh found has child of " + mDagPath.fullPathName); return(null); } RaiseMessage("mFnMesh.fullPathName=" + mFnMesh.fullPathName, 2); // --- prints --- #region prints Action <MFnDagNode> printMFnDagNode = (MFnDagNode mFnDagNode) => { RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.name=" + mFnDagNode.name, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.absoluteName=" + mFnDagNode.absoluteName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.fullPathName=" + mFnDagNode.fullPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.partialPathName=" + mFnDagNode.partialPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.activeColor=" + mFnDagNode.activeColor.toString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.attributeCount=" + mFnDagNode.attributeCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.childCount=" + mFnDagNode.childCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dormantColor=" + mFnDagNode.dormantColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.hasUniqueName=" + mFnDagNode.hasUniqueName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.inUnderWorld=" + mFnDagNode.inUnderWorld, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isDefaultNode=" + mFnDagNode.isDefaultNode, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanceable=" + mFnDagNode.isInstanceable, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(true)=" + mFnDagNode.isInstanced(true), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(false)=" + mFnDagNode.isInstanced(false), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced()=" + mFnDagNode.isInstanced(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(true)=" + mFnDagNode.instanceCount(true), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(false)=" + mFnDagNode.instanceCount(false), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isIntermediateObject=" + mFnDagNode.isIntermediateObject, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isShared=" + mFnDagNode.isShared, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.objectColor=" + mFnDagNode.objectColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentCount=" + mFnDagNode.parentCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentNamespace=" + mFnDagNode.parentNamespace, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.uuid().asString()=" + mFnDagNode.uuid().asString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dagRoot().apiType=" + mFnDagNode.dagRoot().apiType, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.model.equalEqual(mFnDagNode.objectProperty)=" + mFnDagNode.model.equalEqual(mFnDagNode.objectProperty), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.transformationMatrix.toString()=" + mFnDagNode.transformationMatrix.toString(), 3); }; Action <MFnMesh> printMFnMesh = (MFnMesh _mFnMesh) => { printMFnDagNode(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numVertices=" + _mFnMesh.numVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numEdges=" + _mFnMesh.numEdges, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numPolygons=" + _mFnMesh.numPolygons, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numFaceVertices=" + _mFnMesh.numFaceVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numNormals=" + _mFnMesh.numNormals, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVSets=" + _mFnMesh.numUVSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVsProperty=" + _mFnMesh.numUVsProperty, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.displayColors=" + _mFnMesh.displayColors, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorSets=" + _mFnMesh.numColorSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorsProperty=" + _mFnMesh.numColorsProperty, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.currentUVSetName()=" + _mFnMesh.currentUVSetName(), 3); var _uvSetNames = new MStringArray(); mFnMesh.getUVSetNames(_uvSetNames); foreach (var uvSetName in _uvSetNames) { RaiseVerbose("BabylonExporter.Mesh | uvSetName=" + uvSetName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnMesh.numUVs(uvSetName)=" + mFnMesh.numUVs(uvSetName), 4); MFloatArray us = new MFloatArray(); MFloatArray vs = new MFloatArray(); mFnMesh.getUVs(us, vs, uvSetName); RaiseVerbose("BabylonExporter.Mesh | us.Count=" + us.Count, 4); } }; Action <MFnTransform> printMFnTransform = (MFnTransform _mFnMesh) => { printMFnDagNode(mFnMesh); }; RaiseVerbose("BabylonExporter.Mesh | mFnMesh data", 2); printMFnMesh(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | mFnTransform data", 2); printMFnTransform(mFnTransform); Print(mFnTransform, 2, "Print ExportMesh mFnTransform"); Print(mFnMesh, 2, "Print ExportMesh mFnMesh"); //// Geometry //MIntArray triangleCounts = new MIntArray(); //MIntArray trianglesVertices = new MIntArray(); //mFnMesh.getTriangles(triangleCounts, trianglesVertices); //RaiseVerbose("BabylonExporter.Mesh | triangleCounts.ToArray()=" + triangleCounts.ToArray().toString(), 3); //RaiseVerbose("BabylonExporter.Mesh | trianglesVertices.ToArray()=" + trianglesVertices.ToArray().toString(), 3); //int[] polygonsVertexCount = new int[mFnMesh.numPolygons]; //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // polygonsVertexCount[polygonId] = mFnMesh.polygonVertexCount(polygonId); //} //RaiseVerbose("BabylonExporter.Mesh | polygonsVertexCount=" + polygonsVertexCount.toString(), 3); ////MFloatPointArray points = new MFloatPointArray(); ////mFnMesh.getPoints(points); ////RaiseVerbose("BabylonExporter.Mesh | points.ToArray()=" + points.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); ////MFloatVectorArray normals = new MFloatVectorArray(); ////mFnMesh.getNormals(normals); ////RaiseVerbose("BabylonExporter.Mesh | normals.ToArray()=" + normals.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // MIntArray verticesId = new MIntArray(); // RaiseVerbose("BabylonExporter.Mesh | polygonId=" + polygonId, 3); // int nbTriangles = triangleCounts[polygonId]; // RaiseVerbose("BabylonExporter.Mesh | nbTriangles=" + nbTriangles, 3); // for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++) // { // RaiseVerbose("BabylonExporter.Mesh | triangleIndex=" + triangleIndex, 3); // int[] triangleVertices = new int[3]; // mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices); // RaiseVerbose("BabylonExporter.Mesh | triangleVertices=" + triangleVertices.toString(), 3); // foreach (int vertexId in triangleVertices) // { // RaiseVerbose("BabylonExporter.Mesh | vertexId=" + vertexId, 3); // MPoint point = new MPoint(); // mFnMesh.getPoint(vertexId, point); // RaiseVerbose("BabylonExporter.Mesh | point=" + point.toString(), 3); // MVector normal = new MVector(); // mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal); // RaiseVerbose("BabylonExporter.Mesh | normal=" + normal.toString(), 3); // } // } //} #endregion if (IsMeshExportable(mFnMesh, mDagPath) == false) { return(null); } var babylonMesh = new BabylonMesh { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Position / rotation / scaling / hierarchy ExportNode(babylonMesh, mFnTransform, babylonScene); // Misc. // TODO - Retreive from Maya // TODO - What is the difference between isVisible and visibility? // TODO - Fix fatal error: Attempting to save in C:/Users/Fabrice/AppData/Local/Temp/Fabrice.20171205.1613.ma //babylonMesh.isVisible = mDagPath.isVisible; //babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); //babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; //babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; if (mFnMesh.numPolygons < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (mFnMesh.numVertices < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (mFnMesh.numVertices >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has more than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2); } // Material MObjectArray shaders = new MObjectArray(); mFnMesh.getConnectedShaders(0, shaders, new MIntArray()); if (shaders.Count > 0) { List <MFnDependencyNode> materials = new List <MFnDependencyNode>(); foreach (MObject shader in shaders) { // Retreive material MFnDependencyNode shadingEngine = new MFnDependencyNode(shader); MPlug mPlugSurfaceShader = shadingEngine.findPlug("surfaceShader"); MObject materialObject = mPlugSurfaceShader.source.node; MFnDependencyNode material = new MFnDependencyNode(materialObject); materials.Add(material); } if (shaders.Count == 1) { MFnDependencyNode material = materials[0]; // Material is referenced by id babylonMesh.materialId = material.uuid().asString(); // Register material for export if not already done if (!referencedMaterials.Contains(material, new MFnDependencyNodeEqualityComparer())) { referencedMaterials.Add(material); } } else { // Create a new id for the group of sub materials string uuidMultiMaterial = GetMultimaterialUUID(materials); // Multi material is referenced by id babylonMesh.materialId = uuidMultiMaterial; // Register multi material for export if not already done if (!multiMaterials.ContainsKey(uuidMultiMaterial)) { multiMaterials.Add(uuidMultiMaterial, materials); } } } var vertices = new List <GlobalVertex>(); var indices = new List <int>(); var uvSetNames = new MStringArray(); mFnMesh.getUVSetNames(uvSetNames); bool[] isUVExportSuccess = new bool[Math.Min(uvSetNames.Count, 2)]; for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++) { isUVExportSuccess[indexUVSet] = true; } // TODO - color, alpha //var hasColor = unskinnedMesh.NumberOfColorVerts > 0; //var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0; // TODO - Add custom properties var optimizeVertices = false; // meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); // Compute normals var subMeshes = new List <BabylonSubMesh>(); ExtractGeometry(mFnMesh, vertices, indices, subMeshes, uvSetNames, ref isUVExportSuccess, optimizeVertices); if (vertices.Count >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2); if (!optimizeVertices) { RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2); } } for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++) { string uvSetName = uvSetNames[indexUVSet]; // If at least one vertex is mapped to an UV coordinate but some have failed to be exported if (isUVExportSuccess[indexUVSet] == false && mFnMesh.numUVs(uvSetName) > 0) { RaiseWarning($"Failed to export UV set named {uvSetName}. Ensure all vertices are mapped to a UV coordinate.", 2); } } RaiseMessage($"{vertices.Count} vertices, {indices.Count / 3} faces", 2); // Buffers babylonMesh.positions = vertices.SelectMany(v => v.Position).ToArray(); babylonMesh.normals = vertices.SelectMany(v => v.Normal).ToArray(); // TODO - Export colors ? //babylonMesh.colors = vertices.SelectMany(v => v.Color).ToArray(); if (uvSetNames.Count > 0 && isUVExportSuccess[0]) { babylonMesh.uvs = vertices.SelectMany(v => v.UV).ToArray(); } if (uvSetNames.Count > 1 && isUVExportSuccess[1]) { babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2).ToArray(); } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); babylonScene.MeshesList.Add(babylonMesh); RaiseMessage("BabylonExporter.Mesh | done", 2); return(babylonMesh); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above light</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportLight(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above light MFnTransform mFnTransform = new MFnTransform(mDagPath); // Light direct child of the transform MFnLight mFnLight = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.hasFn(MFn.Type.kLight)) { var _mFnLight = new MFnLight(childObject); if (!_mFnLight.isIntermediateObject) { mFnLight = _mFnLight; } } } if (mFnLight == null) { RaiseError("No light found has child of " + mDagPath.fullPathName); return(null); } RaiseMessage("mFnLight.fullPathName=" + mFnLight.fullPathName, 2); // --- prints --- #region prints // MFnLight RaiseVerbose("BabylonExporter.Light | mFnLight data", 2); RaiseVerbose("BabylonExporter.Light | mFnLight.color.toString()=" + mFnLight.color.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.intensity=" + mFnLight.intensity, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.useRayTraceShadows=" + mFnLight.useRayTraceShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.shadowColor.toString()=" + mFnLight.shadowColor.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.centerOfIllumination=" + mFnLight.centerOfIllumination, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.numShadowSamples=" + mFnLight.numShadowSamples, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.rayDepthLimit=" + mFnLight.rayDepthLimit, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.opticalFXvisibility.toString()=" + mFnLight.opticalFXvisibility.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightIntensity.toString()=" + mFnLight.lightIntensity.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.instanceCount(true)=" + mFnLight.instanceCount(true), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightDirection(0).toString()=" + mFnLight.lightDirection(0).toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightAmbient=" + mFnLight.lightAmbient, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightDiffuse=" + mFnLight.lightDiffuse, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightSpecular=" + mFnLight.lightSpecular, 3); switch (mFnLight.objectProperty.apiType) { case MFn.Type.kSpotLight: MFnSpotLight mFnSpotLight = new MFnSpotLight(mFnLight.objectProperty); // MFnNonAmbientLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.decayRate=" + mFnSpotLight.decayRate, 3); // dropdown enum value // MFnNonExtendedLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.shadowRadius=" + mFnSpotLight.shadowRadius, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.castSoftShadows=" + mFnSpotLight.castSoftShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.useDepthMapShadows=" + mFnSpotLight.useDepthMapShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapFilterSize()=" + mFnSpotLight.depthMapFilterSize(), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapResolution()=" + mFnSpotLight.depthMapResolution(), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapBias()=" + mFnSpotLight.depthMapBias(), 3); // MFnSpotLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.coneAngle=" + mFnSpotLight.coneAngle, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.penumbraAngle=" + mFnSpotLight.penumbraAngle, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.dropOff=" + mFnSpotLight.dropOff, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.barnDoors=" + mFnSpotLight.barnDoors, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.useDecayRegions=" + mFnSpotLight.useDecayRegions, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kFirst)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kFirst), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kFirst)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kFirst), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kSecond)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kSecond), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kSecond)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kSecond), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kThird)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kThird), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird), 3); break; } Print(mFnTransform, 2, "Print ExportLight mFnTransform"); Print(mFnLight, 2, "Print ExportLight mFnLight"); #endregion if (IsLightExportable(mFnLight, mDagPath) == false) { return(null); } var babylonLight = new BabylonLight { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Hierarchy ExportHierarchy(babylonLight, mFnTransform); // User custom attributes babylonLight.metadata = ExportCustomAttributeFromTransform(mFnTransform); // Position //RaiseVerbose("BabylonExporter.Light | ExportTransform", 2); float[] position = null; GetTransform(mFnTransform, ref position); babylonLight.position = position; // Direction var vDir = new MVector(0, 0, -1); var transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix); vDir = vDir.multiply(transformationMatrix.asMatrixProperty); vDir.normalize(); babylonLight.direction = new[] { (float)vDir.x, (float)vDir.y, -(float)vDir.z }; // Common fields babylonLight.intensity = mFnLight.intensity; babylonLight.diffuse = mFnLight.lightDiffuse ? mFnLight.color.toArrayRGB() : new float[] { 0, 0, 0 }; babylonLight.specular = mFnLight.lightSpecular ? mFnLight.color.toArrayRGB() : new float[] { 0, 0, 0 }; // Type switch (mFnLight.objectProperty.apiType) { case MFn.Type.kPointLight: babylonLight.type = 0; break; case MFn.Type.kSpotLight: MFnSpotLight mFnSpotLight = new MFnSpotLight(mFnLight.objectProperty); babylonLight.type = 2; babylonLight.angle = (float)mFnSpotLight.coneAngle; babylonLight.exponent = 1; if (mFnSpotLight.useDecayRegions) { babylonLight.range = mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird); // Max distance } break; case MFn.Type.kDirectionalLight: babylonLight.type = 1; break; case MFn.Type.kAmbientLight: babylonLight.type = 3; babylonLight.groundColor = new float[] { 0, 0, 0 }; // No emit diffuse /specular checkbox for ambient light babylonLight.diffuse = mFnLight.color.toArrayRGB(); babylonLight.specular = babylonLight.diffuse; // Direction vDir = new MVector(0, 1, 0); transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix); vDir = vDir.multiply(transformationMatrix.asMatrixProperty); vDir.normalize(); babylonLight.direction = new[] { (float)vDir.x, (float)vDir.y, -(float)vDir.z }; break; case MFn.Type.kAreaLight: case MFn.Type.kVolumeLight: RaiseError("Unsupported light type '" + mFnLight.objectProperty.apiType + "' for DAG path '" + mFnLight.fullPathName + "'. Light is ignored. Supported light types are: ambient, directional, point and spot.", 1); return(null); default: RaiseWarning("Unknown light type '" + mFnLight.objectProperty.apiType + "' for DAG path '" + mFnLight.fullPathName + "'. Light is ignored.", 1); return(null); } // TODO - Shadows //Variable declaration MStringArray enlightedMeshesFullPathNames = new MStringArray(); List <string> includeMeshesIds = new List <string>(); MStringArray kTransMesh = new MStringArray(); String typeMesh = null; MStringArray UUIDMesh = new MStringArray(); //MEL Command that get the enlighted mesh for a given light MGlobal.executeCommand($@"lightlink -query -light {mFnTransform.fullPathName};", enlightedMeshesFullPathNames); //For each enlighted mesh foreach (String Mesh in enlightedMeshesFullPathNames) { //MEL Command use to get the type of each mesh typeMesh = MGlobal.executeCommandStringResult($@"nodeType -api {Mesh};"); //We are targeting the type kMesh and not kTransform (for parenting) if (typeMesh == "kMesh") { MGlobal.executeCommand($@"listRelatives -parent -fullPath {Mesh};", kTransMesh); //And finally the MEL Command for the uuid of each mesh MGlobal.executeCommand($@"ls -uuid {kTransMesh[0]};", UUIDMesh); includeMeshesIds.Add(UUIDMesh[0]); } } babylonLight.includedOnlyMeshesIds = includeMeshesIds.ToArray(); // Animations if (exportParameters.bakeAnimationFrames) { ExportNodeAnimationFrameByFrame(babylonLight, mFnTransform); } else { ExportNodeAnimation(babylonLight, mFnTransform); } babylonScene.LightsList.Add(babylonLight); return(babylonLight); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above camera</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportCamera(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above camera MFnTransform mFnTransform = new MFnTransform(mDagPath); // Camera direct child of the transform MFnCamera mFnCamera = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.apiType == MFn.Type.kCamera) { var _mFnCamera = new MFnCamera(childObject); if (!_mFnCamera.isIntermediateObject) { mFnCamera = _mFnCamera; } } } if (mFnCamera == null) { RaiseError("No camera found has child of " + mDagPath.fullPathName); return(null); } // --- prints --- #region prints RaiseVerbose("BabylonExporter.Camera | mFnCamera data", 2); RaiseVerbose("BabylonExporter.Camera | mFnCamera.eyePoint(MSpace.Space.kWorld).toString()=" + mFnCamera.eyePoint(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.viewDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.viewDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.upDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.upDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.rightDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.rightDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.centerOfInterestPoint(MSpace.Space.kWorld).toString()=" + mFnCamera.centerOfInterestPoint(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.centerOfInterest=" + mFnCamera.centerOfInterest, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.aspectRatio=" + mFnCamera.aspectRatio, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.horizontalFieldOfView=" + mFnCamera.horizontalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.verticalFieldOfView=" + mFnCamera.verticalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.horizontalFieldOfView / mFnCamera.verticalFieldOfView=" + mFnCamera.horizontalFieldOfView / mFnCamera.verticalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.focalLength=" + mFnCamera.focalLength, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.nearFocusDistance=" + mFnCamera.nearFocusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.nearClippingPlane=" + mFnCamera.nearClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.unnormalizedNearClippingPlane=" + mFnCamera.unnormalizedNearClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.farFocusDistance=" + mFnCamera.farFocusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.farClippingPlane=" + mFnCamera.farClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.unnormalizedFarClippingPlane=" + mFnCamera.unnormalizedFarClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isClippingPlanes=" + mFnCamera.isClippingPlanes, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isIntermediateObject=" + mFnCamera.isIntermediateObject, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.focusDistance=" + mFnCamera.focusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isStereo=" + mFnCamera.isStereo, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.eyeOffset=" + mFnCamera.eyeOffset, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.shutterAngle=" + mFnCamera.shutterAngle, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isDepthOfField=" + mFnCamera.isDepthOfField, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.renderPanZoom=" + mFnCamera.renderPanZoom, 3); Print(mFnTransform, 2, "Print ExportCamera mFnTransform"); Print(mFnCamera, 2, "Print ExportCamera mFnCamera"); #endregion if (IsCameraExportable(mFnCamera, mDagPath) == false) { return(null); } var babylonCamera = new BabylonCamera { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Hierarchy ExportHierarchy(babylonCamera, mFnTransform); // Position / rotation RaiseVerbose("BabylonExporter.Camera | ExportTransform", 2); float[] position = null; float[] rotationQuaternion = null; float[] rotation = null; float[] scaling = null; GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref scaling); babylonCamera.position = position; if (_exportQuaternionsInsteadOfEulers) { babylonCamera.rotationQuaternion = rotationQuaternion; } babylonCamera.rotation = rotation; // Field of view of babylon is the vertical one babylonCamera.fov = (float)mFnCamera.verticalFieldOfView; // Clipping planes babylonCamera.minZ = (float)mFnCamera.nearClippingPlane; babylonCamera.maxZ = (float)mFnCamera.farClippingPlane; // Constraints on near clipping plane if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // TODO - Retreive from Maya //// Type //babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); //// Control //babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); //babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); //// Collisions //babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); //babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); //babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Target MFnTransform target = null; MObject cameraGroupObject = mFnCamera.findPlug("centerOfInterest").source.node; if (cameraGroupObject.apiType == MFn.Type.kLookAt) { MFnDependencyNode cameraGroup = new MFnDependencyNode(cameraGroupObject); // Retreive the camera aim transform MPlugArray connections = new MPlugArray(); cameraGroup.getConnections(connections); foreach (MPlug connection in connections) { if (connection.name.EndsWith("targetParentMatrix")) // ugly { MObject connectionSourceObject = connection.source.node; target = new MFnTransform(connectionSourceObject); break; } } } if (target != null) { babylonCamera.lockedTargetId = target.uuid().asString(); } //// TODO - Check if should be local or world //var vDir = new MVector(0, 0, -1); //var transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix); //vDir *= transformationMatrix.asMatrix(1); //vDir = vDir.Add(position); //babylonCamera.target = new[] { vDir.X, vDir.Y, vDir.Z }; // Animations if (target == null) { ExportNodeAnimation(babylonCamera, mFnTransform); } else { ExportNodeAnimationFrameByFrame(babylonCamera, mFnTransform); } babylonScene.CamerasList.Add(babylonCamera); RaiseMessage("BabylonExporter.Camera | done", 2); return(babylonCamera); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above mesh</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above mesh mFnTransform = new MFnTransform(mDagPath); // Mesh direct child of the transform // TODO get the original one rather than the modified? MFnMesh mFnMesh = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.apiType == MFn.Type.kMesh) { var _mFnMesh = new MFnMesh(childObject); if (!_mFnMesh.isIntermediateObject) { mFnMesh = _mFnMesh; } } } if (mFnMesh == null) { RaiseError("No mesh found has child of " + mDagPath.fullPathName); return(null); } RaiseMessage("mFnMesh.fullPathName=" + mFnMesh.fullPathName, 2); // --- prints --- #region prints Action <MFnDagNode> printMFnDagNode = (MFnDagNode mFnDagNode) => { RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.name=" + mFnDagNode.name, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.absoluteName=" + mFnDagNode.absoluteName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.fullPathName=" + mFnDagNode.fullPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.partialPathName=" + mFnDagNode.partialPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.activeColor=" + mFnDagNode.activeColor.toString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.attributeCount=" + mFnDagNode.attributeCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.childCount=" + mFnDagNode.childCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dormantColor=" + mFnDagNode.dormantColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.hasUniqueName=" + mFnDagNode.hasUniqueName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.inUnderWorld=" + mFnDagNode.inUnderWorld, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isDefaultNode=" + mFnDagNode.isDefaultNode, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanceable=" + mFnDagNode.isInstanceable, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(true)=" + mFnDagNode.isInstanced(true), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(false)=" + mFnDagNode.isInstanced(false), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced()=" + mFnDagNode.isInstanced(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(true)=" + mFnDagNode.instanceCount(true), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(false)=" + mFnDagNode.instanceCount(false), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isIntermediateObject=" + mFnDagNode.isIntermediateObject, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isShared=" + mFnDagNode.isShared, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.objectColor=" + mFnDagNode.objectColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentCount=" + mFnDagNode.parentCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentNamespace=" + mFnDagNode.parentNamespace, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.uuid().asString()=" + mFnDagNode.uuid().asString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dagRoot().apiType=" + mFnDagNode.dagRoot().apiType, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.model.equalEqual(mFnDagNode.objectProperty)=" + mFnDagNode.model.equalEqual(mFnDagNode.objectProperty), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.transformationMatrix.toString()=" + mFnDagNode.transformationMatrix.toString(), 3); }; Action <MFnMesh> printMFnMesh = (MFnMesh _mFnMesh) => { printMFnDagNode(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numVertices=" + _mFnMesh.numVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numEdges=" + _mFnMesh.numEdges, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numPolygons=" + _mFnMesh.numPolygons, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numFaceVertices=" + _mFnMesh.numFaceVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numNormals=" + _mFnMesh.numNormals, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVSets=" + _mFnMesh.numUVSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVsProperty=" + _mFnMesh.numUVsProperty, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.displayColors=" + _mFnMesh.displayColors, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorSets=" + _mFnMesh.numColorSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorsProperty=" + _mFnMesh.numColorsProperty, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.currentUVSetName()=" + _mFnMesh.currentUVSetName(), 3); var _uvSetNames = new MStringArray(); mFnMesh.getUVSetNames(_uvSetNames); foreach (var uvSetName in _uvSetNames) { RaiseVerbose("BabylonExporter.Mesh | uvSetName=" + uvSetName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnMesh.numUVs(uvSetName)=" + mFnMesh.numUVs(uvSetName), 4); MFloatArray us = new MFloatArray(); MFloatArray vs = new MFloatArray(); mFnMesh.getUVs(us, vs, uvSetName); RaiseVerbose("BabylonExporter.Mesh | us.Count=" + us.Count, 4); } }; Action <MFnTransform> printMFnTransform = (MFnTransform _mFnMesh) => { printMFnDagNode(mFnMesh); }; RaiseVerbose("BabylonExporter.Mesh | mFnMesh data", 2); printMFnMesh(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | mFnTransform data", 2); printMFnTransform(mFnTransform); Print(mFnTransform, 2, "Print ExportMesh mFnTransform"); Print(mFnMesh, 2, "Print ExportMesh mFnMesh"); //// Geometry //MIntArray triangleCounts = new MIntArray(); //MIntArray trianglesVertices = new MIntArray(); //mFnMesh.getTriangles(triangleCounts, trianglesVertices); //RaiseVerbose("BabylonExporter.Mesh | triangleCounts.ToArray()=" + triangleCounts.ToArray().toString(), 3); //RaiseVerbose("BabylonExporter.Mesh | trianglesVertices.ToArray()=" + trianglesVertices.ToArray().toString(), 3); //int[] polygonsVertexCount = new int[mFnMesh.numPolygons]; //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // polygonsVertexCount[polygonId] = mFnMesh.polygonVertexCount(polygonId); //} //RaiseVerbose("BabylonExporter.Mesh | polygonsVertexCount=" + polygonsVertexCount.toString(), 3); ////MFloatPointArray points = new MFloatPointArray(); ////mFnMesh.getPoints(points); ////RaiseVerbose("BabylonExporter.Mesh | points.ToArray()=" + points.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); ////MFloatVectorArray normals = new MFloatVectorArray(); ////mFnMesh.getNormals(normals); ////RaiseVerbose("BabylonExporter.Mesh | normals.ToArray()=" + normals.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // MIntArray verticesId = new MIntArray(); // RaiseVerbose("BabylonExporter.Mesh | polygonId=" + polygonId, 3); // int nbTriangles = triangleCounts[polygonId]; // RaiseVerbose("BabylonExporter.Mesh | nbTriangles=" + nbTriangles, 3); // for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++) // { // RaiseVerbose("BabylonExporter.Mesh | triangleIndex=" + triangleIndex, 3); // int[] triangleVertices = new int[3]; // mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices); // RaiseVerbose("BabylonExporter.Mesh | triangleVertices=" + triangleVertices.toString(), 3); // foreach (int vertexId in triangleVertices) // { // RaiseVerbose("BabylonExporter.Mesh | vertexId=" + vertexId, 3); // MPoint point = new MPoint(); // mFnMesh.getPoint(vertexId, point); // RaiseVerbose("BabylonExporter.Mesh | point=" + point.toString(), 3); // MVector normal = new MVector(); // mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal); // RaiseVerbose("BabylonExporter.Mesh | normal=" + normal.toString(), 3); // } // } //} #endregion if (IsMeshExportable(mFnMesh, mDagPath) == false) { return(null); } var babylonMesh = new BabylonMesh { name = mFnTransform.name, id = mFnTransform.uuid().asString(), visibility = Loader.GetVisibility(mFnTransform.fullPathName) }; // Instance // For a mesh with instances, we distinguish between master and instance meshes: // - a master mesh stores all the info of the mesh (transform, hierarchy, animations + vertices, indices, materials, bones...) // - an instance mesh only stores the info of the node (transform, hierarchy, animations) // Check if this mesh has already been exported as a master mesh BabylonMesh babylonMasterMesh = GetMasterMesh(mFnMesh, babylonMesh); if (babylonMasterMesh != null) { RaiseMessage($"The master mesh {babylonMasterMesh.name} was already exported. This one will be exported as an instance.", 2); // Export this node as instance var babylonInstanceMesh = new BabylonAbstractMesh { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; //// Add instance to master mesh List <BabylonAbstractMesh> instances = babylonMasterMesh.instances != null?babylonMasterMesh.instances.ToList() : new List <BabylonAbstractMesh>(); instances.Add(babylonInstanceMesh); babylonMasterMesh.instances = instances.ToArray(); // Export transform / hierarchy / animations ExportNode(babylonInstanceMesh, mFnTransform, babylonScene); // Animations ExportNodeAnimation(babylonInstanceMesh, mFnTransform); return(babylonInstanceMesh); } // Position / rotation / scaling / hierarchy ExportNode(babylonMesh, mFnTransform, babylonScene); // Misc. // TODO - Retreive from Maya //babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; //babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; if (mFnMesh.numPolygons < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (mFnMesh.numVertices < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (mFnMesh.numVertices >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has more than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2); } // Animations ExportNodeAnimation(babylonMesh, mFnTransform); // Material MObjectArray shaders = new MObjectArray(); mFnMesh.getConnectedShaders(0, shaders, new MIntArray()); if (shaders.Count > 0) { List <MFnDependencyNode> materials = new List <MFnDependencyNode>(); foreach (MObject shader in shaders) { // Retreive material MFnDependencyNode shadingEngine = new MFnDependencyNode(shader); MPlug mPlugSurfaceShader = shadingEngine.findPlug("surfaceShader"); MObject materialObject = mPlugSurfaceShader.source.node; MFnDependencyNode material = new MFnDependencyNode(materialObject); materials.Add(material); } if (shaders.Count == 1) { MFnDependencyNode material = materials[0]; // Material is referenced by id babylonMesh.materialId = material.uuid().asString(); // Register material for export if not already done if (!referencedMaterials.Contains(material, new MFnDependencyNodeEqualityComparer())) { referencedMaterials.Add(material); } } else { // Create a new id for the group of sub materials string uuidMultiMaterial = GetMultimaterialUUID(materials); // Multi material is referenced by id babylonMesh.materialId = uuidMultiMaterial; // Register multi material for export if not already done if (!multiMaterials.ContainsKey(uuidMultiMaterial)) { multiMaterials.Add(uuidMultiMaterial, materials); } } } var vertices = new List <GlobalVertex>(); var indices = new List <int>(); var uvSetNames = new MStringArray(); mFnMesh.getUVSetNames(uvSetNames); bool[] isUVExportSuccess = new bool[Math.Min(uvSetNames.Count, 2)]; for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++) { isUVExportSuccess[indexUVSet] = true; } // skin if (_exportSkin) { mFnSkinCluster = getMFnSkinCluster(mFnMesh); } int maxNbBones = 0; if (mFnSkinCluster != null) { RaiseMessage($"mFnSkinCluster.name | {mFnSkinCluster.name}", 2); Print(mFnSkinCluster, 3, $"Print {mFnSkinCluster.name}"); // Get the bones dictionary<name, index> => it represents all the bones in the skeleton indexByNodeName = GetIndexByFullPathNameDictionary(mFnSkinCluster); // Get the joint names that influence this mesh allMayaInfluenceNames = GetBoneFullPathName(mFnSkinCluster, mFnTransform); // Get the max number of joints acting on a vertex int maxNumInfluences = GetMaxInfluence(mFnSkinCluster, mFnTransform, mFnMesh); RaiseMessage($"Max influences : {maxNumInfluences}", 2); if (maxNumInfluences > 8) { RaiseWarning($"Too many bones influences per vertex: {maxNumInfluences}. Babylon.js only support up to 8 bones influences per vertex.", 2); RaiseWarning("The result may not be as expected.", 2); } maxNbBones = Math.Min(maxNumInfluences, 8); if (indexByNodeName != null && allMayaInfluenceNames != null) { babylonMesh.skeletonId = GetSkeletonIndex(mFnSkinCluster); } else { mFnSkinCluster = null; } } // Export tangents if option is checked and mesh have tangents bool isTangentExportSuccess = _exportTangents; // TODO - color, alpha //var hasColor = unskinnedMesh.NumberOfColorVerts > 0; //var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0; // TODO - Add custom properties //var optimizeVertices = false; // meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); var optimizeVertices = _optimizeVertices; // global option // Compute normals var subMeshes = new List <BabylonSubMesh>(); ExtractGeometry(mFnMesh, vertices, indices, subMeshes, uvSetNames, ref isUVExportSuccess, ref isTangentExportSuccess, optimizeVertices); if (vertices.Count >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2); if (!optimizeVertices) { RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2); } } for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++) { string uvSetName = uvSetNames[indexUVSet]; // If at least one vertex is mapped to an UV coordinate but some have failed to be exported if (isUVExportSuccess[indexUVSet] == false && mFnMesh.numUVs(uvSetName) > 0) { RaiseWarning($"Failed to export UV set named {uvSetName}. Ensure all vertices are mapped to a UV coordinate.", 2); } } RaiseMessage($"{vertices.Count} vertices, {indices.Count / 3} faces", 2); // Buffers babylonMesh.positions = vertices.SelectMany(v => v.Position).ToArray(); babylonMesh.normals = vertices.SelectMany(v => v.Normal).ToArray(); // export the skin if (mFnSkinCluster != null) { babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray(); babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray(); babylonMesh.numBoneInfluencers = maxNbBones; if (maxNbBones > 4) { babylonMesh.matricesWeightsExtra = vertices.SelectMany(v => v.WeightsExtra != null ? v.WeightsExtra.ToArray() : new[] { 0.0f, 0.0f, 0.0f, 0.0f }).ToArray(); babylonMesh.matricesIndicesExtra = vertices.Select(v => v.BonesIndicesExtra).ToArray(); } } // Tangent if (isTangentExportSuccess) { babylonMesh.tangents = vertices.SelectMany(v => v.Tangent).ToArray(); } // Color string colorSetName; mFnMesh.getCurrentColorSetName(out colorSetName); if (mFnMesh.numColors(colorSetName) > 0) { babylonMesh.colors = vertices.SelectMany(v => v.Color).ToArray(); } // UVs if (uvSetNames.Count > 0 && isUVExportSuccess[0]) { babylonMesh.uvs = vertices.SelectMany(v => v.UV).ToArray(); } if (uvSetNames.Count > 1 && isUVExportSuccess[1]) { babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2).ToArray(); } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); babylonScene.MeshesList.Add(babylonMesh); RaiseMessage("BabylonExporter.Mesh | done", 2); return(babylonMesh); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above light</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportLight(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above light MFnTransform mFnTransform = new MFnTransform(mDagPath); // Light direct child of the transform MFnLight mFnLight = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.hasFn(MFn.Type.kLight)) { mFnLight = new MFnLight(childObject); } } if (mFnLight == null) { RaiseError("No light found has child of " + mDagPath.fullPathName); return(null); } RaiseMessage("mFnLight.fullPathName=" + mFnLight.fullPathName, 2); // --- prints --- #region prints // MFnLight RaiseVerbose("BabylonExporter.Light | mFnLight data", 2); RaiseVerbose("BabylonExporter.Light | mFnLight.color.toString()=" + mFnLight.color.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.intensity=" + mFnLight.intensity, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.useRayTraceShadows=" + mFnLight.useRayTraceShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.shadowColor.toString()=" + mFnLight.shadowColor.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.centerOfIllumination=" + mFnLight.centerOfIllumination, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.numShadowSamples=" + mFnLight.numShadowSamples, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.rayDepthLimit=" + mFnLight.rayDepthLimit, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.opticalFXvisibility.toString()=" + mFnLight.opticalFXvisibility.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightIntensity.toString()=" + mFnLight.lightIntensity.toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.instanceCount(true)=" + mFnLight.instanceCount(true), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightDirection(0).toString()=" + mFnLight.lightDirection(0).toString(), 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightAmbient=" + mFnLight.lightAmbient, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightDiffuse=" + mFnLight.lightDiffuse, 3); RaiseVerbose("BabylonExporter.Light | mFnLight.lightSpecular=" + mFnLight.lightSpecular, 3); switch (mFnLight.objectProperty.apiType) { case MFn.Type.kSpotLight: MFnSpotLight mFnSpotLight = new MFnSpotLight(mFnLight.objectProperty); // MFnNonAmbientLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.decayRate=" + mFnSpotLight.decayRate, 3); // dropdown enum value // MFnNonExtendedLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.shadowRadius=" + mFnSpotLight.shadowRadius, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.castSoftShadows=" + mFnSpotLight.castSoftShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.useDepthMapShadows=" + mFnSpotLight.useDepthMapShadows, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapFilterSize()=" + mFnSpotLight.depthMapFilterSize(), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapResolution()=" + mFnSpotLight.depthMapResolution(), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.depthMapBias()=" + mFnSpotLight.depthMapBias(), 3); // MFnSpotLight RaiseVerbose("BabylonExporter.Light | mFnSpotLight.coneAngle=" + mFnSpotLight.coneAngle, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.penumbraAngle=" + mFnSpotLight.penumbraAngle, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.dropOff=" + mFnSpotLight.dropOff, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.barnDoors=" + mFnSpotLight.barnDoors, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.useDecayRegions=" + mFnSpotLight.useDecayRegions, 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kFirst)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kFirst), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kFirst)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kFirst), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kSecond)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kSecond), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kSecond)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kSecond), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kThird)=" + mFnSpotLight.startDistance(MFnSpotLight.MDecayRegion.kThird), 3); RaiseVerbose("BabylonExporter.Light | mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird)=" + mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird), 3); break; } #endregion if (IsLightExportable(mFnLight, mDagPath) == false) { return(null); } var babylonLight = new BabylonLight { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Hierarchy ExportHierarchy(babylonLight, mFnTransform); // Position RaiseVerbose("BabylonExporter.Light | ExportTransform", 2); float[] position = null; GetTransform(mFnTransform, ref position); babylonLight.position = position; // Direction var vDir = new MVector(0, 0, -1); var transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix); vDir = vDir.multiply(transformationMatrix.asMatrixProperty); vDir.normalize(); babylonLight.direction = new[] { (float)vDir.x, (float)vDir.y, -(float)vDir.z }; // Common fields babylonLight.intensity = mFnLight.intensity; babylonLight.diffuse = mFnLight.lightDiffuse ? mFnLight.color.toArrayRGB() : new float[] { 0, 0, 0 }; babylonLight.specular = mFnLight.lightSpecular ? mFnLight.color.toArrayRGB() : new float[] { 0, 0, 0 }; // Type switch (mFnLight.objectProperty.apiType) { case MFn.Type.kPointLight: babylonLight.type = 0; break; case MFn.Type.kSpotLight: MFnSpotLight mFnSpotLight = new MFnSpotLight(mFnLight.objectProperty); babylonLight.type = 2; babylonLight.angle = (float)mFnSpotLight.coneAngle; babylonLight.exponent = 1; if (mFnSpotLight.useDecayRegions) { babylonLight.range = mFnSpotLight.endDistance(MFnSpotLight.MDecayRegion.kThird); // Max distance } break; case MFn.Type.kDirectionalLight: babylonLight.type = 1; break; case MFn.Type.kAmbientLight: babylonLight.type = 3; babylonLight.groundColor = new float[] { 0, 0, 0 }; break; case MFn.Type.kAreaLight: case MFn.Type.kVolumeLight: RaiseError("Unsupported light type '" + mFnLight.objectProperty.apiType + "' for DAG path '" + mFnLight.fullPathName + "'. Light is ignored. Supported light types are: ambient, directional, point and spot."); return(null); default: RaiseWarning("Unknown light type '" + mFnLight.objectProperty.apiType + "' for DAG path '" + mFnLight.fullPathName + "'. Light is ignored."); return(null); } // TODO - Shadows // TODO - Exclusion // TODO - Animations babylonScene.LightsList.Add(babylonLight); return(babylonLight); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above mesh</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above mesh MFnTransform mFnTransform = new MFnTransform(mDagPath); // Mesh direct child of the transform MFnMesh mFnMesh = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.apiType == MFn.Type.kMesh) { mFnMesh = new MFnMesh(childObject); } } if (mFnMesh == null) { RaiseError("No mesh found has child of " + mDagPath.fullPathName); return(null); } RaiseMessage("mFnMesh.fullPathName=" + mFnMesh.fullPathName, 2); // --- prints --- #region prints Action <MFnDagNode> printMFnDagNode = (MFnDagNode mFnDagNode) => { RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.name=" + mFnDagNode.name, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.absoluteName=" + mFnDagNode.absoluteName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.fullPathName=" + mFnDagNode.fullPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.partialPathName=" + mFnDagNode.partialPathName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.activeColor=" + mFnDagNode.activeColor.toString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.attributeCount=" + mFnDagNode.attributeCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.childCount=" + mFnDagNode.childCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dormantColor=" + mFnDagNode.dormantColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.hasUniqueName=" + mFnDagNode.hasUniqueName, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.inUnderWorld=" + mFnDagNode.inUnderWorld, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isDefaultNode=" + mFnDagNode.isDefaultNode, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanceable=" + mFnDagNode.isInstanceable, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(true)=" + mFnDagNode.isInstanced(true), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(false)=" + mFnDagNode.isInstanced(false), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced()=" + mFnDagNode.isInstanced(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isIntermediateObject=" + mFnDagNode.isIntermediateObject, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isShared=" + mFnDagNode.isShared, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.objectColor=" + mFnDagNode.objectColor, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentCount=" + mFnDagNode.parentCount, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentNamespace=" + mFnDagNode.parentNamespace, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.uuid().asString()=" + mFnDagNode.uuid().asString(), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dagRoot().apiType=" + mFnDagNode.dagRoot().apiType, 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.model.equalEqual(mFnDagNode.objectProperty)=" + mFnDagNode.model.equalEqual(mFnDagNode.objectProperty), 3); RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.transformationMatrix.toString()=" + mFnDagNode.transformationMatrix.toString(), 3); }; Action <MFnMesh> printMFnMesh = (MFnMesh _mFnMesh) => { printMFnDagNode(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numVertices=" + _mFnMesh.numVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numEdges=" + _mFnMesh.numEdges, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numPolygons=" + _mFnMesh.numPolygons, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numFaceVertices=" + _mFnMesh.numFaceVertices, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numNormals=" + _mFnMesh.numNormals, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVSets=" + _mFnMesh.numUVSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVsProperty=" + _mFnMesh.numUVsProperty, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.displayColors=" + _mFnMesh.displayColors, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorSets=" + _mFnMesh.numColorSets, 3); RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorsProperty=" + _mFnMesh.numColorsProperty, 3); }; Action <MFnTransform> printMFnTransform = (MFnTransform _mFnMesh) => { printMFnDagNode(mFnMesh); }; RaiseVerbose("BabylonExporter.Mesh | mFnMesh data", 2); printMFnMesh(mFnMesh); RaiseVerbose("BabylonExporter.Mesh | mFnTransform data", 2); printMFnTransform(mFnTransform); //// Geometry //MIntArray triangleCounts = new MIntArray(); //MIntArray trianglesVertices = new MIntArray(); //mFnMesh.getTriangles(triangleCounts, trianglesVertices); //RaiseVerbose("BabylonExporter.Mesh | triangleCounts.ToArray()=" + triangleCounts.ToArray().toString(), 3); //RaiseVerbose("BabylonExporter.Mesh | trianglesVertices.ToArray()=" + trianglesVertices.ToArray().toString(), 3); //int[] polygonsVertexCount = new int[mFnMesh.numPolygons]; //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // polygonsVertexCount[polygonId] = mFnMesh.polygonVertexCount(polygonId); //} //RaiseVerbose("BabylonExporter.Mesh | polygonsVertexCount=" + polygonsVertexCount.toString(), 3); ////MFloatPointArray points = new MFloatPointArray(); ////mFnMesh.getPoints(points); ////RaiseVerbose("BabylonExporter.Mesh | points.ToArray()=" + points.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); ////MFloatVectorArray normals = new MFloatVectorArray(); ////mFnMesh.getNormals(normals); ////RaiseVerbose("BabylonExporter.Mesh | normals.ToArray()=" + normals.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3); //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) //{ // MIntArray verticesId = new MIntArray(); // RaiseVerbose("BabylonExporter.Mesh | polygonId=" + polygonId, 3); // int nbTriangles = triangleCounts[polygonId]; // RaiseVerbose("BabylonExporter.Mesh | nbTriangles=" + nbTriangles, 3); // for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++) // { // RaiseVerbose("BabylonExporter.Mesh | triangleIndex=" + triangleIndex, 3); // int[] triangleVertices = new int[3]; // mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices); // RaiseVerbose("BabylonExporter.Mesh | triangleVertices=" + triangleVertices.toString(), 3); // foreach (int vertexId in triangleVertices) // { // RaiseVerbose("BabylonExporter.Mesh | vertexId=" + vertexId, 3); // MPoint point = new MPoint(); // mFnMesh.getPoint(vertexId, point); // RaiseVerbose("BabylonExporter.Mesh | point=" + point.toString(), 3); // MVector normal = new MVector(); // mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal); // RaiseVerbose("BabylonExporter.Mesh | normal=" + normal.toString(), 3); // } // } //} #endregion if (IsMeshExportable(mFnMesh, mDagPath) == false) { return(null); } var babylonMesh = new BabylonMesh { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Position / rotation / scaling / hierarchy ExportNode(babylonMesh, mFnTransform, babylonScene); // Misc. // TODO - Retreive from Maya // TODO - What is the difference between isVisible and visibility? // TODO - Fix fatal error: Attempting to save in C:/Users/Fabrice/AppData/Local/Temp/Fabrice.20171205.1613.ma //babylonMesh.isVisible = mDagPath.isVisible; //babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); //babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; //babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; if (mFnMesh.numPolygons < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (mFnMesh.numVertices < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (mFnMesh.numVertices >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has more than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2); } // TODO - Material var vertices = new List <GlobalVertex>(); var indices = new List <int>(); // TODO - UV, color, alpha //var mappingChannels = unskinnedMesh.ActiveMapChannelNum; //bool hasUV = false; //bool hasUV2 = false; //for (int i = 0; i < mappingChannels.Count; ++i) //{ // var indexer = i; // var channelNum = mappingChannels[indexer]; // if (channelNum == 1) // { // hasUV = true; // } // else if (channelNum == 2) // { // hasUV2 = true; // } //} //var hasColor = unskinnedMesh.NumberOfColorVerts > 0; //var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0; // TODO - Add custom properties var optimizeVertices = false; // meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); // Compute normals var subMeshes = new List <BabylonSubMesh>(); ExtractGeometry(mFnMesh, vertices, indices, subMeshes, optimizeVertices); if (vertices.Count >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2); if (!optimizeVertices) { RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2); } } RaiseMessage($"{vertices.Count} vertices, {indices.Count / 3} faces", 2); // Buffers babylonMesh.positions = vertices.SelectMany(v => v.Position).ToArray(); babylonMesh.normals = vertices.SelectMany(v => v.Normal).ToArray(); babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); babylonScene.MeshesList.Add(babylonMesh); RaiseMessage("BabylonExporter.Mesh | done", 2); return(babylonMesh); }