235 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.fog;
 | |
| 
 | |
| import com.google.common.collect.Lists;
 | |
| import com.mojang.blaze3d.buffers.GpuBuffer;
 | |
| import com.mojang.blaze3d.buffers.GpuBufferSlice;
 | |
| import com.mojang.blaze3d.buffers.Std140Builder;
 | |
| import com.mojang.blaze3d.buffers.Std140SizeCalculator;
 | |
| import com.mojang.blaze3d.systems.GpuDevice;
 | |
| import com.mojang.blaze3d.systems.RenderSystem;
 | |
| import java.nio.ByteBuffer;
 | |
| import java.util.List;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.Camera;
 | |
| import net.minecraft.client.DeltaTracker;
 | |
| import net.minecraft.client.multiplayer.ClientLevel;
 | |
| import net.minecraft.client.player.LocalPlayer;
 | |
| import net.minecraft.client.renderer.GameRenderer;
 | |
| import net.minecraft.client.renderer.MappableRingBuffer;
 | |
| import net.minecraft.client.renderer.fog.environment.AtmosphericFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.BlindnessFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.DarknessFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.DimensionOrBossFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.FogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.LavaFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.PowderedSnowFogEnvironment;
 | |
| import net.minecraft.client.renderer.fog.environment.WaterFogEnvironment;
 | |
| import net.minecraft.util.ARGB;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.effect.MobEffects;
 | |
| import net.minecraft.world.entity.Entity;
 | |
| import net.minecraft.world.entity.LivingEntity;
 | |
| import net.minecraft.world.level.material.FogType;
 | |
| import org.joml.Vector4f;
 | |
| import org.lwjgl.system.MemoryStack;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class FogRenderer implements AutoCloseable {
 | |
| 	public static final int FOG_UBO_SIZE = new Std140SizeCalculator().putVec4().putFloat().putFloat().putFloat().putFloat().putFloat().putFloat().get();
 | |
| 	private static final List<FogEnvironment> FOG_ENVIRONMENTS = Lists.<FogEnvironment>newArrayList(
 | |
| 		new LavaFogEnvironment(),
 | |
| 		new PowderedSnowFogEnvironment(),
 | |
| 		new WaterFogEnvironment(),
 | |
| 		new BlindnessFogEnvironment(),
 | |
| 		new DarknessFogEnvironment(),
 | |
| 		new DimensionOrBossFogEnvironment(),
 | |
| 		new AtmosphericFogEnvironment()
 | |
| 	);
 | |
| 	private static boolean fogEnabled = true;
 | |
| 	private final GpuBuffer emptyBuffer;
 | |
| 	private final MappableRingBuffer regularBuffer;
 | |
| 
 | |
| 	public FogRenderer() {
 | |
| 		GpuDevice gpuDevice = RenderSystem.getDevice();
 | |
| 		this.regularBuffer = new MappableRingBuffer(() -> "Fog UBO", 130, FOG_UBO_SIZE);
 | |
| 
 | |
| 		try (MemoryStack memoryStack = MemoryStack.stackPush()) {
 | |
| 			ByteBuffer byteBuffer = memoryStack.malloc(FOG_UBO_SIZE);
 | |
| 			this.updateBuffer(byteBuffer, 0, new Vector4f(0.0F), Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
 | |
| 			this.emptyBuffer = gpuDevice.createBuffer(() -> "Empty fog", 128, byteBuffer.flip());
 | |
| 		}
 | |
| 
 | |
| 		RenderSystem.setShaderFog(this.getBuffer(FogRenderer.FogMode.NONE));
 | |
| 	}
 | |
| 
 | |
| 	public void close() {
 | |
| 		this.emptyBuffer.close();
 | |
| 		this.regularBuffer.close();
 | |
| 	}
 | |
| 
 | |
| 	public void endFrame() {
 | |
| 		this.regularBuffer.rotate();
 | |
| 	}
 | |
| 
 | |
| 	public GpuBufferSlice getBuffer(FogRenderer.FogMode fogMode) {
 | |
| 		if (!fogEnabled) {
 | |
| 			return this.emptyBuffer.slice(0, FOG_UBO_SIZE);
 | |
| 		} else {
 | |
| 			return switch (fogMode) {
 | |
| 				case NONE -> this.emptyBuffer.slice(0, FOG_UBO_SIZE);
 | |
| 				case WORLD -> this.regularBuffer.currentBuffer().slice(0, FOG_UBO_SIZE);
 | |
| 			};
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Vector4f computeFogColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, boolean isFoggy) {
 | |
| 		FogType fogType = this.getFogType(camera, isFoggy);
 | |
| 		Entity entity = camera.getEntity();
 | |
| 		FogEnvironment fogEnvironment = null;
 | |
| 		FogEnvironment fogEnvironment2 = null;
 | |
| 
 | |
| 		for (FogEnvironment fogEnvironment3 : FOG_ENVIRONMENTS) {
 | |
| 			if (fogEnvironment3.isApplicable(fogType, entity)) {
 | |
| 				if (fogEnvironment == null && fogEnvironment3.providesColor()) {
 | |
| 					fogEnvironment = fogEnvironment3;
 | |
| 				}
 | |
| 
 | |
| 				if (fogEnvironment2 == null && fogEnvironment3.modifiesDarkness()) {
 | |
| 					fogEnvironment2 = fogEnvironment3;
 | |
| 				}
 | |
| 			} else {
 | |
| 				fogEnvironment3.onNotApplicable();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (fogEnvironment == null) {
 | |
| 			throw new IllegalStateException("No color source environment found");
 | |
| 		} else {
 | |
| 			int i = fogEnvironment.getBaseColor(level, camera, renderDistance, darkenWorldAmount);
 | |
| 			float f = level.getLevelData().voidDarknessOnsetRange();
 | |
| 			float g = Mth.clamp((f + level.getMinY() - (float)camera.getPosition().y) / f, 0.0F, 1.0F);
 | |
| 			if (fogEnvironment2 != null) {
 | |
| 				LivingEntity livingEntity = (LivingEntity)entity;
 | |
| 				g = fogEnvironment2.getModifiedDarkness(livingEntity, g, partialTick);
 | |
| 			}
 | |
| 
 | |
| 			float h = ARGB.redFloat(i);
 | |
| 			float j = ARGB.greenFloat(i);
 | |
| 			float k = ARGB.blueFloat(i);
 | |
| 			if (g > 0.0F && fogType != FogType.LAVA && fogType != FogType.POWDER_SNOW) {
 | |
| 				float l = Mth.square(1.0F - g);
 | |
| 				h *= l;
 | |
| 				j *= l;
 | |
| 				k *= l;
 | |
| 			}
 | |
| 
 | |
| 			if (darkenWorldAmount > 0.0F) {
 | |
| 				h = Mth.lerp(darkenWorldAmount, h, h * 0.7F);
 | |
| 				j = Mth.lerp(darkenWorldAmount, j, j * 0.6F);
 | |
| 				k = Mth.lerp(darkenWorldAmount, k, k * 0.6F);
 | |
| 			}
 | |
| 
 | |
| 			float l;
 | |
| 			if (fogType == FogType.WATER) {
 | |
| 				if (entity instanceof LocalPlayer) {
 | |
| 					l = ((LocalPlayer)entity).getWaterVision();
 | |
| 				} else {
 | |
| 					l = 1.0F;
 | |
| 				}
 | |
| 			} else if (entity instanceof LivingEntity livingEntity2 && livingEntity2.hasEffect(MobEffects.NIGHT_VISION) && !livingEntity2.hasEffect(MobEffects.DARKNESS)
 | |
| 				)
 | |
| 			 {
 | |
| 				l = GameRenderer.getNightVisionScale(livingEntity2, partialTick);
 | |
| 			} else {
 | |
| 				l = 0.0F;
 | |
| 			}
 | |
| 
 | |
| 			if (h != 0.0F && j != 0.0F && k != 0.0F) {
 | |
| 				float m = 1.0F / Math.max(h, Math.max(j, k));
 | |
| 				h = Mth.lerp(l, h, h * m);
 | |
| 				j = Mth.lerp(l, j, j * m);
 | |
| 				k = Mth.lerp(l, k, k * m);
 | |
| 			}
 | |
| 
 | |
| 			return new Vector4f(h, j, k, 1.0F);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static boolean toggleFog() {
 | |
| 		return fogEnabled = !fogEnabled;
 | |
| 	}
 | |
| 
 | |
| 	public Vector4f setupFog(Camera camera, int renderDistance, boolean isFoggy, DeltaTracker deltaTracker, float darkenWorldAmount, ClientLevel level) {
 | |
| 		float f = deltaTracker.getGameTimeDeltaPartialTick(false);
 | |
| 		Vector4f vector4f = this.computeFogColor(camera, f, level, renderDistance, darkenWorldAmount, isFoggy);
 | |
| 		float g = renderDistance * 16;
 | |
| 		FogType fogType = this.getFogType(camera, isFoggy);
 | |
| 		Entity entity = camera.getEntity();
 | |
| 		FogData fogData = new FogData();
 | |
| 
 | |
| 		for (FogEnvironment fogEnvironment : FOG_ENVIRONMENTS) {
 | |
| 			if (fogEnvironment.isApplicable(fogType, entity)) {
 | |
| 				fogEnvironment.setupFog(fogData, entity, camera.getBlockPosition(), level, g, deltaTracker);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		float h = Mth.clamp(g / 10.0F, 4.0F, 64.0F);
 | |
| 		fogData.renderDistanceStart = g - h;
 | |
| 		fogData.renderDistanceEnd = g;
 | |
| 
 | |
| 		try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.regularBuffer.currentBuffer(), false, true)) {
 | |
| 			this.updateBuffer(
 | |
| 				mappedView.data(),
 | |
| 				0,
 | |
| 				vector4f,
 | |
| 				fogData.environmentalStart,
 | |
| 				fogData.environmentalEnd,
 | |
| 				fogData.renderDistanceStart,
 | |
| 				fogData.renderDistanceEnd,
 | |
| 				fogData.skyEnd,
 | |
| 				fogData.cloudEnd
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		return vector4f;
 | |
| 	}
 | |
| 
 | |
| 	private FogType getFogType(Camera camera, boolean isFoggy) {
 | |
| 		FogType fogType = camera.getFluidInCamera();
 | |
| 		if (fogType == FogType.NONE) {
 | |
| 			return isFoggy ? FogType.DIMENSION_OR_BOSS : FogType.ATMOSPHERIC;
 | |
| 		} else {
 | |
| 			return fogType;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void updateBuffer(
 | |
| 		ByteBuffer buffer,
 | |
| 		int position,
 | |
| 		Vector4f fogColor,
 | |
| 		float environmentalStart,
 | |
| 		float environmentalEnd,
 | |
| 		float renderDistanceStart,
 | |
| 		float renderDistanceEnd,
 | |
| 		float skyEnd,
 | |
| 		float cloudEnd
 | |
| 	) {
 | |
| 		buffer.position(position);
 | |
| 		Std140Builder.intoBuffer(buffer)
 | |
| 			.putVec4(fogColor)
 | |
| 			.putFloat(environmentalStart)
 | |
| 			.putFloat(environmentalEnd)
 | |
| 			.putFloat(renderDistanceStart)
 | |
| 			.putFloat(renderDistanceEnd)
 | |
| 			.putFloat(skyEnd)
 | |
| 			.putFloat(cloudEnd);
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static enum FogMode {
 | |
| 		NONE,
 | |
| 		WORLD;
 | |
| 	}
 | |
| }
 |