Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate materials with mismatching attributes #162

Merged
merged 6 commits into from
Nov 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
136 changes: 108 additions & 28 deletions lib/createGltf.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 : {},
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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)) {
Expand All @@ -207,48 +236,99 @@ 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';
function getMaterialByName(materials, materialName) {
var materialsLength = materials.length;
for (var i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) {
return materials[i];
}
}
}

var i;
var material;
function getMaterialIndex(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 i;
}
}
}

function getOrCreateGltfMaterial(gltf, materials, materialName) {
var material = getMaterialByName(materials, materialName);
var materialIndex = getMaterialIndex(gltf.materials, materialName);

if (!defined(material)) {
material = getDefaultMaterial(options);
material.name = materialName;
if (!defined(materialIndex)) {
materialIndex = addGltfMaterial(gltf, material);
}

var materialIndex;
materialsLength = gltf.materials.length;
for (i = 0; i < materialsLength; ++i) {
if (gltf.materials[i].name === materialName) {
materialIndex = i;
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;
}

if (!defined(materialIndex)) {
materialIndex = addMaterial(gltf, material);
}
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;
}

return materialIndex;
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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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 = {
Expand Down
13 changes: 13 additions & 0 deletions specs/data/box-mixed-attributes-2/box-mixed-attributes-2.mtl
Original file line number Diff line number Diff line change
@@ -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 changes: 67 additions & 0 deletions specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj
Original file line number Diff line number Diff line change
@@ -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
Binary file added specs/data/box-mixed-attributes-2/cesium.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading