瀏覽代碼

glTF file loader:

- Fixed UVs
- Fixed PROJECTION and VIEW matrices for shaders support
luaacro 10 年之前
父節點
當前提交
fffaa3bb73
共有 3 個文件被更改,包括 145 次插入124 次删除
  1. 1 1
      Exporters/3ds Max/readme.md
  2. 68 55
      loaders/glTF/babylon.glTFFileLoader.js
  3. 76 68
      loaders/glTF/babylon.glTFFileLoader.ts

+ 1 - 1
Exporters/3ds Max/readme.md

@@ -3,7 +3,7 @@
 
 This exporter is designed for 3ds Max 2013, 2015 and 2016 (Use 2015 version for 3dsMax 2016). You just have to unzip the content of the archive to [3ds max folder\bin\assemblies]
 
-**After unzipping DLLs, you may have to go through all files, right-click on them, select the Properties menu and click on Unblock button to remove security protection enforce by Windows**
+**Before extracting, please go to downloaded .zip properties and click Unblock button**
 
 If you right click on the scene, on a light, on a camera or on a mesh you fill have a [Babylon...] menu. 
 

+ 68 - 55
loaders/glTF/babylon.glTFFileLoader.js

@@ -160,6 +160,12 @@ var BABYLON;
         if (parameter.semantic === "MODEL") {
             mat = source.getWorldMatrix();
         }
+        else if (parameter.semantic === "PROJECTION") {
+            mat = scene.getProjectionMatrix();
+        }
+        else if (parameter.semantic === "VIEW") {
+            mat = scene.getViewMatrix();
+        }
         else if (parameter.semantic === "MODELVIEWINVERSETRANSPOSE") {
             mat = BABYLON.Matrix.Transpose(source.getWorldMatrix().multiply(scene.getViewMatrix()).invert());
         }
@@ -249,6 +255,9 @@ var BABYLON;
         }
     };
     var normalizeUVs = function (buffer) {
+        if (!buffer) {
+            return;
+        }
         for (var i = 0; i < buffer.length / 2; i++) {
             buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
         }
@@ -272,6 +281,9 @@ var BABYLON;
         else if (attributeParameter.semantic === "WEIGHT") {
             return "matricesWeights";
         }
+        else if (attributeParameter.semantic === "COLOR") {
+            return "color";
+        }
         else if (attributeParameter.semantic.indexOf("TEXCOORD_") !== -1) {
             var channel = Number(attributeParameter.semantic.split("_")[1]);
             return "uv" + (channel === 0 ? "" : channel + 1);
@@ -280,23 +292,6 @@ var BABYLON;
     var isBase64 = function (uri) {
         return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
     };
-    var textureHasAlpha = function (texture) {
-        var image = new Image();
-        image.onload = function (ev) {
-            var canvas = document.createElement('canvas');
-            var context = canvas.getContext('2d');
-            context.drawImage(image, 0, 0);
-            var data = context.getImageData(0, 0, image.width, image.height).data;
-            var foundAlpha = false;
-            for (var i = 0; i < data.length; i += 4) {
-                if (data[i + 3] === 0) {
-                    texture.hasAlpha = true;
-                    break;
-                }
-            }
-        };
-        image.src = texture.url;
-    };
     /**
     * Load animations
     */
@@ -348,20 +343,23 @@ var BABYLON;
                 // Create animation and key frames
                 var babylonAnimation = new BABYLON.Animation(anim, isBone ? "_matrix" : targetPath, 1, animationType, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
                 var keys = [];
+                var arrayOffset = 0;
                 for (var i = 0; i < bufferInput.length; i++) {
                     var value = null;
                     if (targetPath === "rotationQuaternion") {
-                        value = BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.FromArray([bufferOutput[i * 4], bufferOutput[i * 4 + 1], bufferOutput[i * 4 + 2]]).normalize(), bufferOutput[i * 4 + 3]);
+                        value = BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]).normalize(), bufferOutput[arrayOffset + 3]);
+                        arrayOffset += 4;
                     }
                     else {
-                        value = BABYLON.Vector3.FromArray([bufferOutput[i * 3], bufferOutput[i * 3 + 1], bufferOutput[i * 3 + 2]]);
+                        value = BABYLON.Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
+                        arrayOffset += 3;
                     }
                     if (isBone) {
                         var translation = BABYLON.Vector3.Zero();
                         var rotationQuaternion = new BABYLON.Quaternion();
                         var scaling = BABYLON.Vector3.Zero();
                         var bone = targetNode;
-                        var mat = bone.getLocalMatrix();
+                        var mat = bone.getBaseMatrix();
                         mat.decompose(scaling, rotationQuaternion, translation);
                         if (targetPath === "position") {
                             translation = value;
@@ -372,9 +370,6 @@ var BABYLON;
                         else {
                             scaling = value;
                         }
-                        if (targetNode instanceof BABYLON.Mesh) {
-                            targetNode.a;
-                        }
                         value = BABYLON.Matrix.Compose(scaling, rotationQuaternion, translation);
                     }
                     keys.push({
@@ -385,9 +380,7 @@ var BABYLON;
                 // Finish
                 babylonAnimation.setKeys(keys);
                 targetNode.animations.push(babylonAnimation);
-                if (!(targetNode instanceof BABYLON.Bone)) {
-                    gltfRuntime.scene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true);
-                }
+                gltfRuntime.scene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true);
             }
         }
     };
@@ -405,31 +398,34 @@ var BABYLON;
         return mat;
     };
     var getParentBone = function (gltfRuntime, jointName, newSkeleton) {
+        // Try to find
+        for (var i = 0; i < newSkeleton.bones.length; i++) {
+            if (newSkeleton.bones[i].id === jointName) {
+                return newSkeleton.bones[i];
+            }
+        }
+        // Not found
         for (var nde in gltfRuntime.nodes) {
             var node = gltfRuntime.nodes[nde];
             if (!node || !node.jointName) {
                 continue;
             }
             for (var i = 0; i < node.children.length; i++) {
-                var child = gltfRuntime.nodes[node.children[i]];
-                if (!child || !node.jointName) {
+                var childID = node.children[i];
+                var childNode = gltfRuntime.nodes[childID];
+                if (!childNode || !childNode.jointName) {
                     continue;
                 }
-                if (child.jointName === jointName) {
-                    var parent = gltfRuntime.scene.getNodeByID(nde);
-                    if (parent instanceof BABYLON.Bone) {
-                        return parent;
-                    }
-                    return null;
+                if (childID === jointName) {
+                    var mat = configureBoneTransformation(node);
+                    var parentBone = getParentBone(gltfRuntime, node.jointName, newSkeleton);
+                    var bone = new BABYLON.Bone(node.name, newSkeleton, parentBone, mat);
+                    bone.id = node.jointName;
+                    return bone;
                 }
             }
         }
-        return null;
-        for (var i = 0; i < newSkeleton.bones.length; i++) {
-            if (newSkeleton.bones[i].id === jointName) {
-                return newSkeleton.bones[i];
-            }
-        }
+        // Does not exists
         return null;
     };
     var importSkeleton = function (gltfRuntime, skins) {
@@ -444,14 +440,10 @@ var BABYLON;
                 BABYLON.Tools.Warn("Joint named " + skins.jointNames[i] + " does not exist");
                 continue;
             }
-            // Transform
             var mat = configureBoneTransformation(node);
-            // Parent bone
-            var boneID = skins.jointNames[i];
-            var parentBone = getParentBone(gltfRuntime, boneID, newSkeleton);
-            // Create bone
+            var parentBone = getParentBone(gltfRuntime, skins.jointNames[i], newSkeleton);
             var bone = new BABYLON.Bone(node.name, newSkeleton, parentBone, mat);
-            bone.id = boneID;
+            bone.id = skins.jointNames[i];
         }
         newSkeleton.prepare();
         return newSkeleton;
@@ -465,7 +457,6 @@ var BABYLON;
         newMesh.layerMask = 0x0FFFFFFF;
         newMesh.subMeshes = [];
         var multiMat = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
-        multiMat.backFaceCulling = false;
         newMesh.material = multiMat;
         var vertexData = new BABYLON.VertexData();
         var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, true);
@@ -505,8 +496,11 @@ var BABYLON;
                     else if (semantic.indexOf("TEXCOORD_") !== -1) {
                         var channel = Number(semantic.split("_")[1]);
                         var uvKind = BABYLON.VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                        normalizeUVs(buffer);
-                        tempVertexData.set(buffer, uvKind);
+                        tempVertexData.uvs = [];
+                        for (var j = 0; j < buffer.length; j++) {
+                            tempVertexData.uvs.push(buffer[j]);
+                        }
+                        normalizeUVs(tempVertexData.uvs);
                     }
                     else if (semantic === "JOINT") {
                         tempVertexData.set(buffer, BABYLON.VertexBuffer.MatricesIndicesKind);
@@ -514,11 +508,17 @@ var BABYLON;
                     else if (semantic === "WEIGHT") {
                         tempVertexData.set(buffer, BABYLON.VertexBuffer.MatricesWeightsKind);
                     }
+                    else if (semantic === "COLOR") {
+                        tempVertexData.set(buffer, BABYLON.VertexBuffer.ColorKind);
+                    }
                 }
                 // Indices
                 accessor = gltfRuntime.accessors[primitive.indices];
                 buffer = getBufferFromAccessor(gltfRuntime, accessor);
-                tempVertexData.indices = buffer;
+                tempVertexData.indices = [];
+                for (var j = 0; j < buffer.length; j++) {
+                    tempVertexData.indices.push(buffer[j]);
+                }
                 indexCounts.push(buffer.length);
                 vertexData.merge(tempVertexData);
                 tempVertexData = undefined;
@@ -530,6 +530,19 @@ var BABYLON;
                 indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
             }
         }
+        // Apply skin
+        if (skin) {
+            var vector = BABYLON.Vector3.Zero();
+            var mat = BABYLON.Matrix.FromArray(skin.bindShapeMatrix);
+            var positions = vertexData.positions;
+            for (var i = 0; i < positions.length / 3; i++) {
+                vector.copyFromFloats(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
+                var result = BABYLON.Vector3.TransformCoordinates(vector, mat);
+                positions[i * 3] = result.x;
+                positions[i * 3 + 1] = result.y;
+                positions[i * 3 + 2] = result.z;
+            }
+        }
         // Apply geometry
         geometry.setAllVerticesData(vertexData);
         geometry.applyToMesh(newMesh);
@@ -595,6 +608,7 @@ var BABYLON;
                 }
                 if (newMesh.skeleton !== null) {
                     newMesh.useBones = true;
+                    newMesh.computeBonesUsingShaders = true;
                     newMesh.applySkeleton(newMesh.skeleton);
                 }
                 lastNode = newMesh;
@@ -846,11 +860,7 @@ var BABYLON;
                     newTexture = new BABYLON.Texture(gltfRuntime.rootUrl + source.uri, gltfRuntime.scene, true);
                 }
                 newTexture.name = value;
-                textureHasAlpha(newTexture);
                 texture.babylonTexture = newTexture;
-                if (texture.internalFormat && (texture.internalFormat === ETextureFormat.ALPHA || texture.internalFormat === ETextureFormat.RGBA)) {
-                    newTexture.hasAlpha = true;
-                }
                 if (uniform.value) {
                     // Static uniform
                     shaderMaterial.setTexture(unif, newTexture);
@@ -1134,14 +1144,17 @@ var BABYLON;
             // Load shaders and buffers
             load(gltfRuntime);
             // Test on bones
+            /*
             for (var i = 0; i < scene.meshes.length; i++) {
                 var mesh = scene.meshes[i];
+
                 if (mesh.skeleton) {
-                    scene.beginAnimation(mesh.skeleton, 0, 20, true, 0.5, function () {
+                    scene.beginAnimation(mesh.skeleton, 0, 1000, true, 1, () => {
                         console.log("finished");
                     });
                 }
             }
+            */
             // Finish
             return true;
         };

+ 76 - 68
loaders/glTF/babylon.glTFFileLoader.ts

@@ -182,6 +182,12 @@
         if (parameter.semantic === "MODEL") {
             mat = source.getWorldMatrix();
         }
+        else if (parameter.semantic === "PROJECTION") {
+            mat = scene.getProjectionMatrix();
+        }
+        else if (parameter.semantic === "VIEW") {
+            mat = scene.getViewMatrix();
+        }
         else if (parameter.semantic === "MODELVIEWINVERSETRANSPOSE") {
             mat = Matrix.Transpose(source.getWorldMatrix().multiply(scene.getViewMatrix()).invert());
         }
@@ -265,6 +271,10 @@
     };
 
     var normalizeUVs = (buffer: any) => {
+        if (!buffer) {
+            return;
+        }
+
         for (var i = 0; i < buffer.length / 2; i++) {
             buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
         }
@@ -291,6 +301,9 @@
         else if (attributeParameter.semantic === "WEIGHT") {
             return "matricesWeights";
         }
+        else if (attributeParameter.semantic === "COLOR") {
+            return "color";
+        }
         else if (attributeParameter.semantic.indexOf("TEXCOORD_") !== -1) {
             var channel = Number(attributeParameter.semantic.split("_")[1]);
             return "uv" + (channel === 0 ? "" : channel + 1);
@@ -301,28 +314,6 @@
         return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
     };
 
-    var textureHasAlpha = (texture: Texture) => {
-        var image = new Image();
-
-        image.onload = (ev: Event) => {
-            var canvas = document.createElement('canvas');
-            var context = canvas.getContext('2d');
-            context.drawImage(image, 0, 0);
-
-            var data = context.getImageData(0, 0, image.width, image.height).data;
-            var foundAlpha = false;
-
-            for (var i = 0; i < data.length; i+=4) {
-                if (data[i + 3] === 0) {
-                    texture.hasAlpha = true;
-                    break;
-                }
-            }
-        };
-
-        image.src = texture.url;
-    };
-
     /**
     * Load animations
     */
@@ -389,15 +380,18 @@
                 // Create animation and key frames
                 var babylonAnimation = new Animation(anim, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
                 var keys = [];
+                var arrayOffset = 0;
 
                 for (var i = 0; i < bufferInput.length; i++) {
                     var value: any = null;
 
                     if (targetPath === "rotationQuaternion") { // VEC4
-                        value = Quaternion.RotationAxis(Vector3.FromArray([bufferOutput[i * 4], bufferOutput[i * 4 + 1], bufferOutput[i * 4 + 2]]).normalize(), bufferOutput[i * 4 + 3]);
+                        value = Quaternion.RotationAxis(Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]).normalize(), bufferOutput[arrayOffset + 3]);
+                        arrayOffset += 4;
                     }
                     else { // Position and scaling are VEC3
-                        value = Vector3.FromArray([bufferOutput[i * 3], bufferOutput[i * 3 + 1], bufferOutput[i * 3 + 2]]);
+                        value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
+                        arrayOffset += 3;
                     }
 
                     if (isBone) {
@@ -406,7 +400,7 @@
                         var scaling = Vector3.Zero();
                         var bone = <Bone>targetNode;
 
-                        var mat = bone.getLocalMatrix();
+                        var mat = bone.getBaseMatrix();
                         mat.decompose(scaling, rotationQuaternion, translation);
 
                         if (targetPath === "position") {
@@ -419,10 +413,6 @@
                             scaling = value;
                         }
 
-                        if (targetNode instanceof Mesh) {
-                            targetNode.a
-                        }
-
                         value = Matrix.Compose(scaling, rotationQuaternion, translation);
                     }
 
@@ -435,10 +425,8 @@
                 // Finish
                 babylonAnimation.setKeys(keys);
                 targetNode.animations.push(babylonAnimation);
-
-                if (!(targetNode instanceof Bone)) {
-                    gltfRuntime.scene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true);
-                }
+                
+                gltfRuntime.scene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true);
             }
         }
     };
@@ -461,39 +449,42 @@
     };
 
     var getParentBone = (gltfRuntime: IGLTFRuntime, 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
         for (var nde in gltfRuntime.nodes) {
             var node: IGLTFNode = gltfRuntime.nodes[nde];
+
             if (!node || !node.jointName) {
                 continue;
             }
 
             for (var i = 0; i < node.children.length; i++) {
-                var child: IGLTFNode = gltfRuntime.nodes[node.children[i]];
-                if (!child || !node.jointName) {
+                var childID = node.children[i];
+                var childNode: IGLTFNode = gltfRuntime.nodes[childID];
+
+                if (!childNode || !childNode.jointName) {
                     continue;
                 }
 
-                if (child.jointName === jointName) {
-                    var parent = gltfRuntime.scene.getNodeByID(nde);
+                if (childID === jointName) {
+                    var mat = configureBoneTransformation(node);
+                    var parentBone = getParentBone(gltfRuntime, node.jointName, newSkeleton);
 
-                    if (parent instanceof Bone) {
-                        return parent;
-                    }
+                    var bone = new Bone(node.name, newSkeleton, parentBone, mat);
+                    bone.id = node.jointName;
 
-                    return null;
+                    return bone;
                 }
             }
         }
 
-        return null;
-        
-        for (var i = 0; i < newSkeleton.bones.length; i++) {
-            if (newSkeleton.bones[i].id === jointName) {
-                return newSkeleton.bones[i];
-            }
-        }
-
+        // Does not exists
         return null;
     };
 
@@ -512,16 +503,11 @@
                 continue;
             }
 
-            // Transform
             var mat = configureBoneTransformation(node);
+            var parentBone = getParentBone(gltfRuntime, skins.jointNames[i], newSkeleton);
 
-            // Parent bone
-            var boneID = skins.jointNames[i];
-            var parentBone: Bone = getParentBone(gltfRuntime, boneID, newSkeleton);
-
-            // Create bone
             var bone = new Bone(node.name, newSkeleton, parentBone, mat);
-            bone.id = boneID;
+            bone.id = skins.jointNames[i];
         }
 
         newSkeleton.prepare();
@@ -539,7 +525,6 @@
         newMesh.subMeshes = [];
 
         var multiMat = new MultiMaterial("multimat" + id, gltfRuntime.scene);
-        multiMat.backFaceCulling = false;
         newMesh.material = multiMat;
 
         var vertexData = new VertexData();
@@ -589,8 +574,11 @@
                     else if (semantic.indexOf("TEXCOORD_") !== -1) {
                         var channel = Number(semantic.split("_")[1]);
                         var uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                        normalizeUVs(buffer);
-                        tempVertexData.set(buffer, uvKind);
+                        tempVertexData.uvs = [];
+                        for (var j = 0; j < buffer.length; j++) {
+                            tempVertexData.uvs.push(buffer[j]);
+                        }
+                        normalizeUVs(tempVertexData.uvs);
                     }
                     else if (semantic === "JOINT") {
                         tempVertexData.set(buffer, VertexBuffer.MatricesIndicesKind);
@@ -598,12 +586,19 @@
                     else if (semantic === "WEIGHT") {
                         tempVertexData.set(buffer, VertexBuffer.MatricesWeightsKind);
                     }
+                    else if (semantic === "COLOR") {
+                        tempVertexData.set(buffer, VertexBuffer.ColorKind);
+                    }
                 }
 
                 // Indices
                 accessor = gltfRuntime.accessors[primitive.indices];
                 buffer = getBufferFromAccessor(gltfRuntime, accessor);
-                tempVertexData.indices = buffer;
+
+                tempVertexData.indices = [];
+                for (var j = 0; j < buffer.length; j++) {
+                    tempVertexData.indices.push(buffer[j]);
+                }
                 indexCounts.push(buffer.length);
 
                 vertexData.merge(tempVertexData);
@@ -619,6 +614,22 @@
             }
         }
 
+        // Apply skin
+        if (skin) {
+            var vector = Vector3.Zero();
+            var mat = Matrix.FromArray(skin.bindShapeMatrix);
+            var positions = vertexData.positions;
+
+            for (var i = 0; i < positions.length / 3; i++) {
+                vector.copyFromFloats(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
+                var result = Vector3.TransformCoordinates(vector, mat);
+
+                positions[i * 3] = result.x;
+                positions[i * 3 + 1] = result.y;
+                positions[i * 3 + 2] = result.z;
+            }
+        }
+
         // Apply geometry
         geometry.setAllVerticesData(vertexData);
         geometry.applyToMesh(newMesh);
@@ -701,6 +712,7 @@
 
                 if (newMesh.skeleton !== null) {
                     newMesh.useBones = true;
+                    newMesh.computeBonesUsingShaders = true;
                     newMesh.applySkeleton(newMesh.skeleton);
                 }
 
@@ -1008,14 +1020,8 @@
                 }
 
                 newTexture.name = value;
-                textureHasAlpha(newTexture);
-
                 texture.babylonTexture = newTexture;
 
-                if (texture.internalFormat && (texture.internalFormat === ETextureFormat.ALPHA || texture.internalFormat === ETextureFormat.RGBA)) {
-                    newTexture.hasAlpha = true;
-                }
-
                 if (uniform.value) {
                     // Static uniform
                     shaderMaterial.setTexture(unif, newTexture);
@@ -1361,15 +1367,17 @@
             load(gltfRuntime);
 
             // Test on bones
+            /*
             for (var i = 0; i < scene.meshes.length; i++) {
                 var mesh = scene.meshes[i];
 
                 if (mesh.skeleton) {
-                    scene.beginAnimation(mesh.skeleton, 0, 20, true, 0.5, () => {
+                    scene.beginAnimation(mesh.skeleton, 0, 1000, true, 1, () => {
                         console.log("finished");
                     });
                 }
             }
+            */
 
             // Finish
             return true;