From 9cc1ba8ec52b514fce5f9043102e79e2097453ff Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 17 Oct 2018 22:59:54 -0400 Subject: [PATCH 1/5] Split incompatible materials --- lib/createGltf.js | 132 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 28 deletions(-) diff --git a/lib/createGltf.js b/lib/createGltf.js index b5f3f89..27e9b62 100644 --- a/lib/createGltf.js +++ b/lib/createGltf.js @@ -4,6 +4,7 @@ var getBufferPadded = require('./getBufferPadded'); var getDefaultMaterial = require('./loadMtl').getDefaultMaterial; var Texture = require('./Texture'); +var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var WebGLConstants = Cesium.WebGLConstants; @@ -23,6 +24,9 @@ function createGltf(objData, options) { var materials = objData.materials; var name = objData.name; + // Split materials used by primitives with different types of attributes + materials = splitIncompatibleMaterials(nodes, materials, options); + var gltf = { accessors : [], asset : {}, @@ -70,14 +74,14 @@ function createGltf(objData, options) { var meshIndex; if (meshesLength === 1) { - meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, meshes[0], options); + meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, meshes[0]); addNode(gltf, node.name, meshIndex, undefined); } else { // Add meshes as child nodes var parentIndex = addNode(gltf, node.name); for (var j = 0; j < meshesLength; ++j) { var mesh = meshes[j]; - meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, mesh, options); + meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, mesh); addNode(gltf, mesh.name, meshIndex, parentIndex); } } @@ -194,6 +198,31 @@ function getTexture(gltf, texture) { }; } +function cloneMaterial(material, removeTextures) { + if (material === null || typeof material !== 'object') { + return material; + } else if (material instanceof Texture) { + if (removeTextures) { + return undefined; + } + return material; + } else if (Array.isArray(material)) { + var length = material.length; + var clonedArray = new Array(length); + for (var i = 0; i < length; ++i) { + clonedArray[i] = cloneMaterial(material[i], removeTextures); + } + return clonedArray; + } + var clonedObject = {}; + for (var name in material) { + if (material.hasOwnProperty(name)) { + clonedObject[name] = cloneMaterial(material[name], removeTextures); + } + } + return clonedObject; +} + function resolveTextures(gltf, material) { for (var name in material) { if (material.hasOwnProperty(name)) { @@ -214,35 +243,27 @@ function addMaterial(gltf, material) { return materialIndex; } -function getMaterial(gltf, materials, materialName, options) { - if (!defined(materialName)) { - // Create a default material if the primitive does not specify one - materialName = 'default'; - } - - var i; - var material; +function getMaterialByName(materials, materialName) { var materialsLength = materials.length; - for (i = 0; i < materialsLength; ++i) { + for (var i = 0; i < materialsLength; ++i) { if (materials[i].name === materialName) { - material = materials[i]; - break; + return materials[i]; } } +} - if (!defined(material)) { - material = getDefaultMaterial(options); - material.name = materialName; - } - - var materialIndex; - materialsLength = gltf.materials.length; - for (i = 0; i < materialsLength; ++i) { - if (gltf.materials[i].name === materialName) { - materialIndex = i; - break; +function getMaterialIndex(materials, materialName) { + var materialsLength = materials.length; + for (var i = 0; i < materialsLength; ++i) { + if (materials[i].name === materialName) { + return i; } } +} + +function getMaterial(gltf, materials, materialName) { + var material = getMaterialByName(materials, materialName); + var materialIndex = getMaterialIndex(gltf.materials, materialName); if (!defined(materialIndex)) { materialIndex = addMaterial(gltf, material); @@ -251,6 +272,61 @@ function getMaterial(gltf, materials, materialName, options) { return materialIndex; } +function primitiveInfoMatch(a, b) { + return a.hasUvs === b.hasUvs && + a.hasNormals === b.hasNormals; +} + +function splitIncompatibleMaterials(nodes, materials, options) { + var splitMaterials = []; + var primitiveInfoByMaterial = {}; + var nodesLength = nodes.length; + for (var i = 0; i < nodesLength; ++i) { + var meshes = nodes[i].meshes; + var meshesLength = meshes.length; + for (var j = 0; j < meshesLength; ++j) { + var primitives = meshes[j].primitives; + var primitivesLength = primitives.length; + for (var k = 0; k < primitivesLength; ++k) { + var primitive = primitives[k]; + var hasUvs = primitive.uvs.length > 0; + var hasNormals = primitive.normals.length > 0; + var primitiveInfo = { + hasUvs : hasUvs, + hasNormals : hasNormals + }; + var originalMaterialName = defaultValue(primitive.material, 'default'); + var materialName = originalMaterialName; + var suffix = 2; + while (defined(primitiveInfoByMaterial[materialName])) { + if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[materialName])) { + break; + } + materialName = originalMaterialName + '-' + suffix++; + } + + primitive.material = materialName; + primitiveInfoByMaterial[materialName] = primitiveInfo; + + var material = getMaterialByName(splitMaterials, materialName); + if (defined(material)) { + continue; + } + + material = getMaterialByName(materials, originalMaterialName); + if (defined(material)) { + material = cloneMaterial(material, !hasUvs); + } else { + material = getDefaultMaterial(options); + } + material.name = materialName; + splitMaterials.push(material); + } + } + } + return splitMaterials; +} + function addVertexAttribute(gltf, array, components, name) { var count = array.length / components; var minMax = array.getMinMax(components); @@ -309,7 +385,7 @@ function requiresUint32Indices(nodes) { return false; } -function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index, options) { +function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index) { var hasPositions = primitive.positions.length > 0; var hasNormals = primitive.normals.length > 0; var hasUVs = primitive.uvs.length > 0; @@ -346,7 +422,7 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti primitive.uvs = undefined; primitive.indices = undefined; - var materialIndex = getMaterial(gltf, materials, primitive.material, options); + var materialIndex = getMaterial(gltf, materials, primitive.material); return { attributes : attributes, @@ -356,12 +432,12 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti }; } -function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) { +function addMesh(gltf, materials, bufferState, uint32Indices, mesh) { var gltfPrimitives = []; var primitives = mesh.primitives; var primitivesLength = primitives.length; for (var i = 0; i < primitivesLength; ++i) { - gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i, options)); + gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i)); } var gltfMesh = { From 1bca54c376f2e16c51c1f4007192c91c73a0ae53 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Mon, 29 Oct 2018 17:46:53 -0400 Subject: [PATCH 2/5] Added test --- .../box-mixed-attributes-2.mtl | 13 +++ .../box-mixed-attributes-2.obj | 67 +++++++++++++++ specs/data/box-mixed-attributes-2/cesium.png | Bin 0 -> 7665 bytes specs/lib/createGltfSpec.js | 76 ++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl create mode 100644 specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj create mode 100644 specs/data/box-mixed-attributes-2/cesium.png diff --git a/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl b/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl new file mode 100644 index 0000000..d81606d --- /dev/null +++ b/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl @@ -0,0 +1,13 @@ +# 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 +map_Kd cesium.png diff --git a/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj b/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj new file mode 100644 index 0000000..2762b61 --- /dev/null +++ b/specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj @@ -0,0 +1,67 @@ +# Blender v2.78 (sub 0) OBJ File: '' +# www.blender.org +mtllib box-mixed-attributes-2.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 +# Using default material +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9 8/10 6/11 5/12 +f 5/13 6/14 2/15 1/16 +f 3//5 7//5 5//5 1//5 +f 8//6 4//6 2//6 6//6 +usemtl Material +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9 8/10 6/11 5/12 +f 5/13 6/14 2/15 1/16 +f 3//5 7//5 5//5 1//5 +f 8//6 4//6 2//6 6//6 +usemtl Missing +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9 8/10 6/11 5/12 +f 5/13 6/14 2/15 1/16 +f 3//5 7//5 5//5 1//5 +f 8//6 4//6 2//6 6//6 +o CubeCopy +usemtl Material +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9 8/10 6/11 5/12 +f 5/13 6/14 2/15 1/16 +f 3//5 7//5 5//5 1//5 +f 8//6 4//6 2//6 6//6 diff --git a/specs/data/box-mixed-attributes-2/cesium.png b/specs/data/box-mixed-attributes-2/cesium.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8baee1bce0079bd7afeb38d5e0b1bde9732ba5 GIT binary patch literal 7665 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 literal 0 HcmV?d00001 diff --git a/specs/lib/createGltfSpec.js b/specs/lib/createGltfSpec.js index 1c4818a..26f6929 100644 --- a/specs/lib/createGltfSpec.js +++ b/specs/lib/createGltfSpec.js @@ -4,14 +4,17 @@ var Promise = require('bluebird'); var obj2gltf = require('../../lib/obj2gltf'); var createGltf = require('../../lib/createGltf'); var loadObj = require('../../lib/loadObj'); +var getDefaultMaterial = require('../../lib/loadMtl').getDefaultMaterial; var clone = Cesium.clone; +var defined = Cesium.defined; var WebGLConstants = Cesium.WebGLConstants; var boxObjPath = 'specs/data/box/box.obj'; var groupObjPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj'; var complexObjPath = 'specs/data/box-complex-material/box-complex-material.obj'; var noMaterialsObjPath = 'specs/data/box-no-materials/box-no-materials.obj'; +var mixedAttributesObjPath = 'specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj'; var options; @@ -20,6 +23,7 @@ describe('createGltf', function() { var groupObjData; var complexObjData; var noMaterialsObjData; + var mixedAttributesObjData; beforeEach(function(done) { options = clone(obj2gltf.defaults); @@ -42,6 +46,10 @@ describe('createGltf', function() { loadObj(noMaterialsObjPath, options) .then(function(data) { noMaterialsObjData = data; + }), + loadObj(mixedAttributesObjPath, options) + .then(function(data) { + mixedAttributesObjData = data; }) ]).then(done); }); @@ -163,6 +171,74 @@ describe('createGltf', function() { expect(attributes.TEXCOORD_0).toBeUndefined(); }); + it('splits incompatible materials', function() { + var gltf = createGltf(mixedAttributesObjData, options); + var materials = gltf.materials; + var meshes = gltf.meshes; + var i; + var material; + + var referenceMaterial = mixedAttributesObjData.materials[0]; + delete referenceMaterial.name; + referenceMaterial.pbrMetallicRoughness.baseColorTexture = { + index : 0 + }; + + var referenceMaterialNoTextures = clone(referenceMaterial, true); + referenceMaterialNoTextures.pbrMetallicRoughness.baseColorTexture = undefined; + + var defaultMaterial = getDefaultMaterial(options); + delete defaultMaterial.name; + + var materialNames = materials.map(function(material) { + var name = material.name; + delete material.name; + return name; + }); + + // Expect three copies of each material for + // * positions/normals/uvs + // * positions/normals + // * positions/uvs + expect(materialNames).toEqual([ + 'default', + 'default-2', + 'default-3', + 'Material', + 'Material-2', + 'Material-3', + 'Missing', + 'Missing-2', + 'Missing-3' + ]); + + expect(materials.length).toBe(9); + expect(materials[0]).toEqual(defaultMaterial); + expect(materials[1]).toEqual(defaultMaterial); + expect(materials[2]).toEqual(defaultMaterial); + expect(materials[3]).toEqual(referenceMaterial); + expect(materials[4]).toEqual(referenceMaterial); + expect(materials[5]).toEqual(referenceMaterialNoTextures); + expect(materials[6]).toEqual(defaultMaterial); + expect(materials[7]).toEqual(defaultMaterial); + expect(materials[8]).toEqual(defaultMaterial); + + // Test that primitives without uvs reference materials without textures + var meshesLength = meshes.length; + for (i = 0; i < meshesLength; ++i) { + var mesh = meshes[i]; + var primitives = mesh.primitives; + var primitivesLength = primitives.length; + for (var j = 0; j < primitivesLength; ++j) { + var primitive = primitives[j]; + material = materials[primitive.material]; + if (!defined(primitive.attributes.TEXCOORD_0)) { + expect(material.pbrMetallicRoughness.baseColorTexture).toBeUndefined(); + } + } + } + }); + function expandObjData(objData, duplicatesLength) { var primitive = objData.nodes[0].meshes[0].primitives[0]; var indices = primitive.indices; From 1f0278ad0c230962baf00f0efbe8fb23bc00b26c Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Mon, 29 Oct 2018 23:14:24 -0400 Subject: [PATCH 3/5] Update CHANGES.md --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 2ea9df4..6c8718d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ Change Log ========== +### 2.3.2 ????-??-?? +* Improved handling of primitives with different attributes using the same material. Materials are now duplicated. [#162](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/162) +* Fixed a bug where primitives without texture coordinates could use materials containing textures. Those textures are now removed. [#162](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/162) + ### 2.3.1 2018-10-16 * Improved parsing models with concave or n-sided faces. [#157](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/157) From a55ea696617cecf764f179d11657c378edf58ead Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Mon, 29 Oct 2018 23:58:55 -0400 Subject: [PATCH 4/5] Cleanup test --- specs/lib/createGltfSpec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/lib/createGltfSpec.js b/specs/lib/createGltfSpec.js index 26f6929..06eeb58 100644 --- a/specs/lib/createGltfSpec.js +++ b/specs/lib/createGltfSpec.js @@ -175,8 +175,6 @@ describe('createGltf', function() { var gltf = createGltf(mixedAttributesObjData, options); var materials = gltf.materials; var meshes = gltf.meshes; - var i; - var material; var referenceMaterial = mixedAttributesObjData.materials[0]; delete referenceMaterial.name; @@ -225,13 +223,13 @@ describe('createGltf', function() { // Test that primitives without uvs reference materials without textures var meshesLength = meshes.length; - for (i = 0; i < meshesLength; ++i) { + for (var i = 0; i < meshesLength; ++i) { var mesh = meshes[i]; var primitives = mesh.primitives; var primitivesLength = primitives.length; for (var j = 0; j < primitivesLength; ++j) { var primitive = primitives[j]; - material = materials[primitive.material]; + var material = materials[primitive.material]; if (!defined(primitive.attributes.TEXCOORD_0)) { expect(material.pbrMetallicRoughness.baseColorTexture).toBeUndefined(); } From eaca567a259a3d222fa75cfcab524dd027bdb15b Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 31 Oct 2018 20:47:52 -0400 Subject: [PATCH 5/5] Updates --- lib/createGltf.js | 52 +++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/lib/createGltf.js b/lib/createGltf.js index 27e9b62..06a573d 100644 --- a/lib/createGltf.js +++ b/lib/createGltf.js @@ -199,7 +199,7 @@ function getTexture(gltf, texture) { } function cloneMaterial(material, removeTextures) { - if (material === null || typeof material !== 'object') { + if (typeof material !== 'object') { return material; } else if (material instanceof Texture) { if (removeTextures) { @@ -236,7 +236,7 @@ function resolveTextures(gltf, material) { } } -function addMaterial(gltf, material) { +function addGltfMaterial(gltf, material) { resolveTextures(gltf, material); var materialIndex = gltf.materials.length; gltf.materials.push(material); @@ -261,12 +261,12 @@ function getMaterialIndex(materials, materialName) { } } -function getMaterial(gltf, materials, materialName) { +function getOrCreateGltfMaterial(gltf, materials, materialName) { var material = getMaterialByName(materials, materialName); var materialIndex = getMaterialIndex(gltf.materials, materialName); if (!defined(materialIndex)) { - materialIndex = addMaterial(gltf, material); + materialIndex = addGltfMaterial(gltf, material); } return materialIndex; @@ -277,6 +277,18 @@ function primitiveInfoMatch(a, b) { a.hasNormals === b.hasNormals; } +function getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial) { + var splitMaterialName = originalMaterialName; + var suffix = 2; + while (defined(primitiveInfoByMaterial[splitMaterialName])) { + if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[splitMaterialName])) { + break; + } + splitMaterialName = originalMaterialName + '-' + suffix++; + } + return splitMaterialName; +} + function splitIncompatibleMaterials(nodes, materials, options) { var splitMaterials = []; var primitiveInfoByMaterial = {}; @@ -296,31 +308,23 @@ function splitIncompatibleMaterials(nodes, materials, options) { hasNormals : hasNormals }; var originalMaterialName = defaultValue(primitive.material, 'default'); - var materialName = originalMaterialName; - var suffix = 2; - while (defined(primitiveInfoByMaterial[materialName])) { - if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[materialName])) { - break; - } - materialName = originalMaterialName + '-' + suffix++; - } + var splitMaterialName = getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial); + primitive.material = splitMaterialName; + primitiveInfoByMaterial[splitMaterialName] = primitiveInfo; - primitive.material = materialName; - primitiveInfoByMaterial[materialName] = primitiveInfo; - - var material = getMaterialByName(splitMaterials, materialName); - if (defined(material)) { + var splitMaterial = getMaterialByName(splitMaterials, splitMaterialName); + if (defined(splitMaterial)) { continue; } - material = getMaterialByName(materials, originalMaterialName); - if (defined(material)) { - material = cloneMaterial(material, !hasUvs); + var originalMaterial = getMaterialByName(materials, originalMaterialName); + if (defined(originalMaterial)) { + splitMaterial = cloneMaterial(originalMaterial, !hasUvs); } else { - material = getDefaultMaterial(options); + splitMaterial = getDefaultMaterial(options); } - material.name = materialName; - splitMaterials.push(material); + splitMaterial.name = splitMaterialName; + splitMaterials.push(splitMaterial); } } } @@ -422,7 +426,7 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti primitive.uvs = undefined; primitive.indices = undefined; - var materialIndex = getMaterial(gltf, materials, primitive.material); + var materialIndex = getOrCreateGltfMaterial(gltf, materials, primitive.material); return { attributes : attributes,