precision highp float; // Фрагментный шейдер: uniform vec3 uColor; uniform float uDistanceToPlanetSurface; // Расстояние корабля до поверхности // Константы затухания, определенные прямо в шейдере const float DIST_FOG_MAX = 2000.0; const float DIST_FOG_MIN = 1000.0; varying vec3 vWorldNormal; varying vec3 vViewNormal; varying vec3 vViewPosition; // Добавь эти uniform-ы //uniform float uTime; uniform vec3 uLightDirView; uniform vec3 uPlayerDirWorld; // Простая функция псевдослучайного шума float hash(float n) { return fract(sin(n) * 43758.5453123); } float noise(vec3 x) { vec3 p = floor(x); vec3 f = fract(x); f = f * f * (3.0 - 2.0 * f); float n = p.x + p.y * 57.0 + 113.0 * p.z; return mix(mix(mix(hash(n + 0.0), hash(n + 1.0), f.x), mix(hash(n + 57.0), hash(n + 58.0), f.x), f.y), mix(mix(hash(n + 113.0), hash(n + 114.0), f.x), mix(hash(n + 170.0), hash(n + 171.0), f.x), f.y), f.z); } // Fractal Brownian Motion для "кучевости" облаков float fbm(vec3 p) { float f = 0.5000 * noise(p); p *= 2.02; f += 0.2500 * noise(p); p *= 2.03; f += 0.1250 * noise(p); return f; } void main() { //gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5); vec3 normal = normalize(vViewNormal); vec3 viewVector = normalize(-vViewPosition); float NdotV = dot(normal, viewVector); // Вектор направления от центра планеты к текущему фрагменту атмосферы (Мировой) vec3 fragmentDir = normalize(vWorldNormal); // Вектор направления от центра планеты к игроку (нужно передать как uniform) // Передай его в C++: renderer.RenderUniform3fv("uPlayerDirWorld", playerDirWorld.data()); // --- 1. Плавное отсечение за горизонтом (Horizon Mask) --- // Считаем косинус угла между игроком и точкой атмосферы float cosAngle = dot(fragmentDir, uPlayerDirWorld); // Плавно затухаем от 0.0 (горизонт) до 0.2 (над головой) //float horizonMask = smoothstep(0.0, 0.4, cosAngle); float horizonMask = smoothstep(0.93, 1.0, cosAngle); // --- 2. Плавный переход при прохождении сквозь слой (Transition Mask) --- // Определяем "высоту" игрока относительно слоя (напр. слой на 1.03 * R) // uDistanceToPlanetSurface уже вычислен в PlanetData float layerHeight = 600.0; // Примерная толщина слоя атмосферы (3% от 20000) // Делаем прозрачным при приближении к границе (dist около layerHeight) // и снова видимым, когда спустились ниже float distToLayer = abs(uDistanceToPlanetSurface - layerHeight); float transitionMask = smoothstep(0.0, 200.0, distToLayer); // --- 3. Освещение и облака --- float diff = max(dot(normal, uLightDirView), 0.0); if (uDistanceToPlanetSurface < layerHeight) { diff = max(dot(-normal, uLightDirView), 0.0); // Инверсия для взгляда снизу } float lightIntensity = diff + 0.05; vec3 cloudCoord = fragmentDir * 6.0; //cloudCoord.x += uTime * 0.03; float n = fbm(cloudCoord); float cloudMask = smoothstep(0.4, 0.65, n); // --- 4. Финальный расчет альфы --- float atmosphereDensity = pow(1.0 - abs(NdotV), 5.0); float distanceFactor = clamp((uDistanceToPlanetSurface - DIST_FOG_MIN) / (DIST_FOG_MAX - DIST_FOG_MIN), 0.0, 1.0); // Базовая прозрачность облаков float cloudAlpha = cloudMask * 0.8; // Применяем маски: // В космосе важен distanceFactor, на планете важен horizonMask float finalCloudAlpha = cloudAlpha * transitionMask; if (uDistanceToPlanetSurface < layerHeight) { finalCloudAlpha *= horizonMask; // На планете скрываем то, что под ногами } else { finalCloudAlpha *= distanceFactor; // В космосе скрываем по вашей старой логике if (NdotV <=0.0) { //finalCloudAlpha = 0.0; discard; } } vec3 currentAtmo = mix(vec3(0.01, 0.02, 0.1), uColor, lightIntensity); vec3 currentCloud = mix(vec3(0.1, 0.1, 0.15), vec3(1.0, 1.0, 1.0), lightIntensity); vec3 finalRGB = mix(currentAtmo, currentCloud, cloudMask); //vec3 finalRGB = currentAtmo; // Для дымки (atmo) оставляем затухание при посадке float atmoAlpha = atmosphereDensity * distanceFactor; //float atmoAlpha = distanceFactor; float finalAtmoAlpha = atmoAlpha; if (uDistanceToPlanetSurface < layerHeight) { finalCloudAlpha *= horizonMask; finalAtmoAlpha *= horizonMask; // Принудительно гасим дымку под горизонтом } gl_FragColor = vec4(finalRGB, max(finalAtmoAlpha, finalCloudAlpha)); }