Recently I've been making some levels in Blender an importing them into Godot. There are only about 7 or 8 shaders for each level, not counting dynamic objects which will be added later. But to improve rendering performance, it can be a good idea to split the meshes up into sections.
At that point you might be faced with a list like this:
Or it might be even more chaotic, if you didn't use simple names for the objects in your level. So it can take a long time to sort out all the meshes, make them unique and add textures and so on.
Blender imports with simple Blender textures, or with placeholder materials. This is sometimes OK, but if your Godot shaders are very different to those used by Blender, it means applying new materials to every mesh object in the level when you import the scene.
I found that during the design process, I was importing and readying a level several times before I was happy with the final layout. So at first I was wasting a lot of time.
In Blender, I use python scripts to handle this sort of repetitive work, and I've decided to do the same thing in Godot. In order to automate my pipeline, I'm taking advantage of the "tool" and "export" features in gdscript.
Tool scripts can be run in the editor, and export variables can be set without modifying the script, just from the side bar in the editor. Together, these offer a lot of strong automation options.
Here's an example:
My shaders are quite complex, often featuring animated textures or other features that won't be included in an export from Blender. In the following example, I've set up a script with export slots for materials. The script will search through the objects in the scene and match materials to names.
So for example:
extends Spatial
tool
export(bool) var run_script
export(Material) var vehicle
export(Material) var decals
export(Material) var junk
export(Material) var lcars
export(Material) var glass
export(Material) var props
export(Material) var screens
export(Material) var structure
export(Material) var tech
export(Material) var cave
export(Material) var window
Here I've set up the export slots to accept materials. And next I use the ready function to match materials to names of meshes. It also makes the meshes unique, so that there's no worry about them still being attached to the old imported file.
var all_children = []
func get_child_recursive(current_node):
var children = current_node.get_children()
if len(children) > 0:
for child in children:
all_children.append(child)
get_child_recursive(child)
Here's a function to get all children nodes and add them to a child list for processing.
And finally the code for applying materials and making the meshes unique. Just add this script to a node, save it as a scene, then drop it into your imported asset scene, drag and drop to parent all the meshes to this node, then hit the "run_script" check box. As soon as the script is run, the check box reverts back to false, and your meshes have the right materials.
func _process():
if Engine.editor_hint:
if run_script == true:
get_child_recursive(self)
for child in all_children:
var tex_dict = {"vehicle":vehicle,
"decals":decals,
"glass":glass,
"junk":junk,
"lcars":lcars,
"props":props,
"screens":screens,
"structure":structure,
"tech":tech,
"walls":cave,
"window":window}
if not child.mesh.is_local_to_scene():
child.mesh.set_local_to_scene(true)
for tex_key in tex_dict:
var tex = tex_dict[tex_key]
print(tex_key, tex, child.name)
if tex_key in child.name:
if tex != null:
child.set_surface_material(0, null)
child.mesh.surface_set_material(0, tex)
print("changed:", tex_key)
run_script = false
Drag and drop those newly unique mesh instances onto a new spatial node, and save it as a new scene. Now you have your fully prepared level in seconds.
Of course the meshes have to be named in a logical way. All the objects which are going to get the "junk" material, are named {level_name}_junk and so on.
The run_script variable makes sure it only happens once, and doesn't keep running in the editor every time we open the scene.
If you're going to be making a full game, I recommend checking out tool and export features to see if you can find a way to speed up your workflow.
This comment has been removed by the author.
ReplyDeleteYup, automating things with tool scripts etc. is great! I'd say try go even further.
ReplyDeleteOriginally I rewrote the blender-godot-exporter for exactly this purpose: to allow seamless level conversion from blender -> godot. In particular using things like "project://path/to/material.tres" as a material name works as you'd expect. (Actutally I can't remember if that particular PR made it into the public version). Then I used a SConstruct pipeline to do blend -> escn as well as xcf -> png, build datastructures representing levels etc. etc.
My aim for every asset pipeline is that there should be zero manual work involved so that everything can be reproduced from source files. In the VCS you only store the source files (xcf, blend, etc.) and all in-between-files (gltf, png, escn) should be generated automatically (along with appropriate .gitignores). If you need to click a button or store a "copy of the meshes not linked to the originals" then the chances of you losing the source files for those meshes is high.
Hi sdfgeoff, I just saw this comment. Thanks for reading.
DeleteI'd love to write a proper exporter that handles things just the way I want it, but I usually have specific things I want to do on import, so this way works out OK.
For example, if a mesh has transparent textures, I like to add a shadows only material override object to cast shadows for it. And some of my objects need to be added to groups in the game (TV screens and such, so they can be turned on and off).
I'm not sure if I've got the skills to write an exporter anyway, nor and be sure it would work without adding more bugs than it fixes...