Stuttering when material is first used despite preload()

Godot Version

4.6.3-stable

Question

Getting a severe stutter (~430ms) when a material that has been preloaded from a resource file is first seen in the viewport. When the same material is applied the second, third or n-th time, it works instantly.

I must be misunderstanding what preload does apprently. This is how I’m trying to use it:

class_name InteractionComponent extends Node

var parent : Node = null
var mesh : MeshInstance3D = null
# Preloading the material from a resource file
var highlight_material : ShaderMaterial =  preload("res://assets/materials/interactable_highlight_shader.tres")

func _ready() -> void:
	parent = get_parent()
	connect_parent()
	set_default_mesh()

# "focused" signal is emitted when a raycast extended from the center of the 
# camera finds a collider. In other words, when the player is looking at an 
# object. In this case the MeshInstance3D that this script is attached to.
func connect_parent() -> void:
	parent.add_user_signal("focused")
	parent.connect("focused", Callable(self, "in_range"))

# Finds the MeshInstance3D that will receive the material
func set_default_mesh() -> void:
	if mesh:
		pass
	else:
		for i in parent.get_children():
			if i is MeshInstance3D:
				mesh = i

# Applies a material to the overlay slot
func in_range() -> void:
	mesh.material_overlay = highlight_material

This script is attached to a plain node which is a sibling of the MeshInstance3D that its targeting.

The ShaderMaterial in question is dead simple:

shader_type spatial;

void fragment() {
	EMISSION = vec3(0.1, 0.99, 0.12);
	ALPHA = 0.25;
}

I constructed this following a tutorial from stayathomedev and in his demonstration, it does not appear to cause any stuttering. Perhaps my computer is just crap or maybe its movie magic.

So the actual question is an appeal to the big brains here - how to load a (shader) material on demand in such a way that it does not cause stuttering the first time it is used?

Are you using compatibility rendering mode? Or disabled ubershaders elsewhere? The stutter is usually shader compilation.

Output says:

D3D12 12_0 - Forward+

Don’t think I have knowingly changed any shader settings, everything seems to be set to the defaults in Project Settings.

preload() only loads the resources in the CPU side. The shader compilation happens in the GPU side.

You can learn more about shader stutter and how to minimize it here:

it sounds like shader compilations, so do read @mrcdk 's post, but almost 500ms is pretty wild for any shader (and the size of it/line count doesn’t matter that much). How are you assessing this stutter? Have you checked the profiler first?

This is what the profiler is saying on frame 271 when I turned the camera to look at the box.

@mrcdk 's post does hold part of the answer to the question though. The Monitors reveal that 5 Surface Compilations happen at the same time:

As a test I duplicated the stutterbox and set it’s overlay material to the ShaderMaterial and it’s visibility to hidden. This way the surface compilations happen as the game is loading and during runtime there are no stutters.

-edit-

To answer the original question then:

how to load a (shader) material on demand in such a way that it does not cause stuttering the first time it is used

You can’t and you’re not supposed to, it seems? Unless you’re willing to pay the price.