// G1 ground: zone colours from the height field (vertex colour), rockiness in alpha. // Rock areas use the shared limestone texture triplanar, like the Kluft surfaces. shader_type spatial; render_mode diffuse_burley, specular_schlick_ggx; uniform sampler2D stone_map : source_color, filter_linear_mipmap_anisotropic, repeat_enable; varying vec3 world; varying vec3 world_normal; float hash(vec3 p) { p = fract(p * .1031); p += dot(p, p.yzx + 33.33); return fract((p.x + p.y) * p.z); } float noise(vec3 p) { vec3 i = floor(p), f = fract(p); f = f * f * (3.0 - 2.0 * f); return mix(mix(mix(hash(i), hash(i + vec3(1, 0, 0)), f.x), mix(hash(i + vec3(0, 1, 0)), hash(i + vec3(1, 1, 0)), f.x), f.y), mix(mix(hash(i + vec3(0, 0, 1)), hash(i + vec3(1, 0, 1)), f.x), mix(hash(i + vec3(0, 1, 1)), hash(i + vec3(1, 1, 1)), f.x), f.y), f.z); } void vertex() { world = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; world_normal = normalize(mat3(MODEL_MATRIX) * NORMAL); } void fragment() { vec3 weights = pow(abs(world_normal), vec3(5.0)); weights /= max(dot(weights, vec3(1.0)), .0001); vec3 p = world * .21; vec3 stone = texture(stone_map, p.zy).rgb * weights.x + texture(stone_map, p.xz).rgb * weights.y + texture(stone_map, p.xy).rgb * weights.z; float relief = dot(stone, vec3(.333)); float broad = noise(world * .35); float grain = noise(world * 6.0); float rock = COLOR.a; vec3 soil = COLOR.rgb * mix(.84, 1.14, broad) * mix(.9, 1.07, grain); vec3 rocky = COLOR.rgb * mix(vec3(.72), vec3(1.45), stone); ALBEDO = mix(soil, rocky, rock); ROUGHNESS = mix(.93, .84, rock); vec3 n = NORMAL, dx = dFdx(VERTEX), dy = dFdy(VERTEX); vec3 rx = cross(dy, n), ry = cross(n, dx); float det = dot(dx, rx); vec3 gradient = dFdx(relief) * rx + dFdy(relief) * ry; NORMAL = normalize(abs(det) * n - sign(det) * gradient * (.006 + rock * .014)); }