Terrain Mesh Blending with Dithering

[WIP]

 

This shader is used to blend between meshes and terrain, it is applied to the mesh. The blending works by changing the depth. The problems of non-convex meshes, are avoided by setting the render_mode to depth_draw_alpha_prepass.

As height texture the height texture of the terrain is used, also the maximum height has to be set.

Alternatively, a height texture can be created with a viewport and an orthogonal camera.

 

Features:

– works with non-convex meshes

– no triplanar mapping

 

Problems:
– shadow artifacts

 

Shader code
/*
	Terrain Mesh Blending with Dithering Shader by Firerabbit
	
	MIT License
*/
shader_type spatial;
render_mode world_vertex_coords, depth_draw_alpha_prepass, cull_disabled;

// ---- Heightmap ---- //
// size of the terrain
// height_texture from heightmap terrain
uniform vec2 size = vec2(256);
uniform sampler2D height_texture : hint_black;
uniform float max_height = 32.0;

// ---- Transition ---- //
uniform float transition_length : hint_range(0.0, 2.0) = 0.157;
uniform float falloff : hint_range(0.0, 5.0) = 0.455;

// ---- Color and textures
uniform vec4 color : hint_color;
uniform sampler2D albedo : hint_white;


varying vec3 WORLD_VERTEX;

const vec4 dither[4] = {
	vec4(0.0625, 0.5625, 0.1875,  0.6875),
	vec4(0.8125, 0.3125, 0.9375,  0.4375),
	vec4(0.25, 0.75, 0.125, 0.625),
	vec4(1.0, 0.5, 0.875,  0.375)
	};

float getValue(int x, int y) {
	float res = 0.0;
	switch(y) {
		case 0:
			res = dither[x].r;
			break;
		case 1:
			res = dither[x].g;
			break;
		case 2:
			res = dither[x].b;
			break;
		case 3:
			res = dither[x].a;
			break;		
	}
	return res;
}

float get_height() {
	float res = texture(height_texture, WORLD_VERTEX.xz / size).r;
	res *= max_height;
	return res;
}


void vertex() {
	WORLD_VERTEX = VERTEX;
}

void fragment() {
	float height = get_height();
	
	
	// difference
	float diff = WORLD_VERTEX.y - height;
	diff = clamp(diff, 0.0, 1.0);
	diff = smoothstep(0.0, transition_length, diff);
	diff = pow(diff, falloff);
	
	vec4 ndc = PROJECTION_MATRIX * INV_CAMERA_MATRIX * vec4(WORLD_VERTEX, 1.0);
	
	float limit = getValue(int(FRAGCOORD.x) % 4, int(FRAGCOORD.y) % 4);
	
	if (diff < limit && diff < 1.0) {
		ndc.z += 0.01;
		
	}
	
	float depth = (ndc.z / ndc.w) * 0.5 + 0.5;
	DEPTH = depth;
	
	ALBEDO = pow(texture(albedo, UV).rgb, vec3(2.2)) * color.rgb;
}
Tags
blending, dithering, terrain
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Firerabbit

3D Pixelart Upscaler/Filter

Toon Shader for Godot 4

Scale2x filter

Related shaders

Terrain Mesh Blending – Godot 4.3

mesh-terrain blending

Mesh Blending with Alpha

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments