obj2gltf/lib/createGltf.js

545 lines
18 KiB
JavaScript
Raw Normal View History

2017-03-13 15:28:51 -04:00
'use strict';
const BUFFER_MAX_BYTE_LENGTH = require('buffer').constants.MAX_LENGTH;
2019-02-05 20:59:09 -05:00
const Cesium = require('cesium');
const getBufferPadded = require('./getBufferPadded');
const getDefaultMaterial = require('./loadMtl').getDefaultMaterial;
const Texture = require('./Texture');
2016-07-22 14:09:13 -04:00
2019-02-05 20:59:09 -05:00
const defaultValue = Cesium.defaultValue;
const defined = Cesium.defined;
const WebGLConstants = Cesium.WebGLConstants;
2015-10-16 17:32:23 -04:00
module.exports = createGltf;
2017-03-13 15:28:51 -04:00
/**
* Create a glTF from obj data.
*
* @param {Object} objData An object containing an array of nodes containing geometry information and an array of materials.
* @param {Object} options The options object passed along from lib/obj2gltf.js
2017-04-18 11:56:08 -04:00
* @returns {Object} A glTF asset.
2017-03-13 15:28:51 -04:00
*
* @private
*/
2017-04-18 11:56:08 -04:00
function createGltf(objData, options) {
2019-02-05 20:59:09 -05:00
const nodes = objData.nodes;
let materials = objData.materials;
const name = objData.name;
2015-10-16 17:32:23 -04:00
2018-10-17 22:59:54 -04:00
// Split materials used by primitives with different types of attributes
materials = splitIncompatibleMaterials(nodes, materials, options);
2019-02-05 20:59:09 -05:00
const gltf = {
2017-04-18 11:56:08 -04:00
accessors : [],
2016-06-09 13:33:08 -04:00
asset : {},
2017-04-18 11:56:08 -04:00
buffers : [],
bufferViews : [],
2017-05-04 15:39:01 -04:00
extensionsUsed : [],
extensionsRequired : [],
2017-04-18 11:56:08 -04:00
images : [],
materials : [],
meshes : [],
nodes : [],
samplers : [],
scene : 0,
scenes : [],
textures : []
2016-06-09 13:33:08 -04:00
};
gltf.asset = {
2017-03-13 15:28:51 -04:00
generator : 'obj2gltf',
2017-04-18 11:56:08 -04:00
version: '2.0'
2016-06-09 13:33:08 -04:00
};
2017-04-18 11:56:08 -04:00
gltf.scenes.push({
2017-03-13 15:28:51 -04:00
nodes : []
2017-04-18 11:56:08 -04:00
});
2019-02-05 20:59:09 -05:00
const bufferState = {
2017-07-19 17:56:24 -04:00
positionBuffers : [],
normalBuffers : [],
uvBuffers : [],
2017-04-18 11:56:08 -04:00
indexBuffers : [],
2017-07-19 17:56:24 -04:00
positionAccessors : [],
normalAccessors : [],
uvAccessors : [],
indexAccessors : []
2016-06-09 13:33:08 -04:00
};
2019-02-05 20:59:09 -05:00
const uint32Indices = requiresUint32Indices(nodes);
2016-06-09 13:33:08 -04:00
2019-02-05 20:59:09 -05:00
const nodesLength = nodes.length;
for (let i = 0; i < nodesLength; ++i) {
const node = nodes[i];
const meshes = node.meshes;
const meshesLength = meshes.length;
2017-03-13 15:28:51 -04:00
2017-04-18 11:56:08 -04:00
if (meshesLength === 1) {
2019-02-05 20:59:09 -05:00
const meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, meshes[0], options);
addNode(gltf, node.name, meshIndex, undefined);
2017-04-18 11:56:08 -04:00
} else {
// Add meshes as child nodes
2019-02-05 20:59:09 -05:00
const parentIndex = addNode(gltf, node.name);
for (let j = 0; j < meshesLength; ++j) {
const mesh = meshes[j];
const meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, mesh, options);
2017-04-18 11:56:08 -04:00
addNode(gltf, mesh.name, meshIndex, parentIndex);
2017-03-13 15:28:51 -04:00
}
2017-04-18 11:56:08 -04:00
}
2016-06-09 13:33:08 -04:00
}
2015-10-16 17:32:23 -04:00
if (gltf.images.length > 0) {
2017-04-18 11:56:08 -04:00
gltf.samplers.push({
2017-03-13 15:28:51 -04:00
magFilter : WebGLConstants.LINEAR,
2017-07-17 14:38:20 -04:00
minFilter : WebGLConstants.NEAREST_MIPMAP_LINEAR,
2017-03-13 15:28:51 -04:00
wrapS : WebGLConstants.REPEAT,
wrapT : WebGLConstants.REPEAT
2017-04-18 11:56:08 -04:00
});
2017-03-13 15:28:51 -04:00
}
addBuffers(gltf, bufferState, name, options.separate);
if (options.specularGlossiness) {
gltf.extensionsUsed.push('KHR_materials_pbrSpecularGlossiness');
gltf.extensionsRequired.push('KHR_materials_pbrSpecularGlossiness');
2018-08-30 16:02:54 -04:00
}
2018-08-30 15:55:32 -04:00
if (options.unlit) {
gltf.extensionsUsed.push('KHR_materials_unlit');
gltf.extensionsRequired.push('KHR_materials_unlit');
}
2017-04-18 11:56:08 -04:00
return gltf;
}
function addCombinedBufferView(gltf, buffers, accessors, byteStride, target) {
2019-02-05 20:59:09 -05:00
const length = buffers.length;
2017-07-19 17:56:24 -04:00
if (length === 0) {
return;
}
2019-02-05 20:59:09 -05:00
const bufferViewIndex = gltf.bufferViews.length;
const previousBufferView = gltf.bufferViews[bufferViewIndex - 1];
const byteOffset = defined(previousBufferView) ? previousBufferView.byteOffset + previousBufferView.byteLength : 0;
let byteLength = 0;
for (let i = 0; i < length; ++i) {
const accessor = gltf.accessors[accessors[i]];
2017-07-19 17:56:24 -04:00
accessor.bufferView = bufferViewIndex;
accessor.byteOffset = byteLength;
byteLength += buffers[i].length;
}
gltf.bufferViews.push({
name : 'bufferView_' + bufferViewIndex,
buffer : 0,
byteLength : byteLength,
byteOffset : byteOffset,
byteStride : byteStride,
target : target
});
}
2017-04-18 11:56:08 -04:00
function addCombinedBuffers(gltf, bufferState, name) {
addCombinedBufferView(gltf, bufferState.positionBuffers, bufferState.positionAccessors, 12, WebGLConstants.ARRAY_BUFFER);
addCombinedBufferView(gltf, bufferState.normalBuffers, bufferState.normalAccessors, 12, WebGLConstants.ARRAY_BUFFER);
addCombinedBufferView(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER);
addCombinedBufferView(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER);
2017-04-18 11:56:08 -04:00
2019-02-05 20:59:09 -05:00
let buffers = [];
2017-07-19 17:56:24 -04:00
buffers = buffers.concat(bufferState.positionBuffers, bufferState.normalBuffers, bufferState.uvBuffers, bufferState.indexBuffers);
2019-02-05 20:59:09 -05:00
const buffer = getBufferPadded(Buffer.concat(buffers));
2017-04-18 11:56:08 -04:00
gltf.buffers.push({
name : name,
2017-07-19 17:56:24 -04:00
byteLength : buffer.length,
2017-04-18 11:56:08 -04:00
extras : {
_obj2gltf : {
source : buffer
2017-03-13 15:28:51 -04:00
}
2015-10-16 17:32:23 -04:00
}
2017-04-18 11:56:08 -04:00
});
}
function addSeparateBufferView(gltf, buffer, accessor, byteStride, target, name) {
const bufferIndex = gltf.buffers.length;
const bufferViewIndex = gltf.bufferViews.length;
gltf.buffers.push({
name : name + '_' + bufferIndex,
byteLength : buffer.length,
extras : {
_obj2gltf : {
source : buffer
}
}
});
gltf.bufferViews.push({
buffer : bufferIndex,
byteLength : buffer.length,
byteOffset : 0,
byteStride : byteStride,
target : target
});
gltf.accessors[accessor].bufferView = bufferViewIndex;
gltf.accessors[accessor].byteOffset = 0;
}
function addSeparateBufferViews(gltf, buffers, accessors, byteStride, target, name) {
const length = buffers.length;
for (let i = 0; i < length; ++i) {
addSeparateBufferView(gltf, buffers[i], accessors[i], byteStride, target, name);
}
}
function addSeparateBuffers(gltf, bufferState, name) {
addSeparateBufferViews(gltf, bufferState.positionBuffers, bufferState.positionAccessors, 12, WebGLConstants.ARRAY_BUFFER, name);
addSeparateBufferViews(gltf, bufferState.normalBuffers, bufferState.normalAccessors, 12, WebGLConstants.ARRAY_BUFFER, name);
addSeparateBufferViews(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER, name);
addSeparateBufferViews(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER, name);
}
function addBuffers(gltf, bufferState, name, separate) {
const buffers = bufferState.positionBuffers.concat(bufferState.normalBuffers, bufferState.uvBuffers, bufferState.indexBuffers);
const buffersLength = buffers.length;
let buffersByteLength = 0;
for (let i = 0; i < buffersLength; ++i) {
buffersByteLength += buffers[i].length;
}
if (separate && (buffersByteLength > createGltf._getBufferMaxByteLength())) {
// Don't combine buffers if the combined buffer will exceed the Node limit.
addSeparateBuffers(gltf, bufferState, name);
} else {
addCombinedBuffers(gltf, bufferState, name);
}
}
function addTexture(gltf, texture) {
2019-02-05 20:59:09 -05:00
const imageName = texture.name;
const textureName = texture.name;
const imageIndex = gltf.images.length;
const textureIndex = gltf.textures.length;
2016-06-09 13:33:08 -04:00
2017-04-18 11:56:08 -04:00
gltf.images.push({
name : imageName,
extras : {
_obj2gltf : texture
2016-06-09 13:33:08 -04:00
}
2017-04-18 11:56:08 -04:00
});
gltf.textures.push({
name : textureName,
sampler : 0,
source : imageIndex
});
return textureIndex;
2017-04-18 11:56:08 -04:00
}
function getTexture(gltf, texture) {
2019-02-05 20:59:09 -05:00
let textureIndex;
const images = gltf.images;
const length = images.length;
2019-02-05 20:59:09 -05:00
for (let i = 0; i < length; ++i) {
if (images[i].extras._obj2gltf === texture) {
textureIndex = i;
break;
2017-04-18 11:56:08 -04:00
}
2016-06-09 13:33:08 -04:00
}
2017-04-18 11:56:08 -04:00
if (!defined(textureIndex)) {
textureIndex = addTexture(gltf, texture);
2017-04-18 11:56:08 -04:00
}
return {
index : textureIndex
};
2017-04-18 11:56:08 -04:00
}
2017-03-13 15:28:51 -04:00
2018-10-17 22:59:54 -04:00
function cloneMaterial(material, removeTextures) {
2018-10-31 20:47:52 -04:00
if (typeof material !== 'object') {
2018-10-17 22:59:54 -04:00
return material;
} else if (material instanceof Texture) {
if (removeTextures) {
return undefined;
}
return material;
} else if (Array.isArray(material)) {
2019-02-05 20:59:09 -05:00
const length = material.length;
const clonedArray = new Array(length);
for (let i = 0; i < length; ++i) {
2018-10-17 22:59:54 -04:00
clonedArray[i] = cloneMaterial(material[i], removeTextures);
}
return clonedArray;
}
2019-02-05 20:59:09 -05:00
const clonedObject = {};
for (const name in material) {
2019-06-22 06:54:09 -04:00
if (Object.prototype.hasOwnProperty.call(material, name)) {
2018-10-17 22:59:54 -04:00
clonedObject[name] = cloneMaterial(material[name], removeTextures);
}
}
return clonedObject;
}
function resolveTextures(gltf, material) {
2019-02-05 20:59:09 -05:00
for (const name in material) {
2019-06-22 06:54:09 -04:00
if (Object.prototype.hasOwnProperty.call(material, name)) {
2019-02-05 20:59:09 -05:00
const property = material[name];
if (property instanceof Texture) {
material[name] = getTexture(gltf, property);
} else if (!Array.isArray(property) && (typeof property === 'object')) {
resolveTextures(gltf, property);
}
2017-05-04 15:39:01 -04:00
}
}
}
2018-11-24 17:04:09 -05:00
function addGltfMaterial(gltf, material, options) {
resolveTextures(gltf, material);
2019-02-05 20:59:09 -05:00
const materialIndex = gltf.materials.length;
2018-08-30 15:55:32 -04:00
if (options.unlit) {
if (!defined(material.extensions)) {
material.extensions = {};
}
material.extensions.KHR_materials_unlit = {};
}
gltf.materials.push(material);
2017-04-18 11:56:08 -04:00
return materialIndex;
}
2018-10-17 22:59:54 -04:00
function getMaterialByName(materials, materialName) {
2019-02-05 20:59:09 -05:00
const materialsLength = materials.length;
for (let i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) {
2018-10-17 22:59:54 -04:00
return materials[i];
2017-04-18 11:56:08 -04:00
}
}
2018-10-17 22:59:54 -04:00
}
2017-04-18 11:56:08 -04:00
2018-10-17 22:59:54 -04:00
function getMaterialIndex(materials, materialName) {
2019-02-05 20:59:09 -05:00
const materialsLength = materials.length;
for (let i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) {
2018-10-17 22:59:54 -04:00
return i;
2017-04-18 11:56:08 -04:00
}
}
2018-10-17 22:59:54 -04:00
}
2018-11-24 17:04:09 -05:00
function getOrCreateGltfMaterial(gltf, materials, materialName, options) {
2019-02-05 20:59:09 -05:00
const material = getMaterialByName(materials, materialName);
let materialIndex = getMaterialIndex(gltf.materials, materialName);
2017-04-18 11:56:08 -04:00
if (!defined(materialIndex)) {
2018-11-24 17:04:09 -05:00
materialIndex = addGltfMaterial(gltf, material, options);
}
2017-04-18 11:56:08 -04:00
return materialIndex;
}
2018-10-17 22:59:54 -04:00
function primitiveInfoMatch(a, b) {
return a.hasUvs === b.hasUvs &&
a.hasNormals === b.hasNormals;
}
2018-10-31 20:47:52 -04:00
function getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial) {
2019-02-05 20:59:09 -05:00
let splitMaterialName = originalMaterialName;
let suffix = 2;
2018-10-31 20:47:52 -04:00
while (defined(primitiveInfoByMaterial[splitMaterialName])) {
if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[splitMaterialName])) {
2017-05-04 17:58:13 -04:00
break;
}
2018-10-31 20:47:52 -04:00
splitMaterialName = originalMaterialName + '-' + suffix++;
2017-05-04 17:58:13 -04:00
}
2018-10-31 20:47:52 -04:00
return splitMaterialName;
}
2018-10-17 22:59:54 -04:00
function splitIncompatibleMaterials(nodes, materials, options) {
2019-02-05 20:59:09 -05:00
const splitMaterials = [];
const primitiveInfoByMaterial = {};
const nodesLength = nodes.length;
for (let i = 0; i < nodesLength; ++i) {
const meshes = nodes[i].meshes;
const meshesLength = meshes.length;
for (let j = 0; j < meshesLength; ++j) {
const primitives = meshes[j].primitives;
const primitivesLength = primitives.length;
for (let k = 0; k < primitivesLength; ++k) {
const primitive = primitives[k];
const hasUvs = primitive.uvs.length > 0;
const hasNormals = primitive.normals.length > 0;
const primitiveInfo = {
2018-10-17 22:59:54 -04:00
hasUvs : hasUvs,
hasNormals : hasNormals
};
2019-02-05 20:59:09 -05:00
const originalMaterialName = defaultValue(primitive.material, 'default');
const splitMaterialName = getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial);
2018-10-31 20:47:52 -04:00
primitive.material = splitMaterialName;
primitiveInfoByMaterial[splitMaterialName] = primitiveInfo;
2018-10-17 22:59:54 -04:00
2019-02-05 20:59:09 -05:00
let splitMaterial = getMaterialByName(splitMaterials, splitMaterialName);
2018-10-31 20:47:52 -04:00
if (defined(splitMaterial)) {
2018-10-17 22:59:54 -04:00
continue;
}
2019-02-05 20:59:09 -05:00
const originalMaterial = getMaterialByName(materials, originalMaterialName);
2018-10-31 20:47:52 -04:00
if (defined(originalMaterial)) {
splitMaterial = cloneMaterial(originalMaterial, !hasUvs);
2018-10-17 22:59:54 -04:00
} else {
2018-10-31 20:47:52 -04:00
splitMaterial = getDefaultMaterial(options);
2018-10-17 22:59:54 -04:00
}
2018-10-31 20:47:52 -04:00
splitMaterial.name = splitMaterialName;
splitMaterials.push(splitMaterial);
2018-10-17 22:59:54 -04:00
}
}
2017-04-18 11:56:08 -04:00
}
2018-10-17 22:59:54 -04:00
return splitMaterials;
2017-04-18 11:56:08 -04:00
}
2017-07-19 17:56:24 -04:00
function addVertexAttribute(gltf, array, components, name) {
2019-02-05 20:59:09 -05:00
const count = array.length / components;
const minMax = array.getMinMax(components);
const type = (components === 3 ? 'VEC3' : 'VEC2');
2017-04-18 11:56:08 -04:00
2019-02-05 20:59:09 -05:00
const accessor = {
2017-05-04 17:58:13 -04:00
name : name,
2017-04-18 11:56:08 -04:00
componentType : WebGLConstants.FLOAT,
count : count,
min : minMax.min,
max : minMax.max,
type : type
2017-03-13 15:28:51 -04:00
};
2019-02-05 20:59:09 -05:00
const accessorIndex = gltf.accessors.length;
2017-04-18 11:56:08 -04:00
gltf.accessors.push(accessor);
return accessorIndex;
}
2017-07-19 17:56:24 -04:00
function addIndexArray(gltf, array, uint32Indices, name) {
2019-02-05 20:59:09 -05:00
const componentType = uint32Indices ? WebGLConstants.UNSIGNED_INT : WebGLConstants.UNSIGNED_SHORT;
const count = array.length;
const minMax = array.getMinMax(1);
2017-04-18 11:56:08 -04:00
2019-02-05 20:59:09 -05:00
const accessor = {
2017-05-04 17:58:13 -04:00
name : name,
2017-04-18 11:56:08 -04:00
componentType : componentType,
count : count,
min : minMax.min,
max : minMax.max,
type : 'SCALAR'
2017-03-13 15:28:51 -04:00
};
2019-02-05 20:59:09 -05:00
const accessorIndex = gltf.accessors.length;
2017-04-18 11:56:08 -04:00
gltf.accessors.push(accessor);
return accessorIndex;
}
function requiresUint32Indices(nodes) {
2019-02-05 20:59:09 -05:00
const nodesLength = nodes.length;
for (let i = 0; i < nodesLength; ++i) {
const meshes = nodes[i].meshes;
const meshesLength = meshes.length;
for (let j = 0; j < meshesLength; ++j) {
const primitives = meshes[j].primitives;
const primitivesLength = primitives.length;
for (let k = 0; k < primitivesLength; ++k) {
// Reserve the 65535 index for primitive restart
2019-02-05 20:59:09 -05:00
const vertexCount = primitives[k].positions.length / 3;
if (vertexCount > 65534) {
return true;
}
2017-04-18 11:56:08 -04:00
}
}
}
return false;
}
2018-11-24 17:04:09 -05:00
function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index, options) {
2019-02-05 20:59:09 -05:00
const hasPositions = primitive.positions.length > 0;
const hasNormals = primitive.normals.length > 0;
const hasUVs = primitive.uvs.length > 0;
2017-04-18 11:56:08 -04:00
2019-02-05 20:59:09 -05:00
const attributes = {};
2017-04-18 11:56:08 -04:00
if (hasPositions) {
2019-02-05 20:59:09 -05:00
const accessorIndex = addVertexAttribute(gltf, primitive.positions, 3, mesh.name + '_' + index + '_positions');
2017-07-19 17:56:24 -04:00
attributes.POSITION = accessorIndex;
bufferState.positionBuffers.push(primitive.positions.toFloatBuffer());
2017-07-19 17:56:24 -04:00
bufferState.positionAccessors.push(accessorIndex);
2017-04-18 11:56:08 -04:00
}
if (hasNormals) {
2019-02-05 20:59:09 -05:00
const accessorIndex = addVertexAttribute(gltf, primitive.normals, 3, mesh.name + '_' + index + '_normals');
2017-07-19 17:56:24 -04:00
attributes.NORMAL = accessorIndex;
bufferState.normalBuffers.push(primitive.normals.toFloatBuffer());
2017-07-19 17:56:24 -04:00
bufferState.normalAccessors.push(accessorIndex);
2017-04-18 11:56:08 -04:00
}
if (hasUVs) {
2019-02-05 20:59:09 -05:00
const accessorIndex = addVertexAttribute(gltf, primitive.uvs, 2, mesh.name + '_' + index + '_texcoords');
2017-07-19 17:56:24 -04:00
attributes.TEXCOORD_0 = accessorIndex;
bufferState.uvBuffers.push(primitive.uvs.toFloatBuffer());
2017-07-19 17:56:24 -04:00
bufferState.uvAccessors.push(accessorIndex);
2017-04-18 11:56:08 -04:00
}
2019-02-05 20:59:09 -05:00
const indexAccessorIndex = addIndexArray(gltf, primitive.indices, uint32Indices, mesh.name + '_' + index + '_indices');
const indexBuffer = uint32Indices ? primitive.indices.toUint32Buffer() : primitive.indices.toUint16Buffer();
bufferState.indexBuffers.push(indexBuffer);
bufferState.indexAccessors.push(indexAccessorIndex);
2017-04-18 11:56:08 -04:00
// Unload resources
primitive.positions = undefined;
primitive.normals = undefined;
primitive.uvs = undefined;
primitive.indices = undefined;
2019-02-05 20:59:09 -05:00
const materialIndex = getOrCreateGltfMaterial(gltf, materials, primitive.material, options);
return {
attributes : attributes,
indices : indexAccessorIndex,
material : materialIndex,
mode : WebGLConstants.TRIANGLES
};
}
2017-04-18 11:56:08 -04:00
2018-11-24 17:04:09 -05:00
function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) {
2019-02-05 20:59:09 -05:00
const gltfPrimitives = [];
const primitives = mesh.primitives;
const primitivesLength = primitives.length;
for (let i = 0; i < primitivesLength; ++i) {
2018-11-24 17:04:09 -05:00
gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i, options));
2017-04-18 11:56:08 -04:00
}
2019-02-05 20:59:09 -05:00
const gltfMesh = {
2017-04-18 11:56:08 -04:00
name : mesh.name,
primitives : gltfPrimitives
};
2019-02-05 20:59:09 -05:00
const meshIndex = gltf.meshes.length;
2017-04-18 11:56:08 -04:00
gltf.meshes.push(gltfMesh);
return meshIndex;
}
function addNode(gltf, name, meshIndex, parentIndex) {
2019-02-05 20:59:09 -05:00
const node = {
2017-04-18 11:56:08 -04:00
name : name,
mesh : meshIndex
};
2019-02-05 20:59:09 -05:00
const nodeIndex = gltf.nodes.length;
2017-04-18 11:56:08 -04:00
gltf.nodes.push(node);
if (defined(parentIndex)) {
2019-02-05 20:59:09 -05:00
const parentNode = gltf.nodes[parentIndex];
2017-04-18 11:56:08 -04:00
if (!defined(parentNode.children)) {
parentNode.children = [];
}
parentNode.children.push(nodeIndex);
} else {
gltf.scenes[gltf.scene].nodes.push(nodeIndex);
}
return nodeIndex;
2015-10-16 17:32:23 -04:00
}
// Exposed for testing
createGltf._getBufferMaxByteLength = function() {
return BUFFER_MAX_BYTE_LENGTH;
};