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.

3 Likes

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
1 Like

@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

Hello my name is Ovidiu. I am FX Artist in Houdini FX. I have a big issue at this moment . I create one simulation in Houdini. Cubes simulattions, low poly, and i succeed to export is as GLB sequence, my issue is ho to import all texturest to final GLB output? It is a way? Tanks. Good Day.

Hi, If you take out an Obj Seq and you already have a Texture Seq, you can run the code provided by @donmccurdy. Just change the following line to how many frames you have.

const COUNT = 20;

Then I think you will be good to go

Hello , tanks for you fast reply. I try it to make exactly like in that instructions. But tell me please how i create folders. For exaple. I put the all obj sequence in one folder on Desktop folder i will name Simulation, ok? then?where i make modifications in code? Or what i must to do exactly step by step? this will save me for a lot a time, i dont sleep from one week well trying to resolve that Problem. Can you help me with all steps? Tanks.

Hello KT-man, i fallow all steps, i create one agnis folder to match with all code depencyes with obj on desktop, i export as glb sequence and is working only glb, when i try to use >node ./convert.js code from desktop it give me that error:

I dont figure out where i make mistake. All the folders i put them in Desktop, agnis obj sequence, final glb and convert js code. maybe in code i must to change something? i change from 20 to 380 frames how many i have in simulations…