shader_type spatial; render_mode cull_disabled; group_uniforms textures; uniform sampler2D texture_top : source_color, filter_linear_mipmap, repeat_enable; uniform sampler2D texture_side : source_color, filter_linear_mipmap, repeat_enable; group_uniforms blending; uniform float blend_sharpness : hint_range(0.1, 20.0) = 5.0; uniform float slope_threshold : hint_range(0.0, 1.0) = 0.7; group_uniforms uv_scaling; uniform vec3 uv_scale = vec3(0.1, 0.1, 0.1); varying vec3 world_pos; varying vec3 world_normal; void vertex() { world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; world_normal = normalize((MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz); } void fragment() { vec3 abs_normal = abs(world_normal); vec2 uv_xz = world_pos.xz * uv_scale.x; vec2 uv_xy = world_pos.xy * uv_scale.y; vec2 uv_zy = world_pos.zy * uv_scale.z; vec3 weights = pow(abs_normal, vec3(blend_sharpness)); weights /= (weights.x + weights.y + weights.z); vec4 tex_xz = texture(texture_top, uv_xz); vec4 tex_xy = texture(texture_side, uv_xy); vec4 tex_zy = texture(texture_side, uv_zy); vec4 triplanar_color = tex_xz * weights.y + tex_xy * weights.z + tex_zy * weights.x; float up_factor = dot(world_normal, vec3(0.0, 1.0, 0.0)); float slope_blend = smoothstep(slope_threshold - 0.1, slope_threshold + 0.1, up_factor); vec4 top_color = texture(texture_top, uv_xz); vec4 side_color = (tex_xy * weights.z + tex_zy * weights.x) / max(weights.z + weights.x, 0.001); vec4 final_color = mix(side_color, top_color, slope_blend); ALBEDO = final_color.rgb; }