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

Double-sided material property not applied to objects loaded from gltf #3515

Open
maria-korosteleva opened this issue Aug 14, 2024 · 6 comments
Labels
help wanted Extra attention is needed

Comments

@maria-korosteleva
Copy link

maria-korosteleva commented Aug 14, 2024

Description

Hi all
I'm trying to display a garment 3D object, loaded as gltf. The material in my glb file is one-sided, so I tried to use the material settings from niceGUI to convert it to a double-sided material as follows:

# Camera setup
camera_location = [0, -200., 1.25]  
camera = ui.scene.perspective_camera(fov=np.pi / 6.)
camera.x = cam_location[0]
camera.y = cam_location[1]
camera.z = cam_location[2]
camera.look_at_x = 0
camera.look_at_y = 0
camera.look_at_z = cam_location[2] * 2/3

# Create scene
with ui.scene(
	width=1024,
	height=800, 
	camera=camera, 
	grid=False, 
	) as ui_3d_scene:
	ui_3d_scene.gltf(
		'geo/Configured_design_3D.glb', 
	).scale(0.01).rotate(np.pi / 2, 0., 0.).material(side='double')

However, the displayed object is still one-sided (the back of the garment visible through the neck and sleeve holes is not rendered):
image

Here is how I expect it to look like:
image

Seems like currently, material setup in gltf object takes precedence over the additional material setup, but I would expect it to be the other way around, for the material properties that are explicitly set

Here is the glb file:
Configured_design_3D_sim.zip

@falkoschindler
Copy link
Contributor

Thanks for reporting this issue, @maria-korosteleva!
Can you, please, check the glb upload? The link seems to be broken. Thanks!

@maria-korosteleva
Copy link
Author

Hi @falkoschindler, oh, sorry, it should work now!

@fabian0702
Copy link
Contributor

@maria-korosteleva The problem you're experiencing is most likely caused by nicegui loading gtlf's into a group that contains all of the gtlf's models. This would mean that in your case the code is trying to change the material of the group instead of the object itself (see here).

@falkoschindler
Copy link
Contributor

@fabian0702 seems to be right, the GLTF scene is wrapped in a Group:

} else if (type == "gltf") {
const url = args[0];
mesh = new THREE.Group();
this.gltf_loader.load(
url,
(gltf) => mesh.add(gltf.scene),
undefined,
(error) => console.error(error)
);
} else {

Do you have any idea how we could embed the file differently?

Apart from that: The side parameter can be "front", "back" or "both", but not "double". But it doesn't matter in this case.

@falkoschindler falkoschindler added the help wanted Extra attention is needed label Aug 20, 2024
@fabian0702
Copy link
Contributor

fabian0702 commented Aug 20, 2024

@falkoschindler Because gltf files can contain multiple objects, it can be difficult to change the material of just one object. Also, nicegui currently expects objects to be added to the scene immediately and the actual object data to be added later, which the current workaround solves. One possibility would be to change the callback to overwrite the initially created group with the scene instead of adding the scene to it. However, I'm not sure how elegant this would be.

@falkoschindler
Copy link
Contributor

Ok, I see three problems:

  1. Calling material() on a group (or GLTF object) does not work, because the JavaScript implementation of the material() method doesn't traverse children of groups.
  2. Calling material() on a group (or GLTF object) does not work, because the group is added first and their children are added later. So traversing the group doesn't help, because there are no children yet.
  3. Calling material() immediately after creating the GLTF object does not work, because the GLTF loader loads the object(s) asynchronously. Only when this is finished, material() can actually find the corresponding objects.

Problem 1 can be easily fixed.
Problem 2 is more challenging. We could instruct the user to add all children first before calling material() on a group. But this isn't very intuitive, as new children would be uncolored again.
Problem 3 is also tricky. But maybe the loader can transfer the material from the GLTF container onto the loaded objects.

Anyway, I wonder if there is a simpler solution somewhere in three.js. In PR #3549 for instance, we basically only had to change one flag to make groups draggable. Maybe there's something for letting child objects inherit their group's material?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants