uniform sampler2DArray m_DiffuseArray; uniform float m_DiffuseScales[12]; uniform sampler2D m_AlphaMap; #ifdef HAS_ALPHA_1 uniform sampler2D m_AlphaMap_1; #endif #ifdef HAS_ALPHA_2 uniform sampler2D m_AlphaMap_2; #endif #ifdef HAS_STEEP uniform int m_SteepIndex; #endif uniform vec3 m_LightDir; uniform vec3 m_SunColor; uniform vec3 m_AmbientColor; uniform vec3 g_CameraPosition; uniform float m_Wetness; in vec3 vWorldPos; in vec3 vNormal; out vec4 outColor; #ifdef HAS_STEEP // Triplanare Textur-Abfrage aus einem Sampler2DArray-Layer vec4 triplanarArray(vec2 uvX, vec2 uvY, vec2 uvZ, vec3 bw, int idx) { return texture(m_DiffuseArray, vec3(uvX, float(idx))) * bw.x + texture(m_DiffuseArray, vec3(uvY, float(idx))) * bw.y + texture(m_DiffuseArray, vec3(uvZ, float(idx))) * bw.z; } #endif void main() { // World-space splatmap UV (identisch zur Painting-Logik in TerrainEditorState, WORLD_HALF=1024) vec2 splatUV = vec2( (vWorldPos.x + 1024.0) / 2048.0, 1.0 - (vWorldPos.z + 1024.0) / 2048.0 ); vec4 a0 = texture(m_AlphaMap, splatUV); vec4 a1 = vec4(0.0); vec4 a2 = vec4(0.0); #ifdef HAS_ALPHA_1 a1 = texture(m_AlphaMap_1, splatUV); #endif #ifdef HAS_ALPHA_2 a2 = texture(m_AlphaMap_2, splatUV); #endif float overlays[11] = float[](a0.g, a0.b, a0.a, a1.r, a1.g, a1.b, a1.a, a2.r, a2.g, a2.b, a2.a); // Basis (Slot 1) vec4 col = texture(m_DiffuseArray, vec3(vWorldPos.xz / m_DiffuseScales[0], 0.0)); // Overlays (Slots 2-12) sequentiell darüber mischen for (int i = 0; i < 11; i++) { if (overlays[i] > 0.001) { vec2 uv = vWorldPos.xz / m_DiffuseScales[i + 1]; col = mix(col, texture(m_DiffuseArray, vec3(uv, float(i + 1))), overlays[i]); } } #ifdef HAS_STEEP // Klippen-Textur: Triplanar auf steilen Flächen (identisch zu Voxel.frag) vec3 bw = pow(abs(vNormal), vec3(4.0)); bw /= (bw.x + bw.y + bw.z + 0.001); float steepScale = m_DiffuseScales[m_SteepIndex]; vec2 uvX = vWorldPos.yz / steepScale; vec2 uvZ = vWorldPos.xy / steepScale; float flatBlend = smoothstep(0.70, 0.90, vNormal.y); float steepBlend = 1.0 - flatBlend; vec4 steepCol = triplanarArray(uvX, vWorldPos.xz / steepScale, uvZ, bw, m_SteepIndex); col = col * flatBlend + steepCol * steepBlend; #endif vec3 N = normalize(vNormal); vec3 lightDir = normalize(m_LightDir); float diff = max(dot(N, lightDir), 0.0); vec3 light = m_AmbientColor + m_SunColor * diff; // Nass-Effekt: Oberfläche abdunkeln + Blinn-Phong Specular Schimmer float wet = clamp(m_Wetness, 0.0, 1.0); col.rgb *= (1.0 - 0.20 * wet); vec3 viewDir = normalize(g_CameraPosition - vWorldPos); vec3 H = normalize(lightDir + viewDir); float spec = pow(max(dot(N, H), 0.0), 80.0) * wet; const float BRIGHTNESS = 0.80; #ifdef DEBUG_NO_LIGHT outColor = vec4(col.rgb * BRIGHTNESS, col.a); #else outColor = vec4(col.rgb * light * BRIGHTNESS + vec3(spec * 0.35), col.a); #endif #ifdef SHOW_GRID vec2 fw = fwidth(vWorldPos.xz); float maxFw = max(fw.x, fw.y); float fade = 1.0 - smoothstep(0.2, 0.6, maxFw); if (fade > 0.0) { vec2 gp = fract(vWorldPos.xz); vec2 d = min(gp, 1.0 - gp); float ga = 1.0 - min(smoothstep(0.0, max(fw.x, 0.005), d.x), smoothstep(0.0, max(fw.y, 0.005), d.y)); outColor.rgb = mix(outColor.rgb, vec3(0.5), ga * fade * 0.5); } #endif }