Godot beginners: Here's how to fade in a 3D mesh
I'm still a beginner at Godot. I've been playing with Godot and 3D scenes. It's great finally feeling comfortable enough to navigate the UI from watching the tutorials from Zenva/Humble Bundle.
Recently something that sounds straightforward took a long time for me to figure out: Fading in a 3D mesh. The solution is simple:
@onready var mesh: MeshInstance3D = find_child("body-mesh")
func _ready() -> void:
_set_material_alpha(0)
SomeSingleton.some_signal.connect(_fade_in)
func _set_material_alpha(alpha: float) -> void:
var material: Material = mesh.get_active_material(0)
if material is StandardMaterial3D:
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA_DEPTH_PRE_PASS
material.depth_draw_mode = BaseMaterial3D.DEPTH_DRAW_ALWAYS
material.albedo_color.a = alpha
func _fade_in() -> void:
var tween = create_tween()
tween.set_ease(Tween.EASE_IN)
tween.tween_method(_set_material_alpha, 0.0, 1.0, fade_in_duration_seconds)
The key being setting the material properties and using its albedo color to update transparency. The depth draw mode is needed, otherwise the result is ugly with jagged pixels during the tween.
Getting to the solution was the hard part. Searching forum posts I was led down some rabbit holes like using shaders—overkill for this situation. (There is a cool site though, for when I do end up needing custom shaders: https://godotshaders.com/.) Asking an LLM also didn't help much, probably because my prompt was wrong. I tried again just now and it gave me something closer to a correct solution, but missing some parts like the depth draw mode, which (by trial-and-error and reading the docs) I found is necessary for a good quality render, when using transparency.
Another small pitfall I found was that trying to change the material.transparency caused stutter. I was trying to disable transparency when the mesh was at 100% alpha, since I figured opaque rendering is cheaper. However I speculate the engine recompiles the shader when I turn off transparency, which causes the stutter. So I don't modify the material.transparency beyond that initial setting.
Also thought I'd mention, I'm using free placeholder art assets from https://kenney.nl/ - an amazing resource.
Aside: Shaders
During this I learned that adding shaders to an imported 3D model in Godot is somewhat convoluted:
- Import the .glb model
- Clone the auto-created scene to an inherited scene, because I'm not allowed to directly edit that auto-created scene
- Extract the material (UV colormap image) from the .glb by double-clicking it in the FileSystem tab
- Apply the extracted material to the mesh under Surface Material Override
- Add a "Next Pass" material, a ShaderMaterial, to that surface material override
- Create the shader script
- Pass in parameter values from the GDScript to the shader script using code like:
shader_material.set_shader_parameter("color", Color(1.0, 1.0, 1.0, alpha))
This didn't work so well for me though, because the shader I was using was changing the ALBEDO and turning things white. If I knew anything about 3D programming I'd probably find a way to update the existing color value at each pixel, instead of setting albedo white everywhere. The end result of the shader I was using was that the models were turning too white. So that was a dead end.
Anyway mainly leaving this here as reference for posterity. Feel free to share a story or constructive feedback if there's anything.
I don't have anything particularly constructive to add as I haven't worked in 3D much at all, but thanks for sharing! Always interesting to hear about other people's experiences with this stuff. That's wild that fading in a mesh in 3D is so much more complex than fading in a texture in 2D.
+1 for both GodotShaders and Kenney. The former helped a lot when I was venturing into writing shaders for the first time, and the latter is just an excellent part of the indie community.
If you end up making anything cool, please share!