123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- using BabylonExport.Entities;
- using GLTFExport.Entities;
- using System;
- using System.Collections.Generic;
- namespace Max2Babylon
- {
- partial class BabylonExporter
- {
- // Bones stored in BabylonSkeleton array are not assumed to be tree-ordered
- // Meaning, first element could be a leaf thus resulting in exporting all its ancestors before himself
- // Store bones already exported to prevent multiple exportation of same bone
- private Dictionary<BabylonBone, GLTFNode> alreadyExportedBones;
- private GLTFSkin ExportSkin(BabylonSkeleton babylonSkeleton, GLTF gltf, GLTFNode gltfNode)
- {
- // Skin
- GLTFSkin gltfSkin = new GLTFSkin
- {
- name = babylonSkeleton.name
- };
- gltfSkin.index = gltf.SkinsList.Count;
- gltf.SkinsList.Add(gltfSkin);
- var bones = new List<BabylonBone>(babylonSkeleton.bones);
- // Compute and store world matrix of each bone
- var bonesWorldMatrices = new Dictionary<int, BabylonMatrix>();
- foreach (var babylonBone in babylonSkeleton.bones)
- {
- if (!bonesWorldMatrices.ContainsKey(babylonBone.index))
- {
- BabylonMatrix boneWorldMatrix = _getBoneWorldMatrix(babylonBone, bones);
- bonesWorldMatrices.Add(babylonBone.index, boneWorldMatrix);
- }
- }
- // Buffer
- var buffer = GLTFBufferService.Instance.GetBuffer(gltf);
- // Accessor - InverseBindMatrices
- var accessorInverseBindMatrices = GLTFBufferService.Instance.CreateAccessor(
- gltf,
- GLTFBufferService.Instance.GetBufferViewFloatMat4(gltf, buffer),
- "accessorInverseBindMatrices",
- GLTFAccessor.ComponentType.FLOAT,
- GLTFAccessor.TypeEnum.MAT4
- );
- gltfSkin.inverseBindMatrices = accessorInverseBindMatrices.index;
- // World matrix of the node
- var invNodeWorldMatrix = BabylonMatrix.Invert(_getNodeWorldMatrix(gltfNode)); // inverted
- var gltfJoints = new List<int>();
- alreadyExportedBones = new Dictionary<BabylonBone, GLTFNode>();
- foreach (var babylonBone in babylonSkeleton.bones)
- {
- // Export bone as a new node
- var gltfBoneNode = _exportBone(babylonBone, gltf, babylonSkeleton, bones);
- gltfJoints.Add(gltfBoneNode.index);
- // Set this bone as skeleton if it is a root
- if (babylonBone.parentBoneIndex == -1)
- {
- gltfSkin.skeleton = gltfBoneNode.index;
- }
- // Compute inverseBindMatrice for this bone when attached to this node
- var boneLocalMatrix = new BabylonMatrix();
- boneLocalMatrix.m = babylonBone.matrix;
- BabylonMatrix boneWorldMatrix = null;
- if (babylonBone.parentBoneIndex == -1)
- {
- boneWorldMatrix = boneLocalMatrix;
- }
- else
- {
- var parentWorldMatrix = bonesWorldMatrices[babylonBone.parentBoneIndex];
- // Remove scale of parent
- // This actually enable to take into account the scale of the bones, except for the root one
- parentWorldMatrix = _removeScale(parentWorldMatrix);
- boneWorldMatrix = boneLocalMatrix * parentWorldMatrix;
- }
- var inverseBindMatrices = BabylonMatrix.Invert(boneWorldMatrix * invNodeWorldMatrix);
- // Populate accessor
- List<float> matrix = new List<float>(inverseBindMatrices.m);
- matrix.ForEach(n => accessorInverseBindMatrices.bytesList.AddRange(BitConverter.GetBytes(n)));
- accessorInverseBindMatrices.count++;
- }
- gltfSkin.joints = gltfJoints.ToArray();
- return gltfSkin;
- }
- private GLTFNode _exportBone(BabylonBone babylonBone, GLTF gltf, BabylonSkeleton babylonSkeleton, List<BabylonBone> bones)
- {
- if (alreadyExportedBones.ContainsKey(babylonBone))
- {
- return alreadyExportedBones[babylonBone];
- }
- // Node
- var gltfNode = new GLTFNode
- {
- name = babylonBone.name
- };
- gltfNode.index = gltf.NodesList.Count;
- gltf.NodesList.Add(gltfNode);
- alreadyExportedBones.Add(babylonBone, gltfNode);
- // Hierarchy
- if (babylonBone.parentBoneIndex >= 0)
- {
- var babylonParentBone = bones.Find(_babylonBone => _babylonBone.index == babylonBone.parentBoneIndex);
- var gltfParentNode = _exportBone(babylonParentBone, gltf, babylonSkeleton, bones);
- RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as child to " + gltfParentNode.name, 2);
- gltfParentNode.ChildrenList.Add(gltfNode.index);
- gltfNode.parent = gltfParentNode;
- }
- else
- {
- // It's a root node
- // Only root nodes are listed in a gltf scene
- RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as root node to scene", 2);
- gltf.scenes[0].NodesList.Add(gltfNode.index);
- }
- // Transform
- // Bones transform are exported through translation/rotation/scale rather than matrix
- // Because gltf node animation can only target TRS properties, not the matrix one
- // Create matrix from array
- var babylonMatrix = new BabylonMatrix();
- babylonMatrix.m = babylonBone.matrix;
- // Decompose matrix into TRS
- var translationBabylon = new BabylonVector3();
- var rotationQuatBabylon = new BabylonQuaternion();
- var scaleBabylon = new BabylonVector3();
- babylonMatrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon);
- // Store TRS values
- gltfNode.translation = translationBabylon.ToArray();
- gltfNode.rotation = rotationQuatBabylon.ToArray();
- gltfNode.scale = scaleBabylon.ToArray();
- // Animations
- ExportBoneAnimation(babylonBone, gltf, gltfNode);
- return gltfNode;
- }
- private BabylonMatrix _getNodeLocalMatrix(GLTFNode gltfNode)
- {
- return BabylonMatrix.Compose(
- BabylonVector3.FromArray(gltfNode.scale),
- BabylonQuaternion.FromArray(gltfNode.rotation),
- BabylonVector3.FromArray(gltfNode.translation)
- );
- }
- private BabylonMatrix _getNodeWorldMatrix(GLTFNode gltfNode)
- {
- if (gltfNode.parent == null)
- {
- return _getNodeLocalMatrix(gltfNode);
- }
- else
- {
- return _getNodeLocalMatrix(gltfNode) * _getNodeWorldMatrix(gltfNode.parent);
- }
- }
- private BabylonMatrix _getBoneWorldMatrix(BabylonBone babylonBone, List<BabylonBone> bones)
- {
- var boneLocalMatrix = new BabylonMatrix();
- boneLocalMatrix.m = babylonBone.matrix;
- if (babylonBone.parentBoneIndex == -1)
- {
- return boneLocalMatrix;
- }
- else
- {
- var parentBabylonBone = bones.Find(bone => bone.index == babylonBone.parentBoneIndex);
- var parentWorldMatrix = _getBoneWorldMatrix(parentBabylonBone, bones);
- return boneLocalMatrix * parentWorldMatrix;
- }
- }
- private BabylonMatrix _removeScale(BabylonMatrix boneWorldMatrix)
- {
- var translation = new BabylonVector3();
- var rotation = new BabylonQuaternion();
- var scale = new BabylonVector3();
- boneWorldMatrix.decompose(scale, rotation, translation);
- scale.X = 1;
- scale.Y = 1;
- scale.Z = 1;
- return BabylonMatrix.Compose(scale, rotation, translation);
- }
- }
- }
|