diff --git a/src/client/java/su/divan2000/veila/client/render/fog/FogEnvironmentContext.java b/src/client/java/su/divan2000/veila/client/render/fog/FogEnvironmentContext.java index 02d9418..c9626da 100644 --- a/src/client/java/su/divan2000/veila/client/render/fog/FogEnvironmentContext.java +++ b/src/client/java/su/divan2000/veila/client/render/fog/FogEnvironmentContext.java @@ -8,8 +8,9 @@ public final class FogEnvironmentContext { private static float emissionMultiplier = 1.0f; private static float targetDensityMultiplier = 0.0f; - private static float fogDayRandom = 0.5f; // НОВЫЙ uniform + private static float fogDayRandom = 0.5f; private static float rainMultiplier = 0.0f; + private static float heightFadeMax = 90.0f; // НОВОЕ private static float smoothEmission = 1.0f; private static float smoothTargetDensity = 0.0f; @@ -43,7 +44,7 @@ public final class FogEnvironmentContext { double noiseValue = dayNoise.sample(totalDays * 0.05, 0); float dayOffset = (float)(noiseValue * 1000); - float p1 = 16000 + dayOffset; + float p1 = 16000 - dayOffset; float p2 = 20000; float p3 = 23000; float p4 = 3000 + dayOffset; @@ -65,23 +66,26 @@ public final class FogEnvironmentContext { float t4 = 6000; // полдень float baseTargetDensity = trapezoid(timeOfDay, t1, t2, t3, t4); - - // В дождь дымка всегда float rainFactor = rain + thunder * 0.5f; float rawTargetDensity = Math.max(baseTargetDensity, rainFactor); // === 3. Случайное значение для "туманного дня" === - // Это ОТДЕЛЬНЫЙ uniform, НЕ умноженный на трапецию double dayNoiseValue = dayNoise.sample(totalDays * 0.1, 100); - float rawFogDayRandom = (float)(0.5 + dayNoiseValue * 0.5); // 0..1 + float rawFogDayRandom = (float)(0.5 + dayNoiseValue * 0.5); - // === 4. Сглаживание === + // === 4. HeightFadeMax (90 ± 10 от дневного шума) === + double heightNoise = dayNoise.sample(totalDays * 0.1, 200); + float rawHeightFadeMax = 90.0f + (float)(heightNoise * 10.0); + rawHeightFadeMax = Math.max(80.0f, Math.min(100.0f, rawHeightFadeMax)); + + // === 5. Сглаживание === float lerpSpeed = 0.08f; smoothEmission = lerp(smoothEmission, rawEmission, lerpSpeed); smoothTargetDensity = lerp(smoothTargetDensity, rawTargetDensity, lerpSpeed * 2.0f); smoothRain = lerp(smoothRain, rainFactor, lerpSpeed * 2.0f); - // FogDayRandom НЕ сглаживаем — он постоянен в течение дня + fogDayRandom = rawFogDayRandom; + heightFadeMax = rawHeightFadeMax; // Не сглаживаем, постоянен в течение дня emissionMultiplier = smoothEmission; targetDensityMultiplier = smoothTargetDensity; @@ -113,4 +117,5 @@ public final class FogEnvironmentContext { public static float getTargetDensityMultiplier() { return targetDensityMultiplier; } public static float getFogDayRandom() { return fogDayRandom; } public static float getRainMultiplier() { return rainMultiplier; } + public static float getHeightFadeMax() { return heightFadeMax; } } \ No newline at end of file diff --git a/src/client/java/su/divan2000/veila/client/render/fog/FogSimulationShader.java b/src/client/java/su/divan2000/veila/client/render/fog/FogSimulationShader.java index 44018e8..97747aa 100644 --- a/src/client/java/su/divan2000/veila/client/render/fog/FogSimulationShader.java +++ b/src/client/java/su/divan2000/veila/client/render/fog/FogSimulationShader.java @@ -37,6 +37,8 @@ public final class FogSimulationShader { private static int biomeParamsSamplerLocation; private static int fogDayRandomLocation; private static int rainMultiplierLocation; + private static int heightFadeMaxLocation; + private static int skyLightSamplerLocation; private FogSimulationShader() { } @@ -74,6 +76,8 @@ public final class FogSimulationShader { targetDensityMultiplierLocation = program.uniform("TargetDensityMultiplier"); fogDayRandomLocation = program.uniform("FogDayRandom"); rainMultiplierLocation = program.uniform("RainMultiplier"); + heightFadeMaxLocation = program.uniform("HeightFadeMax"); + skyLightSamplerLocation = program.uniform("SkyLightSampler"); fbo = GL30.glGenFramebuffers(); @@ -139,7 +143,7 @@ public final class FogSimulationShader { // Активный текстурный юнит int previousActiveTexture = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE); - // Привязки текстур для юнитов 0 и 1 (2D и 3D) + // Привязки текстур для юнитов (2D и 3D) GL13.glActiveTexture(GL13.GL_TEXTURE0); int previousTex0_2D = GL11.glGetInteger(GL_TEXTURE_BINDING_2D); int previousTex0_3D = GL11.glGetInteger(GL_TEXTURE_BINDING_3D); @@ -152,6 +156,10 @@ public final class FogSimulationShader { int previousTex2_2D = GL11.glGetInteger(GL_TEXTURE_BINDING_2D); int previousTex2_3D = GL11.glGetInteger(GL_TEXTURE_BINDING_3D); + GL13.glActiveTexture(GL13.GL_TEXTURE3); + int previousTex3_2D = GL11.glGetInteger(GL_TEXTURE_BINDING_2D); + int previousTex3_3D = GL11.glGetInteger(GL_TEXTURE_BINDING_3D); + // Blend state (на всякий случай) boolean previousBlend = GL11.glIsEnabled(GL11.GL_BLEND); boolean previousDepthTest = GL11.glIsEnabled(GL11.GL_DEPTH_TEST); @@ -197,6 +205,10 @@ public final class FogSimulationShader { GL11.glBindTexture(GL11.GL_TEXTURE_2D, FogBiomeTexture.getTexture()); GL20.glUniform1i(biomeParamsSamplerLocation, 2); + GL13.glActiveTexture(GL13.GL_TEXTURE3); + GL11.glBindTexture(GL12.GL_TEXTURE_3D, FogLightVolume.getSkyLightTexture()); + GL20.glUniform1i(skyLightSamplerLocation, 3); + // Устанавливаем параметры GL20.glUniform1f(globalEmissionMultiplierLocation, globalEmissionMultiplier); GL20.glUniform1f(globalAbsorptionMultiplierLocation, globalAbsorptionMultiplier); @@ -209,6 +221,7 @@ public final class FogSimulationShader { GL20.glUniform1f(targetDensityMultiplierLocation, FogEnvironmentContext.getTargetDensityMultiplier()); GL20.glUniform1f(fogDayRandomLocation, FogEnvironmentContext.getFogDayRandom()); GL20.glUniform1f(rainMultiplierLocation, FogEnvironmentContext.getRainMultiplier()); + GL20.glUniform1f(heightFadeMaxLocation, FogEnvironmentContext.getHeightFadeMax()); GL20.glUniform3f(voxelSizeLocation, 1.0f / FogWorldVolume.SIZE_X, @@ -268,6 +281,10 @@ public final class FogSimulationShader { GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTex2_2D); GL11.glBindTexture(GL12.GL_TEXTURE_3D, previousTex2_3D); + GL13.glActiveTexture(GL13.GL_TEXTURE3); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTex3_2D); + GL11.glBindTexture(GL12.GL_TEXTURE_3D, previousTex3_3D); + // Восстанавливаем активный текстурный юнит GL13.glActiveTexture(previousActiveTexture); diff --git a/src/client/resources/assets/veila/shaders/sim.frag b/src/client/resources/assets/veila/shaders/sim.frag index c3ed3ba..2220e7b 100644 --- a/src/client/resources/assets/veila/shaders/sim.frag +++ b/src/client/resources/assets/veila/shaders/sim.frag @@ -2,6 +2,7 @@ uniform usampler3D WorldInfoSampler; uniform sampler3D FogReadSampler; +uniform sampler3D SkyLightSampler; uniform sampler2D BiomeParamsSampler; uniform float GlobalEmissionMultiplier; @@ -17,12 +18,19 @@ uniform float CurrentZ; uniform float EmissionMultiplier; uniform float TargetDensityMultiplier; -uniform float FogDayRandom; // НОВЫЙ: случайное значение [0, 1] +uniform float FogDayRandom; uniform float RainMultiplier; +uniform float HeightFadeMax; in vec2 texCoord; out vec4 FragColor; +const float HEIGHT_FADE_MIN = 75.0; +const float MIN_Y = -64.0; +const float SIZE_Y = 384.0; + +const float UNDERGROUND_TARGET_DENSITY = 0.008; // Подземная дымка (слабее поверхностной) + float getEmission(uint magnitude, bool isAbsorber) { if (isAbsorber || magnitude == 0u) return 0.0; return float(magnitude) / 63.0 * 0.05; @@ -60,8 +68,17 @@ void main() { // Для джунглей (timeSensitivity = 0.3): дымка почти всегда float timeFactor = mix(1.0, TargetDensityMultiplier, biomeTimeSensitivity); - // 3. Итоговая плотность - float finalTargetDensity = biomeTargetDensityBase * hasFogToday * timeFactor; + // 3. Дымка плавно затухает к высоте 80-100 + float worldY = uv.y * SIZE_Y + MIN_Y; + float heightFade = 1.0 - clamp((worldY - HEIGHT_FADE_MIN) / (HeightFadeMax - HEIGHT_FADE_MIN), 0.0, 1.0); + + // 4. Под землёй дымка другая + float skyLight = texture(SkyLightSampler, uv).r; + float skyLightSmooth = smoothstep(0.2, 0.8, skyLight); + + // 4. Итоговая плотность + float surfaceTargetDensity = biomeTargetDensityBase * hasFogToday * timeFactor * heightFade; + float finalTargetDensity = mix(UNDERGROUND_TARGET_DENSITY, surfaceTargetDensity, skyLightSmooth); // Читаем воксель мира uint packedSelf = texture(WorldInfoSampler, uv).r;