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

Reimporting a 3D model does not get propagated to inherited scenes #38853

Closed
setzer22 opened this issue May 19, 2020 · 16 comments · Fixed by #57606
Closed

Reimporting a 3D model does not get propagated to inherited scenes #38853

setzer22 opened this issue May 19, 2020 · 16 comments · Fixed by #57606

Comments

@setzer22
Copy link

setzer22 commented May 19, 2020


Bugsquad note: This issue has been confirmed several times already. No need to confirm it further.


Godot version:

Godot Engine v3.2.1.stable.official

OS/device including version:

Arch Linux (rolling release, last updated at the time of submitting).

Issue description:

I have a 3D model imported as a scene (The format does not seem to affect, as I've tried all of them with the same behaviour. I'm using gltf2 for the reproduction example). When the model file gets modified on disk (e.g. by exporting again from a 3d modelling tool), godot reimports the asset, but changes are not shown on the inherited scene.

The chanes are only shown if I open the original scene, and then get propagated to all the scenes where this was instanced.

Steps to reproduce:

This uses the minimal reproduction project below. The project has four important resources:

  • cube.glb, a cube model
  • sphere.glb, a sphere model
  • mesh.glb, a copy of either mesh.glb or cube.glb
  • MeshInherited.tscn, an inherited version of the mesh.glb scene with no modifications, created by double-clicking mesh.glb in the FileSystem tab, selecting "New Inherited" and immediately saving.

The steps to reproduce:

  1. Open the project in godot, and open MeshInherited.tscn. Ensure no other scenes are open.
  2. Minimize godot and, using a file manager, delete mesh.glb and duplicate either cube.glb or sphere.glb to a new file. Rename the new copy as mesh.glb.
  3. Go back to godot. A reimport will be triggered, but the inherited scene will show the old mesh.
  4. Open mesh.glb (double-click in the FileSystem tab, and choose "Open Anyway"). The new mesh will be shown.
  5. Go back to the MeshInherited.tscn tab, the mesh is updated.

Minimal reproduction project:
MeshReimportIssue.zip

@Sl3dge78
Copy link
Contributor

Sl3dge78 commented Jun 18, 2020

Godot version:
Godot Engine 4.0.dev 4e0f31a

OS/device including version:
Windows 10

Issue description:
Also happens with animations embedded inside a .glb :

Steps to reproduce:
1- Import a mesh with an animation with 'Built-In' selected for 'Storage'
2- Create an inherited scene and try to edit the animation > You get a warning that you can't edit the animation (doesn't happen because of Issue #20467)
3- Reimport the asset with either 'Files' option selected. Note that the inherited scene notices a change because you get the (*) next to the scene name if it's open.
4- Go back to the animation player, in the existing Inherited Scene or a new one > The warning is still here and all changes don't get populated
5- Close the project and reopen it : everything works as expected

@phelioz
Copy link

phelioz commented Jul 11, 2020

Have this problem also, serious show stopper for 3d work in Godot. Destroys the iterative workflow

@setzer22
Copy link
Author

setzer22 commented Jul 11, 2020

@phelioz The best workaround (if we can call it that) I've found to keep an iterative workflow between my 3d app and godot is loading the gltf directly and avoid all inheritance.

To complement this, I do the following two things:

  • Try to configure as much as possible in the 3d app. For example, if using blender, you can configure a shader and it will get exported into a spatialmaterial in godot (only when using gltf). For collision shapes, lookup the -col and -colonly attributes import hints.

  • The remaining things that can't be configured in a 3d app, can be added through code: I set up a script that loads the gltf scene and does the necessary changes on top of it when the game loads.

Of course this is still a very uncomfortable workflow, but I thought this may be useful to someone reading the issue. It definitely improved things for me. When modelling, especially at the final stages, it is crucial to be able to see how things will look in-game.

@fuggla
Copy link

fuggla commented Jul 11, 2020

Setzer, thanks for sharing your workaround. Just gonna drop a link to the official docs about the import hints you mentioned (-col etc). I use them with Blender and the escn exporter.

@phelioz
Copy link

phelioz commented Jul 12, 2020

@setzer22 Thanks for sharing :)
Already using the -col and -colonly import hint and that helps a lot in many cases. You are right in that probably a lot can be setup in code on game start. But as you say it's uncomfortable.

For example if you are not doing something procedural and are placing modular meshes together to create something bigger that looks nice it just feels very weird to do all that placement in code when we have a 3d editor. Then a simpler framework without a editor could be used instead of Godot if going that route. Which is a shame because the 3d editor is pretty nice in Godot.

@anarchydev

This comment has been minimized.

@Calinou

This comment has been minimized.

@oparisy
Copy link

oparisy commented Dec 30, 2020

I can confirm I reproduced this today under Windows after building from master (f69c116fa).

Very useful scenario @setzer22, thanks for provided required assets!

@oparisy
Copy link

oparisy commented Dec 31, 2020

After some testing and studying of underlying master code, it turns out that opening mesh.glb is not the only way to get the scene refreshed. Actually, it is the act of switching back to its scene tab that updates the displayed mesh.

To demonstrate this, create a basic 3D scene (a single root Node3D) and open it before step 1 of @setzer22 scenario. Then, at step 4, click on this scene tab instead of opening mesh.glb.

Technically speaking, switching scene tabs triggers the call chain EditorNode::load_scene => EditorNode::set_current_scene => EditorData::check_and_update_scene. This last step will check if the scene needs updating by iterating on its nodes, and comparing their SceneState#get_last_modified_time with their FileAccess::get_modified_time (when meaningful).

To the contrary, when going back to Godot and reimporting (step 3), EditorNode::_resources_reimported is called (in response to a EditorFileSystem signal). It itself calls EditorNode::reload_scene for each reimported scene, so, here, mesh.glb and its material, but not MeshInherited.tscn.

@oparisy
Copy link

oparisy commented Jan 2, 2021

My takes from the previous comment.

Should EditorNode::_resources_reimported be modified to also call EditorNode::reload_scene on MeshInherited.tscn, I reckon it would call EditorNode::load_scene and refresh it, solving this issue.

However, I am wondering about more complex "transitive refresh" scenarios: should a scene S1 instantiate a scene S2 itself instantiating a glTF-imported scene S3, and should S3 be reimported, I don't think even the "switch tab" scenario above would refresh S1. This needs some testing.

Should this be true and EditorNode::_resources_reimported be modified further to take into account "transitive refresh", the fact that there are currently two largely independent ways to detect modified resources (one signal-based: EditorNode::_resources_reimported and one "programmatic": EditorData::_find_updated_instances) may get in the way.

Indeed EditorData::_find_updated_instances would not currently detect this scenario, so EditorNode::load_scene may actually do nothing even if called on S1. Feels like there is a risk of logic duplication here.

I guess one way around this would be to add an extra, optional bool force_reload parameter to EditorData::check_and_update_scene and its call chain to specify that EditorData::_find_updated_instances is not to be called. Not very pretty.

@phelioz
Copy link

phelioz commented Jan 3, 2021

@oparisy Interesting find :)

Did play around with it a little more now and to me it seems to only update when you create a new inherited scene from the glb mesh scene and when you have the glb mesh scene open.

Switching to tabs where the mesh is instanced in the scene tree doesn't refresh it. Neither does switching to a scene that is directly inheriting the mesh scene.

But just keeping the mesh scene open seems to update it even if you aren't looking at the mesh scene.
And also refreshed as I said when creating a new inherited scene from the mesh scene, but only refreshes it once on creation of the inherited scene and not when switching to it later.

@oparisy
Copy link

oparisy commented Jan 3, 2021

Hi @phelioz! May I ask you on which branch/build you did those tests? I only studied a recent build of master for now.

Edit: out of curiosity I compared the latest master and 3.2 source trees: EditorNode and EditorData code where virtually identical, so I'm not sure what to think about this.

Am I correct in my understanding that you cannot reproduce the scenario described by @setzer22? Because I definitely can, and it guided my code study. At which step does the behavior he describes diverge for you?

Under which OS did you perform your test? The code paths I describe rely on file system events and timestamps, so maybe there is some abstraction leak here.

@phelioz
Copy link

phelioz commented Jan 3, 2021

I still have the problem @setzer22 described but I don't need to switch to the imported mesh scene to have it updated, only having it open in a inactive scene tab keeps updating it for me. So what I mean is that I don't need to switch to it or reopen it to get it refreshed in the other scenes. Just keeping the tab open keeps updating the other scenes.

But did notice it refreshes the other scenes also when you are creating a new inherited scene. For example it refreshes once you hit the "right click/New Inhertied Scene" button.

Get the same behavior in @setzer22 minimal reproduction project too.

Do you understand what I mean when it works and not for me now? :)

Right now I am running 3.2.4 beta 4 on Window 10 (10.0.18363)

@shpuld
Copy link

shpuld commented Jul 11, 2021

I'm on 3.3.2 Stable and I'm noticing that scenes made with "New Inherited Scene" get updated when the model is overwritten, when I open the model (.dae) in this case it does show the changes, but the inherited ones do not. The workaround of switching to the original scene doesn't propagate the changes to everything, it seems that only the immediate inherited ones, I have to manually save them to propagate it to users of those scenes again. Needless to say this workflow is slow and it's easy to forget all the steps you need to do when you want to update something.

edit: after trying to reproduce the problem more, it seems more and more inconsistent, sometimes things get updated like mentioned in OP, but not always, and sometimes individual instances of the model disappear and switching between scenes 'fixes' it again.

@sfreed141
Copy link
Contributor

I hit this issue in 4.0.beta7.official. I tried with .glb and .blend assets. The best workaround for me is to create a new inherited scene after the asset is reimported and then immediately close it, as that seems to trigger updating all the existing inherited scenes.

@nan0m
Copy link

nan0m commented Jan 6, 2023

I made a plugin that meanwhile works around this issue in Godot 3.x.

InstantMeshUpdate Its far from perfect but might help some..

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

Successfully merging a pull request may close this issue.

10 participants