• 3D
  • Ideas on decaling / pathing

I realize Decals are coming in 4.0, but my project won't see 4.0 as I'm sticking with 3.4 unto completion. So I'm wondering what might be available to 3.4 Godot as far as decaling or more specifically splatting a mesh for paths or dirt trails.

I was thinking about laying some sprites down on the mesh surfaces for dirt like paths but there seems to be some issues around that method. This is the method I used for footprints in the sand/dirt, which works well - but I don't see it happening for something like paths and trails.

I could use Curve3D and lay the paths out the come back over the points and lay mesh/sprite but I'm having to much a problem laying the sprites flat without getting the flicker effect.

Just wondering if some of you guys have been through the same thing and have a direction to point me towards. :)

Typical way usually would be to have a tiling texture applied to the whole terrain mesh and masked by a vertex color channel, such as red. Assuming the terrain mesh is made in a 3D DCC such as blender you could paint the vertex color channel there. Alternatively you could also use a channel in a image texture, red or green or even alpha channel for it. Again, could just 3D paint the path in blender then.

Either ways you'll likely want to create a custom terrain splat shader for this, shouldn't be overly complex tho.

There's potentially also other applicable solutions but I'm not familiar enough with your project to recommend anything else, the above should be fairly universal and work in pretty much all cases.

a month later

//decal.shader
//Use this material on the cube mesh

shader_type spatial;
render_mode world_vertex_coords, unshaded;
uniform vec4 albedo : hint_color;
uniform sampler2D texture_albedo : hint_albedo;

uniform float cube_half_size = 1.0;


// Credit: https://stackoverflow.com/questions/32227283/getting-world-position-from-depth-buffer-value
vec3 world_pos_from_depth(float depth, vec2 screen_uv, mat4 inverse_proj, mat4 inverse_view) {
	float z = depth * 2.0 - 1.0;
	
	vec4 clipSpacePosition = vec4(screen_uv * 2.0 - 1.0, z, 1.0);
	vec4 viewSpacePosition = inverse_proj * clipSpacePosition;
	
	viewSpacePosition /= viewSpacePosition.w;
	
	vec4 worldSpacePosition = inverse_view * viewSpacePosition;
	
	return worldSpacePosition.xyz;
}

void fragment() {
	float depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
	vec3 world_pos = world_pos_from_depth(depth, SCREEN_UV, INV_PROJECTION_MATRIX, (CAMERA_MATRIX));
	vec4 test_pos = (inverse(WORLD_MATRIX) * vec4(world_pos, 1.0));
	
	if (abs(test_pos.x) > cube_half_size ||abs(test_pos.y) > cube_half_size || abs(test_pos.z) > cube_half_size) {
		discard;
	}
	ALBEDO = texture(texture_albedo, (test_pos.xz * 0.5) + 0.5).rgb * albedo.rgb;
}

For footprints you could use two textures and a shader. This would work for dirt as well (or snow or whatever). I haven't done this before, so I don't have the code, but the idea is that you can alter the terrain (could change the normal mapping, or height if using parallax, or even vertex displacement, whatever). One texture is the standard albedo, and then the other texture you are drawing a height (grayscale) or a displacement map. Then you would read from the displacement texture and do whatever math you need to shade or move the terrain around. For snow you would probably need actual vertex displacement, but for dirt or footprints, just altering the normal and lighting would be good enough.