|
@@ -1,242 +1,167 @@
|
|
|
/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
|
|
|
|
|
|
module BABYLON.GLTF2 {
|
|
|
- /**
|
|
|
- * Values
|
|
|
- */
|
|
|
- var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
|
|
|
- var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
|
|
|
-
|
|
|
- /**
|
|
|
- * Utils
|
|
|
- */
|
|
|
- var normalizeUVs = (buffer: any): void => {
|
|
|
- if (!buffer) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (var i = 0; i < buffer.length / 2; i++) {
|
|
|
- buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- var createStringId = (index: number): string => {
|
|
|
+ var getNodeID = (index: number): string => {
|
|
|
return "node" + index;
|
|
|
};
|
|
|
|
|
|
- /**
|
|
|
- * Returns the animation path (glTF -> Babylon)
|
|
|
- */
|
|
|
- var getAnimationPath = (path: string): string => {
|
|
|
- var index = glTFAnimationPaths.indexOf(path);
|
|
|
-
|
|
|
- if (index !== -1) {
|
|
|
- return babylonAnimationPaths[index];
|
|
|
- }
|
|
|
-
|
|
|
- return path;
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * Loads and creates animations
|
|
|
- */
|
|
|
- var loadAnimations = (runtime: IGLTFRuntime): void => {
|
|
|
- var animations = runtime.gltf.animations;
|
|
|
- if (!animations) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
|
|
|
- var animation = animations[animationIndex];
|
|
|
- if (!animation || !animation.channels || !animation.samplers) {
|
|
|
+ var loadAnimation = (runtime: IGLTFRuntime, animation: IGLTFAnimation, animationIndex: number): void => {
|
|
|
+ for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
|
|
|
+ var channel = animation.channels[channelIndex];
|
|
|
+ if (!channel) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + "] Channel " + channelIndex + " does not exist");
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- var lastAnimation: Animation = null;
|
|
|
-
|
|
|
- for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
|
|
|
- var channel = animation.channels[channelIndex];
|
|
|
- if (!channel) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- var sampler = animation.samplers[channel.sampler];
|
|
|
- if (!sampler) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- var inputData = sampler.input;
|
|
|
- var outputData = sampler.output;
|
|
|
-
|
|
|
- var bufferInput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
|
|
|
- var bufferOutput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
|
|
|
-
|
|
|
- var targetID = channel.target.node;
|
|
|
- var targetNode: any = runtime.babylonScene.getNodeByID(createStringId(targetID));
|
|
|
-
|
|
|
- if (targetNode === null) {
|
|
|
- Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- var isBone = targetNode instanceof Bone;
|
|
|
- var numTargets = 0;
|
|
|
-
|
|
|
- // Get target path (position, rotation, scaling, or weights)
|
|
|
- var targetPath = channel.target.path;
|
|
|
- var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
|
|
|
-
|
|
|
- if (targetPathIndex !== -1) {
|
|
|
- targetPath = babylonAnimationPaths[targetPathIndex];
|
|
|
- }
|
|
|
-
|
|
|
- var isMorph = targetPath === "influence";
|
|
|
+ var samplerIndex = channel.sampler;
|
|
|
+ if (samplerIndex === undefined) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + samplerIndex + "] Sampler is not defined");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- // Determine animation type
|
|
|
- var animationType = Animation.ANIMATIONTYPE_MATRIX;
|
|
|
+ var sampler = animation.samplers[samplerIndex];
|
|
|
+ if (!sampler) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler " + samplerIndex + " does not exist");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if (!isBone) {
|
|
|
- if (targetPath === "rotationQuaternion") {
|
|
|
- animationType = Animation.ANIMATIONTYPE_QUATERNION;
|
|
|
- targetNode.rotationQuaternion = new Quaternion();
|
|
|
- }
|
|
|
- else if (isMorph) {
|
|
|
- animationType = Animation.ANIMATIONTYPE_FLOAT;
|
|
|
- numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
|
|
|
- }
|
|
|
- else {
|
|
|
- animationType = Animation.ANIMATIONTYPE_VECTOR3;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!channel.target) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target does not exist");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- // Create animation and key frames
|
|
|
- var babylonAnimation: Animation = null;
|
|
|
- var keys = [];
|
|
|
- var arrayOffset = 0;
|
|
|
- var modifyKey = false;
|
|
|
+ var targetNode = runtime.babylonScene.getNodeByID(getNodeID(channel.target.node));
|
|
|
+ if (!targetNode) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target node " + channel.target.node + " does not exist");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
|
|
|
- babylonAnimation = lastAnimation;
|
|
|
- modifyKey = true;
|
|
|
- }
|
|
|
+ var targetPath = {
|
|
|
+ "translation": "position",
|
|
|
+ "rotation": "rotationQuaternion",
|
|
|
+ "scale": "scaling",
|
|
|
+ "weights": "influence"
|
|
|
+ }[channel.target.path];
|
|
|
+ if (!targetPath) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target path " + channel.target.path + " is invalid");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- // Each morph animation may have more than one more, so we need a
|
|
|
- // multi dimensional array.
|
|
|
- if (isMorph) {
|
|
|
- for (var influence = 0; influence < numTargets; influence++) {
|
|
|
- keys[influence] = [];
|
|
|
- }
|
|
|
- }
|
|
|
+ var inputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.input]);
|
|
|
+ var outputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.output]);
|
|
|
+ var outputBufferOffset = 0;
|
|
|
|
|
|
- // For each frame
|
|
|
- for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
|
|
|
- var value: any = null;
|
|
|
+ var animationType = {
|
|
|
+ "position": Animation.ANIMATIONTYPE_VECTOR3,
|
|
|
+ "rotationQuaternion": Animation.ANIMATIONTYPE_QUATERNION,
|
|
|
+ "scale": Animation.ANIMATIONTYPE_VECTOR3,
|
|
|
+ "influence": Animation.ANIMATIONTYPE_FLOAT,
|
|
|
+ }[targetPath];
|
|
|
|
|
|
- if (targetPath === "rotationQuaternion") { // VEC4
|
|
|
- value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
|
|
|
- arrayOffset += 4;
|
|
|
- }
|
|
|
- else if (isMorph) { // FLOAT
|
|
|
- value = [];
|
|
|
- // There is 1 value for each morph target for each frame
|
|
|
- for (var influence = 0; influence < numTargets; influence++) {
|
|
|
- value.push(bufferOutput[arrayOffset + influence]);
|
|
|
- }
|
|
|
- arrayOffset += numTargets;
|
|
|
- }
|
|
|
- else { // Position and scaling are VEC3
|
|
|
- value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
|
|
|
- arrayOffset += 3;
|
|
|
+ var getNextOutputValue: () => any = {
|
|
|
+ "position": () => {
|
|
|
+ var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
|
|
|
+ outputBufferOffset += 3;
|
|
|
+ return value;
|
|
|
+ },
|
|
|
+ "rotationQuaternion": () => {
|
|
|
+ var value = Quaternion.FromArray(outputBuffer, outputBufferOffset);
|
|
|
+ outputBufferOffset += 4;
|
|
|
+ return value;
|
|
|
+ },
|
|
|
+ "scale": () => {
|
|
|
+ var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
|
|
|
+ outputBufferOffset += 3;
|
|
|
+ return value;
|
|
|
+ },
|
|
|
+ "influence": () => {
|
|
|
+ var numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
|
|
|
+ var value = new Array(numTargets);
|
|
|
+ for (var i = 0; i < numTargets; i++) {
|
|
|
+ value[i] = outputBuffer[outputBufferOffset++];
|
|
|
}
|
|
|
+ return value;
|
|
|
+ },
|
|
|
+ }[targetPath];
|
|
|
+
|
|
|
+ var getNextKey: (frameIndex) => any = {
|
|
|
+ "LINEAR": frameIndex => ({
|
|
|
+ frame: inputBuffer[frameIndex],
|
|
|
+ value: getNextOutputValue()
|
|
|
+ }),
|
|
|
+ "CUBICSPLINE": frameIndex => ({
|
|
|
+ frame: inputBuffer[frameIndex],
|
|
|
+ inTangent: getNextOutputValue(),
|
|
|
+ value: getNextOutputValue(),
|
|
|
+ outTangent: getNextOutputValue()
|
|
|
+ }),
|
|
|
+ }[sampler.interpolation];
|
|
|
+
|
|
|
+ if (!getNextKey) {
|
|
|
+ Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler interpolation '" + sampler.interpolation + "' is invalid");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if (isBone) {
|
|
|
- var bone = <Bone>targetNode;
|
|
|
- var translation = Vector3.Zero();
|
|
|
- var rotationQuaternion = new Quaternion();
|
|
|
- var scaling = Vector3.Zero();
|
|
|
-
|
|
|
- // Warning on decompose
|
|
|
- var mat = bone.getBaseMatrix();
|
|
|
+ var keys = new Array(inputBuffer.length);
|
|
|
+ for (var frameIndex = 0; frameIndex < inputBuffer.length; frameIndex++) {
|
|
|
+ keys[frameIndex] = getNextKey(frameIndex);
|
|
|
+ }
|
|
|
|
|
|
- if (modifyKey) {
|
|
|
- mat = lastAnimation.getKeys()[frameIndex].value;
|
|
|
- }
|
|
|
+ if (targetPath === "influence") {
|
|
|
+ var targetMesh = <Mesh>targetNode;
|
|
|
|
|
|
- mat.decompose(scaling, rotationQuaternion, translation);
|
|
|
+ for (var targetIndex = 0; targetIndex < targetMesh.morphTargetManager.numTargets; targetIndex++) {
|
|
|
+ var morphTarget = targetMesh.morphTargetManager.getTarget(targetIndex);
|
|
|
+ var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
|
|
|
+ var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
|
|
|
+ babylonAnimation.setKeys(keys.map(key => ({
|
|
|
+ frame: key.frame,
|
|
|
+ inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
|
|
|
+ value: key.value[targetIndex],
|
|
|
+ outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
|
|
|
+ })));
|
|
|
|
|
|
- if (targetPath === "position") {
|
|
|
- translation = value;
|
|
|
- }
|
|
|
- else if (targetPath === "rotationQuaternion") {
|
|
|
- rotationQuaternion = value;
|
|
|
- }
|
|
|
- else {
|
|
|
- scaling = value;
|
|
|
- }
|
|
|
-
|
|
|
- value = Matrix.Compose(scaling, rotationQuaternion, translation);
|
|
|
- }
|
|
|
-
|
|
|
- if (!modifyKey) {
|
|
|
- if (isMorph) {
|
|
|
- for (var influence = 0; influence < numTargets; influence++) {
|
|
|
- keys[influence].push({
|
|
|
- frame: bufferInput[frameIndex],
|
|
|
- value: value[influence]
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- keys.push({
|
|
|
- frame: bufferInput[frameIndex],
|
|
|
- value: value
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- lastAnimation.getKeys()[frameIndex].value = value;
|
|
|
- }
|
|
|
+ morphTarget.animations.push(babylonAnimation);
|
|
|
+ runtime.babylonScene.beginAnimation(morphTarget, 0, inputBuffer[inputBuffer.length - 1], true);
|
|
|
}
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ var animationName = animation.name || "anim" + animationIndex;
|
|
|
+ var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
|
|
|
+ babylonAnimation.setKeys(keys);
|
|
|
|
|
|
- // Finish
|
|
|
- if (!modifyKey) {
|
|
|
- if (isMorph) {
|
|
|
- for (var influence = 0; influence < numTargets; influence++) {
|
|
|
- var morphTarget = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
|
|
|
- if ((<any>morphTarget).animations === undefined) {
|
|
|
- (<any>morphTarget).animations = [];
|
|
|
- }
|
|
|
+ targetNode.animations.push(babylonAnimation);
|
|
|
+ runtime.babylonScene.beginAnimation(targetNode, 0, inputBuffer[inputBuffer.length - 1], true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
|
|
|
- babylonAnimation = new Animation(animationName, targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
|
|
|
+ /**
|
|
|
+ * Loads and creates animations
|
|
|
+ */
|
|
|
+ var loadAnimations = (runtime: IGLTFRuntime): void => {
|
|
|
+ var animations = runtime.gltf.animations;
|
|
|
+ if (!animations || animations.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- babylonAnimation.setKeys(keys[influence]);
|
|
|
- (<any>morphTarget).animations.push(babylonAnimation);
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- var animationName = animation.name || "anim" + animationIndex;
|
|
|
- babylonAnimation = new Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
|
|
|
-
|
|
|
- babylonAnimation.setKeys(keys);
|
|
|
- targetNode.animations.push(babylonAnimation);
|
|
|
- }
|
|
|
- }
|
|
|
+ for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
|
|
|
+ var animation = animations[animationIndex];
|
|
|
+ if (!animation) {
|
|
|
+ Tools.Warn("Animation " + animationIndex + " not found");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- lastAnimation = babylonAnimation;
|
|
|
+ if (!animation.channels || animation.channels.length === 0) {
|
|
|
+ Tools.Warn("Animation " + animationIndex + " has no channels");
|
|
|
+ }
|
|
|
|
|
|
- if (isMorph) {
|
|
|
- for (var influence = 0; influence < numTargets; influence++) {
|
|
|
- var morph = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
|
|
|
- runtime.babylonScene.stopAnimation(morph);
|
|
|
- runtime.babylonScene.beginAnimation(morph, 0, bufferInput[bufferInput.length - 1], true, 1.0);
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- runtime.babylonScene.stopAnimation(targetNode);
|
|
|
- runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
|
|
|
- }
|
|
|
+ if (!animation.samplers || animation.samplers.length === 0) {
|
|
|
+ Tools.Warn("Animation " + animationIndex + " has no samplers");
|
|
|
+ continue;
|
|
|
}
|
|
|
+
|
|
|
+ loadAnimation(runtime, animation, animationIndex);
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -265,7 +190,7 @@ module BABYLON.GLTF2 {
|
|
|
*/
|
|
|
var getParentBone = (runtime: IGLTFRuntime, skin: IGLTFSkin, index: number, newSkeleton: Skeleton): Bone => {
|
|
|
// Try to find
|
|
|
- var nodeStringID = createStringId(index);
|
|
|
+ var nodeStringID = getNodeID(index);
|
|
|
for (var i = 0; i < newSkeleton.bones.length; i++) {
|
|
|
if (newSkeleton.bones[i].id === nodeStringID) {
|
|
|
return newSkeleton.bones[i].getParent();
|
|
@@ -289,8 +214,8 @@ module BABYLON.GLTF2 {
|
|
|
if (childID === index)
|
|
|
{
|
|
|
var mat = configureBoneTransformation(parent);
|
|
|
- var bone = new Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
|
|
|
- bone.id = createStringId(parentID);
|
|
|
+ var bone = new Bone(parent.name || getNodeID(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
|
|
|
+ bone.id = getNodeID(parentID);
|
|
|
return bone;
|
|
|
}
|
|
|
}
|
|
@@ -361,8 +286,8 @@ module BABYLON.GLTF2 {
|
|
|
|
|
|
// Create node to root bone
|
|
|
var mat = configureBoneTransformation(node);
|
|
|
- var bone = new Bone(node.name || createStringId(i), newSkeleton, null, mat);
|
|
|
- bone.id = createStringId(i);
|
|
|
+ var bone = new Bone(node.name || getNodeID(i), newSkeleton, null, mat);
|
|
|
+ bone.id = getNodeID(i);
|
|
|
nodesToRoot.push({ bone: bone, node: node, index: i });
|
|
|
}
|
|
|
|
|
@@ -428,7 +353,7 @@ module BABYLON.GLTF2 {
|
|
|
}
|
|
|
|
|
|
var index = jointNode.index;
|
|
|
- var stringID = createStringId(index);
|
|
|
+ var stringID = getNodeID(index);
|
|
|
|
|
|
// Optimize, if the bone already exists...
|
|
|
var existingBone = runtime.babylonScene.getBoneByID(stringID);
|
|
@@ -493,7 +418,7 @@ module BABYLON.GLTF2 {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- var jointNodeStringId = createStringId(jointNode.index);
|
|
|
+ var jointNodeStringId = getNodeID(jointNode.index);
|
|
|
for (var j = 0; j < bones.length; j++) {
|
|
|
if (bones[j].id === jointNodeStringId) {
|
|
|
babylonSkeleton.bones.push(bones[j]);
|
|
@@ -564,7 +489,7 @@ module BABYLON.GLTF2 {
|
|
|
var indexStarts = [];
|
|
|
var indexCounts = [];
|
|
|
|
|
|
- var morphTargetManager = new BABYLON.MorphTargetManager();
|
|
|
+ var morphTargetManager: MorphTargetManager;
|
|
|
|
|
|
// Positions, normals and UVs
|
|
|
for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
|
|
@@ -578,7 +503,7 @@ module BABYLON.GLTF2 {
|
|
|
|
|
|
var attributes = primitive.attributes;
|
|
|
var accessor: IGLTFAccessor = null;
|
|
|
- var buffer: any = null;
|
|
|
+ var buffer: ArrayBufferView = null;
|
|
|
|
|
|
// Set positions, normal and uvs
|
|
|
for (var semantic in attributes) {
|
|
@@ -588,37 +513,28 @@ module BABYLON.GLTF2 {
|
|
|
buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
|
|
|
|
|
|
if (semantic === "NORMAL") {
|
|
|
- tempVertexData.normals = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.normals).set(buffer);
|
|
|
+ tempVertexData.normals = <Float32Array>buffer;
|
|
|
}
|
|
|
else if (semantic === "POSITION") {
|
|
|
- tempVertexData.positions = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.positions).set(buffer);
|
|
|
+ tempVertexData.positions = <Float32Array>buffer;
|
|
|
verticesCounts.push(tempVertexData.positions.length);
|
|
|
}
|
|
|
else if (semantic === "TANGENT") {
|
|
|
- tempVertexData.tangents = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.tangents).set(buffer);
|
|
|
+ tempVertexData.tangents = <Float32Array>buffer;
|
|
|
}
|
|
|
else if (semantic.indexOf("TEXCOORD_") !== -1) {
|
|
|
var channel = Number(semantic.split("_")[1]);
|
|
|
var uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
|
|
|
- var uvs = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>uvs).set(buffer);
|
|
|
- normalizeUVs(uvs);
|
|
|
- tempVertexData.set(uvs, uvKind);
|
|
|
+ tempVertexData.set(<Float32Array>buffer, uvKind);
|
|
|
}
|
|
|
else if (semantic === "JOINT") {
|
|
|
- tempVertexData.matricesIndices = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.matricesIndices).set(buffer);
|
|
|
+ tempVertexData.matricesIndices = <Float32Array>buffer;
|
|
|
}
|
|
|
else if (semantic === "WEIGHT") {
|
|
|
- tempVertexData.matricesWeights = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.matricesWeights).set(buffer);
|
|
|
+ tempVertexData.matricesWeights = <Float32Array>buffer;
|
|
|
}
|
|
|
else if (semantic === "COLOR_0") {
|
|
|
- tempVertexData.colors = new Float32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.colors).set(buffer);
|
|
|
+ tempVertexData.colors = <Float32Array>buffer;
|
|
|
}
|
|
|
else {
|
|
|
Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
|
|
@@ -629,19 +545,16 @@ module BABYLON.GLTF2 {
|
|
|
accessor = runtime.gltf.accessors[primitive.indices];
|
|
|
if (accessor) {
|
|
|
buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
|
|
|
-
|
|
|
- tempVertexData.indices = new Int32Array(buffer.length);
|
|
|
- (<Float32Array>tempVertexData.indices).set(buffer);
|
|
|
+ tempVertexData.indices = <Uint32Array>buffer;
|
|
|
indexCounts.push(tempVertexData.indices.length);
|
|
|
}
|
|
|
else {
|
|
|
// Set indices on the fly
|
|
|
- var indices: number[] = [];
|
|
|
- for (var index = 0; index < tempVertexData.positions.length / 3; index++) {
|
|
|
- indices.push(index);
|
|
|
+ tempVertexData.indices = new Uint32Array(tempVertexData.positions.length / 3);
|
|
|
+ for (var index = 0; index < tempVertexData.indices.length; index++) {
|
|
|
+ tempVertexData.indices[index] = index;
|
|
|
}
|
|
|
|
|
|
- tempVertexData.indices = new Int32Array(indices);
|
|
|
indexCounts.push(tempVertexData.indices.length);
|
|
|
}
|
|
|
|
|
@@ -653,26 +566,26 @@ module BABYLON.GLTF2 {
|
|
|
multiMat.subMaterials.push(material);
|
|
|
|
|
|
// Morph Targets
|
|
|
- if (primitive.targets !== undefined) {
|
|
|
+ if (primitive.targets) {
|
|
|
for (var targetsIndex = 0; targetsIndex < primitive.targets.length; targetsIndex++) {
|
|
|
var target = primitive.targets[targetsIndex];
|
|
|
|
|
|
var weight = 0.0;
|
|
|
- if (node.weights !== undefined) {
|
|
|
+ if (node.weights) {
|
|
|
weight = node.weights[targetsIndex];
|
|
|
}
|
|
|
- else if (mesh.weights !== undefined) {
|
|
|
+ else if (mesh.weights) {
|
|
|
weight = mesh.weights[targetsIndex];
|
|
|
}
|
|
|
|
|
|
- var morph = new BABYLON.MorphTarget("morph" + targetsIndex, weight);
|
|
|
+ var morph = new MorphTarget("morph" + targetsIndex, weight);
|
|
|
|
|
|
for (var semantic in target) {
|
|
|
// Link accessor and buffer view
|
|
|
accessor = runtime.gltf.accessors[target[semantic]];
|
|
|
- buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
|
|
|
+ var values = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, accessor);
|
|
|
|
|
|
- if (accessor.name !== undefined) {
|
|
|
+ if (accessor.name) {
|
|
|
morph.name = accessor.name;
|
|
|
}
|
|
|
|
|
@@ -681,35 +594,40 @@ module BABYLON.GLTF2 {
|
|
|
// As a result we have to add the original data to the delta to calculate
|
|
|
// the final data.
|
|
|
if (semantic === "NORMAL") {
|
|
|
- for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
|
|
|
- buffer[bufferIndex] += (<Float32Array>vertexData.normals)[bufferIndex];
|
|
|
+ for (var i = 0; i < values.length; i++) {
|
|
|
+ values[i] += vertexData.normals[i];
|
|
|
}
|
|
|
- morph.setNormals(buffer);
|
|
|
+ morph.setNormals(values);
|
|
|
}
|
|
|
else if (semantic === "POSITION") {
|
|
|
- for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
|
|
|
- buffer[bufferIndex] += (<Float32Array>vertexData.positions)[bufferIndex];
|
|
|
+ for (var i = 0; i < values.length; i++) {
|
|
|
+ values[i] += vertexData.positions[i];
|
|
|
}
|
|
|
- morph.setPositions(buffer);
|
|
|
+ morph.setPositions(values);
|
|
|
}
|
|
|
else if (semantic === "TANGENT") {
|
|
|
// Tangent data for morph targets is stored as xyz delta.
|
|
|
// The vertexData.tangent is stored as xyzw.
|
|
|
// So we need to skip every fourth vertexData.tangent.
|
|
|
- for (var bufferIndex = 0, tangentsIndex = 0; bufferIndex < buffer.length; bufferIndex++, tangentsIndex++) {
|
|
|
- buffer[bufferIndex] += (<Float32Array>vertexData.tangents)[tangentsIndex];
|
|
|
- if ((bufferIndex + 1) % 3 == 0) {
|
|
|
- tangentsIndex++;
|
|
|
+ for (var i = 0, j = 0; i < values.length; i++, j++) {
|
|
|
+ values[i] += vertexData.tangents[j];
|
|
|
+ if ((i + 1) % 3 == 0) {
|
|
|
+ j++;
|
|
|
}
|
|
|
}
|
|
|
- morph.setTangents(buffer);
|
|
|
+ morph.setTangents(values);
|
|
|
}
|
|
|
else {
|
|
|
Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if (morph.getPositions() !== undefined) {
|
|
|
+
|
|
|
+ if (morph.getPositions()) {
|
|
|
+ if (!morphTargetManager) {
|
|
|
+ morphTargetManager = new MorphTargetManager();
|
|
|
+ babylonMesh.morphTargetManager = morphTargetManager;
|
|
|
+ }
|
|
|
+
|
|
|
morphTargetManager.addTarget(morph);
|
|
|
}
|
|
|
else {
|
|
@@ -727,11 +645,6 @@ module BABYLON.GLTF2 {
|
|
|
geometry.setAllVerticesData(vertexData, false);
|
|
|
babylonMesh.computeWorldMatrix(true);
|
|
|
|
|
|
- // Set morph target manager after all vertices data has been processed
|
|
|
- if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
|
|
|
- babylonMesh.morphTargetManager = morphTargetManager;
|
|
|
- }
|
|
|
-
|
|
|
// Apply submeshes
|
|
|
babylonMesh.subMeshes = [];
|
|
|
for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
|
|
@@ -889,7 +802,7 @@ module BABYLON.GLTF2 {
|
|
|
newNode = importNode(runtime, node);
|
|
|
|
|
|
if (newNode !== null) {
|
|
|
- newNode.id = createStringId(index);
|
|
|
+ newNode.id = getNodeID(index);
|
|
|
newNode.parent = parent;
|
|
|
}
|
|
|
}
|
|
@@ -1214,7 +1127,7 @@ module BABYLON.GLTF2 {
|
|
|
var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
|
|
|
var samplingMode = GLTFUtils.GetTextureFilterMode(sampler.minFilter);
|
|
|
|
|
|
- var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, () => {
|
|
|
+ var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, false, samplingMode, () => {
|
|
|
onSuccess(babylonTexture);
|
|
|
}, onError);
|
|
|
|
|
@@ -1352,7 +1265,7 @@ module BABYLON.GLTF2 {
|
|
|
|
|
|
private static _loadMaterialsAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
|
|
|
var materials = runtime.gltf.materials;
|
|
|
- if (!materials) {
|
|
|
+ if (!materials || materials.length === 0) {
|
|
|
onSuccess();
|
|
|
return;
|
|
|
}
|