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;
}
