From 6e04bf27ff53930a4e2f817666fb300a7fcc2528 Mon Sep 17 00:00:00 2001 From: Kasper Date: Fri, 1 Aug 2025 02:18:46 +0300 Subject: [PATCH] good progress, but no other compute pass yet --- shaders/agents_cs.glsl | 36 ++++++++++++ shaders/agents_cs.glsl.import | 14 +++++ shaders/decay_cs.glsl | 4 +- slime_simulation.gd | 104 +++++++++++++++++++++++++--------- 4 files changed, 129 insertions(+), 29 deletions(-) create mode 100644 shaders/agents_cs.glsl create mode 100644 shaders/agents_cs.glsl.import diff --git a/shaders/agents_cs.glsl b/shaders/agents_cs.glsl new file mode 100644 index 0000000..3aa9410 --- /dev/null +++ b/shaders/agents_cs.glsl @@ -0,0 +1,36 @@ +#[compute] +#version 450 + +// Invocations in the (x, y, z) dimension +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D current_trail; +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D output_trail; +layout(set = 2, binding = 1) restrict buffer AgentBuffer { + vec2 positions[]; +} agent_buffer; + +layout(push_constant, std430) uniform Params { + vec2 texture_size; +} params; + + +void main() { + + ivec2 size = ivec2(params.texture_size.x - 1, params.texture_size.y - 1); + vec2 position = agent_buffer.positions[gl_GlobalInvocationID.x]; + + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + + ivec2 tl = ivec2(0, 0); + float current_v = imageLoad(current_trail, clamp(uv - ivec2(0, 1), tl, size)).r; + float up_v = imageLoad(current_trail, clamp(uv - ivec2(0, 1), tl, size)).r; + float down_v = imageLoad(current_trail, clamp(uv + ivec2(0, 1), tl, size)).r; + float left_v = imageLoad(current_trail, clamp(uv - ivec2(1, 0), tl, size)).r; + float right_v = imageLoad(current_trail, clamp(uv + ivec2(1, 0), tl, size)).r; + + float new_v = current_v + 0.05; + + vec4 result = vec4(new_v, new_v, new_v, 1.0); + imageStore(output_trail, uv, result); +} diff --git a/shaders/agents_cs.glsl.import b/shaders/agents_cs.glsl.import new file mode 100644 index 0000000..ddad48e --- /dev/null +++ b/shaders/agents_cs.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://u3grg3r2bgi1" +path="res://.godot/imported/agents_cs.glsl-b2836a7ba58df020a54fe9498ba98f67.res" + +[deps] + +source_file="res://shaders/agents_cs.glsl" +dest_files=["res://.godot/imported/agents_cs.glsl-b2836a7ba58df020a54fe9498ba98f67.res"] + +[params] + diff --git a/shaders/decay_cs.glsl b/shaders/decay_cs.glsl index 1b716af..598c93f 100644 --- a/shaders/decay_cs.glsl +++ b/shaders/decay_cs.glsl @@ -6,14 +6,12 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; // Our textures. layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D current_image; -layout(r32f, set = 1, binding = 0) uniform restrict readonly image2D previous_image; -layout(r32f, set = 2, binding = 0) uniform restrict writeonly image2D output_image; +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D output_image; // PushConstants layout(push_constant, std430) uniform Params { vec2 texture_size; float decay_factor; - float dunno_lol; } params; diff --git a/slime_simulation.gd b/slime_simulation.gd index eeeefe7..1e66dda 100644 --- a/slime_simulation.gd +++ b/slime_simulation.gd @@ -16,7 +16,7 @@ func _ready(): func _process(_delta: float) -> void: - next_texture = (next_texture + 1) % 3 + next_texture = (next_texture + 1) % 2 if texture: texture.texture_rd_rid = texture_rds[next_texture] @@ -37,15 +37,22 @@ func _exit_tree() -> void: var rd: RenderingDevice -var shader: RID -var pipeline: RID +var decay_shader: RID +var decay_pipeline: RID + +var agent_shader: RID +var agent_pipeline: RID # We use 3 textures: # - One to render into # - One that contains the last frame rendered # - One for the frame before that -var texture_rds: Array[RID] = [RID(), RID(), RID()] -var texture_sets: Array[RID] = [RID(), RID(), RID()] +var texture_rds: Array[RID] = [RID(), RID()] +var texture_sets: Array[RID] = [RID(), RID()] + +var agent_uniform_sets: Array[RID] = [RID(), RID()] +var agent_buffer: RID +var agent_set: RID func _load_shader(rd_: RenderingDevice, path: String) -> RID: @@ -54,13 +61,12 @@ func _load_shader(rd_: RenderingDevice, path: String) -> RID: return rd_.shader_create_from_spirv(shader_spirv) -func _create_uniform_set(texture_rd: RID) -> RID: +func _create_trail_uniform(texture_rd: RID) -> RDUniform: var uniform := RDUniform.new() uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE uniform.binding = 0 uniform.add_id(texture_rd) - # Even though we're using 3 sets, they are identical, so we're kinda cheating. - return rd.uniform_set_create([uniform], shader, 0) + return uniform func _initialize_compute_code(init_with_texture_size: Vector2i) -> void: @@ -68,9 +74,28 @@ func _initialize_compute_code(init_with_texture_size: Vector2i) -> void: # we use our main rendering device here. rd = RenderingServer.get_rendering_device() - # Create shader - shader = _load_shader(rd, "res://shaders/decay_cs.glsl") - pipeline = rd.compute_pipeline_create(shader) + # Create shaders + decay_shader = _load_shader(rd, "res://shaders/decay_cs.glsl") + decay_pipeline = rd.compute_pipeline_create(decay_shader) + + agent_shader = _load_shader(rd, "res://shaders/agents_cs.glsl") + agent_pipeline = rd.compute_pipeline_create(agent_shader) + + # Create agent buffer + var rng := RandomNumberGenerator.new() + rng.seed = 80085 + var agent_data := PackedVector2Array() + for n in 64 * 16: + var new_position: Vector2i = Vector2( + rng.randi_range(0, init_with_texture_size.x), + rng.randi_range(0, init_with_texture_size.y) + ) + agent_data.push_back(new_position) + + var agent_size_in_bytes := 8 + agent_buffer = rd.storage_buffer_create( + agent_data.size() * agent_size_in_bytes, agent_data.to_byte_array() + ) # Create trail texture var tf: RDTextureFormat = RDTextureFormat.new() @@ -89,38 +114,65 @@ func _initialize_compute_code(init_with_texture_size: Vector2i) -> void: | RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT ) - for i in 3: + + var agent_uniforms = [] + for i in 2: texture_rds[i] = rd.texture_create(tf, RDTextureView.new(), []) - # Make sure our textures are cleared. - rd.texture_clear(texture_rds[i], Color.WHITE, 0, 1, 0, 1) + rd.texture_clear(texture_rds[i], Color.BLACK, 0, 1, 0, 1) - # Now create our uniform set so we can use these textures in our shader. - texture_sets[i] = _create_uniform_set(texture_rds[i]) + var trail_uniform := _create_trail_uniform(texture_rds[i]) + texture_sets[i] = rd.uniform_set_create([trail_uniform], decay_shader, 0) + agent_uniform_sets[i] = rd.uniform_set_create([trail_uniform], agent_shader, 0) + + + var uniform := RDUniform.new() + uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform.binding = 1 + uniform.add_id(agent_buffer) + agent_set = rd.uniform_set_create([uniform], agent_shader, 0) func _render_process(with_next_texture: int, tex_size: Vector2i, decay_fctr: float) -> void: + var next_set := texture_sets[with_next_texture] + var current_set := texture_sets[(with_next_texture - 1) % 2] + + # Run agents var push_constant := PackedFloat32Array() push_constant.push_back(tex_size.x) push_constant.push_back(tex_size.y) + push_constant.push_back(0.0) + push_constant.push_back(0.0) + + + var agent_compute_list := rd.compute_list_begin() + rd.compute_list_bind_compute_pipeline(agent_compute_list, agent_pipeline) + rd.compute_list_bind_uniform_set(agent_compute_list, current_set, 0) + rd.compute_list_bind_uniform_set(agent_compute_list, next_set, 1) + rd.compute_list_bind_uniform_set(agent_compute_list, agent_set, 2) + rd.compute_list_set_push_constant( + agent_compute_list, push_constant.to_byte_array(), push_constant.size() * 4 + ) + rd.compute_list_dispatch(agent_compute_list, 16, 1, 1) + rd.compute_list_end() + + # Decay and dissipate + push_constant.clear() + push_constant.push_back(tex_size.x) + push_constant.push_back(tex_size.y) push_constant.push_back(decay_fctr) - push_constant.push_back(0.0) # not sure if this is needed + push_constant.push_back(0.0) @warning_ignore("integer_division") var x_groups := (tex_size.x - 1) / 8 + 1 @warning_ignore("integer_division") var y_groups := (tex_size.y - 1) / 8 + 1 - var next_set := texture_sets[with_next_texture] - var current_set := texture_sets[(with_next_texture - 1) % 3] - var previous_set := texture_sets[(with_next_texture - 2) % 3] - # Run the compute shader var compute_list := rd.compute_list_begin() - rd.compute_list_bind_compute_pipeline(compute_list, pipeline) + rd.compute_list_bind_compute_pipeline(compute_list, decay_pipeline) rd.compute_list_bind_uniform_set(compute_list, current_set, 0) - rd.compute_list_bind_uniform_set(compute_list, previous_set, 1) - rd.compute_list_bind_uniform_set(compute_list, next_set, 2) + rd.compute_list_bind_uniform_set(compute_list, next_set, 1) rd.compute_list_set_push_constant( compute_list, push_constant.to_byte_array(), push_constant.size() * 4 ) @@ -140,5 +192,5 @@ func _free_compute_resources() -> void: if texture_rds[i]: rd.free_rid(texture_rds[i]) - if shader: - rd.free_rid(shader) + if decay_shader: + rd.free_rid(decay_shader)