└── addons └── noise_shader ├── colorful_noise.glsl.import ├── cycling_noise.glsl.import ├── sliding_noise.glsl.import ├── variable_sliding_noise.glsl.import ├── cycling_noise.glsl ├── sliding_noise.glsl ├── colorful_noise.glsl ├── variable_sliding_noise.glsl ├── cycling_noise_effect.gd ├── colorful_noise_effect.gd ├── variable_sliding_noise_effect.gd └── sliding_noise_effect.gd /addons/noise_shader/colorful_noise.glsl.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="glsl" 4 | type="RDShaderFile" 5 | uid="uid://cb08tu6uy3ae" 6 | path="res://.godot/imported/colorful_noise.glsl-a6f0e6411766f4d326c443e2a46d6f7c.res" 7 | 8 | [deps] 9 | 10 | source_file="res://addons/noise_shader/colorful_noise.glsl" 11 | dest_files=["res://.godot/imported/colorful_noise.glsl-a6f0e6411766f4d326c443e2a46d6f7c.res"] 12 | 13 | [params] 14 | 15 | -------------------------------------------------------------------------------- /addons/noise_shader/cycling_noise.glsl.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="glsl" 4 | type="RDShaderFile" 5 | uid="uid://bu2opyd5sqhhn" 6 | path="res://.godot/imported/cycling_noise.glsl-39775e231ff9d8f722a91bbc04beba4b.res" 7 | 8 | [deps] 9 | 10 | source_file="res://addons/noise_shader/cycling_noise.glsl" 11 | dest_files=["res://.godot/imported/cycling_noise.glsl-39775e231ff9d8f722a91bbc04beba4b.res"] 12 | 13 | [params] 14 | 15 | -------------------------------------------------------------------------------- /addons/noise_shader/sliding_noise.glsl.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="glsl" 4 | type="RDShaderFile" 5 | uid="uid://cc6hii23hmln0" 6 | path="res://.godot/imported/sliding_noise.glsl-01ac057fc907bda231bab1ada739ad4b.res" 7 | 8 | [deps] 9 | 10 | source_file="res://addons/noise_shader/sliding_noise.glsl" 11 | dest_files=["res://.godot/imported/sliding_noise.glsl-01ac057fc907bda231bab1ada739ad4b.res"] 12 | 13 | [params] 14 | 15 | -------------------------------------------------------------------------------- /addons/noise_shader/variable_sliding_noise.glsl.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="glsl" 4 | type="RDShaderFile" 5 | uid="uid://cecxmm6rcjqpy" 6 | path="res://.godot/imported/variable_sliding_noise.glsl-386f3e8d2111de936e87e8d52363b7f4.res" 7 | 8 | [deps] 9 | 10 | source_file="res://addons/noise_shader/variable_sliding_noise.glsl" 11 | dest_files=["res://.godot/imported/variable_sliding_noise.glsl-386f3e8d2111de936e87e8d52363b7f4.res"] 12 | 13 | [params] 14 | 15 | -------------------------------------------------------------------------------- /addons/noise_shader/cycling_noise.glsl: -------------------------------------------------------------------------------- 1 | #[compute] 2 | #version 450 3 | 4 | layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 5 | 6 | layout(rgba16f, set = 0, binding = 0) uniform image2D screen_image; 7 | 8 | // Details parameters to be sent to the shader 9 | layout(push_constant, std430) uniform Params { 10 | vec2 raster_size; 11 | int steps; 12 | float speed; 13 | } params; 14 | 15 | // The noise data the shader reads from 16 | layout(set = 1, binding = 1, std430) restrict buffer FloatBufferIn { 17 | float data[]; 18 | } 19 | buffer_in; 20 | 21 | // The noise data that the shader writes to 22 | layout(set = 1, binding = 2, std430) restrict buffer FloatBufferOut { 23 | float data[]; 24 | } 25 | buffer_out; 26 | 27 | // Returns the index of the buffer according to the uv coordinate 28 | int get_buffer_index(in ivec2 uv, in ivec2 size) { 29 | return uv.y * size.x + uv.x; 30 | } 31 | 32 | // Update the buffer value according to the screen color and speed 33 | void update_value(inout float value, in vec4 screen_color) { 34 | float average = (screen_color.r + screen_color.g + screen_color.b) / 3.0; 35 | value = value + clamp(average, 0.0, 1.0) * params.speed; 36 | value -= floor(value); 37 | } 38 | 39 | // Returns a brightness value according to the buffer value and number of steps 40 | float get_brightness_from_value(in float value) { 41 | float brightness = floor(value * 2.0 * float(params.steps - 1)); 42 | brightness = float(params.steps - 1) - abs(brightness - float(params.steps - 1)); 43 | return brightness / float(params.steps - 1); 44 | } 45 | 46 | void main() { 47 | ivec2 uv = ivec2(gl_GlobalInvocationID.xy); 48 | ivec2 size = ivec2(params.raster_size); 49 | 50 | if (uv.x >= size.x || uv.y >= size.y) { 51 | return; 52 | } 53 | 54 | int index = get_buffer_index(uv, size); 55 | float value = buffer_in.data[index]; 56 | vec4 screen_color = imageLoad(screen_image, uv); 57 | 58 | update_value(value, screen_color); 59 | buffer_out.data[index] = value; 60 | 61 | // Here the output pixel color is set with a cubic function to make the colors more even. 62 | screen_color.rgb = vec3(pow(get_brightness_from_value(value), 3.0)); 63 | imageStore(screen_image, uv, screen_color); 64 | } 65 | -------------------------------------------------------------------------------- /addons/noise_shader/sliding_noise.glsl: -------------------------------------------------------------------------------- 1 | #[compute] 2 | #version 450 3 | 4 | layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 5 | 6 | layout(rgba16f, set = 0, binding = 0) uniform image2D screen_image; 7 | 8 | // Details parameters to be sent to the shader 9 | layout(push_constant, std430) uniform Params { 10 | vec2 raster_size; 11 | ivec2 direction; 12 | bool invert; 13 | } params; 14 | 15 | // The noise data the shader reads from 16 | layout(set = 1, binding = 1, std430) restrict buffer FloatBufferIn { 17 | float data[]; 18 | } 19 | buffer_in; 20 | 21 | // The noise data that the shader writes to 22 | layout(set = 1, binding = 2, std430) restrict buffer FloatBufferOut { 23 | float data[]; 24 | } 25 | buffer_out; 26 | 27 | // Random values that the shader can pull from 28 | layout(set = 1, binding = 3, std430) restrict buffer FloatRandomIn { 29 | float data[]; 30 | } 31 | random_in; 32 | 33 | // Returns the index of the buffer according to the uv coordinate 34 | int get_buffer_index(in ivec2 uv, in ivec2 size) { 35 | return uv.y * size.x + uv.x; 36 | } 37 | 38 | // Wraps a screen coordinate so that it is always within the viewable area 39 | ivec2 wrap(in ivec2 value, in ivec2 size) { 40 | return ivec2(mod(mod(value, size) + size, size)); 41 | } 42 | 43 | // Get the uv of the buffer that a pixel will take from, causing the slide effect 44 | ivec2 get_moved_uv(in ivec2 uv, in ivec2 size) { 45 | return wrap(uv + params.direction, size); 46 | } 47 | 48 | float get_brightness(in vec4 color) { 49 | return (color.r + color.g + color.b) / 3.0; 50 | } 51 | 52 | bool is_bright(in vec4 color) { 53 | return (get_brightness(color) == 0.0) != params.invert; 54 | } 55 | 56 | // Get the value of the given index or give a random value if the given index value is 0 57 | float get_value(in int index, in vec4 color) { 58 | return is_bright(color) ? random_in.data[index] : buffer_in.data[index]; 59 | } 60 | 61 | void main() { 62 | ivec2 uv = ivec2(gl_GlobalInvocationID.xy); 63 | ivec2 size = ivec2(params.raster_size); 64 | 65 | if (uv.x >= size.x || uv.y >= size.y) { 66 | return; 67 | } 68 | 69 | //ivec2 moved_uv = get_moved_uv(uv, size); 70 | float value = get_value(get_buffer_index(uv, size), imageLoad(screen_image, uv)); 71 | 72 | //vec4 screen_color = imageLoad(screen_image, uv); 73 | ivec2 moved_uv = get_moved_uv(uv, size); 74 | vec4 screen_color = imageLoad(screen_image, moved_uv); 75 | int moved_index = get_buffer_index(moved_uv, size); 76 | value = is_bright(screen_color) ? buffer_in.data[moved_index] : value; 77 | 78 | buffer_out.data[moved_index] = value; 79 | screen_color = vec4(value, value, value, 1.0); 80 | imageStore(screen_image, moved_uv, screen_color); 81 | } 82 | -------------------------------------------------------------------------------- /addons/noise_shader/colorful_noise.glsl: -------------------------------------------------------------------------------- 1 | #[compute] 2 | #version 450 3 | 4 | layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 5 | 6 | layout(rgba16f, set = 0, binding = 0) uniform image2D screen_image; 7 | 8 | // Details parameters to be sent to the shader 9 | layout(push_constant, std430) uniform Params { 10 | vec2 raster_size; 11 | int value_steps; 12 | float value_speed; 13 | int hue_steps; 14 | float hue_speed; 15 | float hue_offset; 16 | } params; 17 | 18 | // The noise data the shader reads from 19 | layout(set = 1, binding = 1, std430) restrict buffer FloatBufferIn { 20 | vec2 data[]; 21 | } 22 | buffer_in; 23 | 24 | // The noise data that the shader writes to 25 | layout(set = 1, binding = 2, std430) restrict buffer FloatBufferOut { 26 | vec2 data[]; 27 | } 28 | buffer_out; 29 | 30 | // Returns the index of the buffer according to the uv coordinate 31 | int get_buffer_index(in ivec2 uv, in ivec2 size) { 32 | return uv.y * size.x + uv.x; 33 | } 34 | 35 | // Update the buffer value according to the screen color and speed 36 | void update_value(inout float value, in float brightness, in float speed) { 37 | value = value + clamp(brightness, 0.0, 1.0) * speed; 38 | value -= floor(value); 39 | } 40 | 41 | // Returns a brightness value according to the buffer value and number of steps 42 | float get_brightness_from_value(in float value) { 43 | float brightness = floor(value * 2.0 * float(params.value_steps - 1)); 44 | brightness = float(params.value_steps - 1) - abs(brightness - float(params.value_steps - 1)); 45 | return brightness / float(params.value_steps - 1); 46 | } 47 | 48 | vec3 hsl_to_rgb(in float hue, in float saturation, in float lightness) { 49 | vec3 rgb = clamp(abs(mod(hue * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); 50 | 51 | return lightness + saturation * (rgb - 0.5) * (1.0 - abs(2.0 * lightness - 1.0)); 52 | } 53 | 54 | vec3 hsv_to_rgb(vec3 hsv) { 55 | vec4 k = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 56 | vec3 p = abs(fract(hsv.xxx + k.xyz) * 6.0 - k.www); 57 | return hsv.z * mix(k.xxx, clamp(p - k.xxx, 0.0, 1.0), hsv.y); 58 | } 59 | 60 | void main() { 61 | ivec2 uv = ivec2(gl_GlobalInvocationID.xy); 62 | ivec2 size = ivec2(params.raster_size); 63 | 64 | if (uv.x >= size.x || uv.y >= size.y) { 65 | return; 66 | } 67 | 68 | int index = get_buffer_index(uv, size); 69 | float value = buffer_in.data[index].x; 70 | float hue = buffer_in.data[index].y; 71 | vec4 screen_color = imageLoad(screen_image, uv); 72 | 73 | update_value(value, screen_color.r, params.value_speed); 74 | update_value(hue, screen_color.g, params.hue_speed); 75 | buffer_out.data[index].x = value; 76 | buffer_out.data[index].y = hue; 77 | 78 | hue = floor(hue * float(params.hue_steps)) / float(params.hue_steps); 79 | hue = fract(hue + params.hue_offset); 80 | value = pow(get_brightness_from_value(value), 3.0); 81 | screen_color.rgb = hsv_to_rgb(vec3(hue, 1.0, value)); 82 | imageStore(screen_image, uv, screen_color); 83 | } 84 | -------------------------------------------------------------------------------- /addons/noise_shader/variable_sliding_noise.glsl: -------------------------------------------------------------------------------- 1 | #[compute] 2 | #version 450 3 | 4 | layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 5 | 6 | layout(rgba16f, set = 0, binding = 0) uniform image2D screen_image; 7 | 8 | // Details parameters to be sent to the shader 9 | layout(push_constant, std430) uniform Params { 10 | vec2 raster_size; 11 | ivec2 direction; 12 | int speed_steps; 13 | int frame; 14 | float brightness_exponent; 15 | } params; 16 | 17 | // The noise data the shader reads from 18 | layout(set = 1, binding = 1, std430) restrict buffer FloatBufferIn { 19 | float data[]; 20 | } 21 | buffer_in; 22 | 23 | // The noise data that the shader writes to 24 | layout(set = 1, binding = 2, std430) restrict buffer FloatBufferOut { 25 | float data[]; 26 | } 27 | buffer_out; 28 | 29 | // Random values that the shader can pull from 30 | layout(set = 1, binding = 3, std430) restrict buffer FloatRandomIn { 31 | float data[]; 32 | } 33 | random_in; 34 | 35 | // Returns the index of the buffer according to the uv coordinate 36 | int get_buffer_index(in ivec2 uv, in ivec2 size) { 37 | return uv.y * size.x + uv.x; 38 | } 39 | 40 | // Wraps a screen coordinate so that it is always within the viewable area 41 | ivec2 wrap(in ivec2 value, in ivec2 size) { 42 | return ivec2(mod(mod(value, size) + size, size)); 43 | } 44 | 45 | // Get the uv of the buffer that a pixel will take from, causing the slide effect 46 | ivec2 get_moved_uv(in ivec2 uv, in ivec2 size) { 47 | return wrap(uv + params.direction, size); 48 | } 49 | 50 | float get_brightness(in vec4 color) { 51 | return (color.r + color.g + color.b) / 3.0; 52 | } 53 | 54 | int get_frame_divisor(in float brightness) { 55 | brightness = pow(brightness, params.brightness_exponent); 56 | return params.speed_steps - max(int(ceil(params.speed_steps * min(brightness, 1.0))), 1) + 1; 57 | } 58 | 59 | // Get the value of the given index or give a random value if the given index value is 0 60 | float get_value(in int index, in vec4 color, in float moved_brightness) { 61 | bool is_same_divisor = get_frame_divisor(get_brightness(color)) == get_frame_divisor(moved_brightness); 62 | return get_brightness(color) == 0.0 || !is_same_divisor ? random_in.data[index] : buffer_in.data[index]; 63 | } 64 | 65 | void main() { 66 | ivec2 uv = ivec2(gl_GlobalInvocationID.xy); 67 | ivec2 size = ivec2(params.raster_size); 68 | 69 | if (uv.x >= size.x || uv.y >= size.y) { 70 | return; 71 | } 72 | 73 | ivec2 moved_uv = get_moved_uv(uv, size); 74 | vec4 moved_color = imageLoad(screen_image, moved_uv); 75 | float moved_brightness = get_brightness(moved_color); 76 | float value = get_value(get_buffer_index(uv, size), imageLoad(screen_image, uv), moved_brightness); 77 | int moved_index = get_buffer_index(moved_uv, size); 78 | bool is_right_frame = mod(params.frame, get_frame_divisor(moved_brightness)) == 0; 79 | value = moved_brightness == 0.0 || !is_right_frame ? buffer_in.data[moved_index] : value; 80 | 81 | buffer_out.data[moved_index] = value; 82 | moved_color = vec4(value, value, value, 1.0); 83 | imageStore(screen_image, moved_uv, moved_color); 84 | } 85 | -------------------------------------------------------------------------------- /addons/noise_shader/cycling_noise_effect.gd: -------------------------------------------------------------------------------- 1 | extends CompositorEffect 2 | class_name CyclingNoiseEffect 3 | ## Adds a noisy effect to a camera. 4 | 5 | 6 | const NOISE_SHADER_PATH: String = "res://addons/noise_shader/cycling_noise.glsl" 7 | const BYTES_PER_BUFFER_FLOAT: int = 4 8 | 9 | @export_group("Parameters") 10 | ## If true, it randomizes each pixel every time the window is updated. 11 | @export var randomize_noise_on_resize: bool = true 12 | ## How many different colors there are. 13 | @export var steps: int = 3: 14 | set(value): 15 | steps = maxi(value, 2) 16 | ## How fast each pixel of the noise is cycled through. 17 | @export var speed: float = 0.2: 18 | set(value): 19 | speed = clampf(value, 0.0, 1.0) 20 | 21 | var _rendering_device: RenderingDevice 22 | var _shader: RID 23 | var _pipeline: RID 24 | 25 | var _buffer_size: int = 512 * 512 * BYTES_PER_BUFFER_FLOAT 26 | 27 | var _read_data: PackedByteArray = [] 28 | var _write_data: PackedByteArray = [] 29 | var _read_buffer: RID 30 | var _write_buffer: RID 31 | 32 | var _storage_set: RID 33 | 34 | 35 | func _init() -> void: 36 | effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 37 | _rendering_device = RenderingServer.get_rendering_device() 38 | RenderingServer.call_on_render_thread(_initialize_compute) 39 | 40 | 41 | ## Assigns a random value to each pixel of the noise. 42 | func randomize_noise() -> void: 43 | for offset: int in range(0, _write_data.size(), 4): 44 | _write_data.encode_float(offset, randf()) 45 | for offset: int in range(0, _read_data.size(), 4): 46 | _read_data.encode_float(offset, randf()) 47 | 48 | 49 | ## Assigns a value of 0.0 to each pixel of the noise. 50 | func clear_noise() -> void: 51 | for offset: int in range(0, _write_data.size(), 4): 52 | _write_data.encode_float(offset, 0.0) 53 | for offset: int in range(0, _read_data.size(), 4): 54 | _read_data.encode_float(offset, 0.0) 55 | 56 | 57 | func _notification(what: int) -> void: 58 | if what == NOTIFICATION_PREDELETE: 59 | if _shader.is_valid(): 60 | RenderingServer.free_rid(_shader) 61 | 62 | 63 | func _initialize_compute() -> void: 64 | _rendering_device = RenderingServer.get_rendering_device() 65 | if not _rendering_device: 66 | return 67 | 68 | var shader_file: RDShaderFile = load(NOISE_SHADER_PATH) 69 | var shader_spirv: RDShaderSPIRV = shader_file.get_spirv() 70 | 71 | _shader = _rendering_device.shader_create_from_spirv(shader_spirv) 72 | if not _shader.is_valid(): 73 | return 74 | 75 | _update_storage_set() 76 | 77 | _pipeline = _rendering_device.compute_pipeline_create(_shader) 78 | 79 | 80 | func _render_callback(effect_callback_type: int, render_data: RenderData) -> void: 81 | if ( 82 | not _rendering_device 83 | or effect_callback_type != EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 84 | or not _pipeline.is_valid() 85 | ): 86 | return 87 | 88 | var render_scene_buffers: RenderSceneBuffersRD = render_data.get_render_scene_buffers() 89 | if not render_scene_buffers: 90 | return 91 | 92 | var size: Vector2i = render_scene_buffers.get_internal_size() 93 | if size.x == 0 and size.y == 0: 94 | return 95 | 96 | if not _buffer_size == size.x * size.y * BYTES_PER_BUFFER_FLOAT: 97 | _buffer_size = size.x * size.y * BYTES_PER_BUFFER_FLOAT 98 | _update_storage_set() 99 | 100 | @warning_ignore("integer_division") 101 | var x_groups: int = (size.x - 1) / 8 + 1 102 | @warning_ignore("integer_division") 103 | var y_groups: int = (size.y - 1) / 8 + 1 104 | var z_groups: int = 1 105 | 106 | var push_constant: PackedByteArray = _get_push_constant(size) 107 | 108 | _rendering_device.buffer_update(_read_buffer, 0, _buffer_size, _read_data) 109 | 110 | for view_index: int in render_scene_buffers.get_view_count(): 111 | var screen_image := RDUniform.new() 112 | screen_image.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE 113 | screen_image.binding = 0 114 | var input_image: RID = render_scene_buffers.get_color_layer(view_index) 115 | screen_image.add_id(input_image) 116 | 117 | var screen_set: RID = UniformSetCacheRD.get_cache( 118 | _shader, 119 | 0, 120 | [screen_image], 121 | ) 122 | 123 | var compute_list: int = _rendering_device.compute_list_begin() 124 | _rendering_device.compute_list_bind_compute_pipeline(compute_list, _pipeline) 125 | _rendering_device.compute_list_bind_uniform_set(compute_list, screen_set, 0) 126 | _rendering_device.compute_list_bind_uniform_set(compute_list, _storage_set, 1) 127 | _rendering_device.compute_list_set_push_constant( 128 | compute_list, 129 | push_constant, 130 | push_constant.size(), 131 | ) 132 | _rendering_device.compute_list_dispatch(compute_list, x_groups, y_groups, z_groups) 133 | _rendering_device.compute_list_end() 134 | 135 | # This takes the output of the shader and puts it into the input. 136 | _read_data = _rendering_device.buffer_get_data(_write_buffer) 137 | 138 | 139 | func _get_push_constant(size: Vector2) -> PackedByteArray: 140 | var push_constant: PackedByteArray = [] 141 | push_constant.resize(16) 142 | push_constant.encode_float(0, size.x) 143 | push_constant.encode_float(4, size.y) 144 | push_constant.encode_s32(8, steps) 145 | push_constant.encode_float(12, speed) 146 | return push_constant 147 | 148 | 149 | func _update_storage_set() -> void: 150 | _read_data.resize(_buffer_size) 151 | _write_data.resize(_buffer_size) 152 | 153 | if randomize_noise_on_resize: 154 | randomize_noise() 155 | 156 | var buffer_in := RDUniform.new() 157 | buffer_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 158 | buffer_in.binding = 1 159 | _read_buffer = _rendering_device.storage_buffer_create(_buffer_size, _read_data) 160 | buffer_in.add_id(_read_buffer) 161 | 162 | var buffer_out := RDUniform.new() 163 | buffer_out.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 164 | buffer_out.binding = 2 165 | _write_buffer = _rendering_device.storage_buffer_create(_buffer_size, _write_data) 166 | buffer_out.add_id(_write_buffer) 167 | 168 | _storage_set = _rendering_device.uniform_set_create( 169 | [buffer_in, buffer_out], 170 | _shader, 171 | 1, 172 | ) 173 | -------------------------------------------------------------------------------- /addons/noise_shader/colorful_noise_effect.gd: -------------------------------------------------------------------------------- 1 | extends CompositorEffect 2 | class_name ColorfulNoiseEffect 3 | ## Adds a noisy effect to a camera. 4 | 5 | 6 | const NOISE_SHADER_PATH: String = "res://addons/noise_shader/colorful_noise.glsl" 7 | const BYTES_PER_BUFFER_FLOAT: int = 4 8 | 9 | @export_group("Parameters") 10 | ## If true, it randomizes each pixel every time the window is updated. 11 | @export var randomize_noise_on_resize: bool = true 12 | ## How many different values there are. 13 | @export var value_steps: int = 3: 14 | set(value): 15 | value_steps = maxi(value, 2) 16 | ## How fast each value of the noise is cycled through. 17 | @export var value_speed: float = 0.2: 18 | set(value): 19 | value_speed = clampf(value, 0.0, 1.0) 20 | ## How many different hues there are. 21 | @export var hue_steps: int = 3: 22 | set(value): 23 | hue_steps = maxi(value, 2) 24 | ## How fast each hue of the noise is cycled through. 25 | @export var hue_speed: float = 0.1: 26 | set(value): 27 | hue_speed = clampf(value, 0.0, 1.0) 28 | ## How much the hue is offset by. 29 | @export_range(0.0, 1.0) var hue_offset: float = 0.0 30 | 31 | var _rendering_device: RenderingDevice 32 | var _shader: RID 33 | var _pipeline: RID 34 | 35 | var _buffer_size: int = 512 * 512 * BYTES_PER_BUFFER_FLOAT 36 | 37 | var _read_data: PackedByteArray = [] 38 | var _write_data: PackedByteArray = [] 39 | var _read_buffer: RID 40 | var _write_buffer: RID 41 | 42 | var _storage_set: RID 43 | 44 | 45 | func _init() -> void: 46 | effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 47 | _rendering_device = RenderingServer.get_rendering_device() 48 | RenderingServer.call_on_render_thread(_initialize_compute) 49 | 50 | 51 | ## Assigns a random float to each value of the noise. 52 | func randomize_noise() -> void: 53 | for offset: int in range(0, _write_data.size(), 4): 54 | _write_data.encode_float(offset, randf()) 55 | for offset: int in range(0, _read_data.size(), 4): 56 | _read_data.encode_float(offset, randf()) 57 | 58 | 59 | ## Assigns a float of 0.0 to each value and hue of the noise. 60 | func clear_noise() -> void: 61 | for offset: int in range(0, _write_data.size(), 4): 62 | _write_data.encode_float(offset, 0.0) 63 | for offset: int in range(0, _read_data.size(), 4): 64 | _read_data.encode_float(offset, 0.0) 65 | 66 | 67 | ## Assigns a value of 0.5 to each value of the noise. 68 | func white_out_noise() -> void: 69 | for offset: int in range(0, _write_data.size(), 8): 70 | _write_data.encode_float(offset, 0.5) 71 | for offset: int in range(0, _read_data.size(), 8): 72 | _read_data.encode_float(offset, 0.5) 73 | 74 | 75 | func _notification(what: int) -> void: 76 | if what == NOTIFICATION_PREDELETE: 77 | if _shader.is_valid(): 78 | RenderingServer.free_rid(_shader) 79 | 80 | 81 | func _initialize_compute() -> void: 82 | _rendering_device = RenderingServer.get_rendering_device() 83 | if not _rendering_device: 84 | return 85 | 86 | var shader_file: RDShaderFile = load(NOISE_SHADER_PATH) 87 | var shader_spirv: RDShaderSPIRV = shader_file.get_spirv() 88 | 89 | _shader = _rendering_device.shader_create_from_spirv(shader_spirv) 90 | if not _shader.is_valid(): 91 | return 92 | 93 | _update_storage_set() 94 | 95 | _pipeline = _rendering_device.compute_pipeline_create(_shader) 96 | 97 | 98 | func _render_callback(effect_callback_type: int, render_data: RenderData) -> void: 99 | if ( 100 | not _rendering_device 101 | or effect_callback_type != EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 102 | or not _pipeline.is_valid() 103 | ): 104 | return 105 | 106 | var render_scene_buffers: RenderSceneBuffersRD = render_data.get_render_scene_buffers() 107 | if not render_scene_buffers: 108 | return 109 | 110 | var size: Vector2i = render_scene_buffers.get_internal_size() 111 | if size.x == 0 and size.y == 0: 112 | return 113 | 114 | if not _buffer_size == size.x * size.y * BYTES_PER_BUFFER_FLOAT * 2: 115 | _buffer_size = size.x * size.y * BYTES_PER_BUFFER_FLOAT * 2 116 | _update_storage_set() 117 | 118 | @warning_ignore("integer_division") 119 | var x_groups: int = (size.x - 1) / 8 + 1 120 | @warning_ignore("integer_division") 121 | var y_groups: int = (size.y - 1) / 8 + 1 122 | var z_groups: int = 1 123 | 124 | var push_constant: PackedByteArray = _get_push_constant(size) 125 | 126 | _rendering_device.buffer_update(_read_buffer, 0, _buffer_size, _read_data) 127 | 128 | for view_index: int in render_scene_buffers.get_view_count(): 129 | var screen_image := RDUniform.new() 130 | screen_image.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE 131 | screen_image.binding = 0 132 | var input_image: RID = render_scene_buffers.get_color_layer(view_index) 133 | screen_image.add_id(input_image) 134 | 135 | var screen_set: RID = UniformSetCacheRD.get_cache( 136 | _shader, 137 | 0, 138 | [screen_image], 139 | ) 140 | 141 | var compute_list: int = _rendering_device.compute_list_begin() 142 | _rendering_device.compute_list_bind_compute_pipeline(compute_list, _pipeline) 143 | _rendering_device.compute_list_bind_uniform_set(compute_list, screen_set, 0) 144 | _rendering_device.compute_list_bind_uniform_set(compute_list, _storage_set, 1) 145 | _rendering_device.compute_list_set_push_constant( 146 | compute_list, 147 | push_constant, 148 | push_constant.size(), 149 | ) 150 | _rendering_device.compute_list_dispatch(compute_list, x_groups, y_groups, z_groups) 151 | _rendering_device.compute_list_end() 152 | 153 | # This takes the output of the shader and puts it into the input. 154 | _read_data = _rendering_device.buffer_get_data(_write_buffer) 155 | 156 | 157 | func _get_push_constant(size: Vector2) -> PackedByteArray: 158 | var push_constant: PackedByteArray = [] 159 | push_constant.resize(32) 160 | push_constant.encode_float(0, size.x) 161 | push_constant.encode_float(4, size.y) 162 | push_constant.encode_s32(8, value_steps) 163 | push_constant.encode_float(12, value_speed) 164 | push_constant.encode_s32(16, hue_steps) 165 | push_constant.encode_float(20, hue_speed) 166 | push_constant.encode_float(24, hue_offset) 167 | return push_constant 168 | 169 | 170 | func _update_storage_set() -> void: 171 | _read_data.resize(_buffer_size) 172 | _write_data.resize(_buffer_size) 173 | 174 | if randomize_noise_on_resize: 175 | randomize_noise() 176 | 177 | var buffer_in := RDUniform.new() 178 | buffer_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 179 | buffer_in.binding = 1 180 | _read_buffer = _rendering_device.storage_buffer_create(_buffer_size, _read_data) 181 | buffer_in.add_id(_read_buffer) 182 | 183 | var buffer_out := RDUniform.new() 184 | buffer_out.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 185 | buffer_out.binding = 2 186 | _write_buffer = _rendering_device.storage_buffer_create(_buffer_size, _write_data) 187 | buffer_out.add_id(_write_buffer) 188 | 189 | _storage_set = _rendering_device.uniform_set_create( 190 | [buffer_in, buffer_out], 191 | _shader, 192 | 1, 193 | ) 194 | -------------------------------------------------------------------------------- /addons/noise_shader/variable_sliding_noise_effect.gd: -------------------------------------------------------------------------------- 1 | extends CompositorEffect 2 | class_name VariableSlidingNoiseEffect 3 | ## Adds a noisy effect to a camera. 4 | 5 | 6 | const NOISE_SHADER_PATH: String = "res://addons/noise_shader/variable_sliding_noise.glsl" 7 | const BYTES_PER_BUFFER_FLOAT: int = 4 8 | 9 | @export_group("Parameters") 10 | ## If true, it randomizes each pixel every time the window is updated. 11 | @export var randomize_noise_on_resize: bool = true 12 | ## The direction the noise slides 13 | @export var direction: Vector2i = Vector2i.DOWN 14 | ## How many different speeds the image can slide 15 | @export_range(1, 64) var speed_steps: int = 2 16 | ## Controls how the speed attenuates 17 | @export_range(0.0, 1.0) var brightness_exponent: float = 0.5 18 | 19 | var _frame: int = 1 20 | 21 | var _rendering_device: RenderingDevice 22 | var _shader: RID 23 | var _pipeline: RID 24 | 25 | var _buffer_size: int = 512 * 512 * BYTES_PER_BUFFER_FLOAT 26 | 27 | var _read_data: PackedByteArray = [] 28 | var _write_data: PackedByteArray = [] 29 | var _random_data: PackedByteArray = [] 30 | var _read_buffer: RID 31 | var _write_buffer: RID 32 | var _random_buffer: RID 33 | 34 | var _storage_set: RID 35 | 36 | 37 | func _init() -> void: 38 | effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 39 | _rendering_device = RenderingServer.get_rendering_device() 40 | RenderingServer.call_on_render_thread(_initialize_compute) 41 | 42 | 43 | ## Assigns a random value to each pixel of the noise. 44 | func randomize_noise() -> void: 45 | _randomize_data(_write_data) 46 | _randomize_data(_read_data) 47 | 48 | 49 | ## Assigns a value of 0.0 to each pixel of the noise. 50 | func clear_noise() -> void: 51 | for offset: int in range(0, _write_data.size(), 4): 52 | _write_data.encode_float(offset, 0.0) 53 | for offset: int in range(0, _read_data.size(), 4): 54 | _read_data.encode_float(offset, 0.0) 55 | 56 | 57 | func _notification(what: int) -> void: 58 | if what == NOTIFICATION_PREDELETE: 59 | if _shader.is_valid(): 60 | RenderingServer.free_rid(_shader) 61 | 62 | 63 | func _initialize_compute() -> void: 64 | _rendering_device = RenderingServer.get_rendering_device() 65 | if not _rendering_device: 66 | return 67 | 68 | var shader_file: RDShaderFile = load(NOISE_SHADER_PATH) 69 | var shader_spirv: RDShaderSPIRV = shader_file.get_spirv() 70 | 71 | _shader = _rendering_device.shader_create_from_spirv(shader_spirv) 72 | if not _shader.is_valid(): 73 | return 74 | 75 | _update_storage_set() 76 | 77 | _pipeline = _rendering_device.compute_pipeline_create(_shader) 78 | 79 | 80 | func _render_callback(effect_callback_type: int, render_data: RenderData) -> void: 81 | if ( 82 | not _rendering_device 83 | or effect_callback_type != EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 84 | or not _pipeline.is_valid() 85 | ): 86 | return 87 | 88 | var render_scene_buffers: RenderSceneBuffersRD = render_data.get_render_scene_buffers() 89 | if not render_scene_buffers: 90 | return 91 | 92 | var size: Vector2i = render_scene_buffers.get_internal_size() 93 | if size.x == 0 and size.y == 0: 94 | return 95 | 96 | if not _buffer_size == size.x * size.y * BYTES_PER_BUFFER_FLOAT: 97 | _buffer_size = size.x * size.y * BYTES_PER_BUFFER_FLOAT 98 | _update_storage_set() 99 | 100 | @warning_ignore("integer_division") 101 | var x_groups: int = (size.x - 1) / 8 + 1 102 | @warning_ignore("integer_division") 103 | var y_groups: int = (size.y - 1) / 8 + 1 104 | var z_groups: int = 1 105 | 106 | _frame += 1 107 | var push_constant: PackedByteArray = _get_push_constant(size) 108 | 109 | # instead of randomizing each individual element, we can just shuffle the random array around 110 | # this performs much better 111 | var shuffle_data: Array = Array(_random_data.to_float32_array()) 112 | shuffle_data.shuffle() 113 | _random_data = PackedFloat32Array(shuffle_data).to_byte_array() 114 | #_randomize_data(_random_data) 115 | 116 | _rendering_device.buffer_update(_random_buffer, 0, _buffer_size, _random_data) 117 | _rendering_device.buffer_update(_read_buffer, 0, _buffer_size, _read_data) 118 | 119 | for view_index: int in render_scene_buffers.get_view_count(): 120 | var screen_image := RDUniform.new() 121 | screen_image.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE 122 | screen_image.binding = 0 123 | var input_image: RID = render_scene_buffers.get_color_layer(view_index) 124 | screen_image.add_id(input_image) 125 | 126 | var screen_set: RID = UniformSetCacheRD.get_cache( 127 | _shader, 128 | 0, 129 | [screen_image], 130 | ) 131 | 132 | var compute_list: int = _rendering_device.compute_list_begin() 133 | _rendering_device.compute_list_bind_compute_pipeline(compute_list, _pipeline) 134 | _rendering_device.compute_list_bind_uniform_set(compute_list, screen_set, 0) 135 | _rendering_device.compute_list_bind_uniform_set(compute_list, _storage_set, 1) 136 | _rendering_device.compute_list_set_push_constant( 137 | compute_list, 138 | push_constant, 139 | push_constant.size(), 140 | ) 141 | _rendering_device.compute_list_dispatch(compute_list, x_groups, y_groups, z_groups) 142 | _rendering_device.compute_list_end() 143 | 144 | # This takes the output of the shader and puts it into the input. 145 | _read_data = _rendering_device.buffer_get_data(_write_buffer) 146 | 147 | 148 | func _get_push_constant(size: Vector2) -> PackedByteArray: 149 | var push_constant: PackedByteArray = [] 150 | push_constant.resize(32) 151 | push_constant.encode_float(0, size.x) 152 | push_constant.encode_float(4, size.y) 153 | push_constant.encode_s32(8, direction.x) 154 | push_constant.encode_s32(12, direction.y) 155 | push_constant.encode_s32(16, speed_steps) 156 | push_constant.encode_s32(20, _frame) 157 | push_constant.encode_float(24, brightness_exponent) 158 | return push_constant 159 | 160 | 161 | func _update_storage_set() -> void: 162 | _read_data.resize(_buffer_size) 163 | _write_data.resize(_buffer_size) 164 | _random_data.resize(_buffer_size) 165 | 166 | if randomize_noise_on_resize: 167 | randomize_noise() 168 | 169 | var buffer_in := RDUniform.new() 170 | buffer_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 171 | buffer_in.binding = 1 172 | _read_buffer = _rendering_device.storage_buffer_create(_buffer_size, _read_data) 173 | buffer_in.add_id(_read_buffer) 174 | 175 | var buffer_out := RDUniform.new() 176 | buffer_out.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 177 | buffer_out.binding = 2 178 | _write_buffer = _rendering_device.storage_buffer_create(_buffer_size, _write_data) 179 | buffer_out.add_id(_write_buffer) 180 | 181 | var random_in := RDUniform.new() 182 | random_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 183 | random_in.binding = 3 184 | _randomize_data(_random_data) 185 | _random_buffer = _rendering_device.storage_buffer_create(_buffer_size, _random_data) 186 | random_in.add_id(_random_buffer) 187 | 188 | _storage_set = _rendering_device.uniform_set_create( 189 | [buffer_in, buffer_out, random_in], 190 | _shader, 191 | 1, 192 | ) 193 | 194 | 195 | func _randomize_data(data: PackedByteArray) -> void: 196 | for offset: int in range(0, data.size(), 4): 197 | data.encode_float(offset, randf()) 198 | -------------------------------------------------------------------------------- /addons/noise_shader/sliding_noise_effect.gd: -------------------------------------------------------------------------------- 1 | extends CompositorEffect 2 | class_name SlidingNoiseEffect 3 | ## Adds a noisy effect to a camera. 4 | 5 | 6 | const NOISE_SHADER_PATH: String = "res://addons/noise_shader/sliding_noise.glsl" 7 | const BYTES_PER_BUFFER_FLOAT: int = 4 8 | 9 | @export_group("Parameters") 10 | ## If true, it randomizes each pixel every time the window is updated. 11 | @export var randomize_noise_on_resize: bool = true 12 | ## The direction the noise slides 13 | @export var direction: Vector2i = Vector2i.DOWN 14 | ## Determines which part of the image slides 15 | @export var invert: bool = false 16 | ## How many frames happen per update. Higher numbers make the sliding slower 17 | @export_range(1, 60) var frames_per_update: int = 1: 18 | set(value): 19 | frames_per_update = maxi(value, 1) 20 | 21 | var _frame: int = 1 22 | 23 | var _rendering_device: RenderingDevice 24 | var _shader: RID 25 | var _pipeline: RID 26 | 27 | var _buffer_size: int = 512 * 512 * BYTES_PER_BUFFER_FLOAT 28 | 29 | var _read_data: PackedByteArray = [] 30 | var _write_data: PackedByteArray = [] 31 | var _random_data: PackedByteArray = [] 32 | var _read_buffer: RID 33 | var _write_buffer: RID 34 | var _random_buffer: RID 35 | 36 | var _storage_set: RID 37 | 38 | 39 | func _init() -> void: 40 | effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 41 | _rendering_device = RenderingServer.get_rendering_device() 42 | RenderingServer.call_on_render_thread(_initialize_compute) 43 | 44 | 45 | ## Assigns a random value to each pixel of the noise. 46 | func randomize_noise() -> void: 47 | _randomize_data(_write_data) 48 | _randomize_data(_read_data) 49 | 50 | 51 | ## Assigns a value of 0.0 to each pixel of the noise. 52 | func clear_noise() -> void: 53 | for offset: int in range(0, _write_data.size(), 4): 54 | _write_data.encode_float(offset, 0.0) 55 | for offset: int in range(0, _read_data.size(), 4): 56 | _read_data.encode_float(offset, 0.0) 57 | 58 | 59 | func _notification(what: int) -> void: 60 | if what == NOTIFICATION_PREDELETE: 61 | if _shader.is_valid(): 62 | RenderingServer.free_rid(_shader) 63 | 64 | 65 | func _initialize_compute() -> void: 66 | _rendering_device = RenderingServer.get_rendering_device() 67 | if not _rendering_device: 68 | return 69 | 70 | var shader_file: RDShaderFile = load(NOISE_SHADER_PATH) 71 | var shader_spirv: RDShaderSPIRV = shader_file.get_spirv() 72 | 73 | _shader = _rendering_device.shader_create_from_spirv(shader_spirv) 74 | if not _shader.is_valid(): 75 | return 76 | 77 | _update_storage_set() 78 | 79 | _pipeline = _rendering_device.compute_pipeline_create(_shader) 80 | 81 | 82 | func _render_callback(effect_callback_type: int, render_data: RenderData) -> void: 83 | if ( 84 | not _rendering_device 85 | or effect_callback_type != EFFECT_CALLBACK_TYPE_POST_TRANSPARENT 86 | or not _pipeline.is_valid() 87 | ): 88 | return 89 | 90 | var render_scene_buffers: RenderSceneBuffersRD = render_data.get_render_scene_buffers() 91 | if not render_scene_buffers: 92 | return 93 | 94 | var size: Vector2i = render_scene_buffers.get_internal_size() 95 | if size.x == 0 and size.y == 0: 96 | return 97 | 98 | if not _buffer_size == size.x * size.y * BYTES_PER_BUFFER_FLOAT: 99 | _buffer_size = size.x * size.y * BYTES_PER_BUFFER_FLOAT 100 | _update_storage_set() 101 | 102 | @warning_ignore("integer_division") 103 | var x_groups: int = (size.x - 1) / 8 + 1 104 | @warning_ignore("integer_division") 105 | var y_groups: int = (size.y - 1) / 8 + 1 106 | var z_groups: int = 1 107 | 108 | var update: bool = false 109 | if _frame % frames_per_update == 0: 110 | update = true 111 | _frame = 1 112 | else: 113 | _frame += 1 114 | 115 | var push_constant: PackedByteArray = _get_push_constant(size, update) 116 | 117 | # instead of randomizing each individual element, we can just shuffle the random array around 118 | # this performs much better 119 | var shuffle_data: Array = Array(_random_data.to_float32_array()) 120 | shuffle_data.shuffle() 121 | _random_data = PackedFloat32Array(shuffle_data).to_byte_array() 122 | #_randomize_data(_random_data) 123 | 124 | _rendering_device.buffer_update(_random_buffer, 0, _buffer_size, _random_data) 125 | _rendering_device.buffer_update(_read_buffer, 0, _buffer_size, _read_data) 126 | 127 | for view_index: int in render_scene_buffers.get_view_count(): 128 | var screen_image := RDUniform.new() 129 | screen_image.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE 130 | screen_image.binding = 0 131 | var input_image: RID = render_scene_buffers.get_color_layer(view_index) 132 | screen_image.add_id(input_image) 133 | 134 | var screen_set: RID = UniformSetCacheRD.get_cache( 135 | _shader, 136 | 0, 137 | [screen_image], 138 | ) 139 | 140 | var compute_list: int = _rendering_device.compute_list_begin() 141 | _rendering_device.compute_list_bind_compute_pipeline(compute_list, _pipeline) 142 | _rendering_device.compute_list_bind_uniform_set(compute_list, screen_set, 0) 143 | _rendering_device.compute_list_bind_uniform_set(compute_list, _storage_set, 1) 144 | _rendering_device.compute_list_set_push_constant( 145 | compute_list, 146 | push_constant, 147 | push_constant.size(), 148 | ) 149 | _rendering_device.compute_list_dispatch(compute_list, x_groups, y_groups, z_groups) 150 | _rendering_device.compute_list_end() 151 | 152 | # This takes the output of the shader and puts it into the input. 153 | _read_data = _rendering_device.buffer_get_data(_write_buffer) 154 | 155 | 156 | func _get_push_constant(size: Vector2, do_update: bool) -> PackedByteArray: 157 | var push_constant: PackedByteArray = [] 158 | push_constant.resize(32) 159 | push_constant.encode_float(0, size.x) 160 | push_constant.encode_float(4, size.y) 161 | push_constant.encode_s32(8, direction.x * int(do_update)) 162 | push_constant.encode_s32(12, direction.y * int(do_update)) 163 | push_constant.encode_s32(16, int(invert)) 164 | return push_constant 165 | 166 | 167 | func _update_storage_set() -> void: 168 | _read_data.resize(_buffer_size) 169 | _write_data.resize(_buffer_size) 170 | _random_data.resize(_buffer_size) 171 | 172 | if randomize_noise_on_resize: 173 | randomize_noise() 174 | 175 | var buffer_in := RDUniform.new() 176 | buffer_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 177 | buffer_in.binding = 1 178 | _read_buffer = _rendering_device.storage_buffer_create(_buffer_size, _read_data) 179 | buffer_in.add_id(_read_buffer) 180 | 181 | var buffer_out := RDUniform.new() 182 | buffer_out.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 183 | buffer_out.binding = 2 184 | _write_buffer = _rendering_device.storage_buffer_create(_buffer_size, _write_data) 185 | buffer_out.add_id(_write_buffer) 186 | 187 | var random_in := RDUniform.new() 188 | random_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER 189 | random_in.binding = 3 190 | _randomize_data(_random_data) 191 | _random_buffer = _rendering_device.storage_buffer_create(_buffer_size, _random_data) 192 | random_in.add_id(_random_buffer) 193 | 194 | _storage_set = _rendering_device.uniform_set_create( 195 | [buffer_in, buffer_out, random_in], 196 | _shader, 197 | 1, 198 | ) 199 | 200 | 201 | func _randomize_data(data: PackedByteArray) -> void: 202 | for offset: int in range(0, data.size(), 4): 203 | data.encode_float(offset, randf()) 204 | --------------------------------------------------------------------------------