Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instancing lose node names #1034

Closed
enruilo1 opened this issue Jul 20, 2023 · 5 comments
Closed

Instancing lose node names #1034

enruilo1 opened this issue Jul 20, 2023 · 5 comments

Comments

@enruilo1
Copy link

Hi, when i use "gltf-transform instance", node names was losed in the instancing process. I want to preserve that names because it contains guid info for each node mesh and i have so many info attached to that guid.
Is there any way to preserve that name and when i load in threejs know what guid is for specific instance?
Adjoint a gltf with several nodes with guid names
GpuInstancing_old.zip

@enruilo1 enruilo1 added the bug Something isn't working label Jul 20, 2023
@donmccurdy donmccurdy added feature New enhancement or request package:functions needs investigation and removed bug Something isn't working labels Jul 21, 2023
@donmccurdy donmccurdy added this to the Backlog milestone Jul 21, 2023
@donmccurdy
Copy link
Owner

donmccurdy commented Jul 21, 2023

Hi @enruilo1! Removing nodes is inherent to what the instance operation is doing, as explained a bit more in #1018 (reply in thread). There is no canonical way to associate a string name with each instance in the glTF file, at this time. There are certain ways to associate numerical IDs with instances, not yet implemented in glTF Transform, but I'm not sure whether that works for your goals, and you'd need to write some code in three.js to access those IDs efficiently from the THREE.InstancedMesh object.

More complete workarounds would depend on draft/proposed glTF extensions, such as KhronosGroup/glTF#2082.

@donmccurdy
Copy link
Owner

/cc @javagl FYI!

@javagl
Copy link

javagl commented Jul 21, 2023

With the EXT_instance_features extension, you can assign (numerical) IDs to the instances. This is done by adding an attribute to the EXT_mesh_gpu_instancing object that contains these IDs. These IDs could then be used in a client application, to look up the GUID based on the numeric ID. (You could also use the EXT_structural_metadata extension for this, but if you don't want to associate more "metadata" with the instances, only using the numeric ID may be simpler). The EXT_instance_features extension is not sooo widely supported by viewers, but an example glTF asset that uses it can be found in the 3D Tiles glTF extensions samples.

@enruilo1
Copy link
Author

enruilo1 commented Jul 23, 2023

Cool ¡¡ EXT_instance_features and EXT_mesh_gpu_instancing could be a great solution and THREEJS is able to read EXT_instance_features and introduce that info in a "userData" property:
Captura de pantalla 2023-07-23 130803

BUT we have two problems:
1.- Gltf-Transform not support EXT_instance_features (i dont see it).
2.- When EXT_instance_features refer to EXT_structural_metadata, "propertyTable" is not read by THREEJS properly (could be an issue for that repo), but it could be insteresting to "at least" try to get work of EXT_instance_features.

@donmccurdy @javagl

Adjoin an image when instance GLTF (by GLTF-TRANSFORM) doesnt contain any instance metadata:
Captura de pantalla 2023-07-23 123137

@donmccurdy
Copy link
Owner

@enruilo1 there's no out of the box solution here, three.js does not understand EXT_instance_features, it just passes through the raw JSON from unknown extensions. It's possible to write an implementation that loads the extension and register that with THREE.GLTFLoader, but I suspect it's more work than you may want for this. Similarly, glTF Transform does not include an implementation of the extension either, although it's possible to implement custom extensions yourself.

How many node(s) are you instancing? If the number is <100, then I suspect getting this working may be more work than it is worth to you.


The quickest method I can see would be for you to create a custom version of the instance() function used by glTF Transform. Where it creates each batch ...

return batchExtension
.createInstancedMesh()
.setAttribute('TRANSLATION', batchTranslation)
.setAttribute('ROTATION', batchRotation)
.setAttribute('SCALE', batchScale);

... you'd want to add some code that creates an empty _ID attribute. Then where it writes data for each node ...

for (let i = 0; i < nodes.length; i++) {
let t: vec3, r: vec4, s: vec3;
const node = nodes[i];
batchTranslation.setElement(i, (t = node.getWorldTranslation()));
batchRotation.setElement(i, (r = node.getWorldRotation()));
batchScale.setElement(i, (s = node.getWorldScale()));

... you'd want to set the (integer) ID for each, and create an ordered array of the node names. That array can then be assigned to the instanced mesh or node, and it will be available in three.js as .userData ...

mesh.setExtras({instanceNames: [ 'name1', 'name2', 'name3', ... ]});

Then you can run your custom version of the instance() function on whatever models you need:

import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';

const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const document = await io.read('path/to/model.glb');

await document.transform( customInstance() );

await io.write('path/to/model_out.glb', document);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants