Importing GLTF in script results in different behaviour

Godot Version

v4.4.stable

Question

I have too many gltf files (10k+, I’m porting a game), and godot’s automatic import can’t handle it (~50% after more than 12 hours). So I figured that I would put these files into a ZIP and import them at runtime when needed.

This approach works, but there are some problems. One is that “_loop” suffix of animation names does not get removed as it does in editor imports, which is not a big deal. Second is that I noticed that there are glitches in animations, sometimes mesh gets tilted to one side for whatever reason and blending seems to not work at all.

Is there any way that I can do whatever editor does in script and get an identical “PackedScene” object?

I’m runtime-loading my gltf models (Godot 4.3) and it’s working fine here? I do have animations and textures separate, so I’m loading/linking them at “runtime”, though really I’m pulling them in on a load screen in front of the game so everything’s ready to go.

I’m doing var model: Variant = load("res://whatever.gltf") with some error checking wrapped around it. I’m loading animations and textures the same way, and bolting them together into an object database that lets me essentially do:

var Node = ObjectLoader.spawn("Mushroom")

which calls:

func spawn(thing: String) -> Node:
    return ObjectDB[thing].instantiate()

(names changed for clarity)

1 Like

Since I’m importing from a ZIP, I need to load GLTF from memory (unless it’s possible to use load() on ZIPs).

This is what I’m doing:

func get_mesh() -> PackedScene:
	if mesh:
		return mesh
	var zip = ZIPReader.new()
	var r = zip.open("res://character/mesh.zip")
	if r != OK:
		return null
	var path = "%06d.glb" % [id]
	if !zip.file_exists(path):
		zip.close()
		return null
	var res = zip.read_file(path)
	zip.close()
	var gltf_document_load = GLTFDocument.new()
	var gltf_state_load = GLTFState.new()
	gltf_state_load.create_animations = true
	var error = gltf_document_load.append_from_buffer(res, "", gltf_state_load)
	if error == OK:
		var scene = gltf_document_load.generate_scene(gltf_state_load, 60)
		mesh = PackedScene.new()
		mesh.pack(scene)
		return mesh
	else:
		printerr("Couldn't load glTF scene (error code: %s)." % error_string(error))
		return null

I’d take a step back if I were you and try to eliminate variables to determine where the issue is located. For example, try loading just one problem mesh from a location without it being zipped. Does it still have problems?

If so, then it’s not related to the zipfile and you can dig into that.

If it is related to the zipfile, you can try a different compression level by using a command line zip tool and see if that solves the problem. Again, I recommend testing one file in the zipfile. If that works, then you know it is perhaps the size of your zipfile that is the problem.

And so on.

I know that it’s not a zip file problem.

When I extract the file from zip and load the gltf with a load(), I don’t have these problems.

Essentially, I want to be able to do what editor import + load() does with a file in memory (read from zip).

When you import a gltf model Godot does some post-process (optimize meshes, prepare animations,…) which won’t happen when you load a model at runtime. I think your only option is to manually do that post-process yourself. You could use the engine source code as a guide. Here’s how it reads the gltf and prepares the scene godot/modules/gltf/editor/editor_scene_importer_gltf.cpp at master · godotengine/godot · GitHub and here’s the part where it post-process the scene godot/editor/import/3d/resource_importer_scene.cpp at master · godotengine/godot · GitHub

3 Likes

After looking at the source code, I noticed that GLTFDocument.generate_scene has a remove_immutable_tracks parameter, which is true by default. In editor code, this is set to false, and after changing it to false in my script, animation problem was solved.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.