Weiter gearbeitet
This commit is contained in:
@@ -1,54 +1,125 @@
|
||||
uniform sampler2D m_Tex0;
|
||||
uniform sampler2D m_Tex1;
|
||||
uniform sampler2D m_Tex2;
|
||||
uniform sampler2D m_Tex3;
|
||||
uniform sampler2D m_TexFlat;
|
||||
uniform sampler2D m_TexSteep;
|
||||
uniform sampler2D m_TexCeil;
|
||||
uniform float m_TexScale;
|
||||
|
||||
in vec3 vWorldPos;
|
||||
in vec3 vNormal;
|
||||
in vec4 vMatWeights;
|
||||
#ifdef HAS_NM_FLAT
|
||||
uniform sampler2D m_NormalMapFlat;
|
||||
#endif
|
||||
#ifdef HAS_NM_STEEP
|
||||
uniform sampler2D m_NormalMapSteep;
|
||||
#endif
|
||||
#ifdef HAS_NM_CEIL
|
||||
uniform sampler2D m_NormalMapCeil;
|
||||
#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 blendWeights = abs(vNormal);
|
||||
blendWeights = max(blendWeights - 0.2, 0.0);
|
||||
blendWeights /= (blendWeights.x + blendWeights.y + blendWeights.z + 0.001);
|
||||
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;
|
||||
|
||||
vec4 col = vec4(0.0);
|
||||
// Flach ab ~11° Gefälle (20% grade, normal.y≈0.98); Fels darunter.
|
||||
float flatBlend = smoothstep(0.94, 0.99, vNormal.y);
|
||||
float ceilBlend = 1.0 - smoothstep(-0.6, -0.3, vNormal.y);
|
||||
float steepBlend = max(0.0, 1.0 - flatBlend - ceilBlend);
|
||||
|
||||
float w0 = vMatWeights.r;
|
||||
if (w0 > 0.001) {
|
||||
col += w0 * (texture(m_Tex0, uvX) * blendWeights.x
|
||||
+ texture(m_Tex0, uvY) * blendWeights.y
|
||||
+ texture(m_Tex0, uvZ) * blendWeights.z);
|
||||
}
|
||||
float w1 = vMatWeights.g;
|
||||
if (w1 > 0.001) {
|
||||
col += w1 * (texture(m_Tex1, uvX) * blendWeights.x
|
||||
+ texture(m_Tex1, uvY) * blendWeights.y
|
||||
+ texture(m_Tex1, uvZ) * blendWeights.z);
|
||||
}
|
||||
float w2 = vMatWeights.b;
|
||||
if (w2 > 0.001) {
|
||||
col += w2 * (texture(m_Tex2, uvX) * blendWeights.x
|
||||
+ texture(m_Tex2, uvY) * blendWeights.y
|
||||
+ texture(m_Tex2, uvZ) * blendWeights.z);
|
||||
}
|
||||
float w3 = vMatWeights.a;
|
||||
if (w3 > 0.001) {
|
||||
col += w3 * (texture(m_Tex3, uvX) * blendWeights.x
|
||||
+ texture(m_Tex3, uvY) * blendWeights.y
|
||||
+ texture(m_Tex3, uvZ) * blendWeights.z);
|
||||
}
|
||||
// Flat: reines XZ-UV wie das Terrain (uvY = worldPos.xz / texScale), kein Triplanar.
|
||||
// Steep/Ceil: Triplanar bleibt, da es dort keine eindeutige Projektion gibt.
|
||||
vec4 col = texture(m_TexFlat, uvY) * flatBlend
|
||||
+ triplanar(m_TexSteep, uvX, uvY, uvZ, bw) * steepBlend
|
||||
+ triplanar(m_TexCeil, uvX, uvY, uvZ, bw) * ceilBlend;
|
||||
|
||||
vec3 lightDir = normalize(vec3(0.5, 1.0, 0.3));
|
||||
float diff = max(dot(vNormal, lightDir), 0.0) * 0.7 + 0.3;
|
||||
// Geometrie-Normale für Beleuchtung, ggf. durch Normal-Map ersetzt.
|
||||
vec3 N = normalize(vNormal);
|
||||
|
||||
outColor = vec4(col.rgb * diff, col.a);
|
||||
#if defined(HAS_NM_FLAT) || defined(HAS_NM_STEEP) || defined(HAS_NM_CEIL)
|
||||
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;
|
||||
// Y-Projektion RNM (identisch mit triplanarNormal Y-Achse bei bw.y=1)
|
||||
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
|
||||
#ifdef HAS_NM_CEIL
|
||||
if (ceilBlend > 0.001) {
|
||||
pertN += triplanarNormal(m_NormalMapCeil, uvX, uvY, uvZ, bw, N) * ceilBlend;
|
||||
totalBlend += ceilBlend;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user