Skip to content

Instantly share code, notes, and snippets.

@HungryProton
Last active February 2, 2023 03:46
Show Gist options
  • Save HungryProton/985707a4fe3db0230da9be5f97b82ba2 to your computer and use it in GitHub Desktop.
Save HungryProton/985707a4fe3db0230da9be5f97b82ba2 to your computer and use it in GitHub Desktop.
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():
set_process(false)
_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")
emit_signal("stage_completed")
if _shaders.empty() and _particles.empty() and not _finalize:
_finalize = true
yield(get_tree(), "idle_frame")
visible = false
emit_signal("all_shaders_compiled")
func get_stage_count() -> int:
return _shaders.size() + _particles.size()
func _find_all(path: String, ext: String, target: Array) -> void:
var dir = Directory.new()
dir.open(path)
dir.list_dir_begin(true, true)
var path_root = dir.get_current_dir() + "/"
while true:
var file = dir.get_next()
if file == "":
break
if dir.current_is_dir():
_find_all(path_root + file, ext, target)
elif file.ends_with(ext):
target.append(path_root + file)
dir.list_dir_end()
func _create_mesh_with(shader_path: String) -> MeshInstance:
var mesh = QuadMesh.new()
var mesh_instance = MeshInstance.new()
var material := ShaderMaterial.new()
material.shader = load(shader_path)
mesh.set_size(Vector2.ONE)
mesh_instance.set_mesh(mesh)
mesh_instance.rotation_degrees = Vector3(90, 0.0, 0.0)
mesh_instance.set_material_override(material)
mesh_instance.set_name(shader_path.get_file().split(".")[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
@HungryProton
Copy link
Author

HungryProton commented Jul 27, 2021

Requirements

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

Caveats

  • 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