Skip to content

Commit

Permalink
Shader precompilation (without bug)
Browse files Browse the repository at this point in the history
  • Loading branch information
FailSpy committed Mar 15, 2024
1 parent cfe5446 commit 92ba7fe
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
43 changes: 43 additions & 0 deletions COGITO/Assets/Shader/ShaderLoader.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[gd_scene load_steps=6 format=3 uid="uid://b3bej4wl0tvj0"]

[ext_resource type="Script" path="res://COGITO/Assets/Shader/ShaderPrecompiler.gd" id="1_5rykf"]

[sub_resource type="QuadMesh" id="QuadMesh_8skhu"]
size = Vector2(0, 0)

[sub_resource type="ViewportTexture" id="ViewportTexture_dghy8"]
viewport_path = NodePath("SubViewport")

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_k37ri"]
resource_local_to_scene = true
albedo_texture = SubResource("ViewportTexture_dghy8")

[sub_resource type="QuadMesh" id="QuadMesh_upqev"]

[node name="ShaderCache" type="MeshInstance3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1)
mesh = SubResource("QuadMesh_8skhu")
surface_material_override/0 = SubResource("StandardMaterial3D_k37ri")
script = ExtResource("1_5rykf")

[node name="SubViewport" type="SubViewport" parent="."]

[node name="QuadRender" type="MeshInstance3D" parent="SubViewport"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -20, 0)
layers = 262144
mesh = SubResource("QuadMesh_upqev")
skeleton = NodePath("../..")

[node name="VisibleOnScreenNotifier3D" type="VisibleOnScreenNotifier3D" parent="SubViewport"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -20, 0)
layers = 262144
aabb = AABB(-0.5, 0, -1, 1, 1, 2)

[node name="Camera3D" type="Camera3D" parent="SubViewport"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -20, 0)
cull_mask = 262144
current = true

[connection signal="screen_entered" from="SubViewport/VisibleOnScreenNotifier3D" to="." method="_on_visible_on_screen_notifier_3d_screen_entered"]
[connection signal="screen_exited" from="SubViewport/VisibleOnScreenNotifier3D" to="." method="_on_visible_on_screen_notifier_3d_screen_exited"]
[connection signal="tree_exiting" from="SubViewport/VisibleOnScreenNotifier3D" to="." method="_on_visible_on_screen_notifier_3d_tree_exiting"]
47 changes: 47 additions & 0 deletions COGITO/Assets/Shader/ShaderPrecompiler.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
extends Node3D
class_name ShaderPrecompiler

static var scene = preload("./ShaderLoader.tscn")
static var shader_compiler_scene = null
static var quad = null

var materials : Array[ShaderMaterial]

const placement = Vector3.ONE*9999
const SHADER_LAYER = 19

var is_rendering : bool = false # debugging
static var queued = false

# UNKNOWN: MultimeshInstances? Particles?
static func precompile(tree : SceneTree, shader : ShaderMaterial):
if shader_compiler_scene == null:
shader_compiler_scene = scene.instantiate()
tree.root.get_camera_3d().add_child(shader_compiler_scene)
quad = shader_compiler_scene.get_node("./SubViewport/QuadRender")

shader_compiler_scene.materials.push_back(shader)
if not queued:
queued = true

func _process(delta):
if not queued:
return
if len(shader_compiler_scene.materials) == 0:
queued = false
shader_compiler_scene.queue_free()
else:
var mat = shader_compiler_scene.materials.pop_back()
print(mat)
shader_compiler_scene.material_override = mat

func _on_visible_on_screen_notifier_3d_screen_entered():
is_rendering = true

func _on_visible_on_screen_notifier_3d_screen_exited():
is_rendering = false


func _on_visible_on_screen_notifier_3d_tree_exiting():
if shader_compiler_scene == self:
shader_compiler_scene = null
8 changes: 8 additions & 0 deletions COGITO/Assets/Shader/ShaderSpace.gd
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class_name ShaderSpace
## If you're looking for viewmodel rendering, use ViewmodelSpace.gd
## @experimental

## Godot's rendering engine will only compile a shader when it appears in the camera for the first time which can cause stutters.
## This flag will force Godot to render all shaders when this space enters the scene.
## If you have a lot of shaders,
@export var precompile_on_enter : bool = true
var _bake : bool = false
## This will 'bake' the custom materials this script generates -- otherwise the materials are generated when this node enters the scene.
## WARNING: Please note any changes you make to the *baked* versions of the Materials will not stay if/when you revert back to unbaked.
Expand Down Expand Up @@ -119,10 +123,14 @@ func convert_surface(mat : Material):
if Engine.is_editor_hint() and not _bake:
# un-baking
return mat.get_original_material()
elif precompile_on_enter and not Engine.is_editor_hint():
ShaderPrecompiler.precompile(get_tree(),mat)
return mat
if not mat is StandardMaterial3D:
print("WARNING: Cannot convert ", mat, " to shader material")
else:
var newmaterial = Material3DConversion.convert_to_shadermat(mat,injected_vars,injected_vertex)
if precompile_on_enter and not Engine.is_editor_hint():
ShaderPrecompiler.precompile(get_tree(),newmaterial)
return newmaterial

0 comments on commit 92ba7fe

Please sign in to comment.