precision highp float; varying vec2 TexCoord; varying vec3 vViewDirTangent; varying vec3 Color; varying vec3 worldPosition; varying vec3 vWorldNormal; uniform sampler2D Texture; uniform sampler2D BakedTexture; uniform float uHeightScale; uniform float uDistanceToPlanetSurface; uniform float uCurrentZFar; uniform vec3 uViewPos; const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман uniform vec3 uLightDirWorld; // Направление ЛУЧЕЙ (1, -1, -1) uniform float uPlayerLightFactor; uniform vec3 uPlayerDirWorld; void main() { // --- 1. Расчет освещения поверхности --- // Направление НА источник света vec3 lightToSource = normalize(-uLightDirWorld); vec3 fragmentDir = normalize(vWorldNormal); // Используем vNormal (нормаль в мировом пространстве, так как vPosition тоже в мировом) // Важно: если vNormal не нормализована в вершинном, делаем это здесь vec3 normal = normalize(fragmentDir); // На планете-сфере нормаль совпадает с направлением от центра float diff = max(dot(normal, lightToSource), 0.0); float ambient = 0.3; // Базовая освещенность ночной стороны float surfaceLightIntensity = diff + ambient; // --- 2. Динамический цвет тумана --- // Синхронизируем туман с атмосферой: днем голубой, ночью темно-синий vec3 dayFog = vec3(0.0, 0.5, 1.0); vec3 nightFog = vec3(0.01, 0.01, 0.04); vec3 dynamicFogColor = mix(nightFog, dayFog, uPlayerLightFactor); // --- 3. Основная логика текстур (твой код) --- vec3 viewDir = normalize(vViewDirTangent); float height = texture2D(Texture, TexCoord).a; vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale); vec2 finalTexCoord = TexCoord + p; float realDist = distance(worldPosition, uViewPos); float textureMixFactor = clamp((2000.0 - realDist) / 500.0, 0.0, 1.0); vec4 bakedTextureColor = texture2D(BakedTexture, finalTexCoord); vec4 textureColor = texture2D(Texture, TexCoord); vec4 textureFlavoredColor = vec4(textureColor.rgb * Color, 1.0); if (bakedTextureColor.x < 0.01 && bakedTextureColor.y < 0.01 && bakedTextureColor.z < 0.01) { textureMixFactor = 1.0; } vec4 finalColor = textureMixFactor * textureFlavoredColor + (1.0 - textureMixFactor) * bakedTextureColor; // --- 4. ПРИМЕНЕНИЕ ОСВЕЩЕНИЯ --- // Умножаем результат текстурирования на освещенность finalColor.rgb *= surfaceLightIntensity; // --- 5. Расчет тумана (с использованием динамического цвета) --- float h = uDistanceToPlanetSurface; float fogStart, fogEnd; if (h >= 1000.0) { gl_FragColor = vec4(finalColor.rgb, 1.0); } else { if (h > 100.0) { // Нормализуем высоту от 100 до 1000 (t: 0 -> 1) float t = (h - 100.0) / 900.0; // На высоте 100 туман начинается со 100. // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. fogStart = mix(1500.0, 15000.0, t); // Держим ширину зоны тумана в пределах 400-600 единиц float fogRange = mix(1000.0, 6000.0, t); fogEnd = fogStart + fogRange; } else if (h > 40.0) { float t = (h - 40.0) / 60.0; // На высоте 100 туман начинается со 100. // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. fogStart = mix(800.0, 1500.0, t); fogEnd = mix(1000.0, 2500.0, t); } else if (h > 20.0) { float t = (h - 20.0) / 20.0; fogStart = mix(200.0, 800.0, t); fogEnd = mix(500.0, 1000.0, t); } else { // Минимумы при h = 0: start 25, end 125 float t = clamp(h / 20.0, 0.0, 1.0); fogStart = mix(100.0, 200.0, t); fogEnd = mix(250.0, 500.0, t); } float fogRange = max(fogEnd - fogStart, 1.0); float fogFactor = clamp((realDist - fogStart) / fogRange, 0.0, 1.0); // Смешиваем с динамическим цветом тумана vec3 mixedColor = mix(finalColor.rgb, dynamicFogColor, fogFactor); gl_FragColor = vec4(mixedColor, 1.0); } }