Importing OBJ seq with Texture seq

Hi, I am currently working on a project that requires me to have a .glb output. Threejs helps me to get a .glb output.

I am currently importing an OBJ Seq with a Texture File for each frame of OBJ. i.e. I have an OBJ seq and a Texture seq. The Obj importer is working fine but I have to assign a texture to the corresponding OBJ mesh. Right now I’m assigning one map to every .obj file but that’s not possible for a large number of meshes.

Is there any script that can help me import the the Texture Maps and automatically assign it to the mesh

mesh_1.obj ----- texture_1.jpg
mesh_2.obj ----- texture_2.jpg
mesh_3.obj ----- texture_3.jpg
mesh_4.obj ----- texture_4.jpg

Here are the obj & tex seq I’m working on

Here’s how I’d do this, at least…

const fs = require('fs');
const obj2gltf = require('obj2gltf');
const { Document, BufferUtils, NodeIO } = require('@gltf-transform/core');
const { sequence } = require('@gltf-transform/lib');

const COUNT = 20;
const io = new NodeIO();

// Load OBJ, convert to glTF, and attach the assigned texture.
const promises = [];
for (let i = 1; i <= COUNT; i++) {
	const paddedIndex = (i + '').padStart(3, '0');
	// Use obj2gltf to convert to glTF.
	const promise = obj2gltf(`agnis_${paddedIndex}.obj`, {binary: true})
		.then((glb) => {
			// Open the glTF file for editing.
			const doc = io.readBinary(BufferUtils.trim(glb));

			// Because of some weirdness in the OBJ file (this is common), the
			// MAT file doesn't load correctly, and the glTF that obj2gltf
			// creates has empty materials. We'll add the texture here.
			const baseColorTexture = doc.createTexture()
				.setImage(fs.readFileSync(`agnis_${paddedIndex}.jpeg`))
				.setMimeType('image/jpeg');
			for (const mat of doc.getRoot().listMaterials()) {
				mat.setBaseColorTexture(baseColorTexture);
			}

			// Assign a known name to the root node, referenced by the
			// 'pattern' argument to sequence() later on.
			const rootNode = doc.getRoot().listNodes()[0];
			rootNode.setName(`agnis_${paddedIndex}`);

			return doc;
		});
	promises.push(promise);
}

Promise.all(promises).then(async (documents) => {
	const doc = new Document();
	const root = doc.getRoot();

	// Merge all glTF files
	for (const _doc of documents) {
		doc.merge(_doc);
	}

	// Initially, the merged glTF contains many Buffers and Scenes, one for
	// each input file. To write a GLB animating through each of them we'll
	// need to consolidate.
	const buffer = root.listBuffers()[0];
	const scene = root.listScenes()[0];
	root.listNodes().forEach((n) => scene.addChild(n));
	root.listAccessors().forEach((a) => a.setBuffer(buffer));
	root.listScenes().forEach((s, i) => i > 0 ? s.dispose() : null);
	root.listBuffers().forEach((b, i) => i > 0 ? b.dispose() : null);

	// Animate the nodes, using the naming pattern we assigned earlier.
	await doc.transform(sequence({pattern: /agnis_\d+/}));

	io.write('output.glb', doc);
});

Note that you’ll still have one texture per OBJ file, but they’re assigned programmatically this way. At some point you’ll hit the “too much texture memory” problem, each 2K texture requires ~12MB of GPU memory I think, and there are 20 in this file. That’s where a skinned mesh with a single texture can perform better than a sequence of mesh/texture pairs, but obviously it’s a very different art workflow.

1 Like

Thanks for your reply, but I’m new to threejs, Can you tell me where should I put this code and at which step of the process

The code above runs independently of three.js. If you have a folder with the same files you attached earlier, paste that code into a file named convert.js, and install its dependencies, then you can run it using Node.js.

In a terminal:

# install dependencies
npm install obj2gltf @gltf-transform/core @gltf-transform/lib @gltf-transform/extensions

# run script
node ./convert.js

@donmccurdy You are a LEGEND! Thanks a lot!

1 Like

@donmccurdy Hi, So i was testing your code to see when will it cap. I understood it can easily embed a couple second files in it without any hiccup. But if i decide to Pack 1000 objs in a GLB at 30 fps then it starts to give errors like it only takes one of 4 frames. Any solution for that?

There’s no limit inherent in the script above, other than the hardcoded COUNT = 20 line. I’m not sure what error you are seeing.

Do note that 1000 x 2K textures would be about 12 GB of GPU memory, which is more than any web application is likely able to use.

The ‘inspect’ command in the CLI might help you to see if all of your textures and meshes are present in the final GLB as expected: https://gltf-transform.donmccurdy.com/cli.html