shader_type spatial; render_mode diffuse_burley, specular_schlick_ggx; uniform vec4 base_color : source_color = vec4(.28,.29,.31,1.0); uniform float metalness = 0.0; uniform float base_roughness = .78; uniform float grain_amount = .08; uniform sampler2D rock_map : source_color, filter_linear_mipmap_anisotropic, repeat_enable; varying vec3 local_position; varying vec3 local_normal; float hash3(vec3 p) { p = fract(p * .1031); p += dot(p, p.yzx + 33.33); return fract((p.x + p.y) * p.z); } float noise3(vec3 p) { vec3 i = floor(p); vec3 f = fract(p); f = f*f*(3.0-2.0*f); return mix(mix(mix(hash3(i),hash3(i+vec3(1,0,0)),f.x),mix(hash3(i+vec3(0,1,0)),hash3(i+vec3(1,1,0)),f.x),f.y), mix(mix(hash3(i+vec3(0,0,1)),hash3(i+vec3(1,0,1)),f.x),mix(hash3(i+vec3(0,1,1)),hash3(i+vec3(1,1,1)),f.x),f.y),f.z); } void vertex() { local_position = VERTEX; local_normal = NORMAL; } void fragment() { float veins = noise3(local_position * 16.0); float grain = noise3(local_position * 100.0); float detail_fade = 1.0-smoothstep(.008,.03,length(fwidth(local_position))); grain = mix(.5,grain,detail_fade); float weather = smoothstep(.40,.62,veins); ALBEDO = base_color.rgb * (1.0 - grain_amount + weather * grain_amount * 1.2); vec3 w=pow(abs(local_normal),vec3(5.0)); w/=max(dot(w,vec3(1.0)),.0001); vec3 p=local_position*1.5; vec3 rock=texture(rock_map,p.xy).rgb*w.z+texture(rock_map,p.xz).rgb*w.y+texture(rock_map,p.zy).rgb*w.x; if(metalness < .25) { ALBEDO *= .64 + rock*1.45; grain = dot(rock,vec3(.333)); } ROUGHNESS = clamp(base_roughness + (grain-.5)*grain_amount, .15, .95); METALLIC = metalness; // Sparse pits affect fine normal response while all large detail is geometry. vec3 n = NORMAL; vec3 dpdx = dFdx(VERTEX), dpdy = dFdy(VERTEX); vec3 rx = cross(dpdy,n), ry = cross(n,dpdx); float determinant = dot(dpdx,rx); vec3 gradient = (dFdx(grain)*rx + dFdy(grain)*ry); NORMAL = normalize(abs(determinant)*n - sign(determinant)*gradient*grain_amount*.012); }