diff --git a/lib/loadObj.js b/lib/loadObj.js index 2e082e0..90e4969 100644 --- a/lib/loadObj.js +++ b/lib/loadObj.js @@ -58,9 +58,9 @@ const facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g; */ function loadObj(objPath, options) { // Global store of vertex attributes listed in the obj file - let positions = new ArrayStorage(ComponentDatatype.FLOAT); - let normals = new ArrayStorage(ComponentDatatype.FLOAT); - let uvs = new ArrayStorage(ComponentDatatype.FLOAT); + let globalPositions = new ArrayStorage(ComponentDatatype.FLOAT); + let globalNormals = new ArrayStorage(ComponentDatatype.FLOAT); + let globalUvs = new ArrayStorage(ComponentDatatype.FLOAT); // The current node, mesh, and primitive let node; @@ -144,8 +144,8 @@ function loadObj(objPath, options) { } function faceAndPrimitiveMatch(uvs, normals, primitive) { - const faceHasUvs = uvs[0].length > 0; - const faceHasNormals = normals[0].length > 0; + const faceHasUvs = defined(uvs[0]); + const faceHasNormals = defined(normals[0]); const primitiveHasUvs = primitive.uvs.length > 0; const primitiveHasNormals = primitive.normals.length > 0; return primitiveHasUvs === faceHasUvs && primitiveHasNormals === faceHasNormals; @@ -160,43 +160,58 @@ function loadObj(objPath, options) { } } - function getOffset(a, attributeData, components) { - const i = parseInt(a); + function getIndexFromStart(index, attributeData, components) { + const i = parseInt(index); if (i < 0) { // Negative vertex indexes reference the vertices immediately above it - return (attributeData.length / components + i) * components; + return (attributeData.length / components + i); + } + return i - 1; + } + + function correctAttributeIndices(attributeIndices, attributeData, components) { + const length = attributeIndices.length; + for (let i = 0; i < length; ++i) { + if (attributeIndices[i].length === 0) { + attributeIndices[i] = undefined; + } else { + attributeIndices[i] = getIndexFromStart(attributeIndices[i], attributeData, components); + } + } + } + + function correctVertices(vertices, positions, uvs, normals) { + const length = vertices.length; + for (let i = 0; i < length; ++i) { + vertices[i] = defaultValue(positions[i], '') + '/' + defaultValue(uvs[i], '') + '/' + defaultValue(normals[i], ''); } - return (i - 1) * components; } function createVertex(p, u, n) { // Positions - if (p.length > 0) { - const pi = getOffset(p, positions, 3); - const px = positions.get(pi + 0); - const py = positions.get(pi + 1); - const pz = positions.get(pi + 2); + if (defined(p)) { + const px = globalPositions.get(p * 3); + const py = globalPositions.get(p * 3 + 1); + const pz = globalPositions.get(p * 3 + 2); primitive.positions.push(px); primitive.positions.push(py); primitive.positions.push(pz); } // Normals - if (n.length > 0) { - const ni = getOffset(n, normals, 3); - const nx = normals.get(ni + 0); - const ny = normals.get(ni + 1); - const nz = normals.get(ni + 2); + if (defined(n)) { + const nx = globalNormals.get(n * 3); + const ny = globalNormals.get(n * 3 + 1); + const nz = globalNormals.get(n * 3 + 2); primitive.normals.push(nx); primitive.normals.push(ny); primitive.normals.push(nz); } // UVs - if (u.length > 0) { - const ui = getOffset(u, uvs, 2); - const ux = uvs.get(ui + 0); - const uy = uvs.get(ui + 1); + if (defined(u)) { + const ux = globalUvs.get(u * 2); + const uy = globalUvs.get(u * 2 + 1); primitive.uvs.push(ux); primitive.uvs.push(uy); } @@ -220,18 +235,16 @@ function loadObj(objPath, options) { } function getPosition(index, result) { - const pi = getOffset(index, positions, 3); - const px = positions.get(pi + 0); - const py = positions.get(pi + 1); - const pz = positions.get(pi + 2); + const px = globalPositions.get(index * 3); + const py = globalPositions.get(index * 3 + 1); + const pz = globalPositions.get(index * 3 + 2); return Cartesian3.fromElements(px, py, pz, result); } function getNormal(index, result) { - const ni = getOffset(index, normals, 3); - const nx = normals.get(ni + 0); - const ny = normals.get(ni + 1); - const nz = normals.get(ni + 2); + const nx = globalNormals.get(index * 3); + const ny = globalNormals.get(index * 3 + 1); + const nz = globalNormals.get(index * 3 + 2); return Cartesian3.fromElements(nx, ny, nz, result); } @@ -249,7 +262,7 @@ function loadObj(objPath, options) { const scratchPoints = []; function checkWindingCorrect(positionIndex1, positionIndex2, positionIndex3, normalIndex) { - if (normalIndex.length === 0) { + if (!defined(normalIndex)) { // If no face normal, we have to assume the winding is correct. return true; } @@ -278,7 +291,12 @@ function loadObj(objPath, options) { } function addFace(vertices, positions, uvs, normals) { - checkPrimitive(uvs, normals); + correctAttributeIndices(positions, globalPositions, 3); + correctAttributeIndices(normals, globalNormals, 3); + correctAttributeIndices(uvs, globalUvs, 2); + correctVertices(vertices, positions, uvs, normals); + + checkPrimitive(uvs, faceNormals); if (vertices.length === 3) { const isWindingCorrect = checkWindingCorrect(positions[0], positions[1], positions[2], normals[0]); @@ -336,9 +354,9 @@ function loadObj(objPath, options) { const mtllibLine = line.substring(7).trim(); mtlPaths = mtlPaths.concat(getMtlPaths(mtllibLine)); } else if ((result = vertexPattern.exec(line)) !== null) { - positions.push(parseFloat(result[1])); - positions.push(parseFloat(result[2])); - positions.push(parseFloat(result[3])); + globalPositions.push(parseFloat(result[1])); + globalPositions.push(parseFloat(result[2])); + globalPositions.push(parseFloat(result[3])); } else if ((result = normalPattern.exec(line) ) !== null) { const normal = Cartesian3.fromElements(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]), scratchNormal); if (Cartesian3.equals(normal, Cartesian3.ZERO)) { @@ -346,12 +364,12 @@ function loadObj(objPath, options) { } else { Cartesian3.normalize(normal, normal); } - normals.push(normal.x); - normals.push(normal.y); - normals.push(normal.z); + globalNormals.push(normal.x); + globalNormals.push(normal.y); + globalNormals.push(normal.z); } else if ((result = uvPattern.exec(line)) !== null) { - uvs.push(parseFloat(result[1])); - uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image + globalUvs.push(parseFloat(result[1])); + globalUvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image } else { // face line or invalid line // Because face lines can contain n vertices, we use a line buffer in case the face data spans multiple lines. // If there's a line continuation don't create face yet @@ -386,13 +404,10 @@ function loadObj(objPath, options) { // Parse the obj file return readLines(objPath, parseLine) .then(function() { - // Add hasNormals to options object for loadMtl - options.hasNormals = normals.length > 0; - // Unload resources - positions = undefined; - normals = undefined; - uvs = undefined; + globalPositions = undefined; + globalNormals = undefined; + globalUvs = undefined; // Load materials and textures return finishLoading(nodes, mtlPaths, objPath, defined(activeMaterial), options); diff --git a/specs/data/box-negative-indices/box-negative-indices.obj b/specs/data/box-negative-indices/box-negative-indices.obj index e3b2aa6..c37847f 100644 --- a/specs/data/box-negative-indices/box-negative-indices.obj +++ b/specs/data/box-negative-indices/box-negative-indices.obj @@ -9,12 +9,12 @@ 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 usemtl Material s off -f -8 -7 -5 -6 +f -7 -6 -4 -5 +f -3 -2 -6 -7 +f -5 -1 -3 -7 +v 1.000000 1.000000 -1.000000 +f -1 -5 -7 -3 f -6 -5 -1 -2 f -2 -1 -3 -4 -f -4 -3 -7 -8 -f -6 -2 -4 -8 -f -1 -5 -7 -3 diff --git a/specs/data/box-positions-only/box-positions-only.obj b/specs/data/box-positions-only/box-positions-only.obj index 8d2353f..2c62aac 100644 --- a/specs/data/box-positions-only/box-positions-only.obj +++ b/specs/data/box-positions-only/box-positions-only.obj @@ -13,8 +13,8 @@ v 1.000000 1.000000 -1.000000 usemtl Material s off f 1 2 4 3 -f 3 4 8 7 -f 7 8 6 5 f 5 6 2 1 f 3 7 5 1 f 8 4 2 6 +f 3 4 8 7 +f 7 8 6 5 diff --git a/specs/lib/loadMtlSpec.js b/specs/lib/loadMtlSpec.js index f0529cf..2af7f0a 100644 --- a/specs/lib/loadMtlSpec.js +++ b/specs/lib/loadMtlSpec.js @@ -60,7 +60,6 @@ describe('loadMtl', () => { options = clone(obj2gltf.defaults); options.overridingTextures = {}; options.logger = () => {}; - options.hasNormals = true; }); it('loads mtl', async () => {