Godot Version
4.5.1
Question
I’m seeing some weird visual effects in de -z direction of my heightmap shader that I don’t really understand.
It seems the drawing order is incorrect when the camera faces the -z direction.
Heightmap was created like this:
_heightmap_image = Image.create(region_size, region_size, false, Image.FORMAT_RF)
for x in range(0, region_size):
for y in range(0, region_size):
_heightmap_image.set_pixel(x, y, Color(sin(deg_to_rad((x*10 + y*50) % 360)) * 2.0, 0.0, 0.0, 0.0))
This is my shader code:
shader_type spatial;
// Contains the positions of the heightmaps (can never be more than 4)
uniform ivec2[4] _heightmap_pos;
// Heightmap images themselves (can never be more than 4)
uniform highp sampler2DArray _height_maps : repeat_disable;
// Region size
uniform int _region_size = 1024;
// Active world position
uniform ivec2 _world_position = ivec2(512, 512);
// Active world size
uniform ivec2 _active_world_size = ivec2(1024, 1024);
varying vec2 basePos;
varying flat int _image_index;
varying flat ivec2 _local_heightmap_pos;
int get_heightmap_index(float x, float y) {
ivec2 region_pos = ivec2(int(floor((float(_world_position.x) + x) / float(_region_size))), int(floor((float(_world_position.y) + y) / float(_region_size))));
int index = 0;
while (index < 4)
{
if (_heightmap_pos[index] == region_pos)
return index;
index++;
}
return -1;
}
vec3 get_normal(vec2 uv, float texelSize) {
float t = texelFetch(_height_maps, ivec3(_local_heightmap_pos.x, _local_heightmap_pos.y - 1, 0), _image_index).r;
float r = texelFetch(_height_maps, ivec3(_local_heightmap_pos.x + 1, _local_heightmap_pos.y, 0), _image_index).r;
float l = texelFetch(_height_maps, ivec3(_local_heightmap_pos.x - 1, _local_heightmap_pos.y, 0), _image_index).r;
float b = texelFetch(_height_maps, ivec3(_local_heightmap_pos.x, _local_heightmap_pos.y + 1, 0), _image_index).r;
return -normalize(vec3(2.0 * (r - l), 2.0 * (b - t), -4.0));
}
void vertex() {
// Get the correct image index
_image_index = get_heightmap_index(UV.x * float(_active_world_size.x), UV.y * float(_active_world_size.y));
// Calculate proper UV
_local_heightmap_pos = ivec2(
int(mod( (float(_world_position.x) + UV.x * float(_active_world_size.x)) , float(_region_size) )),
int(mod( (float(_world_position.y) + UV.y * float(_active_world_size.y)) , float(_region_size) ))
);
if (_image_index != -1)
{
VERTEX.y = texelFetch(_height_maps, ivec3(_local_heightmap_pos.x, _local_heightmap_pos.y, 0), _image_index).r;
NORMAL = get_normal(UV, 1.0);
}
}
void fragment() {
ALBEDO=vec3(1.0, 0.2 + mod(basePos.x * 0.1 * basePos.y, 0.5), 0.0);
}
Mesh that is used to display was created like this:
_static_body_3d = StaticBody3D.new()
_static_body_3d.collision_layer = 0b1000000000000001
_static_body_3d.collision_mask = 0b1000000000000001
# Calculate mesh dimensions based on number of active chunks
var mesh_dimension: float = ((active_chunk_range - 1) * 2 + 1) * fg_terrain.chunk_size
_mesh_instance_3d = MeshInstance3D.new()
#_mesh_instance_3d.custom_aabb.size
_shader_material = ShaderMaterial.new()
_shader_material.shader = preload("uid://dvmru2ujiob2d")
_shader_material.set_shader_parameter("_height_pos", [Vector2(0,0), Vector2.ZERO, Vector2.ZERO, Vector2.ZERO])
_shader_material.set_shader_parameter("_height_maps", fg_terrain._rid)
_shader_material.set_shader_parameter("_region_size", fg_terrain.region_size)
_shader_material.set_shader_parameter("_world_position", Vector2(mesh_dimension / 2, mesh_dimension / 2))
_shader_material.set_shader_parameter("_active_world_size", Vector2(mesh_dimension, mesh_dimension))
_plane_mesh = PlaneMesh.new()
_plane_mesh.size = Vector2(mesh_dimension - 1, mesh_dimension - 1)
_plane_mesh.subdivide_width = _plane_mesh.size.x - 1
_plane_mesh.subdivide_depth = _plane_mesh.size.y - 1
_plane_mesh.material = _shader_material
_mesh_instance_3d.mesh = _plane_mesh
_static_body_3d.add_child(_mesh_instance_3d)
add_child(_static_body_3d)
Anybody has any idea what causes this problem? I’ve been googling around, but can’t seem to find a solution.





