IGMatrix WithNoScale(IGMatrix mat) { var mat3 = mat.ExtractMatrix3(); mat3.NoScale(); return(Loader.Global.GMatrix.Create(mat3)); }
/// <summary> /// Export the bones and their animation for the given skin /// </summary> /// <param name="skin">The skin to export</param> /// <returns></returns> private BabylonBone[] ExportBones(IIGameSkin skin) { List <BabylonBone> bones = new List <BabylonBone>(); List <int> nodeIndices = GetNodeIndices(skin); List <IIGameNode> revelantNodes = GetSkinnedBones(skin); foreach (IIGameNode node in revelantNodes) { int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID); string boneId = node.MaxNode.GetGuid().ToString(); // create the bone BabylonBone bone = new BabylonBone() { id = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs parentNodeId = (parentIndex != -1)?node.NodeParent.MaxNode.GetGuid().ToString():null, name = node.Name, index = nodeIndices.IndexOf(node.NodeID), parentBoneIndex = parentIndex, matrix = (parentIndex == -1)?node.GetWorldTM(0).ToArray():node.GetLocalTM(0).ToArray() }; // Apply unit conversion factor to meter // Affect translation only bone.matrix[12] *= scaleFactorToMeters; bone.matrix[13] *= scaleFactorToMeters; bone.matrix[14] *= scaleFactorToMeters; if (exportParameters.exportAnimations) { // export its animation var babylonAnimation = ExportMatrixAnimation("_matrix", key => { IGMatrix mat = node.GetLocalTM(key); float[] matrix = mat.ToArray(); // Apply unit conversion factor to meter // Affect translation only matrix[12] *= scaleFactorToMeters; matrix[13] *= scaleFactorToMeters; matrix[14] *= scaleFactorToMeters; return(matrix); }, false); // Do not remove linear animation keys for bones if (babylonAnimation != null) { babylonAnimation.name = node.Name + "Animation"; // override default animation name bone.animation = babylonAnimation; } } bones.Add(bone); } return(bones.ToArray()); }
public static CurveHandle GetCurve(IINode _node, int[] _frames, int _f, int _samplingRate) { CurveHandle result = new CurveHandle(Vector2.Zero, Vector2.Zero); IIGameNode _GNode = maxGlobal.IGameInterface.GetIGameNode(_node); int _ticks_per_frame = maxGlobal.TicksPerFrame; float delta = 0.0f; if (_f > 0) { List <Vector3> _samples = new List <Vector3>(); int nb_of_frames = _frames[_f] - _frames[_f - 1]; for (int i = _frames[_f - 1]; i <= _frames[_f]; i += _samplingRate) { float proportion = 1.0f - ((_frames[_f] - i) / (float)(nb_of_frames)); IGMatrix _node_LGmatrix = _GNode.GetLocalTM(i * _ticks_per_frame); DualQuaternion _node_LDQ = _node_LGmatrix.convertToDQ(Transformation.Rotation); _samples.Add(new Vector3(proportion, Math.Abs(_node_LDQ.RollPitchYaw.X) + Math.Abs(_node_LDQ.RollPitchYaw.Y) + Math.Abs(_node_LDQ.RollPitchYaw.Z), 0)); } List <BezierCurveFitting.BezierPoint> points = BezierCurveFitting.FitCurves.FitCurveBy(BezierCurveFitting.Method.Length, _samples.ToArray(), 0.01f, 2); delta = points[1].point.Y - points[0].point.Y; float val = points[1].foreHandle.Value.X; if (delta != 0) { val = (points[1].point.Y - points[1].foreHandle.Value.Y) / delta; } result.easeIn = new Vector2(points[1].foreHandle.Value.X, val); } else if (_f == 0) { result.easeIn = new Vector2(0.0f, 0.0f); } if (_f < _frames.Length - 1) { List <Vector3> _samples = new List <Vector3>(); int nb_of_frames = _frames[_f + 1] - _frames[_f]; for (int i = _frames[_f]; i <= _frames[_f + 1]; i += _samplingRate) { float proportion = 1.0f - ((_frames[_f + 1] - i) / (float)(nb_of_frames)); IGMatrix _node_LGmatrix = _GNode.GetLocalTM(i * _ticks_per_frame); DualQuaternion _node_LDQ = _node_LGmatrix.convertToDQ(Transformation.Rotation); _samples.Add(new Vector3(proportion, Math.Abs(_node_LDQ.RollPitchYaw.X) + Math.Abs(_node_LDQ.RollPitchYaw.Y) + Math.Abs(_node_LDQ.RollPitchYaw.Z), 0)); } List <BezierCurveFitting.BezierPoint> points = BezierCurveFitting.FitCurves.FitCurveBy(BezierCurveFitting.Method.Length, _samples.ToArray(), 0.01f, 2); delta = points[1].point.Y - points[0].point.Y; float val = points[0].afterHandle.Value.X; if (delta != 0) { val = (points[1].point.Y - points[0].afterHandle.Value.Y) / delta; } result.easeOut = new Vector2(points[0].afterHandle.Value.X, val); } else if (_f == _frames.Length - 1) { result.easeOut = new Vector2(1f, 1f); } return(result); }
public static DualQuaternion convertToDQ(this IGMatrix _input) { Matrix _matrix = new Matrix(_input.GetRow(0).X, _input.GetRow(0).Y, _input.GetRow(0).Z, 0, _input.GetRow(1).X, _input.GetRow(1).Y, _input.GetRow(1).Z, 0, _input.GetRow(2).X, _input.GetRow(2).Y, _input.GetRow(2).Z, 0, _input.GetRow(3).X, _input.GetRow(3).Y, _input.GetRow(3).Z, 1); Quaternion _node_LQ; Vector3 _node_LS; Vector3 _node_LT; _matrix.Decompose(out _node_LS, out _node_LQ, out _node_LT); DualQuaternion _output = new DualQuaternion(_node_LQ, _node_LT); return(_output); }
public ROD_ExportG() { maxGlobal = Autodesk.Max.GlobalInterface.Instance; maxInterface = maxGlobal.COREInterface14; IPoint3 U = maxGlobal.Point3.Create(1.0, 0.0, 0.0); IPoint3 V = maxGlobal.Point3.Create(0.0, 0.0, 1.0); IPoint3 N = maxGlobal.Point3.Create(0.0, -1.0, 0.0); IPoint3 T = maxGlobal.Point3.Create(0.0, 0.0, 0.0); _leftHanded = maxGlobal.Matrix3.Create(U, V, N, T); _GleftHanded = maxGlobal.GMatrix.Create(_leftHanded); }
public static DualQuaternion GetBoneWorldDQ(IINode _node, int _frame) { IInterval interval = maxGlobal.Interval.Create(); interval.SetInfinite(); IIGameNode GNode = maxGlobal.IGameInterface.GetIGameNode(_node); int _ticks_per_frame = maxGlobal.TicksPerFrame; IGMatrix _node_Gmatrix = GNode.GetWorldTM(_frame * _ticks_per_frame); DualQuaternion DQ = _node_Gmatrix.convertToDQ(); return(DQ); }
public static float[] ToArray(this IGMatrix gmat) { //float eulX =0, eulY=0, eulZ=0; //unsafe //{ // gmat.Rotation.GetEuler( new IntPtr(&eulX), new IntPtr(&eulY), new IntPtr(&eulZ)); //} //return (Matrix.Scaling(gmat.Scaling.X, gmat.Scaling.Y, gmat.Scaling.Z) * Matrix.RotationYawPitchRoll(eulY, eulX, eulZ) * Matrix.Translation(gmat.Translation.X, gmat.Translation.Y, gmat.Translation.Z)).ToArray(); var r0 = gmat.GetRow(0); var r1 = gmat.GetRow(1); var r2 = gmat.GetRow(2); var r3 = gmat.GetRow(3); return new float[] {r0.X, r0.Y, r0.Z, r0.W, r1.X, r1.Y,r1.Z, r1.W, r2.X, r2.Y,r2.Z, r2.W, r3.X, r3.Y,r3.Z, r3.W,}; }
public static DualQuaternion GetBoneLocalDQ(IINode _node, int[] _frames, int _f) { IINode _parent_node = _node.ParentNode; IIGameNode _GNode = maxGlobal.IGameInterface.GetIGameNode(_node); IIGameNode _parentGNode = maxGlobal.IGameInterface.GetIGameNode(_parent_node); int _ticks_per_frame = maxGlobal.TicksPerFrame; // node Local Transform IGMatrix _node_LGmatrix = _GNode.GetLocalTM(_frames[_f] * _ticks_per_frame); DualQuaternion _node_LDQ = _node_LGmatrix.convertToDQ(Transformation.Rotation); _node_LDQ.Normalize(); IGMatrix _node_BLGmatrix = _GNode.GetLocalTM(0); DualQuaternion _node_BLDQ = _node_BLGmatrix.convertToDQ(Transformation.Rotation); _node_BLDQ.Normalize(); DualQuaternion _node_LTDQL = _node_LDQ * DualQuaternion.Conjugate(_node_BLDQ); return(_node_LTDQL); }
public static DualQuaternion convertToDQ(this IGMatrix _input, Transformation _transformation) { Matrix _matrix = new Matrix(_input.GetRow(0).X, _input.GetRow(0).Y, _input.GetRow(0).Z, 0, _input.GetRow(1).X, _input.GetRow(1).Y, _input.GetRow(1).Z, 0, _input.GetRow(2).X, _input.GetRow(2).Y, _input.GetRow(2).Z, 0, _input.GetRow(3).X, _input.GetRow(3).Y, _input.GetRow(3).Z, 1); Quaternion _node_LQ; Vector3 _node_LS; Vector3 _node_LT; _matrix.Decompose(out _node_LS, out _node_LQ, out _node_LT); DualQuaternion _output = DualQuaternion.Identity; if (_transformation == Transformation.All) { _output = new DualQuaternion(_node_LQ, _node_LT); } if (_transformation == Transformation.Rotation) { _output = new DualQuaternion(_node_LQ, Vector3.Zero); } if (_transformation == Transformation.Translation) { _output = new DualQuaternion(Quaternion.Identity, _node_LT); } return(_output); }
private BabylonNode ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene) { if (IsMeshExportable(meshNode) == false) { return(null); } RaiseMessage(meshNode.Name, 1); // Instances var tabs = Loader.Global.NodeTab.Create(); Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs); if (tabs.Count > 1) { // 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 BabylonMesh babylonMasterMesh = null; var index = 0; while (babylonMasterMesh == null && index < tabs.Count) { #if MAX2017 var indexer = index; #else var indexer = new IntPtr(index); #endif var tab = tabs[indexer]; babylonMasterMesh = babylonScene.MeshesList.Find(_babylonMesh => { // Same id return(_babylonMesh.id == tab.GetGuid().ToString() && // Mesh is not a dummy _babylonMesh.isDummy == false); }); index++; } if (babylonMasterMesh != null) { // Mesh already exported // Export this node as instance meshNode.MaxNode.MarkAsInstance(); var babylonInstanceMesh = new BabylonAbstractMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() }; // Add instance to master mesh List <BabylonAbstractMesh> list = babylonMasterMesh.instances != null?babylonMasterMesh.instances.ToList() : new List <BabylonAbstractMesh>(); list.Add(babylonInstanceMesh); babylonMasterMesh.instances = list.ToArray(); // Export transform / hierarchy / animations exportNode(babylonInstanceMesh, meshNode, scene, babylonScene); // Animations exportAnimation(babylonInstanceMesh, meshNode); return(babylonInstanceMesh); } } var gameMesh = meshNode.IGameObject.AsGameMesh(); bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto // translated into a property because it has no parameters var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() }; // Position / rotation / scaling / hierarchy exportNode(babylonMesh, meshNode, scene, babylonScene); // Sounds var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", ""); if (!string.IsNullOrEmpty(soundName)) { var filename = Path.GetFileName(soundName); var meshSound = new BabylonSound { name = filename, autoplay = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1), loop = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1), volume = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f), playbackRate = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f), connectedMeshId = babylonMesh.id, isDirectional = false, spatialSound = false, distanceModel = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"), maxDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f), rolloffFactor = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f), refDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f), }; var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional"); if (isDirectional) { meshSound.isDirectional = true; meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f); meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f); meshSound.coneOuterGain = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f); } babylonScene.SoundsList.Add(meshSound); if (isBabylonExported) { try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } } // Misc. #if MAX2017 babylonMesh.isVisible = meshNode.MaxNode.Renderable; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics; #else babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; #endif babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable"); babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox"); babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox"); babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000); // Actions babylonMesh.actions = ExportNodeAction(meshNode); // Collisions babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); var isSkinned = gameMesh.IsObjectSkinned; var skin = gameMesh.IGameSkin; var unskinnedMesh = gameMesh; IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); List <int> boneIds = null; int maxNbBones = 0; if (isSkinned) { bonesCount = skin.TotalSkinBoneCount; var skinAlreadyStored = skins.Find(_skin => IsSkinEqualTo(_skin, skin)); if (skinAlreadyStored == null) { skins.Add(skin); } else { skin = skinAlreadyStored; } skinnedNodes.Add(meshNode); babylonMesh.skeletonId = skins.IndexOf(skin); skin.GetInitSkinTM(skinInitPoseMatrix); boneIds = SortBones(skin); skinSortedBones[skin] = boneIds; } // Mesh if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null) { if (unskinnedMesh.NumberOfFaces < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (unskinnedMesh.NumberOfVerts < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (unskinnedMesh.NumberOfVerts >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has tmore 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); } if (skin != null) { for (var vertexIndex = 0; vertexIndex < unskinnedMesh.NumberOfVerts; vertexIndex++) { maxNbBones = Math.Max(maxNbBones, skin.GetNumberOfBones(vertexIndex)); } } // Physics var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None"); if (impostorText != "None") { switch (impostorText) { case "Sphere": babylonMesh.physicsImpostor = 1; break; case "Box": babylonMesh.physicsImpostor = 2; break; case "Plane": babylonMesh.physicsImpostor = 3; break; default: babylonMesh.physicsImpostor = 0; break; } babylonMesh.physicsMass = meshNode.MaxNode.GetFloatProperty("babylonjs_mass"); babylonMesh.physicsFriction = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f); babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f); } // Material var mtl = meshNode.NodeMaterial; var multiMatsCount = 1; if (mtl != null) { babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString(); if (!referencedMaterials.Contains(mtl)) { referencedMaterials.Add(mtl); } multiMatsCount = Math.Max(mtl.SubMaterialCount, 1); } babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); var vertices = new List <GlobalVertex>(); var indices = new List <int>(); var mappingChannels = unskinnedMesh.ActiveMapChannelNum; bool hasUV = false; bool hasUV2 = false; for (int i = 0; i < mappingChannels.Count; ++i) { #if MAX2017 var indexer = i; #else var indexer = new IntPtr(i); #endif 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; var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); // Compute normals var subMeshes = new List <BabylonSubMesh>(); ExtractGeometry(vertices, indices, subMeshes, boneIds, skin, unskinnedMesh, hasUV, hasUV2, hasColor, hasAlpha, optimizeVertices, multiMatsCount, meshNode); 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 => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); babylonMesh.normals = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); if (hasUV) { babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray(); } if (hasUV2) { babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray(); } if (skin != 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(); } } if (hasColor) { babylonMesh.colors = vertices.SelectMany(v => v.Color.ToArray()).ToArray(); babylonMesh.hasVertexAlpha = hasAlpha; } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); // ------------------------ // ---- Morph targets ----- // ------------------------ // Retreive modifiers with morpher flag List <IIGameModifier> modifiers = new List <IIGameModifier>(); for (int i = 0; i < meshNode.IGameObject.NumModifiers; i++) { var modifier = meshNode.IGameObject.GetIGameModifier(i); if (modifier.ModifierType == Autodesk.Max.IGameModifier.ModType.Morpher) { modifiers.Add(modifier); } } // Cast modifiers to morphers List <IIGameMorpher> morphers = modifiers.ConvertAll(new Converter <IIGameModifier, IIGameMorpher>(modifier => modifier.AsGameMorpher())); var hasMorphTarget = false; morphers.ForEach(morpher => { if (morpher.NumberOfMorphTargets > 0) { hasMorphTarget = true; } }); if (hasMorphTarget) { RaiseMessage("Export morph targets", 2); // Morph Target Manager var babylonMorphTargetManager = new BabylonMorphTargetManager(); babylonScene.MorphTargetManagersList.Add(babylonMorphTargetManager); babylonMesh.morphTargetManagerId = babylonMorphTargetManager.id; // Morph Targets var babylonMorphTargets = new List <BabylonMorphTarget>(); // All morphers are considered identical // Their targets are concatenated morphers.ForEach(morpher => { for (int i = 0; i < morpher.NumberOfMorphTargets; i++) { // Morph target var maxMorphTarget = morpher.GetMorphTarget(i); // Ensure target still exists (green color legend) if (maxMorphTarget != null) { var babylonMorphTarget = new BabylonMorphTarget { name = maxMorphTarget.Name }; babylonMorphTargets.Add(babylonMorphTarget); // TODO - Influence babylonMorphTarget.influence = 0f; // Target geometry var targetVertices = ExtractVertices(maxMorphTarget, optimizeVertices); babylonMorphTarget.positions = targetVertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); babylonMorphTarget.normals = targetVertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); // Animations var animations = new List <BabylonAnimation>(); var morphWeight = morpher.GetMorphWeight(i); ExportFloatGameController(morphWeight, "influence", animations); if (animations.Count > 0) { babylonMorphTarget.animations = animations.ToArray(); } } } }); babylonMorphTargetManager.targets = babylonMorphTargets.ToArray(); } } // Animations // Done last to avoid '0 vertex found' error (unkown cause) exportAnimation(babylonMesh, meshNode); babylonScene.MeshesList.Add(babylonMesh); return(babylonMesh); }
private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene) { if (meshNode.MaxNode.IsInstance()) { return; } if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport")) { return; } if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false)) { return; } var gameMesh = meshNode.IGameObject.AsGameMesh(); bool initialized = gameMesh.InitializeData; //needed, the property is in fact a method initializing the exporter that has wrongly been auto // translated into a property because it has no parameters var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() }; if (meshNode.NodeParent != null) { babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene); } // Sounds var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", ""); if (!string.IsNullOrEmpty(soundName)) { var filename = Path.GetFileName(soundName); var meshSound = new BabylonSound { name = filename, autoplay = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1), loop = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1), volume = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f), playbackRate = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f), connectedMeshId = babylonMesh.id, isDirectional = false, spatialSound = false, distanceModel = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"), maxDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f), rolloffFactor = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f), refDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f), }; var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional"); if (isDirectional) { meshSound.isDirectional = true; meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f); meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f); meshSound.coneOuterGain = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f); } babylonScene.SoundsList.Add(meshSound); try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } // Misc. #if MAX2017 babylonMesh.isVisible = meshNode.MaxNode.Renderable; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics; #else babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; #endif babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable"); babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox"); babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox"); babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000); // Actions babylonMesh.actions = ExportNodeAction(meshNode); // Collisions babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); var isSkinned = gameMesh.IsObjectSkinned; var skin = gameMesh.IGameSkin; var unskinnedMesh = gameMesh; IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); List <int> boneIds = null; int maxNbBones = 0; if (isSkinned) { bonesCount = skin.TotalSkinBoneCount; skins.Add(skin); skinnedNodes.Add(meshNode); babylonMesh.skeletonId = skins.IndexOf(skin); skin.GetInitSkinTM(skinInitPoseMatrix); boneIds = SortBones(skin); skinSortedBones[skin] = boneIds; } // Position / rotation / scaling var localTM = meshNode.GetObjectTM(0); if (meshNode.NodeParent != null) { var parentWorld = meshNode.NodeParent.GetObjectTM(0); localTM.MultiplyBy(parentWorld.Inverse); } var meshTrans = localTM.Translation; var meshRotation = localTM.Rotation; var meshScale = localTM.Scaling; var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions"); babylonMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z }; if (exportQuaternions) { babylonMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W }; } else { RotationToEulerAngles(babylonMesh, meshRotation); } babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z }; // Mesh RaiseMessage(meshNode.Name, 1); if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null) { if (unskinnedMesh.NumberOfFaces < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (unskinnedMesh.NumberOfVerts < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (unskinnedMesh.NumberOfVerts >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has tmore 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); } if (skin != null) { for (var vertexIndex = 0; vertexIndex < unskinnedMesh.NumberOfVerts; vertexIndex++) { maxNbBones = Math.Max(maxNbBones, skin.GetNumberOfBones(vertexIndex)); } } // Physics var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None"); if (impostorText != "None") { switch (impostorText) { case "Sphere": babylonMesh.physicsImpostor = 1; break; case "Box": babylonMesh.physicsImpostor = 2; break; case "Plane": babylonMesh.physicsImpostor = 3; break; default: babylonMesh.physicsImpostor = 0; break; } babylonMesh.physicsMass = meshNode.MaxNode.GetFloatProperty("babylonjs_mass"); babylonMesh.physicsFriction = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f); babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f); } // Material var mtl = meshNode.NodeMaterial; var multiMatsCount = 1; if (mtl != null) { babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString(); if (!referencedMaterials.Contains(mtl)) { referencedMaterials.Add(mtl); } multiMatsCount = Math.Max(mtl.SubMaterialCount, 1); } babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); var vertices = new List <GlobalVertex>(); var indices = new List <int>(); var mappingChannels = unskinnedMesh.ActiveMapChannelNum; bool hasUV = false; bool hasUV2 = false; for (int i = 0; i < mappingChannels.Count; ++i) { #if MAX2017 var indexer = i; #else var indexer = new IntPtr(i); #endif 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; var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); // Compute normals List <GlobalVertex>[] verticesAlreadyExported = null; if (optimizeVertices) { verticesAlreadyExported = new List <GlobalVertex> [unskinnedMesh.NumberOfVerts]; } var subMeshes = new List <BabylonSubMesh>(); var indexStart = 0; for (int i = 0; i < multiMatsCount; ++i) { int materialId = meshNode.NodeMaterial?.GetMaterialID(i) ?? 0; var indexCount = 0; var minVertexIndex = int.MaxValue; var maxVertexIndex = int.MinValue; var subMesh = new BabylonSubMesh { indexStart = indexStart, materialIndex = i }; if (multiMatsCount == 1) { for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j) { var face = unskinnedMesh.GetFace(j); ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds); } } else { ITab <IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId); for (int j = 0; j < materialFaces.Count; ++j) { #if MAX2017 var faceIndexer = j; #else var faceIndexer = new IntPtr(j); #endif var face = materialFaces[faceIndexer]; #if !MAX2017 Marshal.FreeHGlobal(faceIndexer); #endif ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds); } } if (indexCount != 0) { subMesh.indexCount = indexCount; subMesh.verticesStart = minVertexIndex; subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1; indexStart += indexCount; subMeshes.Add(subMesh); } } 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 => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); babylonMesh.normals = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); if (hasUV) { babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray(); } if (hasUV2) { babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray(); } if (skin != 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(); } } if (hasColor) { babylonMesh.colors = vertices.SelectMany(v => v.Color.ToArray()).ToArray(); babylonMesh.hasVertexAlpha = hasAlpha; } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); } // Instances var tabs = Loader.Global.NodeTab.Create(); Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs); var instances = new List <BabylonAbstractMesh>(); for (var index = 0; index < tabs.Count; index++) { #if MAX2017 var indexer = index; #else var indexer = new IntPtr(index); #endif var tab = tabs[indexer]; #if !MAX2017 Marshal.FreeHGlobal(indexer); #endif if (meshNode.MaxNode.GetGuid() == tab.GetGuid()) { continue; } var instanceGameNode = scene.GetIGameNode(tab); if (instanceGameNode == null) { continue; } tab.MarkAsInstance(); var instance = new BabylonAbstractMesh { name = tab.Name }; { var instanceLocalTM = instanceGameNode.GetObjectTM(0); var instanceTrans = instanceLocalTM.Translation; var instanceRotation = instanceLocalTM.Rotation; var instanceScale = instanceLocalTM.Scaling; instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z }; if (exportQuaternions) { instance.rotationQuaternion = new[] { instanceRotation.X, instanceRotation.Y, instanceRotation.Z, -instanceRotation.W }; } else { RotationToEulerAngles(instance, instanceRotation); } instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z }; } var instanceAnimations = new List <BabylonAnimation>(); GenerateCoordinatesAnimations(meshNode, instanceAnimations); instance.animations = instanceAnimations.ToArray(); instances.Add(instance); } babylonMesh.instances = instances.ToArray(); // Animations var animations = new List <BabylonAnimation>(); GenerateCoordinatesAnimations(meshNode, animations); if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations)) { ExportFloatAnimation("visibility", animations, key => new[] { meshNode.MaxNode.GetVisibility(key, Tools.Forever) }); } babylonMesh.animations = animations.ToArray(); if (meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1)) { babylonMesh.autoAnimate = true; babylonMesh.autoAnimateFrom = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonMesh.autoAnimateTo = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100); babylonMesh.autoAnimateLoop = meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1); } babylonScene.MeshesList.Add(babylonMesh); }
public static Matrix convertTo(this IGMatrix _input) { Matrix _output = new Matrix(_input.GetRow(0).X, _input.GetRow(0).Y, _input.GetRow(0).Z, 0, _input.GetRow(1).X, _input.GetRow(1).Y, _input.GetRow(1).Z, 0, _input.GetRow(2).X, _input.GetRow(2).Y, _input.GetRow(2).Z, 0, _input.GetRow(3).X, _input.GetRow(3).Y, _input.GetRow(3).Z, 1); return(_output); }
IGMatrix WithNoScale(IGMatrix mat) { var mat3 = mat.ExtractMatrix3(); mat3.NoScale(); return Loader.Global.GMatrix.Create(mat3); }
private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene) { var gameMesh = meshNode.IGameObject.AsGameMesh(); try { bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto // translated into a property because it has no parameters } catch (Exception e) { RaiseWarning($"Mesh {meshNode.Name} failed to initialize. Mesh is exported as dummy.", 2); return(ExportDummy(scene, meshNode, babylonScene)); } var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() }; // Position / rotation / scaling / hierarchy exportNode(babylonMesh, meshNode, scene, babylonScene); // Sounds var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", ""); if (!string.IsNullOrEmpty(soundName)) { var filename = Path.GetFileName(soundName); var meshSound = new BabylonSound { name = filename, autoplay = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1), loop = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1), volume = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f), playbackRate = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f), connectedMeshId = babylonMesh.id, isDirectional = false, spatialSound = false, distanceModel = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"), maxDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f), rolloffFactor = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f), refDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f), }; var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional"); if (isDirectional) { meshSound.isDirectional = true; meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f); meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f); meshSound.coneOuterGain = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f); } babylonScene.SoundsList.Add(meshSound); if (isBabylonExported) { try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } } // Misc. #if MAX2017 || MAX2018 || MAX2019 babylonMesh.isVisible = meshNode.MaxNode.Renderable; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics; #else babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1; babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; #endif babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable"); babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox"); babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox"); babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000); // Collisions babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); // Skin var isSkinned = gameMesh.IsObjectSkinned; var skin = gameMesh.IGameSkin; var unskinnedMesh = gameMesh; IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); List <int> boneIds = null; int maxNbBones = 0; if (isSkinned && GetRelevantNodes(skin).Count > 0) // if the mesh has a skin with at least one bone { var skinAlreadyStored = skins.Find(_skin => IsSkinEqualTo(_skin, skin)); if (skinAlreadyStored == null) { skins.Add(skin); babylonMesh.skeletonId = skins.IndexOf(skin); } else { babylonMesh.skeletonId = skins.IndexOf(skinAlreadyStored); } skin.GetInitSkinTM(skinInitPoseMatrix); boneIds = GetNodeIndices(skin); } else { skin = null; } // Mesh if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null) { if (unskinnedMesh.NumberOfFaces < 1) { RaiseError($"Mesh {babylonMesh.name} has no face", 2); } if (unskinnedMesh.NumberOfVerts < 3) { RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2); } if (unskinnedMesh.NumberOfVerts >= 65536) { RaiseWarning($"Mesh {babylonMesh.name} has tmore 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); } if (skin != null) { for (var vertexIndex = 0; vertexIndex < unskinnedMesh.NumberOfVerts; vertexIndex++) { maxNbBones = Math.Max(maxNbBones, skin.GetNumberOfBones(vertexIndex)); } } // Physics var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None"); if (impostorText != "None") { switch (impostorText) { case "Sphere": babylonMesh.physicsImpostor = 1; break; case "Box": babylonMesh.physicsImpostor = 2; break; case "Plane": babylonMesh.physicsImpostor = 3; break; default: babylonMesh.physicsImpostor = 0; break; } babylonMesh.physicsMass = meshNode.MaxNode.GetFloatProperty("babylonjs_mass"); babylonMesh.physicsFriction = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f); babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f); } // Material var mtl = meshNode.NodeMaterial; var multiMatsCount = 1; // The DirectXShader material is a passthrough to its render material. // The shell material is a passthrough to its baked material. while (mtl != null && (isShellMaterial(mtl) || isDirectXShaderMaterial(mtl))) { if (isShellMaterial(mtl)) { // Retrieve the baked material from the shell material. mtl = GetBakedMaterialFromShellMaterial(mtl); } else // isDirectXShaderMaterial(mtl) { // Retrieve the render material from the directX shader mtl = GetRenderMaterialFromDirectXShader(mtl); } } if (mtl != null) { IIGameMaterial unsupportedMaterial = isMaterialSupported(mtl); if (unsupportedMaterial == null) { babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString(); if (!referencedMaterials.Contains(mtl)) { referencedMaterials.Add(mtl); } multiMatsCount = Math.Max(mtl.SubMaterialCount, 1); } else { if (mtl.SubMaterialCount == 0 || mtl == unsupportedMaterial) { RaiseWarning("Unsupported material type '" + unsupportedMaterial.MaterialClass + "'. Material is ignored.", 2); } else { RaiseWarning("Unsupported sub-material type '" + unsupportedMaterial.MaterialClass + "'. Material is ignored.", 2); } } } babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); var vertices = new List <GlobalVertex>(); var indices = new List <int>(); var mappingChannels = unskinnedMesh.ActiveMapChannelNum; bool hasUV = false; bool hasUV2 = false; for (int i = 0; i < mappingChannels.Count; ++i) { #if MAX2017 || MAX2018 || MAX2019 var channelNum = mappingChannels[i]; #else var channelNum = mappingChannels[new IntPtr(i)]; #endif if (channelNum == 1) { hasUV = true; } else if (channelNum == 2) { hasUV2 = true; } } var hasColor = unskinnedMesh.NumberOfColorVerts > 0; var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0; var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); var invertedWorldMatrix = GetInvertWorldTM(meshNode, 0); var offsetTM = GetOffsetTM(meshNode, 0); // Compute normals var subMeshes = new List <BabylonSubMesh>(); List <int> faceIndexes = null; ExtractGeometry(babylonMesh, vertices, indices, subMeshes, boneIds, skin, unskinnedMesh, invertedWorldMatrix, offsetTM, hasUV, hasUV2, hasColor, hasAlpha, optimizeVertices, multiMatsCount, meshNode, ref faceIndexes); 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 => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); babylonMesh.normals = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); // Export tangents if option is checked and mesh has tangents if (exportParameters.exportTangents) { babylonMesh.tangents = vertices.SelectMany(v => v.Tangent).ToArray(); } if (hasUV) { babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray(); } if (hasUV2) { babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray(); } if (skin != 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(); } } if (hasColor) { babylonMesh.colors = vertices.SelectMany(v => v.Color.ToArray()).ToArray(); babylonMesh.hasVertexAlpha = hasAlpha; } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); // ------------------------ // ---- Morph targets ----- // ------------------------ // Retreive modifiers with morpher flag List <IIGameModifier> modifiers = new List <IIGameModifier>(); for (int i = 0; i < meshNode.IGameObject.NumModifiers; i++) { var modifier = meshNode.IGameObject.GetIGameModifier(i); if (modifier.ModifierType == Autodesk.Max.IGameModifier.ModType.Morpher) { modifiers.Add(modifier); } } // Cast modifiers to morphers List <IIGameMorpher> morphers = modifiers.ConvertAll(new Converter <IIGameModifier, IIGameMorpher>(modifier => modifier.AsGameMorpher())); var hasMorphTarget = false; morphers.ForEach(morpher => { if (morpher.NumberOfMorphTargets > 0) { hasMorphTarget = true; } }); if (hasMorphTarget) { RaiseMessage("Export morph targets", 2); var rawScene = Loader.Core.RootNode; // Morph Target Manager var babylonMorphTargetManager = new BabylonMorphTargetManager(); babylonScene.MorphTargetManagersList.Add(babylonMorphTargetManager); babylonMesh.morphTargetManagerId = babylonMorphTargetManager.id; // Morph Targets var babylonMorphTargets = new List <BabylonMorphTarget>(); // All morphers are considered identical // Their targets are concatenated morphers.ForEach(morpher => { for (int i = 0; i < morpher.NumberOfMorphTargets; i++) { // Morph target var maxMorphTarget = morpher.GetMorphTarget(i); // Ensure target still exists (green color legend) if (maxMorphTarget != null) { var babylonMorphTarget = new BabylonMorphTarget { name = maxMorphTarget.Name }; babylonMorphTargets.Add(babylonMorphTarget); // TODO - Influence babylonMorphTarget.influence = 0f; // Target geometry var targetVertices = ExtractVertices(babylonMesh, maxMorphTarget, optimizeVertices, faceIndexes); babylonMorphTarget.positions = targetVertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); if (rawScene.GetBoolProperty("babylonjs_export_Morph_Normals", 1)) { babylonMorphTarget.normals = targetVertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); } // Tangent if (exportParameters.exportTangents && rawScene.GetBoolProperty("babylonjs_export_Morph_Tangents")) { babylonMorphTarget.tangents = targetVertices.SelectMany(v => v.Tangent).ToArray(); } // Animations var animations = new List <BabylonAnimation>(); var morphWeight = morpher.GetMorphWeight(i); ExportFloatGameController(morphWeight, "influence", animations); if (animations.Count > 0) { babylonMorphTarget.animations = animations.ToArray(); } } } }); babylonMorphTargetManager.targets = babylonMorphTargets.ToArray(); } } // World Modifiers ExportWorldModifiers(meshNode, babylonScene, babylonMesh); // Animations // Done last to avoid '0 vertex found' error (unkown cause) exportAnimation(babylonMesh, meshNode); babylonScene.MeshesList.Add(babylonMesh); return(babylonMesh); }
public ROD_ExportG() { maxGlobal = Autodesk.Max.GlobalInterface.Instance; maxInterface = maxGlobal.COREInterface13; IPoint3 U = maxGlobal.Point3.Create(1.0, 0.0, 0.0); IPoint3 V = maxGlobal.Point3.Create(0.0, 0.0, 1.0); IPoint3 N = maxGlobal.Point3.Create(0.0, -1.0, 0.0); IPoint3 T = maxGlobal.Point3.Create(0.0, 0.0, 0.0); _leftHanded = maxGlobal.Matrix3.Create(U, V, N, T); _GleftHanded = maxGlobal.GMatrix.Create(_leftHanded); }