mirror of
https://github.com/CesiumGS/obj2gltf.git
synced 2024-11-23 08:34:14 -05:00
Merge pull request #162 from AnalyticalGraphicsInc/material-duplication
Duplicate materials with mismatching attributes
This commit is contained in:
commit
ac03e9f8ee
@ -2,7 +2,8 @@ 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)
|
||||
* Improved parsing of faces with mismatching attributes. [#161](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/161)
|
||||
|
||||
### 2.3.1 2018-10-16
|
||||
|
@ -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 (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)) {
|
||||
@ -207,50 +236,101 @@ function resolveTextures(gltf, material) {
|
||||
}
|
||||
}
|
||||
|
||||
function addMaterial(gltf, material) {
|
||||
function addGltfMaterial(gltf, material) {
|
||||
resolveTextures(gltf, material);
|
||||
var materialIndex = gltf.materials.length;
|
||||
gltf.materials.push(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 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;
|
||||
}
|
||||
|
||||
function primitiveInfoMatch(a, b) {
|
||||
return a.hasUvs === b.hasUvs &&
|
||||
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 = {};
|
||||
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 splitMaterialName = getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial);
|
||||
primitive.material = splitMaterialName;
|
||||
primitiveInfoByMaterial[splitMaterialName] = primitiveInfo;
|
||||
|
||||
var splitMaterial = getMaterialByName(splitMaterials, splitMaterialName);
|
||||
if (defined(splitMaterial)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var originalMaterial = getMaterialByName(materials, originalMaterialName);
|
||||
if (defined(originalMaterial)) {
|
||||
splitMaterial = cloneMaterial(originalMaterial, !hasUvs);
|
||||
} else {
|
||||
splitMaterial = getDefaultMaterial(options);
|
||||
}
|
||||
splitMaterial.name = splitMaterialName;
|
||||
splitMaterials.push(splitMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
return splitMaterials;
|
||||
}
|
||||
|
||||
function addVertexAttribute(gltf, array, components, name) {
|
||||
var count = array.length / components;
|
||||
var minMax = array.getMinMax(components);
|
||||
@ -309,7 +389,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 +426,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 = getOrCreateGltfMaterial(gltf, materials, primitive.material);
|
||||
|
||||
return {
|
||||
attributes : attributes,
|
||||
@ -356,12 +436,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 = {
|
||||
|
13
specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl
Normal file
13
specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl
Normal file
@ -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
|
67
specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj
Normal file
67
specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj
Normal file
@ -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
|
BIN
specs/data/box-mixed-attributes-2/cesium.png
Normal file
BIN
specs/data/box-mixed-attributes-2/cesium.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
@ -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,72 @@ 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 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 (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];
|
||||
var 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;
|
||||
|
Loading…
Reference in New Issue
Block a user