shader_type spatial; render_mode cull_disabled; uniform sampler2D color_map : source_color, filter_linear_mipmap_anisotropic, repeat_enable; uniform sampler2D normal_map : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable; uniform bool scanned_uv = false; varying vec3 world_pos; varying vec3 world_normal; void vertex() { world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; world_normal = normalize(MODEL_NORMAL_MATRIX * NORMAL); } void fragment() { vec3 weights = pow(abs(world_normal), vec3(5.0)); weights /= max(dot(weights, vec3(1.0)), 0.0001); vec3 surface = texture(color_map, UV).rgb; if (!scanned_uv) { surface = texture(color_map, world_pos.zy * vec2(0.15, 0.30)).rgb * weights.x + texture(color_map, world_pos.xz * 0.22).rgb * weights.y + texture(color_map, world_pos.xy * vec2(0.15, 0.30)).rgb * weights.z; } float luma = dot(surface, vec3(0.2126, 0.7152, 0.0722)); float strata = sin(world_pos.y * 1.7 + sin(world_pos.x * 0.055 + world_pos.z * 0.045) * 0.65); float seam = smoothstep(0.82, 0.99, sin(world_pos.y * 4.6 + sin(world_pos.x * 0.18 + world_pos.z * 0.08) * 0.25)); vec3 sandstone = mix(vec3(0.32, 0.235, 0.15), vec3(0.66, 0.51, 0.34), clamp(luma * 1.35, 0.0, 1.0)); sandstone *= 0.94 + strata * 0.06 - seam * 0.045; float dust = (1.0 - smoothstep(0.0, 4.0, world_pos.y)) * 0.34; ALBEDO = mix(sandstone, vec3(0.53, 0.425, 0.29), dust); ROUGHNESS = 0.94; if (scanned_uv) { NORMAL_MAP = texture(normal_map, UV).rgb; NORMAL_MAP_DEPTH = 0.65; } else { vec3 nx = texture(normal_map, world_pos.zy * vec2(0.15, 0.30)).xyz * 2.0 - 1.0; vec3 ny = texture(normal_map, world_pos.xz * 0.22).xyz * 2.0 - 1.0; vec3 nz = texture(normal_map, world_pos.xy * vec2(0.15, 0.30)).xyz * 2.0 - 1.0; vec3 detail = vec3(0.0, nx.y, nx.x) * weights.x + vec3(ny.x, 0.0, ny.y) * weights.y + vec3(nz.x, nz.y, 0.0) * weights.z; NORMAL = normalize((VIEW_MATRIX * vec4(normalize(world_normal + detail * 0.8), 0.0)).xyz); } }