125 lines
5.2 KiB
Plaintext
125 lines
5.2 KiB
Plaintext
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));
|
||
} |