Gaps appearing between custom texture tiles (compute shading)

Godot Version

4.6.beta

Question

No compute shader tag available
Hi,

I’m playing around with procedural generation, including diving into compute shaders. My basic idea is to take various plane meshes, generate heightmaps, and apply those heightmaps to the planes that are laid out in a grid. I’ve managed to make the heightmap itself seamless - the edges of the tiles look like they are continuations of each other - but there’s a literal, physical line between each of them.

Zooming in, it seems that the “higher” mesh is always a little higher along the edges, the “lower” mesh always a little lower:

I’m trying to bridge those little gaps, somehow. I tried extending the dimensions for what is drawn, but the problem persists - they just overlap with each other in a noticeable fashion. Looking at it from directly above, it seems they match up in X and Z coordinates (all visible distances are from shadows), so I assume it’s something about how my height is applied.

Here is some of my GLSL code for how heightmaps are applied (cutting out non-height-related calculations):

#[compute]
#version 460

layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;

layout(r32f, binding = 0) uniform readonly image2D heightmap;

layout(set = 0, binding = 1, std430) buffer Vertices {
    vec4 data[];
} vertices;

layout(push_constant, std430) uniform Params {
    float dimension;
    float resolution;
} params;

float get_height(float x, float y) {
    float u = (x / params.dimension + 0.5) * (params.dimension - 0.5);
    float v = (y / params.dimension + 0.5) * (params.dimension - 0.5);

    ivec2 coord = ivec2(u, v);
    return imageLoad(heightmap, coord).r;
}

void main() {
    uint gid = gl_GlobalInvocationID.x;

    vec3 vertex = vertices.data[gid].xyz;
    vertices.data[gid].y = get_height(vertex.x, vertex.z);
}

Do you see if there’s an obvious error that’s causing this slight offset?

For reference, my heightmap generator code as well. This is a starter code, I’m hoping to make it much cooler in the future.

#[compute]
#version 460

layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;

layout(r32f, binding = 0) uniform writeonly image2D heightmap;

layout(push_constant,std430) uniform Params {
	float height_scale;
	float frequency;
	float seed;
	float tile_offset_x;
	float tile_offset_z;
}params;


float hash(vec2 p) {
	return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}

float noise(vec2 p) {
	vec2 i = floor(p);
	vec2 f = fract(p);
	f = f*f*(3.0 - 2.0*f);
	float a = hash(i);
	float b = hash(i + vec2(1.0, 0.0));
	float c = hash(i + vec2(0.0, 1.0));
	float d = hash(i + vec2(1.0, 1.0));
	return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}

float fbm(vec2 p) {
	float total = 0.0;
	float amplitude = 1.0;
	float freq = 1.0;
	float divisor = 0.;
	for (int i = 0; i < 5; i++) {
		divisor += amplitude;
		total += noise(p * freq) * amplitude;
		freq *= 2.0;
		amplitude *= 0.5;

	}
    return total / divisor;
}

void main() {
	ivec2 coords = ivec2(gl_GlobalInvocationID.xy);
	ivec2 dims = imageSize(heightmap);
	if (coords.x >= dims.x || coords.y >= dims.y) return;

	vec2 uv = (vec2(coords) + vec2(params.tile_offset_x, params.tile_offset_z)) * params.frequency;
	float n = fbm(uv + vec2(params.seed));
	float height = (n - 0.5) * 2.0 * params.height_scale;
	imageStore(heightmap, coords, vec4(height, 0.0, 0.0, 1.0));
}

Got it. I calculated the tile_offset push constants by multiplying the grid number by the dimension size - I had to multiply it by the dimension size - 1.