layout(location = 0) out vec3 colortex7Out;
layout(location = 1) out vec4 reflectionData;
layout(location = 2) out vec4 colortex3Out;

/* DRAWBUFFERS:723 */

#include "/lib/Head/Common.inc"

uniform sampler2D tex;
#ifdef MC_NORMAL_MAP
    uniform sampler2D normals;
#endif

#include "/lib/Head/Uniforms.inc"

// Добавляем uniforms для расчета глубины воды
uniform sampler2D depthtex0;
uniform sampler2D depthtex1;
uniform sampler2D colortex4;  // История для temporal accumulation

in vec2 texcoord;
in vec2 lightmap;

in vec3 minecraftPos;

in vec4 tint;
in vec4 viewPos;

flat in mat3 tbnMatrix;
flat in uint materialIDs;

#include "/lib/Atmosphere/Atmosphere.glsl"

#define PHYSICS_OCEAN_SUPPORT

#ifdef PHYSICS_OCEAN
	#define PHYSICS_FRAGMENT
	#include "/lib/Water/PhysicsOceans.glsl"
#endif

#include "/lib/Water/WaterWave.glsl"

// ============================================================================
// 🌊 УЛУЧШЕННАЯ СИСТЕМА ОПРЕДЕЛЕНИЯ ГЛУБИНЫ ВОДЫ
// ============================================================================

// Рассчитываем глубину воды в блоках
float CalculateWaterDepthInBlocks(in vec3 viewPos, in vec2 screenCoord) {
    // Глубина поверхности воды
    float waterDepth = gl_FragCoord.z;
    
    // Глубина того, что под водой (дно или блок)
    float solidDepth = texture(depthtex1, screenCoord).x;
    
    // Конвертируем в линейное пространство
    float waterLinear = GetDepthLinear(waterDepth);
    float solidLinear = GetDepthLinear(solidDepth);
    
    // Разница в блоках (примерно)
    float depthInBlocks = abs(solidLinear - waterLinear);
    
    return depthInBlocks;
}

// Расчет цвета воды по глубине
vec3 CalculateWaterColorByDepth(in float depthInBlocks, in vec3 baseColor, in float skylight) {
    // Мелкая вода (0-2 блока) - яркая бирюзовая/голубая
    vec3 shallowColor = vec3(0.2, 0.8, 1.0);  // Светло-голубая (как у пляжа)
    
    // Средняя глубина (2-5 блоков) - голубая
    vec3 mediumColor = vec3(0.12, 0.55, 0.85);     // Голубая
    
    // Глубокая вода (5-10 блоков) - темно-синяя
    vec3 deepColor = vec3(0.04, 0.25, 0.5);    // Темно-синяя
    
    // Очень глубокая вода (10+ блоков) - почти черная с синевой
    vec3 veryDeepColor = vec3(0.01, 0.08, 0.15); // Очень темная
    
    // Плавная интерполяция между цветами
    vec3 waterColor;
    
    if (depthInBlocks < 2.0) {
        // Мелкая вода - светлая и прозрачная
        float t = saturate(depthInBlocks / 2.0);
        waterColor = mix(shallowColor, mediumColor, t * t); // Квадратичная для более яркого мелководья
    } else if (depthInBlocks < 5.0) {
        // Средняя глубина
        float t = saturate((depthInBlocks - 2.0) / 3.0);
        waterColor = mix(mediumColor, deepColor, t);
    } else if (depthInBlocks < 10.0) {
        // Глубокая вода
        float t = saturate((depthInBlocks - 5.0) / 5.0);
        waterColor = mix(deepColor, veryDeepColor, t);
    } else {
        // Очень глубокая
        waterColor = veryDeepColor;
    }
    
    // Учитываем освещенность
    waterColor *= mix(0.3, 1.0, skylight);
    
    return waterColor;
}

// Расчет эффекта "близость к пляжу"
float CalculateShoreProximity(in vec3 worldPos, in float depthInBlocks) {
    // Используем высоту Y как индикатор близости к берегу
    // В Minecraft пляжи обычно на уровне Y=62-65
    float seaLevel = 63.0;
    float heightDiff = abs(worldPos.y - seaLevel);
    
    // Чем ближе к уровню моря, тем больше shore proximity
    float shoreProximity = exp(-heightDiff * 0.25);
    
    // Также учитываем глубину - мелкая вода = ближе к берегу
    shoreProximity *= exp(-depthInBlocks * 0.3);
    
    return saturate(shoreProximity);
}

// ============================================================================
// 🎯 TEMPORAL ANTI-ALIASING ДЛЯ ОТРАЖЕНИЙ (Убирает мерцание)
// ============================================================================

vec3 TemporalStabilizeReflections(in vec3 currentReflection, in vec2 screenCoord) {
    // Читаем предыдущий кадр
    vec3 previousReflection = texture(colortex4, screenCoord).rgb;
    
    // Temporal accumulation с весами
    // Используем более высокий вес для истории, чтобы убрать мерцание
    float historyWeight = 0.85;  // 85% предыдущего кадра
    float currentWeight = 0.15;  // 15% текущего кадра
    
    // Смешиваем
    vec3 stabilizedReflection = mix(currentReflection, previousReflection, historyWeight);
    
    // Защита от ghosting - если разница слишком большая, используем текущий кадр
    float difference = length(currentReflection - previousReflection);
    if (difference > 0.3) {
        stabilizedReflection = mix(stabilizedReflection, currentReflection, 0.5);
    }
    
    return stabilizedReflection;
}

vec2 GetWaterParallaxCoord(in vec3 position, in vec3 tangentViewVector) {
	vec3 stepSize = tangentViewVector * vec3(vec2(0.1 * WATER_WAVE_HEIGHT), 1.0);
    stepSize *= 0.02 / abs(stepSize.z);

    vec3 samplePos = vec3(position.xz - position.y, 1.0) + stepSize;
	float sampleHeight = WaterHeight(samplePos.xy);

	for (uint i = 0u; sampleHeight < samplePos.z && i < 60u; ++i) {
        samplePos += stepSize;
		sampleHeight = WaterHeight(samplePos.xy);
	}

	return samplePos.xy;
}

#include "/lib/Surface/RainEffect.glsl"
#include "/lib/Head/Functions.inc"
#include "/lib/Head/Material.inc"
#include "/lib/Surface/ScreenSpaceReflections.glsl"

//============================================================================//
// 🌊 УСОВЕРШЕНСТВОВАННЫЕ ПОДВОДНЫЕ ОТРАЖЕНИЯ С УВЕЛИЧЕННЫМИ СЕМПЛАМИ
//============================================================================//

// Improved Fresnel with more accurate underwater behavior
float ImprovedFresnelUnderwater(float NdotV, float ior) {
    // При погружении под воду используем инверсию IOR
    float n = 1.0 / ior;
    
    // Schlick approximation with proper underwater handling
    float R0 = pow((1.0 - n) / (1.0 + n), 2.0);
    float fresnel = R0 + (1.0 - R0) * pow(1.0 - NdotV, 5.0);
    
    // Underwater: increase reflection at grazing angles even more
    fresnel = mix(fresnel, 1.0, pow(1.0 - NdotV, 3.0) * 0.45);
    
    return fresnel;
}

// Advanced caustics with better depth integration
vec3 GenerateAdvancedCaustics(in vec3 worldPos, in float time, in float depth) {
    vec2 causticsPos = worldPos.xz * 0.35;
    float t = time * 0.3;
    
    // Multi-octave caustics with depth variation
    vec3 caustics = vec3(0.0);
    float amplitude = 1.0;
    float frequency = 1.0;
    
    for (int i = 0; i < 3; i++) {
        vec2 uv1 = causticsPos * frequency * 2.2 + vec2(t * 0.2, t * 0.15) * frequency;
        vec2 uv2 = causticsPos.yx * frequency * 2.8 - vec2(t * 0.18, t * 0.22) * frequency;
        
        float wave1 = WaterHeight(uv1);
        float wave2 = WaterHeight(uv2);
        
        float caustic = pow(max(0.0, wave1 * wave2), 2.0 + float(i) * 0.5);
        caustics += vec3(caustic) * amplitude;
        
        amplitude *= 0.5;
        frequency *= 2.0;
    }
    
    // Depth-based intensity (stronger in shallower water)
    float depthFactor = exp(-depth * 0.08);
    caustics *= depthFactor * 5.0;
    
    return caustics;
}

// Chromatic underwater caustics with improved dispersion
vec3 ChromaticUnderwaterCaustics(in vec3 caustics, in vec3 normal, in vec3 viewDir, in float depth) {
    float NdotV = abs(dot(normal, -viewDir));
    
    // Chromatic dispersion based on viewing angle and depth
    float chromaStrength = (1.0 - NdotV * NdotV) * 0.28;
    chromaStrength *= exp(-depth * 0.05); // Less dispersion in deep water
    
    // RGB channel separation
    float causticR = caustics.r * (1.0 + chromaStrength * 0.65);
    float causticG = caustics.g;
    float causticB = caustics.b * (1.0 - chromaStrength * 0.55);
    
    // Edge detection for light rays
    float edgeStrength = length(fwidth(caustics)) * 28.0;
    vec3 edgeGlow = vec3(
        edgeStrength * 1.6,
        edgeStrength * 1.3,
        edgeStrength * 0.85
    );
    
    vec3 chromatic = vec3(causticR, causticG, causticB);
    chromatic += edgeGlow * 0.85;
    
    // Underwater color tint (cyan-blue)
    vec3 waterTint = vec3(0.3, 0.8, 1.0);
    chromatic *= waterTint;
    
    return chromatic;
}

//============================================================================//
// 🔮 УЛУЧШЕННЫЕ ПОДВОДНЫЕ ОТРАЖЕНИЯ - БОЛЬШЕ СЕМПЛОВ
//============================================================================//

// Multi-bounce underwater reflections с увеличенным количеством семплов
vec3 CalculateUnderwaterReflections(
    in vec3 viewPos, 
    in vec3 normal, 
    in vec3 viewDir,
    in float roughness,
    in float skylight,
    in float dither
) {
    vec3 reflection = vec3(0.0);
    
    // Primary reflection ray
    vec3 rayDir = reflect(viewDir, normal);
    
    // Roughness-based ray cone
    vec2 randomOffset = vec2(
        fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453),
        fract(cos(dot(gl_FragCoord.xy, vec2(4.898, 7.23))) * 23421.631)
    );
    
    vec3 tangent = normalize(cross(normal, vec3(0.0, 1.0, 0.0)));
    if (length(tangent) < 0.1) tangent = normalize(cross(normal, vec3(1.0, 0.0, 0.0)));
    vec3 bitangent = cross(normal, tangent);
    
    // Apply roughness offset
    vec2 offset = (randomOffset - 0.5) * roughness * 0.25;
    rayDir = normalize(rayDir + tangent * offset.x + bitangent * offset.y);
    
    // Screen space ray trace с УВЕЛИЧЕННЫМ количеством семплов для подводных отражений
    vec3 screenPos = vec3(gl_FragCoord.xy * screenPixelSize, gl_FragCoord.z);
    
    // 64 семпла для подводных отражений (вместо 16-32)
    bool hit = ScreenSpaceRayTrace(viewPos, rayDir, dither, 64u, screenPos);
    
    if (hit) {
        // Primary reflection
        reflection = texelFetch(colortex4, ivec2(screenPos.xy), 0).rgb;
        
        // Add secondary bounce approximation (fake GI)
        vec3 worldPos = transMAD(gbufferModelViewInverse, viewPos);
        vec3 worldRayDir = mat3(gbufferModelViewInverse) * rayDir;
        
        // Sample environment at hit point for secondary bounce
        float secondaryBounce = max(0.0, dot(worldRayDir, vec3(0.0, 1.0, 0.0))) * 0.35;
        reflection += vec3(0.12, 0.45, 0.85) * secondaryBounce * skylight;
    } else {
        // Fallback: sample underwater ambient
        reflection = vec3(0.08, 0.4, 0.8) * 0.5 * skylight;
    }
    
    return reflection;
}

// Enhanced surface reflections with better fallback
vec4 CalculateEnhancedSurfaceReflections(
    in vec3 normal, 
    in float skylight, 
    in vec3 viewPos,
    in bool isUnderwater
) {
    skylight = smoothstep(0.3, 0.8, skylight);
    vec3 viewDir = normalize(viewPos);
    vec3 rayDir = reflect(viewDir, normal);
    
    float NdotV = max(1e-6, dot(normal, -viewDir));
    float NdotL = dot(normal, rayDir);
    if (NdotL < 1e-6) return vec4(0.0);
    
    float dither = InterleavedGradientNoiseTemporal(gl_FragCoord.xy);
    vec3 screenPos = vec3(gl_FragCoord.xy * screenPixelSize, gl_FragCoord.z);
    
    // Увеличенное количество семплов под водой: 64 вместо 32
    int samples = isUnderwater ? 64 : RAYTRACE_SAMPLES;
    bool hit = ScreenSpaceRayTrace(viewPos, rayDir, dither, samples, screenPos);
    
    vec3 reflection = vec3(0.0);
    
    if (materialIDs == 17u) {
        if (isUnderwater) {
            // УЛУЧШЕННАЯ ЛОГИКА: Мощные подводные отражения с большим количеством семплов
            reflection = CalculateUnderwaterReflections(
                viewPos, normal, viewDir, 0.12, skylight, dither
            );
            
            // Усиление интенсивности отражений под водой
            reflection *= 3.0;
            
            // Добавляем ambient occlusion simulation
            float depth = length(viewPos);
            float ao = exp(-depth * 0.025);
            reflection *= ao;
            
        } else {
            // Surface reflections (above water)
            #ifdef REAL_SKY_REFLECTION
                if (skylight > 1e-3) {
                    vec3 rayDirWorld = mat3(gbufferModelViewInverse) * rayDir;
                    float NdotU = saturate((dot(normal, gbufferModelView[1].xyz) + 0.7) * 2.0) * 0.75 + 0.25;
                    vec4 skyboxData = textureBicubic(colortex5, ProjectSky(rayDirWorld) + vec2(0.0, skyCaptureRes.y * screenPixelSize.y));
                    
                    vec3 sunmoon = RenderSunReflection(rayDirWorld, worldSunVector);
                    sunmoon += RenderMoonReflection(rayDirWorld, worldSunVector);
                    
                    reflection = hit ? texelFetch(colortex4, ivec2(screenPos.xy), 0).rgb : skyboxData.rgb * skylight * NdotU;
                    reflection += sunmoon * skyboxData.a * skylight * AtmosphereAbsorption(rayDirWorld, AtmosphereExtent);
                }
            #else
                if (hit) {
                    reflection = texelFetch(colortex4, ivec2(screenPos.xy), 0).rgb;
                }
                #if defined IS_OVERWORLD
                    else if (skylight > 1e-3) {
                        vec3 rayDirWorld = mat3(gbufferModelViewInverse) * rayDir;
                        float NdotU = saturate((dot(normal, gbufferModelView[1].xyz) + 0.7) * 2.0) * 0.75 + 0.25;
                        vec4 skyboxData = textureBicubic(colortex5, ProjectSky(rayDirWorld) + vec2(0.0, skyCaptureRes.y * screenPixelSize.y));
                        reflection = skyboxData.rgb * skylight * NdotU * 1.3;
                    }
                #endif
            #endif
        }
    } else {
        // Glass/other transparent materials
        if (hit) {
            reflection = texelFetch(colortex4, ivec2(screenPos.xy), 0).rgb;
        }
        #if defined IS_OVERWORLD
            else if (skylight > 1e-3) {
                vec3 rayDirWorld = mat3(gbufferModelViewInverse) * rayDir;
                float NdotU = saturate((dot(normal, gbufferModelView[1].xyz) + 0.7) * 2.0) * 0.75 + 0.25;
                vec4 skyboxData = textureBicubic(colortex5, ProjectSky(rayDirWorld) + vec2(0.0, skyCaptureRes.y * screenPixelSize.y));
                reflection = skyboxData.rgb * skylight * NdotU;
            }
        #endif
    }
    
    // АНТИ-МЕРЦАНИЕ: Temporal stabilization
    if (materialIDs == 17u) {
        reflection = TemporalStabilizeReflections(reflection, screenPos.xy);
    }
    
    // Improved Fresnel calculation
    float specular;
    if (isUnderwater) {
        specular = ImprovedFresnelUnderwater(NdotV, WATER_REFRACT_IOR);
        // Усиление отражений под водой
        specular = mix(specular, 1.0, 0.35);
    } else {
        specular = FresnelDielectricN(NdotV, materialIDs == 17u ? WATER_REFRACT_IOR : GLASS_REFRACT_IOR);
    }
    
    return clamp16F(vec4(reflection * specular, 1.0 - specular));
}

//============================================================================//

vec3 GenerateWaterCaustics(in vec3 worldPos, in float time) {
    vec2 causticsPos = worldPos.xz * 0.4;
    float t = time * 0.25;
    
    // Первый слой - основные лучи
    vec2 uv1 = causticsPos + vec2(t * 0.2, t * 0.15);
    float wave1 = WaterHeight(uv1 * 2.2);
    float caustic1 = pow(max(0.0, wave1), 2.5);
    
    // Второй слой - перекрестные лучи
    vec2 uv2 = causticsPos.yx - vec2(t * 0.18, t * 0.22);
    float wave2 = WaterHeight(uv2 * 2.8);
    float caustic2 = pow(max(0.0, wave2), 2.5);
    
    // Третий слой - детали
    vec2 uv3 = causticsPos * 1.5 + vec2(t * 0.12, -t * 0.15);
    float wave3 = WaterHeight(uv3 * 3.5);
    float caustic3 = pow(max(0.0, wave3), 3.0);
    
    // Комбинируем слои с весами
    float caustics = caustic1 * 0.5 + caustic2 * 0.35 + caustic3 * 0.15;
    caustics = pow(caustics, 0.7) * 3.5;
    
    return vec3(caustics);
}

vec3 ChromaticCaustics(in vec3 caustics, in vec3 normal, in vec3 viewDir) {
    float NdotV = abs(dot(normal, -viewDir));
    float chromaFactor = (1.0 - NdotV * NdotV) * 0.18;
    
    float causticR = caustics.r * (1.0 + chromaFactor * 0.45);
    float causticG = caustics.g;
    float causticB = caustics.b * (1.0 - chromaFactor * 0.45);
    
    float edgeStrength = length(fwidth(caustics)) * 22.0;
    
    vec3 edgeGlow = vec3(
        edgeStrength * 1.4,
        edgeStrength * 1.1,
        edgeStrength * 0.75
    );
    
    vec3 chromatic = vec3(causticR, causticG, causticB);
    chromatic += edgeGlow * 0.7;
    
    vec3 waterColor = vec3(0.35, 0.9, 1.0);
    chromatic *= waterColor;
    
    return chromatic;
}

void main() {
    // 1. Базовый цвет текстуры
    vec4 albedo = texture(tex, texcoord) * tint;

    // 2. Расчет нормалей воды
    vec3 normalData;
    #ifdef PHYSICS_OCEAN
        if (materialIDs == 17u) {
            WavePixelData wave = physics_wavePixel(physics_localPosition.xz, physics_localWaviness, physics_iterationsNormal, physics_gameTime);
            normalData = mat3(gbufferModelView) * wave.normal;
            normalData = isEyeInWater == 1 ? -normalData : normalData;
        } else {
            #ifdef MC_NORMAL_MAP
                normalData = texture(normals, texcoord).rgb;
                DecodeNormalTex(normalData);
            #else
                normalData = vec3(0.0, 0.0, 1.0);
            #endif

            #if defined IS_OVERWORLD
                #ifdef RAIN_SPLASH_EFFECT
                    if (wetnessCustom > 1e-2) {
                        vec2 rainNormal = GetRainNormal(wetnessCustom, minecraftPos);
                        normalData.xy += rainNormal * wetnessCustom * saturate(lightmap.y * 10.0 - 9.0);
                    }
                #endif
            #endif

            normalData = normalize(tbnMatrix * normalData);
        }
    #else
        if (materialIDs == 17u) {
            #ifdef WATER_PARALLAX
                vec2 position = GetWaterParallaxCoord(minecraftPos, normalize(viewPos.xyz * tbnMatrix));
                normalData = GetWavesNormal(position);
            #else
                normalData = GetWavesNormal(minecraftPos.xz - minecraftPos.y);
            #endif
        } else {
            #ifdef MC_NORMAL_MAP
                normalData = texture(normals, texcoord).rgb;
                DecodeNormalTex(normalData);
            #else
                normalData = vec3(0.0, 0.0, 1.0);
            #endif
        }

        #if defined IS_OVERWORLD
            #ifdef RAIN_SPLASH_EFFECT
                if (wetnessCustom > 1e-2) {
                    vec2 rainNormal = GetRainNormal(minecraftPos);
                    normalData.xy += rainNormal * wetnessCustom * saturate(lightmap.y * 10.0 - 9.0);
                }
            #endif
        #endif

        normalData = normalize(tbnMatrix * normalData);
    #endif

    // 3. СИСТЕМА ГЛУБИНЫ ВОДЫ И ЦВЕТА
    if (materialIDs == 17u) {
        vec2 screenCoord = gl_FragCoord.xy * screenPixelSize;
        float depthInBlocks = CalculateWaterDepthInBlocks(viewPos.xyz, screenCoord);
        
        // Расчет мировых координат для определения близости к пляжу
        vec3 worldPos = mat3(gbufferModelViewInverse) * viewPos.xyz + gbufferModelViewInverse[3].xyz;
        float shoreProximity = CalculateShoreProximity(worldPos, depthInBlocks);
        
        // Получаем цвет воды в зависимости от глубины
        vec3 depthColor = CalculateWaterColorByDepth(depthInBlocks, albedo.rgb, lightmap.g);
        
        // Эффект пляжа - чем ближе к берегу, тем светлее и голубее
        vec3 shoreColor = vec3(0.25, 0.85, 1.0); // Яркий бирюзовый у берега
        depthColor = mix(depthColor, shoreColor, shoreProximity * 0.6);
        
        // Применяем цвет глубины к альбедо
        // Смешиваем с оригинальным цветом воды
        float depthInfluence = saturate(depthInBlocks * 0.5);
        albedo.rgb = mix(albedo.rgb, depthColor, depthInfluence * 0.7);
        
        // Дополнительное затемнение для глубокой воды
        float darkeningFactor = exp(-depthInBlocks * 0.15);
        albedo.rgb *= mix(0.4, 1.0, darkeningFactor);
    }

    // 4. УЛУЧШЕННЫЕ ПОДВОДНЫЕ КАУСТИКИ
    #ifndef WATER_CAUSTICS_DISABLED
    if (materialIDs == 17u && isEyeInWater == 1) {
        vec3 worldPos = mat3(gbufferModelViewInverse) * viewPos.xyz + gbufferModelViewInverse[3].xyz;
        
        float depth = length(viewPos.xyz);
        vec3 rawCaustics = GenerateAdvancedCaustics(worldPos, frameTimeCounter, depth);
        
        vec3 viewDir = normalize(viewPos.xyz);
        vec3 chromaticCaustics = ChromaticUnderwaterCaustics(rawCaustics, normalData, viewDir, depth);
        
        float depthFade = exp(-depth * 0.035);
        chromaticCaustics *= depthFade;
        
        float lightInfluence = saturate(lightmap.y * 1.6);
        chromaticCaustics *= lightInfluence;
        
        // Усиленная интенсивность
        albedo.rgb += chromaticCaustics * 1.4;
    }
    #endif

    #if WATER_CHROMATIC_ABERRATION == 1
    if (materialIDs == 17u && isEyeInWater == 0) {
        vec3 normalForCA = normalData;
        vec3 viewDir = normalize(viewPos.xyz);
        float NdotV = abs(dot(normalForCA, -viewDir));

        float angleFactor = 1.0 - NdotV;
        angleFactor = angleFactor * angleFactor;
        angleFactor = angleFactor * angleFactor * 0.018;

        float waveSteepness = length(fwidth(normalForCA.xz));
        float aberrationStrength = angleFactor + waveSteepness * 0.012;
        aberrationStrength *= WATER_CA_STRENGTH;
        aberrationStrength = min(aberrationStrength, 0.035);

        vec2 uvOffset = normalForCA.xy * aberrationStrength;
        uvOffset.x *= viewWidth / viewHeight;

        vec2 offsetR = uvOffset * 1.12;
        vec2 offsetG = uvOffset * 0.98;
        vec2 offsetB = uvOffset * 0.82;

        albedo.r = texture(tex, texcoord + offsetR).r * tint.r;
        albedo.g = texture(tex, texcoord + offsetG).g * tint.g;
        albedo.b = texture(tex, texcoord + offsetB).b * tint.b;
        albedo.a = texture(tex, texcoord).a * tint.a;
    }
    #endif

    // 5. Финальный вывод
    colortex7Out.xy = lightmap + (bayer4(gl_FragCoord.xy) - 0.5) * rcp(255.0);
    colortex7Out.z = float(materialIDs + 0.1) * rcp(255.0);

    colortex3Out.xy = EncodeNormal(normalData);
    colortex3Out.z = PackUnorm2x8(albedo.rg);
    colortex3Out.w = PackUnorm2x8(albedo.ba);

    // 6. УСОВЕРШЕНСТВОВАННЫЕ ОТРАЖЕНИЯ С АНТИ-МЕРЦАНИЕМ
    reflectionData = CalculateEnhancedSurfaceReflections(
        normalData, 
        cube(lightmap.g), 
        viewPos.xyz,
        isEyeInWater == 1
    );
}
