diff --git a/bin/obj2gltf.js b/bin/obj2gltf.js index e1d1abe..1cca9a2 100755 --- a/bin/obj2gltf.js +++ b/bin/obj2gltf.js @@ -67,6 +67,11 @@ const argv = yargs type: "boolean", default: defaults.separateTextures, }, + noCombineBuffers: { + describe: "Do not combine data buffers.", + type: "boolean", + default: defaults.noCombineBuffers, + }, checkTransparency: { describe: "Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures are considered to be opaque.", @@ -205,6 +210,7 @@ const options = { binary: binary, separate: argv.separate, separateTextures: argv.separateTextures, + noCombineBuffers: argv.noCombineBuffers, checkTransparency: argv.checkTransparency, secure: argv.secure, packOcclusion: argv.packOcclusion, diff --git a/lib/createGltf.js b/lib/createGltf.js index 6bdf34a..bed598b 100644 --- a/lib/createGltf.js +++ b/lib/createGltf.js @@ -108,7 +108,7 @@ function createGltf(objData, options) { }); } - addBuffers(gltf, bufferState, name, options.separate); + addBuffers(gltf, bufferState, name, options.separate, options.noCombineBuffers); if (options.specularGlossiness) { gltf.extensionsUsed.push("KHR_materials_pbrSpecularGlossiness"); @@ -289,7 +289,7 @@ function addSeparateBuffers(gltf, bufferState, name) { ); } -function addBuffers(gltf, bufferState, name, separate) { +function addBuffers(gltf, bufferState, name, separate, noCombineBuffers) { const buffers = bufferState.positionBuffers.concat( bufferState.normalBuffers, bufferState.uvBuffers, @@ -301,8 +301,8 @@ function addBuffers(gltf, bufferState, name, separate) { buffersByteLength += buffers[i].length; } - if (separate && buffersByteLength > createGltf._getBufferMaxByteLength()) { - // Don't combine buffers if the combined buffer will exceed the Node limit. + if ((separate && buffersByteLength > createGltf._getBufferMaxByteLength()) || noCombineBuffers) { + // Don't combine buffers if the combined buffer will exceed the Node limit, or the user asked for it. addSeparateBuffers(gltf, bufferState, name); } else { addCombinedBuffers(gltf, bufferState, name); diff --git a/lib/obj2gltf.js b/lib/obj2gltf.js index 0916df9..35f2521 100644 --- a/lib/obj2gltf.js +++ b/lib/obj2gltf.js @@ -20,6 +20,7 @@ module.exports = obj2gltf; * @param {Boolean} [options.binary=false] Convert to binary glTF. * @param {Boolean} [options.separate=false] Write out separate buffer files and textures instead of embedding them in the glTF. * @param {Boolean} [options.separateTextures=false] Write out separate textures only. + * @param {Boolean} [options.noCombineBuffers=false] Do not combine buffers, * @param {Boolean} [options.checkTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. * @param {Boolean} [options.secure=false] Prevent the converter from reading textures or mtl files outside of the input obj directory. * @param {Boolean} [options.packOcclusion=false] Pack the occlusion texture in the red channel of the metallic-roughness texture. @@ -50,6 +51,7 @@ function obj2gltf(objPath, options) { options.separateTextures = defaultValue(options.separateTextures, defaults.separateTextures) || options.separate; + options.noCombineBuffers = defaultValue(options.noCombineBuffers, defaults.noCombineBuffers); options.checkTransparency = defaultValue( options.checkTransparency, defaults.checkTransparency @@ -173,6 +175,12 @@ obj2gltf.defaults = { * @default false */ separateTextures: false, + /** + * Gets or sets whether to use different buffers for different meshes. + * @type Boolean + * @default false + */ + noCombineBuffers: false, /** * Gets or sets whether the converter will do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. * @type Boolean diff --git a/lib/writeGltf.js b/lib/writeGltf.js index fc68b7a..e17effb 100644 --- a/lib/writeGltf.js +++ b/lib/writeGltf.js @@ -36,7 +36,7 @@ function writeGltf(gltf, options) { if (separate) { promises.push(writeSeparateBuffers(gltf, options)); } else if (!binary) { - writeEmbeddedBuffer(gltf); + writeEmbeddedBuffers(gltf); } const binaryBuffer = gltf.buffers[0].extras._obj2gltf.source; @@ -158,20 +158,23 @@ function writeSeparateTextures(gltf, options) { ); } -function writeEmbeddedBuffer(gltf) { - const buffer = gltf.buffers[0]; - const source = buffer.extras._obj2gltf.source; +function writeEmbeddedBuffers(gltf) { + const buffersLength = gltf.buffers.length; + for (let i = 0; i < buffersLength; ++i) { + const buffer = gltf.buffers[i]; + const source = buffer.extras._obj2gltf.source; + + // Buffers larger than ~192MB cannot be base64 encoded due to a NodeJS limitation. Source: https://github.com/nodejs/node/issues/4266 + if (source.length > 201326580) { + throw new RuntimeError( + "Buffer is too large to embed in the glTF. Use the --separate flag instead." + ); + } - // Buffers larger than ~192MB cannot be base64 encoded due to a NodeJS limitation. Source: https://github.com/nodejs/node/issues/4266 - if (source.length > 201326580) { - throw new RuntimeError( - "Buffer is too large to embed in the glTF. Use the --separate flag instead." - ); + buffer.uri = `data:application/octet-stream;base64,${source.toString( + "base64" + )}`; } - - buffer.uri = `data:application/octet-stream;base64,${source.toString( - "base64" - )}`; } function writeEmbeddedTextures(gltf) {