make the sky loop around under the horizon

This commit is contained in:
wisplite
2026-06-12 18:11:40 -05:00
parent 33947801ad
commit 75e0a72d89
7 changed files with 130 additions and 8 deletions
+2 -1
View File
@@ -85,7 +85,8 @@ subprojects {
runs.configureEach {
vmArg("-XX:+AllowEnhancedClassRedefinition")
vmArg("-XX:+IgnoreUnrecognizedVMOptions")
vmArg("-Dmixin.debug.export=true")
// Disabled by default: exports every mixin target to disk and can make startup hang for minutes.
// Enable manually when debugging mixins: -Dmixin.debug.export=true
vmArg("-Dmixin.env.remapRefMap=true")
vmArg("-Dmixin.env.refMapRemappingFile=${projectDir}/build/createSrgToMcp/output.srg")
}
@@ -4,6 +4,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import io.github.slimeistdev.crystalline_sky.compat.Mods;
import io.github.slimeistdev.crystalline_sky.compat.iris.IrisHelpers;
@@ -15,10 +16,12 @@ import net.minecraft.client.Camera;
import net.minecraft.client.CloudStatus;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
@@ -48,6 +51,9 @@ public abstract class LevelRendererMixin implements LevelRenderer_Duck {
@Shadow
public abstract void renderClouds(PoseStack matrices, Matrix4f matrix4f, Matrix4f matrix4f2, float tickDelta, double cameraX, double cameraY, double cameraZ);
@Shadow
public abstract void renderSky(Matrix4f frustumMatrix, Matrix4f projectionMatrix, float partialTick, Camera camera, boolean isFoggy, Runnable skyFogSetup);
@Unique
@Nullable
private RenderTarget crystalline_sky$skyBuffer;
@@ -104,9 +110,15 @@ public abstract class LevelRendererMixin implements LevelRenderer_Duck {
Matrix4f matrix4f, Matrix4f matrix4f2, CallbackInfo ci) {
var skyBuffer = crystalline_sky$getSkyFramebuffer();
skyBuffer.clear(Minecraft.ON_OSX);
var copiedFromIris = Mods.IRIS.runIfInstalled(() -> () -> IrisHelpers.copySkyToBuffer(skyBuffer));
if (!copiedFromIris.orElse(false))
((RenderTarget_Duck) skyBuffer).crystalline_sky$copyColorFrom(minecraft.getMainRenderTarget());
float partialTick = tickCounter.getGameTimeDeltaPartialTick(false);
if (crystalline_sky$isBelowHorizon(partialTick)) {
crystalline_sky$renderSkyBuffer(skyBuffer, tickCounter, camera, gameRenderer, matrix4f, matrix4f2);
} else {
var copiedFromIris = Mods.IRIS.runIfInstalled(() -> () -> IrisHelpers.copySkyToBuffer(skyBuffer));
if (!copiedFromIris.orElse(false))
((RenderTarget_Duck) skyBuffer).crystalline_sky$copyColorFrom(minecraft.getMainRenderTarget());
}
// render clouds
CloudStatus cloudRenderMode = this.minecraft.options.getCloudsType();
@@ -143,4 +155,60 @@ public abstract class LevelRendererMixin implements LevelRenderer_Duck {
renderSectionLayer(CrystallineRenderTypes.SKY, x, y, z, matrix4f, positionMatrix);
renderSectionLayer(CrystallineRenderTypes.SKYBOX, x, y, z, matrix4f, positionMatrix);
}
@Unique
private boolean crystalline_sky$isBelowHorizon(float partialTick) {
var level = minecraft.level;
var player = minecraft.player;
if (level == null || player == null) {
return false;
}
double eyeY = player.getEyePosition(partialTick).y;
double horizon = level.getLevelData().getHorizonHeight(level);
return eyeY < horizon;
}
@Unique
private void crystalline_sky$renderSkyBuffer(
RenderTarget skyBuffer,
DeltaTracker tickCounter,
Camera camera,
GameRenderer gameRenderer,
Matrix4f frustumMatrix,
Matrix4f projectionMatrix
) {
float partialTick = tickCounter.getGameTimeDeltaPartialTick(false);
Vec3 cameraPos = camera.getPosition();
float renderDistance = gameRenderer.getRenderDistance();
boolean isFoggy = minecraft.level.effects().isFoggyAt(Mth.floor(cameraPos.x), Mth.floor(cameraPos.y))
|| minecraft.gui.getBossOverlay().shouldCreateWorldFog();
skyBuffer.bindWrite(false);
SharedRenderVariables.pushSkipVoidSky();
try {
FogRenderer.setupColor(
camera,
partialTick,
minecraft.level,
minecraft.options.getEffectiveRenderDistance(),
gameRenderer.getDarkenWorldAmount(partialTick)
);
FogRenderer.levelFogColor();
RenderSystem.clear(16640, Minecraft.ON_OSX);
FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, isFoggy, partialTick);
RenderSystem.setShader(GameRenderer::getPositionShader);
this.renderSky(
frustumMatrix,
projectionMatrix,
partialTick,
camera,
isFoggy,
() -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, isFoggy, partialTick)
);
} finally {
SharedRenderVariables.popSkipVoidSky();
minecraft.getMainRenderTarget().bindWrite(false);
}
}
}
@@ -0,0 +1,32 @@
package io.github.slimeistdev.crystalline_sky.mixin.client;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.slimeistdev.crystalline_sky.util.SharedRenderVariables;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.world.level.LevelHeightAccessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(value = LevelRenderer.class, remap = false)
public class LevelRendererRenderSkyMixin {
@WrapOperation(
method = "renderSky",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/ClientLevel$ClientLevelData;getHorizonHeight(Lnet/minecraft/world/level/LevelHeightAccessor;)D"
)
)
private double crystalline_sky$skipVoidSkyWhenCapturing(
ClientLevel.ClientLevelData levelData,
LevelHeightAccessor level,
Operation<Double> original
) {
if (SharedRenderVariables.shouldSkipVoidSky()) {
return Double.NEGATIVE_INFINITY;
}
return original.call(levelData, level);
}
}
@@ -8,6 +8,7 @@ public class SharedRenderVariables {
// because chunk meshing is multithreaded :(
public static final ThreadLocal<MutableInt> shadeFullBright = ThreadLocal.withInitial(() -> new MutableInt(0));
private static int blockIrisShaderFramebufferBind = 0;
private static int skipVoidSky = 0;
public static boolean shouldShadeFullBright() {
return shadeFullBright.get().intValue() > 0;
@@ -32,4 +33,16 @@ public class SharedRenderVariables {
public static void popBlockIrisShaderFramebufferBind() {
blockIrisShaderFramebufferBind--;
}
public static boolean shouldSkipVoidSky() {
return skipVoidSky > 0;
}
public static void pushSkipVoidSky() {
skipVoidSky++;
}
public static void popSkipVoidSky() {
skipVoidSky--;
}
}
@@ -22,6 +22,7 @@
"client.GameRendererMixin",
"client.LevelRenderer_NoSodium_Mixin",
"client.LevelRendererMixin",
"client.LevelRendererRenderSkyMixin",
"client.ModelBlockRendererMixin",
"client.RenderTargetMixin",
"client.TextureAtlasAccessor",
+9 -2
View File
@@ -2,7 +2,10 @@
org.gradle.jvmargs=-Xmx2G -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
# -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006
org.gradle.caching=true
org.gradle.configureondemand=true
# Disabled: with configure-on-demand, :fabric is not configured when running :neoforge:runClient,
# but prepareArchitecturyTransformer queries all Loom projects and fails with
# "Cannot get MappingsProvider before it has been setup".
org.gradle.configureondemand=false
# IntelliJ's run configs don't work with the configuration cache
org.gradle.configuration-cache=false
# Loom
@@ -26,7 +29,11 @@ modVersion=0.2.0
branchName=1.21.1
compatibleVersions=1.21.1
# mod compat
# mod compat (compileOnly)
enable_sodium=true
enable_iris=true
# modLocalRuntime for Sodium/Iris hangs NeoForge dev startup for minutes (mixin stalls on RenderTarget).
# For in-game Sodium/Iris testing, copy the jars into neoforge/run/mods/ instead.
enable_sodium_runtime=false
enable_iris_runtime=false
enable_axiom=false
+2 -2
View File
@@ -32,12 +32,12 @@ dependencies {
modCompileOnly(libs.ffapi.renderer) // only for sodium compat
modCompileOnly(libs.sodium.neoforge)
if (!inCI && "enable_sodium"().toBoolean()) { // this doesn't work, because of jar-in-jar. Sodium must be placed in the mods folder
if (!inCI && "enable_sodium_runtime"().toBoolean()) { // Sodium must be in run/mods for jar-in-jar; modLocalRuntime stalls dev startup
modLocalRuntime(libs.sodium.neoforge)
}
modCompileOnly(libs.iris.neoforge)
if (!inCI && "enable_iris"().toBoolean()) { // this doesn't work, because of jar-in-jar. Iris must be placed in the mods folder
if (!inCI && "enable_iris_runtime"().toBoolean()) { // Iris must be in run/mods for jar-in-jar; modLocalRuntime stalls dev startup
modLocalRuntime(libs.iris.neoforge)
/*modLocalRuntime("org.antlr:antlr4-runtime:4.13.1")
modLocalRuntime("io.github.douira:glsl-transformer:2.0.1")