|
@@ -88,7 +88,7 @@
|
|
|
|
|
|
/**
|
|
|
* Tokenizer. Used for shaders compatibility
|
|
|
- * Automatically map world, view, projection, worldViewProjection and attributes
|
|
|
+ * Automatically map world, view, projection, worldViewProjection, attributes and so on
|
|
|
*/
|
|
|
enum ETokenType {
|
|
|
IDENTIFIER = 1,
|
|
@@ -481,75 +481,182 @@
|
|
|
/**
|
|
|
* Returns the parent bone
|
|
|
*/
|
|
|
- var getParentBone = (jointName: string, newSkeleton: Skeleton): Bone => {
|
|
|
+ var getParentBone = (gltfRuntime: IGLTFRuntime, skins: IGLTFSkins, jointName: string, newSkeleton: Skeleton): Bone => {
|
|
|
// Try to find
|
|
|
for (var i = 0; i < newSkeleton.bones.length; i++) {
|
|
|
if (newSkeleton.bones[i].id === jointName) {
|
|
|
return newSkeleton.bones[i];
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Not found, search in gltf nodes
|
|
|
+ var nodes = gltfRuntime.nodes;
|
|
|
+ for (var nde in nodes) {
|
|
|
+ var node: IGLTFNode = nodes[nde];
|
|
|
+
|
|
|
+ if (!node.jointName) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var children = node.children;
|
|
|
+ for (var i = 0; i < children.length; i++) {
|
|
|
+ var child: IGLTFNode = gltfRuntime.nodes[children[i]];
|
|
|
+ if (!child.jointName) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (child.jointName === jointName) {
|
|
|
+ var mat = configureBoneTransformation(node);
|
|
|
+ var bone = new Bone(node.name, newSkeleton, getParentBone(gltfRuntime, skins, node.jointName, newSkeleton), mat);
|
|
|
+ bone.id = nde;
|
|
|
+ return bone;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Imports a skeleton
|
|
|
+ * Returns the appropriate root node
|
|
|
*/
|
|
|
- var importSkeleton = (gltfRuntime: IGLTFRuntime, skins: IGLTFSkins, mesh: Mesh, newSkeleton: Skeleton): Skeleton => {
|
|
|
+ var getNodeToRoot = (nodesToRoot: INodeToRoot[], id: string): Bone => {
|
|
|
+ for (var i = 0; i < nodesToRoot.length; i++) {
|
|
|
+ var nodeToRoot = nodesToRoot[i];
|
|
|
+
|
|
|
+ for (var j = 0; j < nodeToRoot.node.children.length; j++) {
|
|
|
+ var child = nodeToRoot.node.children[j];
|
|
|
+ if (child === id) {
|
|
|
+ return nodeToRoot.bone;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (!newSkeleton) {
|
|
|
- newSkeleton = new Skeleton(skins.name, "", gltfRuntime.scene);
|
|
|
+ return null;
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the node with the joint name
|
|
|
+ */
|
|
|
+ var getJointNode = (gltfRuntime: IGLTFRuntime, jointName: string): IJointNode => {
|
|
|
+ var nodes = gltfRuntime.nodes;
|
|
|
+ var node: IGLTFNode = nodes[jointName];
|
|
|
+ if (node) {
|
|
|
+ return {
|
|
|
+ node: node,
|
|
|
+ id: jointName
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
- if (!skins.babylonSkeleton) {
|
|
|
- return newSkeleton;
|
|
|
+ for (var nde in nodes) {
|
|
|
+ node = nodes[nde];
|
|
|
+ if (node.jointName === jointName) {
|
|
|
+ return {
|
|
|
+ node: node,
|
|
|
+ id: nde
|
|
|
+ };
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // Matrices
|
|
|
- var accessor = gltfRuntime.accessors[skins.inverseBindMatrices];
|
|
|
- var buffer = getBufferFromAccessor(gltfRuntime, accessor);
|
|
|
- var bindShapeMatrix = Matrix.FromArray(skins.bindShapeMatrix);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- (<any>newSkeleton)._identity = bindShapeMatrix;
|
|
|
+ /**
|
|
|
+ * Checks if a nodes is in joints
|
|
|
+ */
|
|
|
+ var nodeIsInJoints = (skins: IGLTFSkins, id: string): boolean => {
|
|
|
+ for (var i = 0; i < skins.jointNames.length; i++) {
|
|
|
+ if (skins.jointNames[i] === id) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // Find the root bone
|
|
|
- var nodeToRoot: Bone = null;
|
|
|
+ /**
|
|
|
+ * Fills the nodes to root for bones and builds hierarchy
|
|
|
+ */
|
|
|
+ var getNodesToRoot = (gltfRuntime: IGLTFRuntime, newSkeleton: Skeleton, skins: IGLTFSkins, nodesToRoot: INodeToRoot[]) => {
|
|
|
+ // Creates nodes for root
|
|
|
for (var nde in gltfRuntime.nodes) {
|
|
|
var node: IGLTFNode = gltfRuntime.nodes[nde];
|
|
|
+ var id = nde;
|
|
|
|
|
|
- if (!node) {
|
|
|
+ if (!node.jointName || nodeIsInJoints(skins, node.jointName)) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (node.jointName) {
|
|
|
- var isInJoints = false;
|
|
|
- for (var i = 0; i < skins.jointNames.length; i++) {
|
|
|
- if (skins.jointNames[i] === nde) {
|
|
|
- isInJoints = true;
|
|
|
+ // Create node to root bone
|
|
|
+ var mat = configureBoneTransformation(node);
|
|
|
+ var bone = new Bone(node.name, newSkeleton, null, mat);
|
|
|
+ bone.id = id;
|
|
|
+ nodesToRoot.push({ bone: bone, node: node, id: id });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Parenting
|
|
|
+ for (var i = 0; i < nodesToRoot.length; i++) {
|
|
|
+ var nodeToRoot = nodesToRoot[i];
|
|
|
+ var children = nodeToRoot.node.children;
|
|
|
+
|
|
|
+ for (var j = 0; j < children.length; j++) {
|
|
|
+ var child: INodeToRoot = null;
|
|
|
+
|
|
|
+ for (var k = 0; k < nodesToRoot.length; k++) {
|
|
|
+ if (nodesToRoot[k].id === children[j]) {
|
|
|
+ child = nodesToRoot[k];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (child) {
|
|
|
+ (<any>child.bone)._parent = nodeToRoot.bone;
|
|
|
+ nodeToRoot.bone.children.push(child.bone);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- if (!isInJoints) {
|
|
|
- var mat = configureBoneTransformation(node);
|
|
|
- nodeToRoot = new Bone(node.name, newSkeleton, null, mat);
|
|
|
- nodeToRoot.id = nde;
|
|
|
- // Remove root from bones
|
|
|
- newSkeleton.bones = [];
|
|
|
- break;
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Imports a skeleton
|
|
|
+ */
|
|
|
+ var importSkeleton = (gltfRuntime: IGLTFRuntime, skins: IGLTFSkins, mesh: Mesh, newSkeleton: Skeleton): Skeleton => {
|
|
|
+
|
|
|
+ if (!newSkeleton) {
|
|
|
+ newSkeleton = new Skeleton(skins.name, "", gltfRuntime.scene);
|
|
|
}
|
|
|
|
|
|
+ if (!skins.babylonSkeleton) {
|
|
|
+ return newSkeleton;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Matrices
|
|
|
+ var accessor = gltfRuntime.accessors[skins.inverseBindMatrices];
|
|
|
+ var buffer = getBufferFromAccessor(gltfRuntime, accessor);
|
|
|
+
|
|
|
+ var bindShapeMatrix = Matrix.FromArray(skins.bindShapeMatrix);
|
|
|
+ (<any>newSkeleton)._identity = bindShapeMatrix;
|
|
|
+
|
|
|
+ // Find the root bones
|
|
|
+ var nodesToRoot: INodeToRoot[] = [];
|
|
|
+ var nodesToRootToAdd: Bone[] = [];
|
|
|
+
|
|
|
+ getNodesToRoot(gltfRuntime, newSkeleton, skins, nodesToRoot);
|
|
|
+ newSkeleton.bones = [];
|
|
|
+
|
|
|
// Joints
|
|
|
for (var i = 0; i < skins.jointNames.length; i++) {
|
|
|
- var node: IGLTFNode = gltfRuntime.nodes[skins.jointNames[i]];
|
|
|
+ var jointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
|
|
|
+ var node = jointNode.node;
|
|
|
+
|
|
|
if (!node) {
|
|
|
Tools.Warn("Joint named " + skins.jointNames[i] + " does not exist");
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
+ var id = jointNode.id;
|
|
|
|
|
|
- var id = skins.jointNames[i];
|
|
|
-
|
|
|
- // Check if node exists, should never happen
|
|
|
+ // Check if node already exists
|
|
|
var foundBone = false;
|
|
|
for (var j = 0; j < newSkeleton.bones.length; j++) {
|
|
|
if (newSkeleton.bones[j].id === id) {
|
|
@@ -563,9 +670,9 @@
|
|
|
}
|
|
|
|
|
|
// Search for parent bone
|
|
|
- var parentBone = null;
|
|
|
+ var parentBone: Bone = null;
|
|
|
for (var j = 0; j < i; j++) {
|
|
|
- var joint: IGLTFNode = gltfRuntime.nodes[skins.jointNames[j]];
|
|
|
+ var joint: IGLTFNode = getJointNode(gltfRuntime, skins.jointNames[j]).node;
|
|
|
|
|
|
if (!joint) {
|
|
|
Tools.Warn("Joint named " + skins.jointNames[j] + " does not exist when looking for parent");
|
|
@@ -577,12 +684,12 @@
|
|
|
|
|
|
for (var k = 0; k < children.length; k++) {
|
|
|
if (children[k] === id) {
|
|
|
- parentBone = getParentBone(skins.jointNames[j], newSkeleton);
|
|
|
+ parentBone = getParentBone(gltfRuntime, skins, skins.jointNames[j], newSkeleton);
|
|
|
foundBone = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (foundBone) {
|
|
|
break;
|
|
|
}
|
|
@@ -591,14 +698,44 @@
|
|
|
// Create bone
|
|
|
var mat = configureBoneTransformation(node);
|
|
|
|
|
|
- var bone = new Bone(node.name, newSkeleton, parentBone ? parentBone : nodeToRoot, mat);
|
|
|
+ if (!parentBone) {
|
|
|
+ parentBone = getNodeToRoot(nodesToRoot, id);
|
|
|
+
|
|
|
+ if (parentBone) {
|
|
|
+ if (nodesToRootToAdd.indexOf(parentBone) === -1) {
|
|
|
+ nodesToRootToAdd.push(parentBone);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var bone = new Bone(node.name, newSkeleton, parentBone, mat);
|
|
|
bone.id = id;
|
|
|
}
|
|
|
|
|
|
+ // Polish
|
|
|
+ var bones = newSkeleton.bones;
|
|
|
+ newSkeleton.bones = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < skins.jointNames.length; i++) {
|
|
|
+ var jointNode: IJointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
|
|
|
+
|
|
|
+ if (!jointNode) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var j = 0; j < bones.length; j++) {
|
|
|
+ if (bones[j].id === jointNode.id) {
|
|
|
+ newSkeleton.bones.push(bones[j]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Finish
|
|
|
newSkeleton.prepare();
|
|
|
|
|
|
- if (nodeToRoot) {
|
|
|
- newSkeleton.bones.push(nodeToRoot);
|
|
|
+ for (var i = 0; i < nodesToRootToAdd.length; i++) {
|
|
|
+ newSkeleton.bones.push(nodesToRootToAdd[i]);
|
|
|
}
|
|
|
|
|
|
return newSkeleton;
|
|
@@ -959,22 +1096,6 @@
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * Util for ImportMesh function, checks if a given node
|
|
|
- * is a descendant of the included mesh(es)
|
|
|
- */
|
|
|
- var nodeIsDescendantOf = (node: IGLTFRuntime, gltfRuntime: IGLTFRuntime): boolean => {
|
|
|
- for (var nde in gltfRuntime.nodes) {
|
|
|
- var n: IGLTFNode = gltfRuntime.nodes[nde];
|
|
|
-
|
|
|
- for (var i = 0; i < n.children.length; i++) {
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* Traverses nodes and creates them
|
|
|
*/
|
|
|
var traverseNodes = (gltfRuntime: IGLTFRuntime, id: string, parent: Node, meshIncluded?: boolean) => {
|