private void exportTransform(BabylonAbstractMesh babylonAbstractMesh, IIGameNode maxGameNode) { // Position / rotation / scaling var localTM = maxGameNode.GetObjectTM(0); if (maxGameNode.NodeParent != null) { var parentWorld = maxGameNode.NodeParent.GetObjectTM(0); localTM.MultiplyBy(parentWorld.Inverse); } var meshTrans = localTM.Translation; var meshRotation = localTM.Rotation; var meshScale = localTM.Scaling; babylonAbstractMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z }; var rotationQuaternion = new BabylonQuaternion { X = meshRotation.X, Y = meshRotation.Y, Z = meshRotation.Z, W = -meshRotation.W }; if (ExportQuaternionsInsteadOfEulers) { babylonAbstractMesh.rotationQuaternion = rotationQuaternion.ToArray(); } else { babylonAbstractMesh.rotation = rotationQuaternion.toEulerAngles().ToArray(); } babylonAbstractMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z }; }
private void exportTransform(BabylonAbstractMesh babylonAbstractMesh, IIGameNode maxGameNode) { // Position / rotation / scaling var localTM = GetLocalTM(maxGameNode, 0); var meshTrans = localTM.Translation; var meshRotation = localTM.Rotation; var meshScale = localTM.Scaling; babylonAbstractMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z }; var rotationQuaternion = new BabylonQuaternion { X = meshRotation.X, Y = meshRotation.Y, Z = meshRotation.Z, W = -meshRotation.W }; if (ExportQuaternionsInsteadOfEulers) { babylonAbstractMesh.rotationQuaternion = rotationQuaternion.ToArray(); } else { babylonAbstractMesh.rotation = rotationQuaternion.toEulerAngles().ToArray(); } babylonAbstractMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z }; }
private void exportTransform(BabylonAbstractMesh babylonAbstractMesh, IIGameNode maxGameNode) { // Position / rotation / scaling var localTM = maxGameNode.GetLocalTM(0); // use babylon decomposition, as 3ds max built-in values are no correct var tm_babylon = new BabylonMatrix(); tm_babylon.m = localTM.ToArray(); var s_babylon = new BabylonVector3(); var q_babylon = new BabylonQuaternion(); var t_babylon = new BabylonVector3(); tm_babylon.decompose(s_babylon, q_babylon, t_babylon); if (ExportQuaternionsInsteadOfEulers) { babylonAbstractMesh.rotationQuaternion = q_babylon.ToArray(); } else { babylonAbstractMesh.rotation = q_babylon.toEulerAngles().ToArray(); } // normalize quaternion var q = q_babylon; float q_length = (float)Math.Sqrt(q.X * q.X + q.Y * q.Y + q.Z * q.Z + q.W * q.W); babylonAbstractMesh.rotationQuaternion = new[] { q_babylon.X / q_length, q_babylon.Y / q_length, q_babylon.Z / q_length, q_babylon.W / q_length }; babylonAbstractMesh.scaling = new[] { s_babylon.X, s_babylon.Y, s_babylon.Z }; babylonAbstractMesh.position = new[] { t_babylon.X, t_babylon.Y, t_babylon.Z }; }
/// <summary> /// Default space is transform /// Default rotation order is YXZ /// </summary> /// <param name="mTransformationMatrix"></param> /// <returns></returns> public static float[] getRotation(this MTransformationMatrix mTransformationMatrix) { double x = 0, y = 0, z = 0, w = 0; mTransformationMatrix.getRotationQuaternion(ref x, ref y, ref z, ref w); // Maya conversion algorithm is bugged when reaching limits (angle like (-90,89,90)) // Convert quaternion to vector3 using Babylon conversion algorithm BabylonQuaternion babylonQuaternion = new BabylonQuaternion((float)x, (float)y, (float)z, (float)w); return(babylonQuaternion.toEulerAngles().ToArray()); }
private void printMatrix(string name, BabylonMatrix matrix) { // Decompose matrix into TRS var translation = new BabylonVector3(); var rotationQuat = new BabylonQuaternion(); var scale = new BabylonVector3(); matrix.decompose(scale, rotationQuat, translation); var rotation = rotationQuat.toEulerAngles(); rotation *= (float)(180 / Math.PI); var lvl = 3; RaiseWarning(name + ".translation=[" + translation.X + ", " + translation.Y + ", " + translation.Z + "]", lvl); RaiseWarning(name + ".rotation=[" + rotation.X + ", " + rotation.Y + ", " + rotation.Z + "]", lvl); RaiseWarning(name + ".scale=[" + scale.X + ", " + scale.Y + ", " + scale.Z + "]", lvl); }
/// <summary> /// In 3DS Max default element can look in different direction than the same default element in Babylon or in glTF. /// This function correct the node rotation. /// </summary> /// <param name="node"></param> /// <param name="babylonScene"></param> /// <param name="angle"></param> private void FixNodeRotation(ref BabylonNode node, ref BabylonScene babylonScene, double angle) { string id = node.id; IList <BabylonMesh> meshes = babylonScene.MeshesList.FindAll(mesh => mesh.parentId == null ? false : mesh.parentId.Equals(id)); RaiseMessage($"{node.name}", 2); // fix the vue // Rotation around the axis X of PI / 2 in the indirect direction for camera // double angle = Math.PI / 2; // for camera // double angle = -Math.PI / 2; // for light if (node.rotation != null) { node.rotation[0] += (float)angle; } if (node.rotationQuaternion != null) { BabylonQuaternion rotationQuaternion = FixCameraQuaternion(node, angle); node.rotationQuaternion = rotationQuaternion.ToArray(); node.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // animation List <BabylonAnimation> animations = new List <BabylonAnimation>(node.animations); BabylonAnimation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } else // if the camera has a lockedTargetId, it is the extraAnimations that stores the rotation animation { if (node.extraAnimations != null) { List <BabylonAnimation> extraAnimations = new List <BabylonAnimation>(node.extraAnimations); animationRotationQuaternion = extraAnimations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } } } // fix direct children // Rotation around the axis X of -PI / 2 in the direct direction for camera children angle = -angle; foreach (var mesh in meshes) { RaiseVerbose($"{mesh.name}", 3); mesh.position = new float[] { mesh.position[0], mesh.position[2], -mesh.position[1] }; // Add a rotation of PI/2 axis X in direct direction if (mesh.rotationQuaternion != null) { // Rotation around the axis X of -PI / 2 in the direct direction BabylonQuaternion quaternion = FixChildQuaternion(mesh, angle); mesh.rotationQuaternion = quaternion.ToArray(); } if (mesh.rotation != null) { mesh.rotation[0] += (float)angle; } // Animations animations = new List <BabylonAnimation>(mesh.animations); // Position BabylonAnimation animationPosition = animations.Find(animation => animation.property.Equals("position")); if (animationPosition != null) { foreach (BabylonAnimationKey key in animationPosition.keys) { key.values = new float[] { key.values[0], key.values[2], -key.values[1] }; } } // Rotation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixChildQuaternion(key.values, angle); } } } }
private GLTFAnimation ExportBoneAnimation(BabylonBone babylonBone, GLTF gltf, GLTFNode gltfNode) { GLTFAnimation gltfAnimation = null; if (gltf.AnimationsList.Count > 0) { gltfAnimation = gltf.AnimationsList[0]; } else { gltfAnimation = new GLTFAnimation(); gltf.AnimationsList.Add(gltfAnimation); } var channelList = gltfAnimation.ChannelList; var samplerList = gltfAnimation.SamplerList; if (babylonBone.animation != null && babylonBone.animation.property == "_matrix") { RaiseMessage("GLTFExporter.Animation | Export animation of bone named: " + babylonBone.name, 2); var babylonAnimation = babylonBone.animation; // --- Input --- var accessorInput = _createAndPopulateInput(gltf, babylonAnimation); // --- Output --- var paths = new string[] { "translation", "rotation", "scale" }; var accessorOutputByPath = new Dictionary <string, GLTFAccessor>(); foreach (string path in paths) { GLTFAccessor accessorOutput = _createAccessorOfPath(path, gltf); accessorOutputByPath.Add(path, accessorOutput); } // Populate accessors foreach (var babylonAnimationKey in babylonAnimation.keys) { var matrix = new BabylonMatrix(); matrix.m = babylonAnimationKey.values; var translationBabylon = new BabylonVector3(); var rotationQuatBabylon = new BabylonQuaternion(); var scaleBabylon = new BabylonVector3(); matrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon); translationBabylon.Z *= -1; BabylonVector3 rotationVector3 = rotationQuatBabylon.toEulerAngles(); rotationVector3.X *= -1; rotationVector3.Y *= -1; rotationQuatBabylon = rotationVector3.toQuaternion(); var outputValuesByPath = new Dictionary <string, float[]>(); outputValuesByPath.Add("translation", translationBabylon.ToArray()); outputValuesByPath.Add("rotation", rotationQuatBabylon.ToArray()); outputValuesByPath.Add("scale", scaleBabylon.ToArray()); // Store values as bytes foreach (string path in paths) { var accessorOutput = accessorOutputByPath[path]; var outputValues = outputValuesByPath[path]; foreach (var outputValue in outputValues) { accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue)); } accessorOutput.count++; } } ; foreach (string path in paths) { var accessorOutput = accessorOutputByPath[path]; // Animation sampler var gltfAnimationSampler = new GLTFAnimationSampler { input = accessorInput.index, output = accessorOutput.index }; gltfAnimationSampler.index = samplerList.Count; samplerList.Add(gltfAnimationSampler); // Target var gltfTarget = new GLTFChannelTarget { node = gltfNode.index }; gltfTarget.path = path; // Channel var gltfChannel = new GLTFChannel { sampler = gltfAnimationSampler.index, target = gltfTarget }; channelList.Add(gltfChannel); } } return(gltfAnimation); }
private BabylonCamera ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (IsCameraExportable(cameraNode) == false) { return(null); } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = cameraNode.NodeParent.MaxNode.GetGuid().ToString(); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // 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"); // Position / rotation var localTM = GetLocalTM(cameraNode, 0); var position = localTM.Translation; var rotation = localTM.Rotation; babylonCamera.position = new[] { position.X, position.Y, position.Z }; var rotationQuaternion = new BabylonQuaternion { X = rotation.X, Y = rotation.Y, Z = rotation.Z, W = -rotation.W }; if (ExportQuaternionsInsteadOfEulers) { babylonCamera.rotationQuaternion = rotationQuaternion.ToArray(); } else { babylonCamera.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } else { // TODO - Check if should be local or world var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = localTM.ExtractMatrix3().VectorTransform(vDir).Normalize; vDir = vDir.Add(position); babylonCamera.target = new[] { vDir.X, vDir.Y, vDir.Z }; } // Animations var animations = new List <BabylonAnimation>(); GeneratePositionAnimation(cameraNode, animations); if (target == null) { // Export rotation animation //GenerateRotationAnimation(cameraNode, animations); ExportVector3Animation("target", animations, key => { var wmCam = GetLocalTM(cameraNode, key); var positionCam = wmCam.Translation; var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = wmCam.ExtractMatrix3().VectorTransform(vDir).Normalize; vDir = vDir.Add(positionCam); return(new[] { vDir.X, vDir.Y, vDir.Z }); }); } // Animation temporary stored for gltf but not exported for babylon // TODO - Will cause an issue when externalizing the glTF export process var extraAnimations = new List <BabylonAnimation>(); // Do not check if node rotation properties are animated GenerateRotationAnimation(cameraNode, extraAnimations, true); babylonCamera.extraAnimations = extraAnimations; ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }
private BabylonCamera ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (IsCameraExportable(cameraNode) == false) { return(null); } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = cameraNode.NodeParent.MaxNode.GetGuid().ToString(); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // 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"); // Position / rotation var localTM = cameraNode.GetObjectTM(0); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(0); localTM.MultiplyBy(parentWorld.Inverse); } var position = localTM.Translation; var rotation = localTM.Rotation; babylonCamera.position = new[] { position.X, position.Y, position.Z }; var rotationQuaternion = new BabylonQuaternion { X = rotation.X, Y = rotation.Y, Z = rotation.Z, W = -rotation.W }; if (ExportQuaternionsInsteadOfEulers) { babylonCamera.rotationQuaternion = rotationQuaternion.ToArray(); } else { babylonCamera.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } else { var dir = localTM.GetRow(3); babylonCamera.target = new [] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z }; } // Animations var animations = new List <BabylonAnimation>(); ExportVector3Animation("position", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; return(new [] { translation.X, translation.Y, translation.Z }); }); if (gameCamera.CameraTarget == null) { ExportVector3Animation("target", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; var dir = tm.GetRow(3); return(new float[] { translation.X - dir.X, translation.Y - dir.Y, translation.Z - dir.Z }); }); } ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }