Files
blight/blight-assets/src/main/resources/Shaders/Voxel.frag

137 lines
4.4 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
uniform sampler2D m_TexFlat;
uniform sampler2D m_TexSteep;
#ifdef HAS_SPLAT
uniform sampler2D m_SplatMap;
uniform sampler2D m_TexFlat2;
uniform sampler2D m_TexFlat3;
uniform sampler2D m_TexFlat4;
#endif
uniform float m_TexScale;
#ifdef HAS_NM_FLAT
uniform sampler2D m_NormalMapFlat;
#endif
#ifdef HAS_NM_STEEP
uniform sampler2D m_NormalMapSteep;
#endif
in vec3 vWorldPos;
in vec3 vNormal;
out vec4 outColor;
#ifdef HAS_LIGHTDIR
uniform vec3 m_LightDir;
#endif
#ifdef HAS_SCENE_LIGHT
uniform vec3 m_SunColor;
uniform vec3 m_AmbientColor;
#endif
vec4 triplanar(sampler2D tex, vec2 uvX, vec2 uvY, vec2 uvZ, vec3 bw) {
return texture(tex, uvX) * bw.x
+ texture(tex, uvY) * bw.y
+ texture(tex, uvZ) * bw.z;
}
// Triplanare Normal-Map-Mischung (Whiteout-Blending, world-space Ausgabe).
// N = geometrische Weltoberflächen-Normale, bw = triplanare Gewichte.
vec3 triplanarNormal(sampler2D nmap, vec2 uvX, vec2 uvY, vec2 uvZ, vec3 bw, vec3 N) {
vec3 tnX = texture(nmap, uvX).rgb * 2.0 - 1.0;
vec3 tnY = texture(nmap, uvY).rgb * 2.0 - 1.0;
vec3 tnZ = texture(nmap, uvZ).rgb * 2.0 - 1.0;
// Reorientiertes Normal-Mapping (RNM / Whiteout): Tangent → World
tnX = vec3(tnX.xy + N.zy, abs(tnX.z) * N.x);
tnY = vec3(tnY.xy + N.xz, abs(tnY.z) * N.y);
tnZ = vec3(tnZ.xy + N.xy, abs(tnZ.z) * N.z);
return normalize(tnX.zyx * bw.x + tnY.xzy * bw.y + tnZ.xyz * bw.z);
}
void main() {
vec3 bw = pow(abs(vNormal), vec3(4.0));
bw /= (bw.x + bw.y + bw.z + 0.001);
vec2 uvX = vWorldPos.yz / m_TexScale;
vec2 uvY = vWorldPos.xz / m_TexScale;
vec2 uvZ = vWorldPos.xy / m_TexScale;
// Flach bis ~45° Gefälle. LOD0-Smoothing (3 Passes, 0.3 Stärke) kann die Normalen
// an Rampenfüßen (14°-Rampe, ideal normal.y≈0.97) auf 0.70-0.85 herunterziehen.
// Untere Grenze 0.70 (≈45°) echte Klippen (normal.y<0.70) zeigen weiter Gebirge.
float flatBlend = smoothstep(0.70, 0.90, vNormal.y);
float steepBlend = 1.0 - flatBlend;
// Flat: reines XZ-UV wie das Terrain (uvY = worldPos.xz / texScale), kein Triplanar.
// Steep: Triplanar für alle nicht-flachen Flächen inkl. Decken und Tunnelwände.
#ifdef HAS_SPLAT
// Splatmap-UV: worldPos.xz linear auf [0,1] (kein Flip nötig Konvention im Editor: pz=0 → worldZ=-2048)
vec2 splatUV = (vWorldPos.xz + 2048.0) / 4096.0;
vec4 splat = texture(m_SplatMap, splatUV);
float w2 = splat.g;
float w3 = splat.b;
float w4 = splat.a;
float w1 = max(0.0, 1.0 - w2 - w3 - w4);
vec4 flatCol = texture(m_TexFlat, uvY) * w1
+ texture(m_TexFlat2, uvY) * w2
+ texture(m_TexFlat3, uvY) * w3
+ texture(m_TexFlat4, uvY) * w4;
#else
vec4 flatCol = texture(m_TexFlat, uvY);
#endif
vec4 col = flatCol * flatBlend
+ triplanar(m_TexSteep, uvX, uvY, uvZ, bw) * steepBlend;
// Geometrie-Normale für Beleuchtung, ggf. durch Normal-Map ersetzt.
vec3 N = normalize(vNormal);
#if defined(HAS_NM_FLAT) || defined(HAS_NM_STEEP)
vec3 pertN = vec3(0.0);
float totalBlend = 0.0;
#ifdef HAS_NM_FLAT
if (flatBlend > 0.001) {
vec3 nmFlat = texture(m_NormalMapFlat, uvY).rgb * 2.0 - 1.0;
nmFlat = vec3(nmFlat.xy + N.xz, abs(nmFlat.z) * N.y);
pertN += normalize(nmFlat.xzy) * flatBlend;
totalBlend += flatBlend;
}
#endif
#ifdef HAS_NM_STEEP
if (steepBlend > 0.001) {
pertN += triplanarNormal(m_NormalMapSteep, uvX, uvY, uvZ, bw, N) * steepBlend;
totalBlend += steepBlend;
}
#endif
if (totalBlend > 0.001) {
N = normalize(pertN / totalBlend);
}
#endif
// Flache Voxel-Flächen Richtung (0,1,0) korrigieren, um Abweichungen der
// Marching-Cubes-Normalen auszugleichen und das Terrain-Lighting zu matchen.
N = normalize(mix(N, vec3(0.0, 1.0, 0.0), flatBlend));
#ifdef HAS_LIGHTDIR
vec3 lightDir = normalize(m_LightDir);
#else
vec3 lightDir = normalize(vec3(0.6, 1.0, 0.4));
#endif
float diff = max(dot(N, lightDir), 0.0);
#ifdef HAS_SCENE_LIGHT
vec3 light = m_AmbientColor + m_SunColor * diff;
#else
vec3 light = vec3(diff * 0.65 + 0.35);
#endif
const float BRIGHTNESS = 0.80;
#ifdef DEBUG_NO_LIGHT
outColor = vec4(col.rgb * BRIGHTNESS, col.a);
#else
outColor = vec4(col.rgb * light * BRIGHTNESS, col.a);
#endif
if (outColor.a < 0.1) discard;
}