Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add demo showing the use of RenderingEffects to do post processing #942

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compute/post_effects/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
2 changes: 2 additions & 0 deletions compute/post_effects/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Godot 4+ specific ignores
.godot/
11 changes: 11 additions & 0 deletions compute/post_effects/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Post effects

This demo shows how to implement post effects using the new RenderingEffect class.

Renderer: Forward Plus

> Note: this demo requires Godot 4.2 or later

## Screenshots

![Screenshot](screenshots/compute_texture.webp)
74 changes: 74 additions & 0 deletions compute/post_effects/gray_scale/gray_scale.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
@tool
extends RenderingEffect
class_name RenderingEffectGrayScale
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API renamed to CompositorEffect, should be changed in multiple files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I need to revisit this


# This is a very simple effects demo that takes our color values and writes
# back gray scale values.

func _init():
effect_callback_type = RenderingEffect.EFFECT_CALLBACK_TYPE_POST_TRANSPARENT
RenderingServer.call_on_render_thread(_initialize_compute)

func _notification(what):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _notification(what):
func _notification(what):

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)
Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pipeline RID is not being freed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you free a shader, all dependencies of the shader will be freed, including all pipelines related to that 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():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _initialize_compute():
func _initialize_compute():

rd = RenderingServer.get_rendering_device()
if !rd:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if !rd:
if not rd:

return

# Create our shader
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Create our shader
# 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, p_render_data):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _render_callback(p_effect_callback_type, p_render_data):
func _render_callback(effect_callback_type, render_data):

if rd and p_effect_callback_type == RenderingEffect.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!
var size = render_scene_buffers.get_internal_size()
if size.x == 0 and size.y == 0:
return

# We can use a compute shader here
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# We can use a compute shader here
# We can use a compute shader here .

var x_groups = (size.x - 1) / 8 + 1
var y_groups = (size.y - 1) / 8 + 1

# Barrier
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Barrier
# Barrier.

rd.barrier(RenderingDevice.BARRIER_MASK_ALL_BARRIERS, RenderingDevice.BARRIER_MASK_COMPUTE)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manual barriers are deprecated and should be removed, should be changed in multiple files.


# 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 range(view_count):
# Get the RID for our color image, we will be reading from and writing to it.
var input_image = render_scene_buffers.get_color_layer(view)

# Create a uniform set, this will be cached, the cache will be cleared if our viewports configuration is changed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Create a uniform set, this will be cached, the cache will be cleared if our viewports configuration is changed
# Create a uniform set, this will be cached, the cache will be cleared if our viewports configuration is changed.

var uniform : RDUniform = 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Run our compute shader
# 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()
18 changes: 18 additions & 0 deletions compute/post_effects/gray_scale/gray_scale.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[compute]
#version 450

// Invocations in the (x, y, z) dimension
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;

layout(rgba16f, set = 0, binding = 0) uniform image2D color_image;

// The code we want to execute in each invocation
void main() {
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);

vec4 color = imageLoad(color_image, uv);
float gray = color.r * 0.2125 + color.g * 0.7154 + color.b * 0.0721;
color.rgb = vec3(gray);

imageStore(color_image, uv, color);
}
14 changes: 14 additions & 0 deletions compute/post_effects/gray_scale/gray_scale.glsl.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[remap]

importer="glsl"
type="RDShaderFile"
uid="uid://cycdb7vyg3b6g"
path="res://.godot/imported/gray_scale.glsl-cdec27ad421b3dcac596053515285dc6.res"

[deps]

source_file="res://gray_scale/gray_scale.glsl"
dest_files=["res://.godot/imported/gray_scale.glsl-cdec27ad421b3dcac596053515285dc6.res"]

[params]

1 change: 1 addition & 0 deletions compute/post_effects/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions compute/post_effects/icon.svg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cm88hfhyutq2d"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
52 changes: 52 additions & 0 deletions compute/post_effects/main.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
extends Node3D

@onready var sssr_button = $UI/MarginContainer/VBoxContainer/SSSR
@onready var gray_scale_button = $UI/MarginContainer/VBoxContainer/GrayScaleBtn

var create_depth_mips_effect : RenderingEffectCreateDepthMips
var apply_sssr_effect : RenderingEffectApplySSSR
var gray_scale_effect : RenderingEffectGrayScale

# Called when the node enters the scene tree for the first time.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Called when the node enters the scene tree for the first time.
# Called when the node enters the scene tree for the first time.

func _ready():
var environment : Environment = $WorldEnvironment.environment
for effect in environment.rendering_effects:
if effect.get_script() == RenderingEffectCreateDepthMips:
create_depth_mips_effect = effect
elif effect.get_script() == RenderingEffectApplySSSR:
apply_sssr_effect = effect
elif effect.get_script() == RenderingEffectGrayScale:
gray_scale_effect = effect

if create_depth_mips_effect and apply_sssr_effect:
sssr_button.button_pressed = create_depth_mips_effect.enabled

if gray_scale_effect:
gray_scale_button.button_pressed = gray_scale_effect.enabled

var cam_x = 0.0
var cam_y = 0.0

func _input(event):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _input(event):
func _input(event):

if event is InputEventMouseMotion:
var mouse_event : InputEventMouseMotion = event

if mouse_event.button_mask & MOUSE_BUTTON_MASK_LEFT:
cam_x = clamp(cam_x + mouse_event.relative.y * 0.01, -PI * 0.1, PI * 0.25)
cam_y -= mouse_event.relative.x * 0.01

var b1 : Basis = Basis(Vector3.UP, cam_y)
var b2 : Basis = Basis(Vector3.LEFT, cam_x)

$Pivot.transform.basis = b1 * b2

func _on_simple_ssr_toggled(toggled_on):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _on_simple_ssr_toggled(toggled_on):
func _on_simple_ssr_toggled(toggled_on):

if create_depth_mips_effect and apply_sssr_effect:
create_depth_mips_effect.enabled = toggled_on
apply_sssr_effect.enabled = toggled_on

func _on_gray_scale_btn_toggled(toggled_on):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func _on_gray_scale_btn_toggled(toggled_on):
func _on_gray_scale_btn_toggled(toggled_on):

if gray_scale_effect:
gray_scale_effect.enabled = toggled_on


161 changes: 161 additions & 0 deletions compute/post_effects/main.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
[gd_scene load_steps=23 format=3 uid="uid://hay7hbv1cp62"]

[ext_resource type="Script" path="res://gray_scale/gray_scale.gd" id="1_di38g"]
[ext_resource type="Script" path="res://main.gd" id="1_ekxfu"]
[ext_resource type="Texture2D" uid="uid://bshdn70nudsun" path="res://pattern.png" id="2_d1qxb"]
[ext_resource type="Script" path="res://simple_ssr/create_depth_mips.gd" id="2_lv16x"]
[ext_resource type="Script" path="res://simple_ssr/apply_sssr.gd" id="3_ygheb"]
[ext_resource type="Texture2D" uid="uid://d0e66wb8yplkw" path="res://uv.jpg" id="5_ybioc"]

[sub_resource type="RenderingEffect" id="RenderingEffect_rprpc"]
resource_local_to_scene = false
resource_name = ""
enabled = true
effect_callback_type = 0
access_resolved_color = false
access_resolved_depth = true
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("2_lv16x")

[sub_resource type="RenderingEffect" id="RenderingEffect_sm2nk"]
resource_local_to_scene = false
resource_name = ""
enabled = true
effect_callback_type = 2
access_resolved_color = false
access_resolved_depth = false
needs_motion_vectors = false
needs_normal_roughness = true
needs_separate_specular = true
script = ExtResource("3_ygheb")
max_distance = 1.0
max_steps = 32

[sub_resource type="RenderingEffect" id="RenderingEffect_jcxua"]
resource_local_to_scene = false
resource_name = ""
enabled = true
effect_callback_type = 4
needs_motion_vectors = false
needs_normal_roughness = false
script = ExtResource("1_di38g")

[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_ptioq"]
sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)

[sub_resource type="Sky" id="Sky_gkygq"]
sky_material = SubResource("ProceduralSkyMaterial_ptioq")

[sub_resource type="Environment" id="Environment_kx13e"]
background_mode = 2
sky = SubResource("Sky_gkygq")
tonemap_mode = 2
ssr_depth_tolerance = 3.41
glow_enabled = true
rendering_effects = Array[RenderingEffect]([SubResource("RenderingEffect_rprpc"), SubResource("RenderingEffect_sm2nk"), SubResource("RenderingEffect_jcxua")])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must use the new Compositor API.


[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tvupy"]
albedo_texture = ExtResource("5_ybioc")
metallic = 0.5
roughness = 0.75
uv1_scale = Vector3(5, 5, 5)

[sub_resource type="PlaneMesh" id="PlaneMesh_fbrjs"]
size = Vector2(20, 20)

[sub_resource type="SphereMesh" id="SphereMesh_nqw7b"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_mwci7"]
albedo_texture = ExtResource("2_d1qxb")
metallic = 0.78
roughness = 0.24

[sub_resource type="SphereMesh" id="SphereMesh_lau6s"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qdjdj"]
albedo_color = Color(1, 0.298039, 0.247059, 1)
albedo_texture = ExtResource("2_d1qxb")
metallic = 0.26
roughness = 0.59

[sub_resource type="CylinderMesh" id="CylinderMesh_jepk0"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xkdqw"]
albedo_color = Color(0.580392, 0.658824, 1, 1)
albedo_texture = ExtResource("2_d1qxb")
metallic = 0.86
roughness = 0.29

[sub_resource type="BoxMesh" id="BoxMesh_syokj"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_chobt"]
albedo_color = Color(0.588235, 0.282353, 0.443137, 1)
albedo_texture = ExtResource("2_d1qxb")
metallic = 0.52
roughness = 0.42

[node name="Main" type="Node3D"]
script = ExtResource("1_ekxfu")

[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_kx13e")

[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.959131, 0.245052, -0.141481, -0.0849703, 0.726354, 0.682048, 0.269902, -0.642152, 0.717491, 0, 1.94732, 0)
shadow_enabled = true

[node name="Pivot" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.553607, 0.779114, 0)

[node name="Camera3D" type="Camera3D" parent="Pivot"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3)

[node name="Floor" type="MeshInstance3D" parent="."]
material_override = SubResource("StandardMaterial3D_tvupy")
mesh = SubResource("PlaneMesh_fbrjs")

[node name="MetalSphere" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.721009, 0)
mesh = SubResource("SphereMesh_nqw7b")
surface_material_override/0 = SubResource("StandardMaterial3D_mwci7")

[node name="RedSphere" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.17882, 0.628256, -0.532507)
mesh = SubResource("SphereMesh_lau6s")
surface_material_override/0 = SubResource("StandardMaterial3D_qdjdj")

[node name="Cylinder" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.29466, 0, 0.409778)
mesh = SubResource("CylinderMesh_jepk0")
surface_material_override/0 = SubResource("StandardMaterial3D_xkdqw")

[node name="Box" type="MeshInstance3D" parent="."]
transform = Transform3D(0.682049, -0.297997, -0.667837, -1.49012e-08, 0.913212, -0.407486, 0.731306, 0.277925, 0.622855, 2.41454, 0.500351, 0.0996274)
mesh = SubResource("BoxMesh_syokj")
surface_material_override/0 = SubResource("StandardMaterial3D_chobt")

[node name="UI" type="CanvasLayer" parent="."]

[node name="MarginContainer" type="MarginContainer" parent="UI"]
offset_right = 40.0
offset_bottom = 40.0
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5

[node name="VBoxContainer" type="VBoxContainer" parent="UI/MarginContainer"]
layout_mode = 2

[node name="SSSR" type="CheckBox" parent="UI/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "SSSR"

[node name="GrayScaleBtn" type="CheckBox" parent="UI/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "Gray scale"

[connection signal="toggled" from="UI/MarginContainer/VBoxContainer/SSSR" to="." method="_on_simple_ssr_toggled"]
[connection signal="toggled" from="UI/MarginContainer/VBoxContainer/GrayScaleBtn" to="." method="_on_gray_scale_btn_toggled"]
Binary file added compute/post_effects/pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading