Godot Version
4.7
Question
I am having problems reproducing the effect of a heightfield texture in a compute shader - the values just don’t look right. There is enough shared memory, The second shader uses an additional 64 floats but the max might be 32 kb.
I have a 2 stage compute shader and the debugging process is difficult, are there any tools for the task?
1st pass… reduce 4096 x 4096 sized texture to 512 by 512 and only store the min and max heights from the 8 x 8 tiles. (santiy check, 512 x 8 = 4096)
#[compute]
#version 450
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, r16) uniform image2D height_image;
layout(set = 0, binding = 1, rgba32f) uniform image2D data_output_image;
shared float sdata[64];
void main() {
ivec2 UV = ivec2( int(gl_GlobalInvocationID.x), int(gl_GlobalInvocationID.y) );
ivec2 UV_out = ivec2( int( float(UV.x) / 8), int( float(UV.y) / 8) );
uint local_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 8;
sdata[local_index] = 500.0*imageLoad(height_image, UV ).r;
memoryBarrierShared();
barrier();
float min_h = 100000.0;
float max_h = -100000.0;
for (uint i = 0; i<64; i++){
if ( sdata[i] > max_h ){
max_h = sdata[i];
}
if ( sdata[i] < min_h ){
min_h = sdata[i];
}
}
memoryBarrierShared();
barrier();
vec4 output_data_vec = vec4( min_h, max_h, min_h, max_h);
imageStore(data_output_image, UV_out, output_data_vec);
}
Second pass … take the 512 x 512 data array and compute the min and max values for 64 x 64 tiles
(sanity check 64 x 8 = 512 )
#[compute]
#version 450
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba32f) uniform image2D height_image;
layout(set = 0, binding = 1, rgba32f) uniform image2D data_output_image;
shared float sdata_min[64];
shared float sdata_max[64];
void main() {
ivec2 UV = ivec2( int(gl_GlobalInvocationID.x), int(gl_GlobalInvocationID.y) );
ivec2 UV_out = ivec2( int( float(UV.x) / 8), int( float(UV.y) / 8) );
uint local_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 8;
sdata_min[local_index] = imageLoad(height_image, UV ).r;
sdata_max[local_index] = imageLoad(height_image, UV ).g;
memoryBarrierShared();
barrier();
float min_h = 100000.0;
float max_h = -100000.0;
for (uint i = 0; i<64; i++){
if ( sdata_min[i] < min_h ){
min_h = sdata_min[i];
}
if ( sdata_max[i] > max_h ){
max_h = sdata_max[i];
}
}
memoryBarrierShared();
barrier();
vec4 output_data_vec = vec4( min_h, max_h, min_h, max_h);
imageStore(data_output_image, UV_out, output_data_vec);
}
The code (using the EasyCompute addon ). The values that are printed should be min and max near the center … but the heightfield is quite high altitude when rendered as a heightfield, the values printed by this function are like 5.0 and 6.0 not 400.0 . What could be going on?
func texture_fill2():
compute.load_shader("fill", "res://examples/fill2.glsl")
var tex :CompressedTexture2D= load("res://examples/height2.exr")
var image = tex.get_image()
if image.is_compressed():
image.decompress()
image.convert(Image.FORMAT_R16)
var texture = ImageTexture.create_from_image(image)
var source_size = 4096
compute.register_texture("height_image", 0, source_size, source_size, image.get_data(), RenderingDevice.DATA_FORMAT_R16_UNORM)
compute.register_texture("data_output_image", 1, 512, 512,[], RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT)
# FIRST PASS, Find min and max height values
compute.execute("fill", 512,512)
compute.sync()
var image_data = compute.fetch_texture("data_output_image")
#print(image_data.to_vector4_array())
# SECOND PASS, Find min and max height values
compute.load_shader("fill_min_max", "res://examples/fill_min_max2.glsl")
compute.register_texture("height_image", 0, 512, 512, image_data, RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT)
compute.register_texture("data_output_image", 0, 64, 64, [], RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT)
compute.execute("fill_min_max", 64,64)
compute.sync()
var final_image_data = compute.fetch_texture("data_output_image")
var float_data = final_image_data.to_vector4_array()
var index1 = 32 + 32*64
var index2 = 33 + 32*64
var index3 = 32 + 33*64
var index4 = 33 + 33*64
var max:float = 0.0
var min:float = 10000.0
if float_data[index1].x < min:
min =float_data[index1].x
if float_data[index2].x < min:
min =float_data[index2].x
if float_data[index3].x < min:
min =float_data[index3].x
if float_data[index4].x < min:
min =float_data[index4].x
#print(float_data[index])
if float_data[index1].y > max:
max =float_data[index1].y
if float_data[index2].y > max:
max =float_data[index2].y
if float_data[index3].y > max:
max =float_data[index3].y
if float_data[index4].y > max:
max =float_data[index4].y
print(min)
print(max)
var output_image = Image.create_from_data(64, 64, false, Image.FORMAT_RGBAF, final_image_data)
var texture2 = ImageTexture.create_from_image(output_image)
sprite_2d.texture = texture2
sprite_2d_2.texture = texture
