Godot Version
4.2
Question
I’m trying to create a compute shader to modify an array of vertices in a mesh using a compute shader. What I’m doing for now is getting a list of values to modify the vertices by from the compute shader and then multiplying the vertices from the cpu side. But I’m getting a bunch of seemingly completely random outputs from the compute shader:
Here is what my code looks like on the cpu side:
# Vertex buffer.
var vertex_array_bytes := vertices.to_byte_array()
var vertex_buffer := rd.storage_buffer_create(vertex_array_bytes.size(), vertex_array_bytes)
var vertex_uniform := RDUniform.new()
vertex_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
vertex_uniform.binding = 0
vertex_uniform.add_id(vertex_buffer)
var vertex_set := rd.uniform_set_create([vertex_uniform], shader, 0)
# Params buffer.
var parameters_array := PackedFloat32Array([get_parent().test_val, vertices_per_face * 8 - (resolution + 2) * 12 + 6])
var parameters_array_bytes := parameters_array.to_byte_array()
var parameter_buffer := rd.storage_buffer_create(parameters_array_bytes.size(), parameters_array_bytes)
var parameter_uniform := RDUniform.new()
parameter_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
parameter_uniform.binding = 1
parameter_uniform.add_id(parameter_buffer)
var parameter_set := rd.uniform_set_create([parameter_uniform], shader, 1)
# Heights buffer.
var blank_heights_array := PackedFloat32Array()
blank_heights_array.resize(vertices.size())
var blank_heights_array_bytes := blank_heights_array.to_byte_array()
var heights_buffer := rd.storage_buffer_create(blank_heights_array_bytes.size(), blank_heights_array_bytes)
var heights_uniform := RDUniform.new()
heights_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
heights_uniform.binding = 2
heights_uniform.add_id(heights_buffer)
var heights_set := rd.uniform_set_create([heights_uniform], shader, 2)
# Create compute pipeline
var pipeline := rd.compute_pipeline_create(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, vertex_set, 0)
rd.compute_list_bind_uniform_set(compute_list, parameter_set, 1)
rd.compute_list_bind_uniform_set(compute_list, heights_set, 2)
rd.compute_list_dispatch(compute_list, 512, 1, 1)
rd.compute_list_end()
rd.submit()
rd.sync()
# Retrieve output of compute shader.
var heights_array_bytes := rd.buffer_get_data(heights_buffer)
var heights_array := heights_array_bytes.to_float32_array()
for i in range(0, heights_array.size()):
vertices[i] *= heights_array[i]
I know that my vertices array that I start with has all the correct values and the parameters buffer isn’t being used for now.
The heights buffer starts out as all zero but gets modified by the shader:
#[compute]
#version 450
layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0) restrict buffer VerticesBuffer {
vec3 data[];
}
vertices_buffer;
layout(set = 1, binding = 1) buffer Parameters {
float test_val;
float num_vertices;
} parameters;
layout(set = 2, binding = 2) restrict buffer HeightsBuffer {
float data[];
}
heights_buffer;
// The code we want to execute in each invocation
void main() {
// gl_GlobalInvocationID.x uniquely identifies this invocation across all work groups
if (gl_GlobalInvocationID.x > parameters.num_vertices) { return; }
vec3 vertexPos = vertices_buffer.data[gl_GlobalInvocationID.x];
heights_buffer.data[gl_GlobalInvocationID.x] = length(vertexPos) * 2;
}
These weird values end up in the mesh looking like a crumpled paper ball.
It seems like any values I pass into the compute shader get messed up afterword and I’m not sure why.
Thanks for the help.