Skip to content

Instantly share code, notes, and snippets.

Last active February 2, 2023 03:46
What would you like to do?
Shader Cache v2
class_name ShaderCache
extends Spatial
signal stage_completed
signal all_shaders_compiled
export var shaders_folder := "res://material/shaders/"
export var particles_folder := "res://vfx/"
var _shaders := []
var _particles := []
var _count := 0
var _finalize := false
func _ready():
_find_all(shaders_folder, ".shader", _shaders)
_find_all(particles_folder, ".tscn", _particles)
func compile_next() -> void:
if not _shaders.empty():
var shader = _shaders.pop_front()
var mesh = _create_mesh_with(shader)
yield(mesh, "ready")
yield(get_tree(), "idle_frame")
elif not _particles.empty():
var particles = _create_particles(_particles.pop_front())
yield(particles, "ready")
yield(get_tree(), "idle_frame")
if _shaders.empty() and _particles.empty() and not _finalize:
_finalize = true
yield(get_tree(), "idle_frame")
visible = false
func get_stage_count() -> int:
return _shaders.size() + _particles.size()
func _find_all(path: String, ext: String, target: Array) -> void:
var dir =
dir.list_dir_begin(true, true)
var path_root = dir.get_current_dir() + "/"
while true:
var file = dir.get_next()
if file == "":
if dir.current_is_dir():
_find_all(path_root + file, ext, target)
elif file.ends_with(ext):
target.append(path_root + file)
func _create_mesh_with(shader_path: String) -> MeshInstance:
var mesh =
var mesh_instance =
var material :=
material.shader = load(shader_path)
mesh_instance.rotation_degrees = Vector3(90, 0.0, 0.0)
call_deferred("add_child", mesh_instance)
return mesh_instance
func _create_particles(particles_path: String) -> Particles:
var particles = load(particles_path).instance()
particles.emitting = true
particles.one_shot = false
call_deferred("add_child", particles)
return particles
Copy link

HungryProton commented Jul 27, 2021


This script assumes the following:

  • All your materials are using shaders saved as their own *.shader files
  • Your particles are stored in their own folder

How to use

  • Right click on your main camera
  • Press Add child node
  • Search for ShaderCache in the list and confirm
  • Update the shader and particle folder path in the node inspector
  • Call compile_next() until everything is compiled


  • This doesn't handle the regular spatial materials, although support could be easy to add.
  • Doesn't work if the shader file is embedded to the shader material resource (needs to be saved as it's own .shader file)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment