diff --git a/lib/loadObj.js b/lib/loadObj.js index a714457..0fd3f21 100644 --- a/lib/loadObj.js +++ b/lib/loadObj.js @@ -112,17 +112,17 @@ function loadObj(objPath, options) { mesh.name = getName(name); node.meshes.push(mesh); addPrimitive(); - - // Clear the vertex cache for each new mesh - vertexCache = {}; - vertexCacheCount = 0; - vertexCount = 0; } function addPrimitive() { primitive = new Primitive(); primitive.material = activeMaterial; mesh.primitives.push(primitive); + + // Clear the vertex cache for each new primitive + vertexCache = {}; + vertexCacheCount = 0; + vertexCount = 0; } function useMaterial(name) { @@ -373,6 +373,17 @@ function loadObj(objPath, options) { var isWindingCorrect = true; var faceNormal; + var firstFace = primitive.indices.length === 0; + var faceHasUvs = uvs[0].length > 0; + var faceHasNormals = normals[0].length > 0; + var primitiveHasUvs = primitive.uvs.length > 0; + var primitiveHasNormals = primitive.normals.length > 0; + + if (!firstFace && (faceHasUvs !== primitiveHasUvs || faceHasNormals !== primitiveHasNormals)) { + // Discard faces that don't use the same attributes + return; + } + // If normals are defined, find a face normal to use in winding order sanitization. // If no face normal, we have to assume the winding is correct. if (normals[0].length > 0) { diff --git a/specs/data/box-mixed-attributes/box-mixed-attributes.mtl b/specs/data/box-mixed-attributes/box-mixed-attributes.mtl new file mode 100644 index 0000000..4f8d129 --- /dev/null +++ b/specs/data/box-mixed-attributes/box-mixed-attributes.mtl @@ -0,0 +1,12 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl Material +Ns 96.078431 +Ka 0.100000 0.000000 0.000000 +Kd 0.640000 0.640000 0.640000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.100000 +Ni 1.000000 +d 1.000000 +illum 2 diff --git a/specs/data/box-mixed-attributes/box-mixed-attributes.obj b/specs/data/box-mixed-attributes/box-mixed-attributes.obj new file mode 100644 index 0000000..cb9055e --- /dev/null +++ b/specs/data/box-mixed-attributes/box-mixed-attributes.obj @@ -0,0 +1,46 @@ +# Blender v2.78 (sub 0) OBJ File: '' +# www.blender.org +mtllib box-mixed-attributes.mtl +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 0.0000 +vt 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +usemtl Material +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3 4 8 7 +f 7/9/3 8/10/3 6/11/3 5/12/3 +f 5/13/4 6/14/4 2/15/4 1/16/4 +f 3//5 7//5 5//5 1//5 +f 8/19 4/6 2/15 6/20 diff --git a/specs/lib/loadObjSpec.js b/specs/lib/loadObjSpec.js index dbc6fee..2426169 100644 --- a/specs/lib/loadObjSpec.js +++ b/specs/lib/loadObjSpec.js @@ -38,6 +38,7 @@ var objWindowsPaths = 'specs/data/box-windows-paths/box-windows-paths.obj'; var objInvalidContentsPath = 'specs/data/box/box.mtl'; var objConcavePath = 'specs/data/concave/concave.obj'; var objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj'; +var objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj'; var objInvalidPath = 'invalid.obj'; function getMeshes(data) { @@ -486,6 +487,14 @@ describe('loadObj', function() { }), done).toResolve(); }); + it('discards faces that don\'t use the same attributes as other faces in the primitive', function(done) { + expect(loadObj(objMixedAttributesPath, options) + .then(function(data) { + var primitive = getPrimitives(data)[0]; + expect(primitive.indices.length).toBe(18); // 3 faces removed + }), done).toResolve(); + }); + it('throws when file has invalid contents', function(done) { expect(loadObj(objInvalidContentsPath, options), done).toRejectWith(RuntimeError); });