forked from godotengine/godot-demo-projects
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgray_scale.gd
78 lines (63 loc) · 3.22 KB
/
gray_scale.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@tool
extends CompositorEffect
class_name CompositorEffectGrayScale
# This is a very simple effects demo that takes our color values and writes
# back gray scale values.
func _init() -> void:
effect_callback_type = CompositorEffect.EFFECT_CALLBACK_TYPE_POST_TRANSPARENT
RenderingServer.call_on_render_thread(_initialize_compute)
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
# When this is called it should be safe to clean up our shader.
# If not we'll crash anyway because we can no longer call our _render_callback.
if shader.is_valid():
rd.free_rid(shader)
###############################################################################
# Everything after this point is designed to run on our rendering thread
var rd: RenderingDevice
var shader: RID
var pipeline: RID
func _initialize_compute() -> void:
rd = RenderingServer.get_rendering_device()
if not rd:
OS.alert("RenderingDevice is not available, aborting.\nCompositor effects require RenderingDevice to be available, which means you have to use the Forward+ or Mobile rendering method.")
return
# Create our shader.
var shader_file := load("res://gray_scale/gray_scale.glsl")
var shader_spirv: RDShaderSPIRV = shader_file.get_spirv()
shader = rd.shader_create_from_spirv(shader_spirv)
pipeline = rd.compute_pipeline_create(shader)
func _render_callback(p_effect_callback_type: int, p_render_data: RenderData) -> void:
if rd and p_effect_callback_type == CompositorEffect.EFFECT_CALLBACK_TYPE_POST_TRANSPARENT:
# Get our render scene buffers object, this gives us access to our render buffers.
# Note that implementation differs per renderer hence the need for the cast.
var render_scene_buffers: RenderSceneBuffersRD = p_render_data.get_render_scene_buffers()
if render_scene_buffers:
# Get our render size. This is the 3D render resolution (which can be affected by the
# `scaling_3d_scale` property), not the window size.
var size := render_scene_buffers.get_internal_size()
if size.x <= 0 and size.y <= 0:
push_error("Render size is too small.")
return
# We can use a compute shader here.
@warning_ignore("integer_division")
var x_groups := (size.x - 1) / 8 + 1
@warning_ignore("integer_division")
var y_groups := (size.y - 1) / 8 + 1
# Loop through views just in case we're doing stereo rendering. No extra cost if this is mono.
var view_count := render_scene_buffers.get_view_count()
for view in view_count:
# Get the RID for our color image. We will be reading from and writing to it.
var input_image: RID = render_scene_buffers.get_color_layer(view)
# Create a uniform set. This will be cached: the cache will be cleared if our viewport's configuration is changed.
var uniform := RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
uniform.binding = 0
uniform.add_id(input_image)
var uniform_set := UniformSetCacheRD.get_cache(shader, 0, [ uniform ])
# Run our compute shader.
var compute_list := rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, pipeline)
rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0)
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()