355 lines
12 KiB
Java
355 lines
12 KiB
Java
package net.minecraft.client.renderer;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.mojang.blaze3d.shaders.FogShape;
|
|
import java.util.List;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.Camera;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.client.player.LocalPlayer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.tags.BiomeTags;
|
|
import net.minecraft.util.ARGB;
|
|
import net.minecraft.util.CubicSampler;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.effect.MobEffect;
|
|
import net.minecraft.world.effect.MobEffectInstance;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.level.biome.Biome;
|
|
import net.minecraft.world.level.biome.BiomeManager;
|
|
import net.minecraft.world.level.material.FogType;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.joml.Vector3f;
|
|
import org.joml.Vector4f;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class FogRenderer {
|
|
private static final int WATER_FOG_DISTANCE = 96;
|
|
private static final List<FogRenderer.MobEffectFogFunction> MOB_EFFECT_FOG = Lists.<FogRenderer.MobEffectFogFunction>newArrayList(
|
|
new FogRenderer.BlindnessFogFunction(), new FogRenderer.DarknessFogFunction()
|
|
);
|
|
public static final float BIOME_FOG_TRANSITION_TIME = 5000.0F;
|
|
private static int targetBiomeFog = -1;
|
|
private static int previousBiomeFog = -1;
|
|
private static long biomeChangedTime = -1L;
|
|
private static boolean fogEnabled = true;
|
|
|
|
public static Vector4f computeFogColor(Camera camera, float f, ClientLevel clientLevel, int i, float g) {
|
|
FogType fogType = camera.getFluidInCamera();
|
|
Entity entity = camera.getEntity();
|
|
float u;
|
|
float v;
|
|
float w;
|
|
if (fogType == FogType.WATER) {
|
|
long l = Util.getMillis();
|
|
int j = clientLevel.getBiome(BlockPos.containing(camera.getPosition())).value().getWaterFogColor();
|
|
if (biomeChangedTime < 0L) {
|
|
targetBiomeFog = j;
|
|
previousBiomeFog = j;
|
|
biomeChangedTime = l;
|
|
}
|
|
|
|
int k = targetBiomeFog >> 16 & 0xFF;
|
|
int m = targetBiomeFog >> 8 & 0xFF;
|
|
int n = targetBiomeFog & 0xFF;
|
|
int o = previousBiomeFog >> 16 & 0xFF;
|
|
int p = previousBiomeFog >> 8 & 0xFF;
|
|
int q = previousBiomeFog & 0xFF;
|
|
float h = Mth.clamp((float)(l - biomeChangedTime) / 5000.0F, 0.0F, 1.0F);
|
|
float r = Mth.lerp(h, (float)o, (float)k);
|
|
float s = Mth.lerp(h, (float)p, (float)m);
|
|
float t = Mth.lerp(h, (float)q, (float)n);
|
|
u = r / 255.0F;
|
|
v = s / 255.0F;
|
|
w = t / 255.0F;
|
|
if (targetBiomeFog != j) {
|
|
targetBiomeFog = j;
|
|
previousBiomeFog = Mth.floor(r) << 16 | Mth.floor(s) << 8 | Mth.floor(t);
|
|
biomeChangedTime = l;
|
|
}
|
|
} else if (fogType == FogType.LAVA) {
|
|
u = 0.6F;
|
|
v = 0.1F;
|
|
w = 0.0F;
|
|
biomeChangedTime = -1L;
|
|
} else if (fogType == FogType.POWDER_SNOW) {
|
|
u = 0.623F;
|
|
v = 0.734F;
|
|
w = 0.785F;
|
|
biomeChangedTime = -1L;
|
|
} else {
|
|
float x = 0.25F + 0.75F * i / 32.0F;
|
|
x = 1.0F - (float)Math.pow(x, 0.25);
|
|
int y = clientLevel.getSkyColor(camera.getPosition(), f);
|
|
float z = ARGB.from8BitChannel(ARGB.red(y));
|
|
float aa = ARGB.from8BitChannel(ARGB.green(y));
|
|
float ab = ARGB.from8BitChannel(ARGB.blue(y));
|
|
float ac = Mth.clamp(Mth.cos(clientLevel.getTimeOfDay(f) * (float) (Math.PI * 2)) * 2.0F + 0.5F, 0.0F, 1.0F);
|
|
BiomeManager biomeManager = clientLevel.getBiomeManager();
|
|
Vec3 vec3 = camera.getPosition().subtract(2.0, 2.0, 2.0).scale(0.25);
|
|
Vec3 vec32 = CubicSampler.gaussianSampleVec3(
|
|
vec3,
|
|
(ix, jx, k) -> clientLevel.effects().getBrightnessDependentFogColor(Vec3.fromRGB24(biomeManager.getNoiseBiomeAtQuart(ix, jx, k).value().getFogColor()), ac)
|
|
);
|
|
u = (float)vec32.x();
|
|
v = (float)vec32.y();
|
|
w = (float)vec32.z();
|
|
if (i >= 4) {
|
|
float h = Mth.sin(clientLevel.getSunAngle(f)) > 0.0F ? -1.0F : 1.0F;
|
|
Vector3f vector3f = new Vector3f(h, 0.0F, 0.0F);
|
|
float s = camera.getLookVector().dot(vector3f);
|
|
if (s < 0.0F) {
|
|
s = 0.0F;
|
|
}
|
|
|
|
if (s > 0.0F && clientLevel.effects().isSunriseOrSunset(clientLevel.getTimeOfDay(f))) {
|
|
int ad = clientLevel.effects().getSunriseOrSunsetColor(clientLevel.getTimeOfDay(f));
|
|
s *= ARGB.from8BitChannel(ARGB.alpha(ad));
|
|
u = u * (1.0F - s) + ARGB.from8BitChannel(ARGB.red(ad)) * s;
|
|
v = v * (1.0F - s) + ARGB.from8BitChannel(ARGB.green(ad)) * s;
|
|
w = w * (1.0F - s) + ARGB.from8BitChannel(ARGB.blue(ad)) * s;
|
|
}
|
|
}
|
|
|
|
u += (z - u) * x;
|
|
v += (aa - v) * x;
|
|
w += (ab - w) * x;
|
|
float hx = clientLevel.getRainLevel(f);
|
|
if (hx > 0.0F) {
|
|
float r = 1.0F - hx * 0.5F;
|
|
float sx = 1.0F - hx * 0.4F;
|
|
u *= r;
|
|
v *= r;
|
|
w *= sx;
|
|
}
|
|
|
|
float r = clientLevel.getThunderLevel(f);
|
|
if (r > 0.0F) {
|
|
float sx = 1.0F - r * 0.5F;
|
|
u *= sx;
|
|
v *= sx;
|
|
w *= sx;
|
|
}
|
|
|
|
biomeChangedTime = -1L;
|
|
}
|
|
|
|
float xx = ((float)camera.getPosition().y - clientLevel.getMinY()) * clientLevel.getLevelData().getClearColorScale();
|
|
FogRenderer.MobEffectFogFunction mobEffectFogFunction = getPriorityFogFunction(entity, f);
|
|
if (mobEffectFogFunction != null) {
|
|
LivingEntity livingEntity = (LivingEntity)entity;
|
|
xx = mobEffectFogFunction.getModifiedVoidDarkness(livingEntity, livingEntity.getEffect(mobEffectFogFunction.getMobEffect()), xx, f);
|
|
}
|
|
|
|
if (xx < 1.0F && fogType != FogType.LAVA && fogType != FogType.POWDER_SNOW) {
|
|
if (xx < 0.0F) {
|
|
xx = 0.0F;
|
|
}
|
|
|
|
xx *= xx;
|
|
u *= xx;
|
|
v *= xx;
|
|
w *= xx;
|
|
}
|
|
|
|
if (g > 0.0F) {
|
|
u = u * (1.0F - g) + u * 0.7F * g;
|
|
v = v * (1.0F - g) + v * 0.6F * g;
|
|
w = w * (1.0F - g) + w * 0.6F * g;
|
|
}
|
|
|
|
float zx;
|
|
if (fogType == FogType.WATER) {
|
|
if (entity instanceof LocalPlayer) {
|
|
zx = ((LocalPlayer)entity).getWaterVision();
|
|
} else {
|
|
zx = 1.0F;
|
|
}
|
|
} else if (entity instanceof LivingEntity livingEntity2 && livingEntity2.hasEffect(MobEffects.NIGHT_VISION) && !livingEntity2.hasEffect(MobEffects.DARKNESS)) {
|
|
zx = GameRenderer.getNightVisionScale(livingEntity2, f);
|
|
} else {
|
|
zx = 0.0F;
|
|
}
|
|
|
|
if (u != 0.0F && v != 0.0F && w != 0.0F) {
|
|
float aax = Math.min(1.0F / u, Math.min(1.0F / v, 1.0F / w));
|
|
u = u * (1.0F - zx) + u * aax * zx;
|
|
v = v * (1.0F - zx) + v * aax * zx;
|
|
w = w * (1.0F - zx) + w * aax * zx;
|
|
}
|
|
|
|
return new Vector4f(u, v, w, 1.0F);
|
|
}
|
|
|
|
public static boolean toggleFog() {
|
|
return fogEnabled = !fogEnabled;
|
|
}
|
|
|
|
@Nullable
|
|
private static FogRenderer.MobEffectFogFunction getPriorityFogFunction(Entity entity, float partialTick) {
|
|
return entity instanceof LivingEntity livingEntity
|
|
? (FogRenderer.MobEffectFogFunction)MOB_EFFECT_FOG.stream()
|
|
.filter(mobEffectFogFunction -> mobEffectFogFunction.isEnabled(livingEntity, partialTick))
|
|
.findFirst()
|
|
.orElse(null)
|
|
: null;
|
|
}
|
|
|
|
public static FogParameters setupFog(Camera camera, FogRenderer.FogMode fogMode, Vector4f vector4f, float f, boolean bl, float g) {
|
|
if (!fogEnabled) {
|
|
return FogParameters.NO_FOG;
|
|
} else {
|
|
FogType fogType = camera.getFluidInCamera();
|
|
Entity entity = camera.getEntity();
|
|
FogRenderer.FogData fogData = new FogRenderer.FogData(fogMode);
|
|
FogRenderer.MobEffectFogFunction mobEffectFogFunction = getPriorityFogFunction(entity, g);
|
|
if (fogType == FogType.LAVA) {
|
|
if (entity.isSpectator()) {
|
|
fogData.start = -8.0F;
|
|
fogData.end = f * 0.5F;
|
|
} else if (entity instanceof LivingEntity && ((LivingEntity)entity).hasEffect(MobEffects.FIRE_RESISTANCE)) {
|
|
fogData.start = 0.0F;
|
|
fogData.end = 5.0F;
|
|
} else {
|
|
fogData.start = 0.25F;
|
|
fogData.end = 1.0F;
|
|
}
|
|
} else if (fogType == FogType.POWDER_SNOW) {
|
|
if (entity.isSpectator()) {
|
|
fogData.start = -8.0F;
|
|
fogData.end = f * 0.5F;
|
|
} else {
|
|
fogData.start = 0.0F;
|
|
fogData.end = 2.0F;
|
|
}
|
|
} else if (mobEffectFogFunction != null) {
|
|
LivingEntity livingEntity = (LivingEntity)entity;
|
|
MobEffectInstance mobEffectInstance = livingEntity.getEffect(mobEffectFogFunction.getMobEffect());
|
|
if (mobEffectInstance != null) {
|
|
mobEffectFogFunction.setupFog(fogData, livingEntity, mobEffectInstance, f, g);
|
|
}
|
|
} else if (fogType == FogType.WATER) {
|
|
fogData.start = -8.0F;
|
|
fogData.end = 96.0F;
|
|
if (entity instanceof LocalPlayer localPlayer) {
|
|
fogData.end = fogData.end * Math.max(0.25F, localPlayer.getWaterVision());
|
|
Holder<Biome> holder = localPlayer.level().getBiome(localPlayer.blockPosition());
|
|
if (holder.is(BiomeTags.HAS_CLOSER_WATER_FOG)) {
|
|
fogData.end *= 0.85F;
|
|
}
|
|
}
|
|
|
|
if (fogData.end > f) {
|
|
fogData.end = f;
|
|
fogData.shape = FogShape.CYLINDER;
|
|
}
|
|
} else if (bl) {
|
|
fogData.start = f * 0.05F;
|
|
fogData.end = Math.min(f, 192.0F) * 0.5F;
|
|
} else if (fogMode == FogRenderer.FogMode.FOG_SKY) {
|
|
fogData.start = 0.0F;
|
|
fogData.end = f;
|
|
fogData.shape = FogShape.CYLINDER;
|
|
} else if (fogMode == FogRenderer.FogMode.FOG_TERRAIN) {
|
|
float h = Mth.clamp(f / 10.0F, 4.0F, 64.0F);
|
|
fogData.start = f - h;
|
|
fogData.end = f;
|
|
fogData.shape = FogShape.CYLINDER;
|
|
}
|
|
|
|
return new FogParameters(fogData.start, fogData.end, fogData.shape, vector4f.x, vector4f.y, vector4f.z, vector4f.w);
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class BlindnessFogFunction implements FogRenderer.MobEffectFogFunction {
|
|
@Override
|
|
public Holder<MobEffect> getMobEffect() {
|
|
return MobEffects.BLINDNESS;
|
|
}
|
|
|
|
@Override
|
|
public void setupFog(FogRenderer.FogData fogData, LivingEntity entity, MobEffectInstance effectInstance, float farPlaneDistance, float f) {
|
|
float g = effectInstance.isInfiniteDuration() ? 5.0F : Mth.lerp(Math.min(1.0F, effectInstance.getDuration() / 20.0F), farPlaneDistance, 5.0F);
|
|
if (fogData.mode == FogRenderer.FogMode.FOG_SKY) {
|
|
fogData.start = 0.0F;
|
|
fogData.end = g * 0.8F;
|
|
} else if (fogData.mode == FogRenderer.FogMode.FOG_TERRAIN) {
|
|
fogData.start = g * 0.25F;
|
|
fogData.end = g;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class DarknessFogFunction implements FogRenderer.MobEffectFogFunction {
|
|
@Override
|
|
public Holder<MobEffect> getMobEffect() {
|
|
return MobEffects.DARKNESS;
|
|
}
|
|
|
|
@Override
|
|
public void setupFog(FogRenderer.FogData fogData, LivingEntity entity, MobEffectInstance effectInstance, float farPlaneDistance, float f) {
|
|
float g = Mth.lerp(effectInstance.getBlendFactor(entity, f), farPlaneDistance, 15.0F);
|
|
|
|
fogData.start = switch (fogData.mode) {
|
|
case FOG_SKY -> 0.0F;
|
|
case FOG_TERRAIN -> g * 0.75F;
|
|
};
|
|
fogData.end = g;
|
|
}
|
|
|
|
@Override
|
|
public float getModifiedVoidDarkness(LivingEntity entity, MobEffectInstance effectInstance, float f, float partialTick) {
|
|
return 1.0F - effectInstance.getBlendFactor(entity, partialTick);
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class FogData {
|
|
public final FogRenderer.FogMode mode;
|
|
public float start;
|
|
public float end;
|
|
public FogShape shape = FogShape.SPHERE;
|
|
|
|
public FogData(FogRenderer.FogMode mode) {
|
|
this.mode = mode;
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static enum FogMode {
|
|
FOG_SKY,
|
|
FOG_TERRAIN;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
interface MobEffectFogFunction {
|
|
Holder<MobEffect> getMobEffect();
|
|
|
|
void setupFog(FogRenderer.FogData fogData, LivingEntity entity, MobEffectInstance effectInstance, float farPlaneDistance, float f);
|
|
|
|
default boolean isEnabled(LivingEntity entity, float f) {
|
|
return entity.hasEffect(this.getMobEffect());
|
|
}
|
|
|
|
default float getModifiedVoidDarkness(LivingEntity entity, MobEffectInstance effectInstance, float f, float partialTick) {
|
|
MobEffectInstance mobEffectInstance = entity.getEffect(this.getMobEffect());
|
|
if (mobEffectInstance != null) {
|
|
if (mobEffectInstance.endsWithin(19)) {
|
|
f = 1.0F - mobEffectInstance.getDuration() / 20.0F;
|
|
} else {
|
|
f = 0.0F;
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
}
|
|
}
|