Hey everyone, I’m running into a strange shader-related issue in Godot. When I instantiate a character scene that uses a shader for a flashing damage effect, the sprite briefly shows the full texture (like an uninitialized state) for one frame. It only happens for the first instance—the others spawn normally. After testing, I confirmed disabling the shader entirely fixes the bug. Looks like it might be related to runtime shader compilation or GPU material setup lag on first render. Has anyone else seen this or knows if it’s a known issue?
#Shader bug
1 messages · Page 1 of 1 (latest)
Since it happens only on the first instance, it sounds like shader compilation and/or loading slowness.
Have you tried putting your shader/scene/etc into some preload() or earlier scene? Basically, this is why "loading screens" exist. 😉
@ruby narwhal Yes, I’ve tried preloading the shader, but the issue still persists—the first instantiated prefab with the shader still flashes the full texture briefly before correcting. So far, no combination of preloading, assigning early, or using ShaderMaterial.duplicate() has prevented this initial visual glitch.
These are the things I tried so far.
sprite.material = ShaderMaterial.new()
sprite.material.shader = preload("res://Shaders/character.gdshader")
sprite.material = shader.duplicate()
sprite.visible = false
await get_tree().create_timer(1).timeout
sprite.visible = true
I think the shader actually needs to be in view in order to be compiled, so just doing preload() without anything on the screen might not be enough.
Have you tried something like this: https://gist.github.com/fguillen/2327f281c7827f39f7873550273fbe63 ?
Again, you need a real way to load all your shaders (and whatever else is "heavy") before you start the game and want to display whatever it is you wanna put on the screen.
I will try and let you know
Before you need your shader, make sure it's been actually rendered, meaning it should've been on the screen for at least 1 frame. 🙂
Well, it worked, but that's not a ideal solution 😅
Make it a (pretty) loading screen and you're good to go.
😕
I guess this solves the problem, but I hoped to fix it a "better" way.
shader_type canvas_item;
uniform bool flash_hurt = false;
uniform float flash_strength = 1.0;
void fragment() {
vec4 tex_color = texture(TEXTURE, UV);
vec3 exclude_color1 = vec3(252.0/255.0, 240.0/255.0, 217.0/255.0);
vec3 exclude_color2 = vec3(29.0/255.0, 32.0/255.0, 34.0/255.0);
vec3 flash_color = vec3(238.0/255.0, 69.0/255.0, 63.0/255.0);
float tolerance = 0.01;
bool is_excluded =
distance(tex_color.rgb, exclude_color1) < tolerance ||
distance(tex_color.rgb, exclude_color2) < tolerance;
vec3 final_color = tex_color.rgb;
if (flash_hurt && tex_color.a > 0.0 && !is_excluded) {
final_color = mix(tex_color.rgb, flash_color, flash_strength);
}
COLOR = vec4(final_color, tex_color.a);
}
This is my shader logic, after comenting these lines:
uniform bool flash_hurt = false;
uniform float flash_strength = 1.0;
The problem dissapears
But that doesn't fix the problem. I need these lines 😂
I guess make the screen black until a signal "loaded" or "finished loading" is sent out? It's an interesting problem to say the least
@spice eagle Yeah I guess that's the only thing I can do at this point
maybe hide it behind your own logo fade in / fade out and no one will be one the wiser
Yeah, a loading screen will do the work,