Split incompatible materials

This commit is contained in:
Sean Lilley 2018-10-17 22:59:54 -04:00
parent b781459234
commit 9cc1ba8ec5
1 changed files with 104 additions and 28 deletions

View File

@ -4,6 +4,7 @@ var getBufferPadded = require('./getBufferPadded');
var getDefaultMaterial = require('./loadMtl').getDefaultMaterial; var getDefaultMaterial = require('./loadMtl').getDefaultMaterial;
var Texture = require('./Texture'); var Texture = require('./Texture');
var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; var defined = Cesium.defined;
var WebGLConstants = Cesium.WebGLConstants; var WebGLConstants = Cesium.WebGLConstants;
@ -23,6 +24,9 @@ function createGltf(objData, options) {
var materials = objData.materials; var materials = objData.materials;
var name = objData.name; var name = objData.name;
// Split materials used by primitives with different types of attributes
materials = splitIncompatibleMaterials(nodes, materials, options);
var gltf = { var gltf = {
accessors : [], accessors : [],
asset : {}, asset : {},
@ -70,14 +74,14 @@ function createGltf(objData, options) {
var meshIndex; var meshIndex;
if (meshesLength === 1) { 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); addNode(gltf, node.name, meshIndex, undefined);
} else { } else {
// Add meshes as child nodes // Add meshes as child nodes
var parentIndex = addNode(gltf, node.name); var parentIndex = addNode(gltf, node.name);
for (var j = 0; j < meshesLength; ++j) { for (var j = 0; j < meshesLength; ++j) {
var mesh = meshes[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); 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) { function resolveTextures(gltf, material) {
for (var name in material) { for (var name in material) {
if (material.hasOwnProperty(name)) { if (material.hasOwnProperty(name)) {
@ -214,35 +243,27 @@ function addMaterial(gltf, material) {
return materialIndex; return materialIndex;
} }
function getMaterial(gltf, materials, materialName, options) { function getMaterialByName(materials, materialName) {
if (!defined(materialName)) {
// Create a default material if the primitive does not specify one
materialName = 'default';
}
var i;
var material;
var materialsLength = materials.length; var materialsLength = materials.length;
for (i = 0; i < materialsLength; ++i) { for (var i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) { if (materials[i].name === materialName) {
material = materials[i]; return materials[i];
break;
} }
} }
}
if (!defined(material)) { function getMaterialIndex(materials, materialName) {
material = getDefaultMaterial(options); var materialsLength = materials.length;
material.name = materialName; for (var i = 0; i < materialsLength; ++i) {
} if (materials[i].name === materialName) {
return i;
var materialIndex;
materialsLength = gltf.materials.length;
for (i = 0; i < materialsLength; ++i) {
if (gltf.materials[i].name === materialName) {
materialIndex = i;
break;
} }
} }
}
function getMaterial(gltf, materials, materialName) {
var material = getMaterialByName(materials, materialName);
var materialIndex = getMaterialIndex(gltf.materials, materialName);
if (!defined(materialIndex)) { if (!defined(materialIndex)) {
materialIndex = addMaterial(gltf, material); materialIndex = addMaterial(gltf, material);
@ -251,6 +272,61 @@ function getMaterial(gltf, materials, materialName, options) {
return materialIndex; 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) { function addVertexAttribute(gltf, array, components, name) {
var count = array.length / components; var count = array.length / components;
var minMax = array.getMinMax(components); var minMax = array.getMinMax(components);
@ -309,7 +385,7 @@ function requiresUint32Indices(nodes) {
return false; 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 hasPositions = primitive.positions.length > 0;
var hasNormals = primitive.normals.length > 0; var hasNormals = primitive.normals.length > 0;
var hasUVs = primitive.uvs.length > 0; var hasUVs = primitive.uvs.length > 0;
@ -346,7 +422,7 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti
primitive.uvs = undefined; primitive.uvs = undefined;
primitive.indices = undefined; primitive.indices = undefined;
var materialIndex = getMaterial(gltf, materials, primitive.material, options); var materialIndex = getMaterial(gltf, materials, primitive.material);
return { return {
attributes : attributes, 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 gltfPrimitives = [];
var primitives = mesh.primitives; var primitives = mesh.primitives;
var primitivesLength = primitives.length; var primitivesLength = primitives.length;
for (var i = 0; i < primitivesLength; ++i) { 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 = { var gltfMesh = {