From c06cb8ddf5967ca771f7da1a7a2bbcd5302f261f Mon Sep 17 00:00:00 2001 From: Jenya Date: Tue, 7 Apr 2026 00:48:50 +0300 Subject: [PATCH 1/7] Initial black hole implementation --- build.gradle | 4 + .../java/net/neganote/monilabs/MoniLabs.java | 21 +- .../client/render/BlackHoleRenderer.java | 263 ++++++++++++++++++ .../render/BlackHoleRendererHelpers.java | 73 +++++ .../client/render/CreativeEnergyRender.java | 36 +-- .../mixin/DefaultChunkRendererMixin.java | 61 ++++ .../mixin/ShaderChunkRendererMixin.java | 37 +++ .../monilabs/mixin/ShaderLoaderMixin.java | 39 +++ .../mixin/TranslucentRenderMixin.java | 43 +++ .../accessor/ShaderChunkRendererAccessor.java | 14 + .../accessor/TerrainRenderPassAccessor.java | 14 + .../shaders/core/rendertype_wormhole.fsh | 132 ++++++++- .../shaders/core/rendertype_wormhole.json | 19 +- .../shaders/core/rendertype_wormhole.vsh | 17 +- src/main/resources/monilabs.mixins.json | 10 +- 15 files changed, 744 insertions(+), 39 deletions(-) create mode 100644 src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java create mode 100644 src/main/java/net/neganote/monilabs/client/render/BlackHoleRendererHelpers.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/accessor/ShaderChunkRendererAccessor.java create mode 100644 src/main/java/net/neganote/monilabs/mixin/accessor/TerrainRenderPassAccessor.java diff --git a/build.gradle b/build.gradle index 0a5994e0..a8732e16 100644 --- a/build.gradle +++ b/build.gradle @@ -201,6 +201,10 @@ dependencies { compileOnly(annotationProcessor("com.github.bawnorton.mixinsquared:mixinsquared-common:0.3.7-beta.1")) implementation(jarJar("com.github.bawnorton.mixinsquared:mixinsquared-forge:0.3.7-beta.1")) + //mixinextras for WrapOperation + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.5.3")) + implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.5.3")) + // JEI, EMI, Jade modCompileOnly("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}") modCompileOnly("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}") diff --git a/src/main/java/net/neganote/monilabs/MoniLabs.java b/src/main/java/net/neganote/monilabs/MoniLabs.java index 5c79f07b..3bc3986a 100644 --- a/src/main/java/net/neganote/monilabs/MoniLabs.java +++ b/src/main/java/net/neganote/monilabs/MoniLabs.java @@ -15,9 +15,13 @@ import com.gregtechceu.gtceu.common.data.GTCreativeModeTabs; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.item.CreativeModeTab; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.client.event.RegisterParticleProvidersEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; @@ -129,7 +133,7 @@ public MoniLabs(FMLJavaModLoadingContext context) { modEventBus .addGenericListener(MachineDefinition.class, this::registerMachines); modEventBus.addGenericListener(CoverDefinition.class, this::registerCovers); - + modEventBus.addListener(this::onRegisterReloadListeners); // Most other events are fired on Forge's bus. // If we want to use annotations to register event listeners, // we need to register our object like this! @@ -220,6 +224,21 @@ private void registerMachines(GTCEuAPI.RegisterEvent event) {} + private void onRegisterReloadListeners(RegisterClientReloadListenersEvent event) { + event.registerReloadListener(new SimplePreparableReloadListener() { + + @Override + protected Object prepare(ResourceManager resourceManager, ProfilerFiller profilerFiller) { + return null; + } + + @Override + protected void apply(Object o, ResourceManager resourceManager, ProfilerFiller profilerFiller) { + BlackHoleRenderer.updateTextures(); + } + }); + } + public void registerAdditionalModels(ModelEvent.RegisterAdditional event) { event.register(CreativeEnergyRender.SPHERE); } diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java new file mode 100644 index 00000000..0ec5ec4a --- /dev/null +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -0,0 +1,263 @@ +package net.neganote.monilabs.client.render; + +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.neganote.monilabs.MoniLabs; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.pipeline.TextureTarget; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; +import org.lwjgl.opengl.*; + +import java.util.ArrayList; +import java.util.List; + +@Mod.EventBusSubscriber(modid = MoniLabs.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +public class BlackHoleRenderer { + + private static RenderTarget depthTextureForTranslucency; + private static int cachedSlot = -1; + + // Settings + private static final float uMass = 9.05f; + private static final float uDistModifier = 0.20f; + private static final float uSchwarzschildRadius = 2.55f; + private static final int uAABBSize = 14; + private static final float uSphereRadius = 5.2f; + + private static final List blackHoles = new ArrayList<>(); + public static RenderTarget worldTexture = null; + public static RenderTarget miscTranslucentTexture = null; + + private static int findFreeTextureSlot() { + int maxUnits = GL41.glGetInteger(GL41.GL_MAX_TEXTURE_IMAGE_UNITS) - 1; + int freeSlot = -1; + + int originalActiveUnit = GL41.glGetInteger(GL41.GL_ACTIVE_TEXTURE); + + for (int i = maxUnits - 1; i >= 0; i--) { + GL41.glActiveTexture(GL41.GL_TEXTURE0 + i); + int boundTexture = GL41.glGetInteger(GL41.GL_TEXTURE_BINDING_2D); + + if (boundTexture == 0) { + freeSlot = i; + break; + } + } + + GL41.glActiveTexture(originalActiveUnit); + + if (freeSlot == -1) { + throw new RuntimeException("Failed to find free texture slot."); + } + + return freeSlot; + } + + private static void drawBlackHoleToDepthBuffer(PoseStack poseStack, Vector3f bhPos, Camera camera) { + // Draws the black hole to a separate depth buffer for future minecraft transparent passes filtering + Vec3 camPos = camera.getPosition(); + poseStack.pushPose(); + + var viewSpaceSpherePos = poseStack.last().pose().transform( + new Vector4f(bhPos.x - (float) camPos.x, bhPos.y - (float) camPos.y, bhPos.z - (float) camPos.z, 1.0f)); + + Tesselator tessellator = Tesselator.getInstance(); + BufferBuilder builder = tessellator.getBuilder(); + + depthTextureForTranslucency.bindWrite(true); + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(true); + RenderSystem.depthFunc(GL11.GL_ALWAYS); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.clearDepth(1); + RenderSystem.clear(GL41.GL_DEPTH_BUFFER_BIT, false); + GL31.glCullFace(GL11.GL_FRONT); // To render only back faces + ShaderInstance shader = MoniShaders.WORMHOLE_SHADER; + RenderSystem.setShader(() -> shader); + + shader.safeGetUniform("SpherePos").set(viewSpaceSpherePos.x, viewSpaceSpherePos.y, + viewSpaceSpherePos.z); + shader.safeGetUniform("uSphereRadius").set(uSphereRadius); + shader.safeGetUniform("uWriteOnlyDepth").set(1); + + AABB box = BlackHoleRendererHelpers.createAABBAt(bhPos, uAABBSize); + builder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR); + BlackHoleRendererHelpers.addBoxTriangles(poseStack, builder, + (float) (box.minX - camPos.x), (float) (box.minY - camPos.y), (float) (box.minZ - camPos.z), + (float) (box.maxX - camPos.x), (float) (box.maxY - camPos.y), (float) (box.maxZ - camPos.z), + 1, 1, 0, 1); + + tessellator.end(); + + poseStack.popPose(); + GL31.glCullFace(GL31.GL_BACK); + RenderSystem.depthFunc(GL31.GL_LEQUAL); + } + + public static void updateTextures() { + cachedSlot = -1; + Window w = Minecraft.getInstance().getWindow(); + int mcWidth = w.getWidth(); + int mcHeight = w.getHeight(); + if (mcWidth == 0 || mcHeight == 0) + return; + if (depthTextureForTranslucency != null) + depthTextureForTranslucency.resize(mcWidth, mcHeight, false); + else + depthTextureForTranslucency = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + + if (BlackHoleRenderer.worldTexture != null) + BlackHoleRenderer.worldTexture.resize(mcWidth, mcHeight, false); + else + BlackHoleRenderer.worldTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + + if (miscTranslucentTexture != null) + miscTranslucentTexture.resize(mcWidth, mcHeight, false); + else + miscTranslucentTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + } + + public static void render(Vector3f position) { + blackHoles.add(position); + } + + public static void handleTranslucentPassBegin(int programHandle) { + if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer) + return; + + int activeUnit = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE); + int uDepthLocation = GL41.glGetUniformLocation(programHandle, "u_BlackHoleDepthTexture"); + + if (uDepthLocation != -1) { + if (cachedSlot == -1) { + cachedSlot = findFreeTextureSlot(); + } + int targetUnit = cachedSlot; + + GL41.glUniform1i(uDepthLocation, targetUnit); + + GL13.glActiveTexture(GL13.GL_TEXTURE0 + targetUnit); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTextureForTranslucency.getDepthTextureId()); + + GL13.glActiveTexture(activeUnit); + } + } + + public static void preTranslucentPass(LevelRenderer instance, + RenderType renderType, + PoseStack poseStack, + double camX, + double camY, + double camZ, + Matrix4f projectionMatrix, + Operation original, + Camera camera) { + miscTranslucentTexture.copyDepthFrom(Minecraft.getInstance().getMainRenderTarget()); + miscTranslucentTexture.bindWrite(true); + RenderSystem.clear(GL31.GL_COLOR_BUFFER_BIT, false); + + int currentFBO = GL41.glGetInteger(GL41.GL_FRAMEBUFFER_BINDING); + + for (Vector3f bh : blackHoles) + drawBlackHoleToDepthBuffer(poseStack, bh, camera); + + GL41.glBindFramebuffer(GL41.GL_FRAMEBUFFER, currentFBO); + + BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer = true; + original.call(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix); + BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer = false; + } + + @SubscribeEvent + public static void onRenderLevel(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null) + return; + + Window w = Minecraft.getInstance().getWindow(); + if (worldTexture.width != w.getWidth() || + worldTexture.height != w.getHeight()) + updateTextures(); + Vec3 camPos = event.getCamera().getPosition(); + PoseStack poseStack = event.getPoseStack(); + poseStack.pushPose(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(true); + GL31.glCullFace(GL11.GL_FRONT); + + var mcWorldTexture = Minecraft.getInstance().getMainRenderTarget(); + + GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, mcWorldTexture.frameBufferId); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, worldTexture.frameBufferId); + GlStateManager._glBlitFrameBuffer(0, 0, w.getWidth(), w.getHeight(), 0, 0, w.getWidth(), w.getHeight(), + GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + GlStateManager._glBlitFrameBuffer(0, 0, w.getWidth(), w.getHeight(), 0, 0, w.getWidth(), w.getHeight(), + GL31.GL_DEPTH_BUFFER_BIT, GL31.GL_NEAREST); + + mcWorldTexture.bindWrite(true); + + ShaderInstance shader = MoniShaders.WORMHOLE_SHADER; + RenderSystem.setShader(() -> shader); + shader.setSampler("WorldColor", worldTexture); + RenderSystem.setShaderTexture(0, worldTexture.getColorTextureId()); + + shader.safeGetUniform("uMass").set(uMass); + shader.safeGetUniform("uDistModifier").set(uDistModifier); + shader.safeGetUniform("uSchwarzschildRadius").set(uSchwarzschildRadius); + shader.safeGetUniform("uSphereRadius").set(uSphereRadius); + shader.safeGetUniform("uWriteOnlyDepth").set(0); + + Tesselator tessellator = Tesselator.getInstance(); + BufferBuilder builder = tessellator.getBuilder(); + builder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR); + + for (Vector3f blackHolePos : blackHoles) { + var viewSpaceSpherePos = poseStack.last().pose().transform( + new Vector4f(blackHolePos.x - (float) camPos.x, blackHolePos.y - (float) camPos.y, + blackHolePos.z - (float) camPos.z, 1.0f)); + shader.safeGetUniform("SpherePos").set(viewSpaceSpherePos.x, viewSpaceSpherePos.y, + viewSpaceSpherePos.z); + + AABB box = BlackHoleRendererHelpers.createAABBAt(blackHolePos, uAABBSize); + + BlackHoleRendererHelpers.addBoxTriangles(poseStack, builder, + (float) (box.minX - camPos.x), (float) (box.minY - camPos.y), (float) (box.minZ - camPos.z), + (float) (box.maxX - camPos.x), (float) (box.maxY - camPos.y), (float) (box.maxZ - camPos.z), + 1, 1, 0, 1); + } + tessellator.end(); + GL11.glCullFace(GL11.GL_BACK); + poseStack.popPose(); + + Minecraft.getInstance().getMainRenderTarget().bindWrite(true); + RenderSystem.enableBlend(); + miscTranslucentTexture.blitToScreen(miscTranslucentTexture.width, miscTranslucentTexture.height, false); + RenderSystem.enableDepthTest(); + blackHoles.clear(); + } + + @SubscribeEvent + public static void onResize(ScreenEvent.Init.Post event) { + updateTextures(); + } +} diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRendererHelpers.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRendererHelpers.java new file mode 100644 index 00000000..eda2d647 --- /dev/null +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRendererHelpers.java @@ -0,0 +1,73 @@ +package net.neganote.monilabs.client.render; + +import net.minecraft.world.phys.AABB; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class BlackHoleRendererHelpers { + + public static boolean isRenderingMinecraftTranslucentLayer = false; + public static boolean isTranslucentShader; + + public static void addBoxTriangles(PoseStack poseStack, BufferBuilder builder, + float x0, float y0, float z0, + float x1, float y1, float z1, + float r, float g, float b, float a) { + Matrix4f mat = poseStack.last().pose(); + // Front face (z1) + builder.vertex(mat, x0, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z1).color(r, g, b, a).endVertex(); + // Back face (z0) + builder.vertex(mat, x1, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z0).color(r, g, b, a).endVertex(); + // Top face (y1) + builder.vertex(mat, x0, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z0).color(r, g, b, a).endVertex(); + // Bottom face (y0) + builder.vertex(mat, x0, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z1).color(r, g, b, a).endVertex(); + // Right face (x1) + builder.vertex(mat, x1, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x1, y1, z1).color(r, g, b, a).endVertex(); + // Left face (x0) + builder.vertex(mat, x0, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y0, z0).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z1).color(r, g, b, a).endVertex(); + builder.vertex(mat, x0, y1, z0).color(r, g, b, a).endVertex(); + } + + public static AABB createAABBAt(Vector3f center, float size) { + double halfX = (double) size / 2.0; + double halfY = (double) size / 2.0; + double halfZ = (double) size / 2.0; + + return new AABB( + center.x - halfX, center.y - halfY, center.z - halfZ, + center.x + halfX, center.y + halfY, center.z + halfZ); + } +} diff --git a/src/main/java/net/neganote/monilabs/client/render/CreativeEnergyRender.java b/src/main/java/net/neganote/monilabs/client/render/CreativeEnergyRender.java index 02e4a930..5db0b7ff 100644 --- a/src/main/java/net/neganote/monilabs/client/render/CreativeEnergyRender.java +++ b/src/main/java/net/neganote/monilabs/client/render/CreativeEnergyRender.java @@ -1,35 +1,30 @@ package net.neganote.monilabs.client.render; -import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderType; import com.gregtechceu.gtceu.client.util.ModelUtils; -import net.irisshaders.iris.Iris; import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.RandomSource; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.model.data.ModelData; import net.neganote.monilabs.MoniLabs; import net.neganote.monilabs.common.machine.multiblock.CreativeEnergyMultiMachine; +import net.neganote.monilabs.utils.LaserUtil; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.serialization.Codec; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import org.joml.Vector3f; -import java.util.List; +import java.util.Objects; import javax.annotation.ParametersAreNonnullByDefault; @@ -69,9 +64,6 @@ public void render(CreativeEnergyMultiMachine machine, float partialTick, PoseSt Direction upwards = RelativeDirection.UP.getRelative(frontFacing, upwardsFacing, machine.isFlipped()); - List sphereQuads = sphereModel.getQuads(null, null, RandomSource.create(), ModelData.EMPTY, - null); - poseStack.pushPose(); float translateX = 0.5f; float translateY = 0.5f; @@ -81,23 +73,23 @@ public void render(CreativeEnergyMultiMachine machine, float partialTick, PoseSt Vec3i backVec = back.getNormal().multiply(6); Vec3i upVec = upwards.getNormal().multiply(13); + Vec3i bhPos = machine.getPos().relative(back, 6).relative(upwards, 13); translateX += backVec.getX() + upVec.getX(); translateY += backVec.getY() + upVec.getY(); translateZ += backVec.getZ() + upVec.getZ(); poseStack.translate(translateX, translateY, translateZ); - float radius = 3.25f; - poseStack.scale(radius, radius, radius); - - PoseStack.Pose pose = poseStack.last(); - VertexConsumer consumer = buffer - .getBuffer(GTCEu.isModLoaded(GTValues.MODID_OCULUS) && Iris.getCurrentPack().isPresent() ? - RenderType.solid() : MoniRenderTypes.WORMHOLE); + int gameTime = Objects.requireNonNull(Minecraft.getInstance().player).tickCount; + poseStack.pushPose(); + poseStack.scale(4, 1, 4); + LaserUtil.renderLaser(new Vector3f(0, 256, 0), poseStack, buffer, 0.6f, 1f, 1f, 1f, 0, -translateY, 0, + partialTick, + gameTime, + false); + poseStack.popPose(); - for (BakedQuad quad : sphereQuads) { - consumer.putBulkData(pose, quad, 1.0f, 1.0f, 1.0f, packedLight, packedOverlay); - } + BlackHoleRenderer.render(new Vector3f(bhPos.getX() + 0.5f, bhPos.getY() + 0.5f, bhPos.getZ() + 0.5f)); poseStack.popPose(); } diff --git a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java new file mode 100644 index 00000000..8b16be50 --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java @@ -0,0 +1,61 @@ +package net.neganote.monilabs.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.neganote.monilabs.client.render.BlackHoleRenderer; +import net.neganote.monilabs.mixin.accessor.ShaderChunkRendererAccessor; +import net.neganote.monilabs.mixin.accessor.TerrainRenderPassAccessor; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.systems.RenderSystem; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.MultiDrawBatch; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.render.chunk.DefaultChunkRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import org.lwjgl.opengl.GL31; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = DefaultChunkRenderer.class, remap = false) +public class DefaultChunkRendererMixin { + + @Shadow + private static void executeDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch) {}; + + @Redirect( + method = "render", + at = @At( + value = "INVOKE", + target = "Lme/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer;executeDrawBatch(Lme/jellysquid/mods/sodium/client/gl/device/CommandList;Lme/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation;Lme/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch;)V")) + private void redirectExecuteDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch, + @Local(argsOnly = true) TerrainRenderPass renderPass) { + DefaultChunkRenderer instance = (DefaultChunkRenderer) (Object) this; + if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent()) { + executeDrawBatch(commandList, + tessellation, + batch); + return; + } + // Draw everything NOT in FRONT of black hole + Minecraft.getInstance().getMainRenderTarget().bindWrite(true); + GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), + "uDrawInFrontOfBlackHole"), 0); + executeDrawBatch(commandList, + tessellation, + batch); + + // Somewhat unoptimized. Should be in the beginning of render method (the uniform and glBindFramebuffer part) + GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), + "uDrawInFrontOfBlackHole"), 1); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, BlackHoleRenderer.miscTranslucentTexture.frameBufferId); + RenderSystem.disableBlend(); + executeDrawBatch(commandList, + tessellation, + batch); + RenderSystem.enableBlend(); + } +} diff --git a/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java new file mode 100644 index 00000000..aceafa57 --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java @@ -0,0 +1,37 @@ +package net.neganote.monilabs.mixin; + +import net.minecraft.client.renderer.RenderType; +import net.neganote.monilabs.client.render.BlackHoleRenderer; +import net.neganote.monilabs.client.render.BlackHoleRendererHelpers; +import net.neganote.monilabs.mixin.accessor.TerrainRenderPassAccessor; + +import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; +import me.jellysquid.mods.sodium.client.render.chunk.ShaderChunkRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderOptions; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = ShaderChunkRenderer.class, remap = false) +public class ShaderChunkRendererMixin { + + @Shadow + protected GlProgram activeProgram; + + @Inject(method = "createShader", at = @At("HEAD"), remap = false) + private void createShader(String path, ChunkShaderOptions options, + CallbackInfoReturnable> cir) { + BlackHoleRendererHelpers.isTranslucentShader = ((TerrainRenderPassAccessor) options.pass()).getLayer() == + RenderType.translucent(); + } + + @Inject(method = "begin", at = @At("TAIL"), remap = false) + private void begin(TerrainRenderPass pass, CallbackInfo ci) { + BlackHoleRenderer.handleTranslucentPassBegin(activeProgram.handle()); + } +} diff --git a/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java b/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java new file mode 100644 index 00000000..8d0a987b --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java @@ -0,0 +1,39 @@ +package net.neganote.monilabs.mixin; + +import net.minecraft.resources.ResourceLocation; +import net.neganote.monilabs.client.render.BlackHoleRendererHelpers; + +import me.jellysquid.mods.sodium.client.gl.shader.ShaderLoader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = ShaderLoader.class, remap = false) +public class ShaderLoaderMixin { + + @Inject(method = "getShaderSource", at = @At("RETURN"), cancellable = true, remap = false) + private static void monilabs$interceptGetShaderSource(ResourceLocation name, + CallbackInfoReturnable cir) { + if (BlackHoleRendererHelpers.isTranslucentShader) { + if (name.toString().endsWith(".fsh")) { + String originalSource = cir.getReturnValue(); + String myUniform = "\nuniform sampler2D u_BlackHoleDepthTexture;\nuniform int uDrawInFrontOfBlackHole;\n"; + String regex = "(?s)(.*)(uniform sampler2D\\s+\\w+;)([^\r\n]*)"; + + var replaced = originalSource.replaceFirst(regex, "$1$2$3\n" + myUniform) + .replace("void main() {", + """ + void main() { + float sphereDepth = texture(u_BlackHoleDepthTexture, gl_FragCoord.xy / vec2(textureSize(u_BlackHoleDepthTexture, 0))).r; + bool isBehindBlackHole = gl_FragCoord.z >= sphereDepth; + if (uDrawInFrontOfBlackHole == 0 && !isBehindBlackHole && sphereDepth < 1.0) + discard; + if (uDrawInFrontOfBlackHole == 1 && (sphereDepth >= 1.0 || isBehindBlackHole)) + discard; + """); + cir.setReturnValue(replaced); + } + } + } +} diff --git a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java new file mode 100644 index 00000000..9bc8246f --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java @@ -0,0 +1,43 @@ +package net.neganote.monilabs.mixin; + +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.RenderType; +import net.neganote.monilabs.client.render.BlackHoleRenderer; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.vertex.PoseStack; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(LevelRenderer.class) +public class TranslucentRenderMixin { + + @WrapOperation( + method = "renderLevel", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/LevelRenderer;renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V")) + private void wrapSecondRenderChunkLayer( + LevelRenderer instance, + RenderType renderType, + PoseStack poseStack, + double camX, + double camY, + double camZ, + Matrix4f projectionMatrix, + Operation original, + @Local(argsOnly = true) Camera camera) { + if (renderType == RenderType.translucent()) { + BlackHoleRenderer.preTranslucentPass(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix, + original, + camera); + + } else { + original.call(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix); + } + } +} diff --git a/src/main/java/net/neganote/monilabs/mixin/accessor/ShaderChunkRendererAccessor.java b/src/main/java/net/neganote/monilabs/mixin/accessor/ShaderChunkRendererAccessor.java new file mode 100644 index 00000000..8593d10f --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/accessor/ShaderChunkRendererAccessor.java @@ -0,0 +1,14 @@ +package net.neganote.monilabs.mixin.accessor; + +import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; +import me.jellysquid.mods.sodium.client.render.chunk.ShaderChunkRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ShaderChunkRenderer.class) +public interface ShaderChunkRendererAccessor { + + @Accessor(value = "activeProgram", remap = false) + GlProgram getActiveProgram(); +} diff --git a/src/main/java/net/neganote/monilabs/mixin/accessor/TerrainRenderPassAccessor.java b/src/main/java/net/neganote/monilabs/mixin/accessor/TerrainRenderPassAccessor.java new file mode 100644 index 00000000..07269502 --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/accessor/TerrainRenderPassAccessor.java @@ -0,0 +1,14 @@ +package net.neganote.monilabs.mixin.accessor; + +import net.minecraft.client.renderer.RenderType; + +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = TerrainRenderPass.class, remap = false) +public interface TerrainRenderPassAccessor { + + @Accessor("layer") + RenderType getLayer(); +} diff --git a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh index a7f2ef39..1e945347 100644 --- a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh +++ b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh @@ -1,9 +1,135 @@ -#version 150 +#version 330 core -#moj_import +in vec3 rayOrigin; +in vec3 rayDirection; +uniform vec3 SpherePos; +uniform mat4 ProjMat; +uniform mat4 ViewMat; +uniform sampler2D WorldColor; +uniform int uWriteOnlyDepth; out vec4 fragColor; +bool hitSphere(vec3 ro, vec3 rd, float radius, out float t, out bool inside) { + t = -1.0; + inside = false; + vec3 oc = ro - SpherePos; + float b = dot(oc, rd); + float c = dot(oc, oc) - radius * radius; + float h = b * b - c; + + if (c < 0.0) + { + inside = true; + } + if (h < 0.0) return false; + + float sqrtH = sqrt(h); + float t0 = -b - sqrtH; + float t1 = -b + sqrtH; + + t = (t0 > 0.0) ? t0 : t1; + + return t > 0.0; +} + +float writeDepth(float t, vec3 ro, vec3 rd) { + vec3 hitPoint = ro + rd * t; + vec4 clipPos = ProjMat * vec4(hitPoint, 1.0); + float ndcDepth = clipPos.z / clipPos.w; + float writtenDepth = (ndcDepth + 1.0) * 0.5; + if (writtenDepth <= 0.01) + { + gl_FragDepth = gl_FragCoord.z; + return writtenDepth; + } + gl_FragDepth = writtenDepth; + return writtenDepth; +} + +vec2 getViewSpaceUV(vec3 posView, mat4 projectionMatrix) { + vec4 clipSpace = projectionMatrix * vec4(posView, 1.0); + + if (clipSpace.w <= 0.0) { + return normalize(posView.xy) * 100.0; + } + + vec3 ndc = clipSpace.xyz / clipSpace.w; + return ndc.xy * 0.5 + 0.5; +} + +uniform float uMass; +uniform float uDistModifier; +uniform float uSchwarzschildRadius; +uniform float uSphereRadius; + + +vec2 getDistortedRayUV(out bool absorbed) { + absorbed = false; + vec2 resolution = vec2(textureSize(WorldColor, 0)); + + vec2 fragUV = gl_FragCoord.xy / resolution; + vec2 bhUV = getViewSpaceUV(SpherePos, ProjMat); + bhUV = clamp(bhUV, 0.0, 1.0); + + vec2 delta = fragUV - bhUV; + + float t; + bool inside; + vec3 rd = normalize(rayDirection); + vec3 ro = rayOrigin; + absorbed = hitSphere(ro, rd, uSchwarzschildRadius, t, inside); + + vec3 L = SpherePos - ro; + float t_closest = dot(L, rd); + if (t_closest < 0.0) + { + t_closest = 0; + } + vec3 closestPoint = ro + rd * t_closest; + float d3D = length(SpherePos - closestPoint); + + float surfaceDist = max(d3D - uSchwarzschildRadius, 0.001); + + float base = (uMass * 0.1) / (surfaceDist + 0.05); + float decay = exp(-pow(surfaceDist * uDistModifier * 5.0, 2.0)); + float gravityStrength = base * decay; + + return bhUV + delta * (1.0 - gravityStrength); +} + +vec2 getDistortedTextureUV(out bool isBlack) +{ + isBlack = false; + return fract(getDistortedRayUV(isBlack)); +} + void main() { - fragColor = vec4(0.0f, 0.0f, 0.0f, 0.5f); + vec3 rayDir = normalize(rayDirection); + float t; + bool inside; + hitSphere(rayOrigin, rayDir, uSphereRadius, t, inside); + if (uWriteOnlyDepth == 1) + { + float writtenDepth = writeDepth(t, rayOrigin, rayDir); + if (inside || writtenDepth <= 0.01) + { + gl_FragDepth = 0.0; + } + return; + } + + bool isBlack; + vec2 uvCoord = getDistortedTextureUV(isBlack); + vec4 backgroundColor = texture(WorldColor, uvCoord); + + fragColor = backgroundColor; + fragColor.a = 1.0; + if (isBlack) + fragColor = vec4(0, 0, 0, 1); + float writtenDepth = writeDepth(t, rayOrigin, rayDir); + if (inside || writtenDepth <= 0.01) + { + gl_FragDepth = 0.0; + } } \ No newline at end of file diff --git a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json index ceb91ae8..6a862e2f 100644 --- a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json +++ b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json @@ -7,11 +7,22 @@ "vertex": "monilabs:rendertype_wormhole", "fragment": "monilabs:rendertype_wormhole", "attributes": [], - "samplers": [], + "samplers": [ + { "name": "WorldColor" } + ], "uniforms": [ - { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "GameTime", "type": "float", "count": 1, "values": [ 0.0 ] }, - { "name": "ScrollSpeed", "type": "float", "count": 1, "values": [ 600.0 ] } + { + "name": "SpherePos", + "type": "float", + "count": 3, + "values": [ 0.0, 0.0, 0.0 ] + }, + + { "name": "uMass", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "uDistModifier", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "uSchwarzschildRadius", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "uSphereRadius", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "uWriteOnlyDepth", "type": "int", "count": 1, "values": [ 0.0 ] } ] } \ No newline at end of file diff --git a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.vsh b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.vsh index cf45a250..d15ba984 100644 --- a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.vsh +++ b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.vsh @@ -1,12 +1,17 @@ -#version 150 - -#moj_import +#version 330 core in vec3 Position; -uniform mat4 ModelViewMat; uniform mat4 ProjMat; +out vec3 rayOrigin; +out vec3 rayDirection; + void main() { - gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); -} \ No newline at end of file + vec4 viewPos4 = vec4(Position, 1.0); + + rayOrigin = vec3(0.0); + gl_Position = ProjMat * viewPos4; + + rayDirection = viewPos4.xyz; +} diff --git a/src/main/resources/monilabs.mixins.json b/src/main/resources/monilabs.mixins.json index 7a396b8d..8ee86186 100644 --- a/src/main/resources/monilabs.mixins.json +++ b/src/main/resources/monilabs.mixins.json @@ -15,9 +15,13 @@ "aae.MixinEncodedPatternItemShim", "aae.MixinGuiTextShim", "aae.MixinPatternDetailsHelperShim", - "aae.MixinProcessingPatternItemShim" - ], - "client": [ + "aae.MixinProcessingPatternItemShim", + "TranslucentRenderMixin", + "ShaderChunkRendererMixin", + "ShaderLoaderMixin", + "DefaultChunkRendererMixin", + "accessor.TerrainRenderPassAccessor", + "accessor.ShaderChunkRendererAccessor" ], "injectors": { "defaultRequire": 1 From 2db4aa41f8c3b81d3bb8007f354b73d5ae2f0371 Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 04:17:36 +0300 Subject: [PATCH 2/7] cleanup, spotless, other --- .../client/render/BlackHoleRenderer.java | 170 ++++++++++-------- .../mixin/DefaultChunkRendererMixin.java | 15 +- .../monilabs/mixin/GameRendererMixin.java | 26 +++ .../mixin/ShaderChunkRendererMixin.java | 6 +- .../mixin/TranslucentRenderMixin.java | 23 +-- .../shaders/core/rendertype_wormhole.fsh | 29 ++- .../shaders/core/rendertype_wormhole.json | 16 +- src/main/resources/monilabs.mixins.json | 1 + 8 files changed, 168 insertions(+), 118 deletions(-) create mode 100644 src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index 0ec5ec4a..896e1f54 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -1,5 +1,7 @@ package net.neganote.monilabs.client.render; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.shadows.ShadowRenderer; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LevelRenderer; @@ -35,26 +37,25 @@ public class BlackHoleRenderer { private static RenderTarget depthTextureForTranslucency; private static int cachedSlot = -1; - // Settings - private static final float uMass = 9.05f; - private static final float uDistModifier = 0.20f; - private static final float uSchwarzschildRadius = 2.55f; private static final int uAABBSize = 14; - private static final float uSphereRadius = 5.2f; - private static final List blackHoles = new ArrayList<>(); - public static RenderTarget worldTexture = null; + + private static RenderTarget worldTexture = null; public static RenderTarget miscTranslucentTexture = null; + private static final Matrix4f projectionMatrix = new Matrix4f(); + private static final Matrix4f viewMatrix = new Matrix4f(); + private static Vec3 lastCameraPos = new Vec3(0f, 0f, 0f); + private static int findFreeTextureSlot() { - int maxUnits = GL41.glGetInteger(GL41.GL_MAX_TEXTURE_IMAGE_UNITS) - 1; + int maxUnits = GL31.glGetInteger(GL31.GL_MAX_TEXTURE_IMAGE_UNITS) - 1; int freeSlot = -1; - int originalActiveUnit = GL41.glGetInteger(GL41.GL_ACTIVE_TEXTURE); + int originalActiveUnit = GL31.glGetInteger(GL31.GL_ACTIVE_TEXTURE); for (int i = maxUnits - 1; i >= 0; i--) { - GL41.glActiveTexture(GL41.GL_TEXTURE0 + i); - int boundTexture = GL41.glGetInteger(GL41.GL_TEXTURE_BINDING_2D); + GL31.glActiveTexture(GL31.GL_TEXTURE0 + i); + int boundTexture = GL31.glGetInteger(GL31.GL_TEXTURE_BINDING_2D); if (boundTexture == 0) { freeSlot = i; @@ -62,7 +63,7 @@ private static int findFreeTextureSlot() { } } - GL41.glActiveTexture(originalActiveUnit); + GL31.glActiveTexture(originalActiveUnit); if (freeSlot == -1) { throw new RuntimeException("Failed to find free texture slot."); @@ -82,21 +83,11 @@ private static void drawBlackHoleToDepthBuffer(PoseStack poseStack, Vector3f bhP Tesselator tessellator = Tesselator.getInstance(); BufferBuilder builder = tessellator.getBuilder(); - depthTextureForTranslucency.bindWrite(true); - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - RenderSystem.depthFunc(GL11.GL_ALWAYS); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.clearDepth(1); - RenderSystem.clear(GL41.GL_DEPTH_BUFFER_BIT, false); - GL31.glCullFace(GL11.GL_FRONT); // To render only back faces ShaderInstance shader = MoniShaders.WORMHOLE_SHADER; RenderSystem.setShader(() -> shader); shader.safeGetUniform("SpherePos").set(viewSpaceSpherePos.x, viewSpaceSpherePos.y, viewSpaceSpherePos.z); - shader.safeGetUniform("uSphereRadius").set(uSphereRadius); shader.safeGetUniform("uWriteOnlyDepth").set(1); AABB box = BlackHoleRendererHelpers.createAABBAt(bhPos, uAABBSize); @@ -109,8 +100,6 @@ private static void drawBlackHoleToDepthBuffer(PoseStack poseStack, Vector3f bhP tessellator.end(); poseStack.popPose(); - GL31.glCullFace(GL31.GL_BACK); - RenderSystem.depthFunc(GL31.GL_LEQUAL); } public static void updateTextures() { @@ -118,22 +107,28 @@ public static void updateTextures() { Window w = Minecraft.getInstance().getWindow(); int mcWidth = w.getWidth(); int mcHeight = w.getHeight(); - if (mcWidth == 0 || mcHeight == 0) + if (mcWidth == 0 || mcHeight == 0 || + (worldTexture != null && mcWidth == worldTexture.width && mcHeight == worldTexture.height)) { return; - if (depthTextureForTranslucency != null) + } + + if (depthTextureForTranslucency != null) { depthTextureForTranslucency.resize(mcWidth, mcHeight, false); - else + } else { depthTextureForTranslucency = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + } - if (BlackHoleRenderer.worldTexture != null) - BlackHoleRenderer.worldTexture.resize(mcWidth, mcHeight, false); - else - BlackHoleRenderer.worldTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + if (BlackHoleRenderer.worldTexture != null) { + worldTexture.resize(mcWidth, mcHeight, false); + } else { + worldTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + } - if (miscTranslucentTexture != null) + if (miscTranslucentTexture != null) { miscTranslucentTexture.resize(mcWidth, mcHeight, false); - else + } else { miscTranslucentTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); + } } public static void render(Vector3f position) { @@ -141,11 +136,12 @@ public static void render(Vector3f position) { } public static void handleTranslucentPassBegin(int programHandle) { - if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer) + if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer || Iris.getCurrentPack().isPresent()) { return; + } - int activeUnit = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE); - int uDepthLocation = GL41.glGetUniformLocation(programHandle, "u_BlackHoleDepthTexture"); + int activeUnit = GL31.glGetInteger(GL31.GL_ACTIVE_TEXTURE); + int uDepthLocation = GL31.glGetUniformLocation(programHandle, "u_BlackHoleDepthTexture"); if (uDepthLocation != -1) { if (cachedSlot == -1) { @@ -153,12 +149,12 @@ public static void handleTranslucentPassBegin(int programHandle) { } int targetUnit = cachedSlot; - GL41.glUniform1i(uDepthLocation, targetUnit); + GL31.glUniform1i(uDepthLocation, targetUnit); - GL13.glActiveTexture(GL13.GL_TEXTURE0 + targetUnit); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTextureForTranslucency.getDepthTextureId()); + GL31.glActiveTexture(GL31.GL_TEXTURE0 + targetUnit); + GL31.glBindTexture(GL31.GL_TEXTURE_2D, depthTextureForTranslucency.getDepthTextureId()); - GL13.glActiveTexture(activeUnit); + GL31.glActiveTexture(activeUnit); } } @@ -175,35 +171,43 @@ public static void preTranslucentPass(LevelRenderer instance, miscTranslucentTexture.bindWrite(true); RenderSystem.clear(GL31.GL_COLOR_BUFFER_BIT, false); - int currentFBO = GL41.glGetInteger(GL41.GL_FRAMEBUFFER_BINDING); + int currentFBO = GL31.glGetInteger(GL31.GL_FRAMEBUFFER_BINDING); + + depthTextureForTranslucency.bindWrite(true); + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(true); + RenderSystem.depthFunc(GL31.GL_ALWAYS); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.clearDepth(1); + RenderSystem.clear(GL31.GL_DEPTH_BUFFER_BIT, false); + GL31.glCullFace(GL31.GL_FRONT); // To render only back faces - for (Vector3f bh : blackHoles) + for (Vector3f bh : blackHoles) { drawBlackHoleToDepthBuffer(poseStack, bh, camera); + } - GL41.glBindFramebuffer(GL41.GL_FRAMEBUFFER, currentFBO); + GL31.glCullFace(GL31.GL_BACK); + RenderSystem.depthFunc(GL31.GL_LEQUAL); + GL31.glBindFramebuffer(GL31.GL_FRAMEBUFFER, currentFBO); BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer = true; original.call(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix); BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer = false; } - @SubscribeEvent - public static void onRenderLevel(RenderLevelStageEvent event) { - if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null) - return; - + private static void renderCore(PoseStack poseStack, Vec3 cameraPos, Matrix4f projectionMatrix) { Window w = Minecraft.getInstance().getWindow(); if (worldTexture.width != w.getWidth() || - worldTexture.height != w.getHeight()) + worldTexture.height != w.getHeight()) { updateTextures(); - Vec3 camPos = event.getCamera().getPosition(); - PoseStack poseStack = event.getPoseStack(); + } + poseStack.pushPose(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); + RenderSystem.backupProjectionMatrix(); + RenderSystem.setProjectionMatrix(projectionMatrix, null); RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - GL31.glCullFace(GL11.GL_FRONT); + GL31.glCullFace(GL31.GL_FRONT); var mcWorldTexture = Minecraft.getInstance().getMainRenderTarget(); @@ -221,39 +225,63 @@ public static void onRenderLevel(RenderLevelStageEvent event) { shader.setSampler("WorldColor", worldTexture); RenderSystem.setShaderTexture(0, worldTexture.getColorTextureId()); - shader.safeGetUniform("uMass").set(uMass); - shader.safeGetUniform("uDistModifier").set(uDistModifier); - shader.safeGetUniform("uSchwarzschildRadius").set(uSchwarzschildRadius); - shader.safeGetUniform("uSphereRadius").set(uSphereRadius); shader.safeGetUniform("uWriteOnlyDepth").set(0); - Tesselator tessellator = Tesselator.getInstance(); - BufferBuilder builder = tessellator.getBuilder(); - builder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR); + Tesselator tesselator = Tesselator.getInstance(); for (Vector3f blackHolePos : blackHoles) { + BufferBuilder builder = tesselator.getBuilder(); + builder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR); var viewSpaceSpherePos = poseStack.last().pose().transform( - new Vector4f(blackHolePos.x - (float) camPos.x, blackHolePos.y - (float) camPos.y, - blackHolePos.z - (float) camPos.z, 1.0f)); + new Vector4f(blackHolePos.x - (float) cameraPos.x, blackHolePos.y - (float) cameraPos.y, + blackHolePos.z - (float) cameraPos.z, 1.0f)); shader.safeGetUniform("SpherePos").set(viewSpaceSpherePos.x, viewSpaceSpherePos.y, viewSpaceSpherePos.z); - AABB box = BlackHoleRendererHelpers.createAABBAt(blackHolePos, uAABBSize); - BlackHoleRendererHelpers.addBoxTriangles(poseStack, builder, - (float) (box.minX - camPos.x), (float) (box.minY - camPos.y), (float) (box.minZ - camPos.z), - (float) (box.maxX - camPos.x), (float) (box.maxY - camPos.y), (float) (box.maxZ - camPos.z), + (float) (box.minX - cameraPos.x), (float) (box.minY - cameraPos.y), + (float) (box.minZ - cameraPos.z), + (float) (box.maxX - cameraPos.x), (float) (box.maxY - cameraPos.y), + (float) (box.maxZ - cameraPos.z), 1, 1, 0, 1); + tesselator.end(); } - tessellator.end(); - GL11.glCullFace(GL11.GL_BACK); + + GL31.glCullFace(GL31.GL_BACK); poseStack.popPose(); - Minecraft.getInstance().getMainRenderTarget().bindWrite(true); RenderSystem.enableBlend(); miscTranslucentTexture.blitToScreen(miscTranslucentTexture.width, miscTranslucentTexture.height, false); RenderSystem.enableDepthTest(); blackHoles.clear(); + RenderSystem.restoreProjectionMatrix(); + } + + @SubscribeEvent + public static void onRenderLevel(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null || + ShadowRenderer.ACTIVE) + return; + if (Iris.getCurrentPack().isPresent()) { + lastCameraPos = event.getCamera().getPosition(); + // copy because viewMatrix = event.getPoseStack().last().pose() doesnt work :( + viewMatrix.identity().mul(event.getPoseStack().last().pose()); + projectionMatrix.identity().mul(event.getProjectionMatrix()); + return; + } + renderCore(event.getPoseStack(), event.getCamera().getPosition(), event.getProjectionMatrix()); + } + + public static void renderWithShadersOn() { + Window w = Minecraft.getInstance().getWindow(); + if (worldTexture.width != w.getWidth() || + worldTexture.height != w.getHeight()) { + updateTextures(); + } + PoseStack poseStack = new PoseStack(); + poseStack.setIdentity(); + poseStack.mulPoseMatrix(viewMatrix); + renderCore(poseStack, lastCameraPos, projectionMatrix); } @SubscribeEvent diff --git a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java index 8b16be50..b482080e 100644 --- a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java @@ -1,5 +1,6 @@ package net.neganote.monilabs.mixin; +import net.irisshaders.iris.Iris; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; import net.neganote.monilabs.client.render.BlackHoleRenderer; @@ -14,7 +15,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.DefaultChunkRenderer; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import org.lwjgl.opengl.GL31; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -24,17 +24,19 @@ public class DefaultChunkRendererMixin { @Shadow - private static void executeDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch) {}; + private static void executeDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch) {} @Redirect( method = "render", at = @At( value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer;executeDrawBatch(Lme/jellysquid/mods/sodium/client/gl/device/CommandList;Lme/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation;Lme/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch;)V")) - private void redirectExecuteDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch, - @Local(argsOnly = true) TerrainRenderPass renderPass) { + private void moniLabs$redirectExecuteDrawBatch(CommandList commandList, GlTessellation tessellation, + MultiDrawBatch batch, + @Local(argsOnly = true) TerrainRenderPass renderPass) { DefaultChunkRenderer instance = (DefaultChunkRenderer) (Object) this; - if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent()) { + if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent() || + Iris.getCurrentPack().isPresent()) { executeDrawBatch(commandList, tessellation, batch); @@ -48,7 +50,8 @@ private void redirectExecuteDrawBatch(CommandList commandList, GlTessellation te tessellation, batch); - // Somewhat unoptimized. Should be in the beginning of render method (the uniform and glBindFramebuffer part) + // Somewhat unoptimized (but should be fine). Should be in the beginning of render method (the uniform and + // glBindFramebuffer part) GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), "uDrawInFrontOfBlackHole"), 1); GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, BlackHoleRenderer.miscTranslucentTexture.frameBufferId); diff --git a/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java new file mode 100644 index 00000000..a1a90fb2 --- /dev/null +++ b/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java @@ -0,0 +1,26 @@ +package net.neganote.monilabs.mixin; + +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.shadows.ShadowRenderer; +import net.minecraft.client.renderer.GameRenderer; +import net.neganote.monilabs.client.render.BlackHoleRenderer; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = GameRenderer.class) +public class GameRendererMixin { + + @Inject(method = "render", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/LevelRenderer;doEntityOutline()V")) + public void moniLabs$renderBlackHoleWithShaders(float partialTicks, long nanoTime, boolean renderLevel, + CallbackInfo ci) { + if (Iris.getCurrentPack().isPresent() && renderLevel && !ShadowRenderer.ACTIVE) { + BlackHoleRenderer.renderWithShadersOn(); + } + } +} diff --git a/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java index aceafa57..db323141 100644 --- a/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/ShaderChunkRendererMixin.java @@ -24,14 +24,14 @@ public class ShaderChunkRendererMixin { protected GlProgram activeProgram; @Inject(method = "createShader", at = @At("HEAD"), remap = false) - private void createShader(String path, ChunkShaderOptions options, - CallbackInfoReturnable> cir) { + private void moniLabs$saveShaderType(String path, ChunkShaderOptions options, + CallbackInfoReturnable> cir) { BlackHoleRendererHelpers.isTranslucentShader = ((TerrainRenderPassAccessor) options.pass()).getLayer() == RenderType.translucent(); } @Inject(method = "begin", at = @At("TAIL"), remap = false) - private void begin(TerrainRenderPass pass, CallbackInfo ci) { + private void moniLabs$handleTranslucentPassBegin(TerrainRenderPass pass, CallbackInfo ci) { BlackHoleRenderer.handleTranslucentPassBegin(activeProgram.handle()); } } diff --git a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java index 9bc8246f..461c2795 100644 --- a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java @@ -1,5 +1,6 @@ package net.neganote.monilabs.mixin; +import net.irisshaders.iris.Iris; import net.minecraft.client.Camera; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.RenderType; @@ -21,17 +22,17 @@ public class TranslucentRenderMixin { at = @At( value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V")) - private void wrapSecondRenderChunkLayer( - LevelRenderer instance, - RenderType renderType, - PoseStack poseStack, - double camX, - double camY, - double camZ, - Matrix4f projectionMatrix, - Operation original, - @Local(argsOnly = true) Camera camera) { - if (renderType == RenderType.translucent()) { + private void moniLabs$wrapSecondRenderChunkLayer( + LevelRenderer instance, + RenderType renderType, + PoseStack poseStack, + double camX, + double camY, + double camZ, + Matrix4f projectionMatrix, + Operation original, + @Local(argsOnly = true) Camera camera) { + if (renderType == RenderType.translucent() && Iris.getCurrentPack().isEmpty()) { BlackHoleRenderer.preTranslucentPass(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix, original, camera); diff --git a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh index 1e945347..951fa1cd 100644 --- a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh +++ b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.fsh @@ -18,8 +18,7 @@ bool hitSphere(vec3 ro, vec3 rd, float radius, out float t, out bool inside) { float c = dot(oc, oc) - radius * radius; float h = b * b - c; - if (c < 0.0) - { + if (c < 0.0) { inside = true; } if (h < 0.0) return false; @@ -38,8 +37,7 @@ float writeDepth(float t, vec3 ro, vec3 rd) { vec4 clipPos = ProjMat * vec4(hitPoint, 1.0); float ndcDepth = clipPos.z / clipPos.w; float writtenDepth = (ndcDepth + 1.0) * 0.5; - if (writtenDepth <= 0.01) - { + if (writtenDepth <= 0.01) { gl_FragDepth = gl_FragCoord.z; return writtenDepth; } @@ -82,8 +80,7 @@ vec2 getDistortedRayUV(out bool absorbed) { vec3 L = SpherePos - ro; float t_closest = dot(L, rd); - if (t_closest < 0.0) - { + if (t_closest < 0.0) { t_closest = 0; } vec3 closestPoint = ro + rd * t_closest; @@ -98,8 +95,7 @@ vec2 getDistortedRayUV(out bool absorbed) { return bhUV + delta * (1.0 - gravityStrength); } -vec2 getDistortedTextureUV(out bool isBlack) -{ +vec2 getDistortedTextureUV(out bool isBlack) { isBlack = false; return fract(getDistortedRayUV(isBlack)); } @@ -108,12 +104,13 @@ void main() { vec3 rayDir = normalize(rayDirection); float t; bool inside; - hitSphere(rayOrigin, rayDir, uSphereRadius, t, inside); - if (uWriteOnlyDepth == 1) - { + bool hit = hitSphere(rayOrigin, rayDir, uSphereRadius, t, inside); + if (uWriteOnlyDepth == 1) { + if (!hit) { + discard; + } float writtenDepth = writeDepth(t, rayOrigin, rayDir); - if (inside || writtenDepth <= 0.01) - { + if (inside || writtenDepth <= 0.01) { gl_FragDepth = 0.0; } return; @@ -125,11 +122,11 @@ void main() { fragColor = backgroundColor; fragColor.a = 1.0; - if (isBlack) + if (isBlack) { fragColor = vec4(0, 0, 0, 1); + } float writtenDepth = writeDepth(t, rayOrigin, rayDir); - if (inside || writtenDepth <= 0.01) - { + if (inside || writtenDepth <= 0.01) { gl_FragDepth = 0.0; } } \ No newline at end of file diff --git a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json index 6a862e2f..3f4477b5 100644 --- a/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json +++ b/src/main/resources/assets/monilabs/shaders/core/rendertype_wormhole.json @@ -12,17 +12,11 @@ ], "uniforms": [ { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { - "name": "SpherePos", - "type": "float", - "count": 3, - "values": [ 0.0, 0.0, 0.0 ] - }, - - { "name": "uMass", "type": "float", "count": 1, "values": [ 0.0 ] }, - { "name": "uDistModifier", "type": "float", "count": 1, "values": [ 0.0 ] }, - { "name": "uSchwarzschildRadius", "type": "float", "count": 1, "values": [ 0.0 ] }, - { "name": "uSphereRadius", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "SpherePos", "type": "float", "count": 3, "values": [ 0.0, 0.0, 0.0 ] }, + { "name": "uMass", "type": "float", "count": 1, "values": [ 9.05 ] }, + { "name": "uDistModifier", "type": "float", "count": 1, "values": [ 0.2 ] }, + { "name": "uSchwarzschildRadius", "type": "float", "count": 1, "values": [ 2.55 ] }, + { "name": "uSphereRadius", "type": "float", "count": 1, "values": [ 5.2 ] }, { "name": "uWriteOnlyDepth", "type": "int", "count": 1, "values": [ 0.0 ] } ] } \ No newline at end of file diff --git a/src/main/resources/monilabs.mixins.json b/src/main/resources/monilabs.mixins.json index 8ee86186..3204b2ce 100644 --- a/src/main/resources/monilabs.mixins.json +++ b/src/main/resources/monilabs.mixins.json @@ -20,6 +20,7 @@ "ShaderChunkRendererMixin", "ShaderLoaderMixin", "DefaultChunkRendererMixin", + "GameRendererMixin", "accessor.TerrainRenderPassAccessor", "accessor.ShaderChunkRendererAccessor" ], From 381c83f6ce46cb5252ece20666ea253e22621336 Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 04:27:26 +0300 Subject: [PATCH 3/7] minor cleanup part 2 --- .../client/render/BlackHoleRenderer.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index 896e1f54..afb4a67c 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -2,6 +2,7 @@ import net.irisshaders.iris.Iris; import net.irisshaders.iris.shadows.ShadowRenderer; +import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LevelRenderer; @@ -23,6 +24,8 @@ import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; @@ -31,20 +34,25 @@ import java.util.ArrayList; import java.util.List; +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(modid = MoniLabs.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) public class BlackHoleRenderer { - private static RenderTarget depthTextureForTranslucency; - private static int cachedSlot = -1; - + public static RenderTarget miscTranslucentTexture = null; private static final int uAABBSize = 14; private static final List blackHoles = new ArrayList<>(); + private static final Matrix4f projectionMatrix = new Matrix4f(); + private static final Matrix4f viewMatrix = new Matrix4f(); + + private static RenderTarget depthTextureForTranslucency; + private static int cachedSlot = -1; private static RenderTarget worldTexture = null; - public static RenderTarget miscTranslucentTexture = null; - private static final Matrix4f projectionMatrix = new Matrix4f(); - private static final Matrix4f viewMatrix = new Matrix4f(); private static Vec3 lastCameraPos = new Vec3(0f, 0f, 0f); private static int findFreeTextureSlot() { @@ -118,7 +126,7 @@ public static void updateTextures() { depthTextureForTranslucency = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); } - if (BlackHoleRenderer.worldTexture != null) { + if (worldTexture != null) { worldTexture.resize(mcWidth, mcHeight, false); } else { worldTexture = new TextureTarget(mcWidth, mcHeight, true, Minecraft.ON_OSX); @@ -260,8 +268,9 @@ private static void renderCore(PoseStack poseStack, Vec3 cameraPos, Matrix4f pro @SubscribeEvent public static void onRenderLevel(RenderLevelStageEvent event) { if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null || - ShadowRenderer.ACTIVE) + ShadowRenderer.ACTIVE) { return; + } if (Iris.getCurrentPack().isPresent()) { lastCameraPos = event.getCamera().getPosition(); // copy because viewMatrix = event.getPoseStack().last().pose() doesnt work :( From 0b491b71cbbed8efab0d5f15354a7b9531aab9fa Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 04:34:15 +0300 Subject: [PATCH 4/7] oopsie! --- .../monilabs/client/render/BlackHoleRenderer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index afb4a67c..11e972b3 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -258,9 +258,12 @@ private static void renderCore(PoseStack poseStack, Vec3 cameraPos, Matrix4f pro GL31.glCullFace(GL31.GL_BACK); poseStack.popPose(); - RenderSystem.enableBlend(); - miscTranslucentTexture.blitToScreen(miscTranslucentTexture.width, miscTranslucentTexture.height, false); - RenderSystem.enableDepthTest(); + if (Iris.getCurrentPack().isEmpty()) { + RenderSystem.enableBlend(); + miscTranslucentTexture.blitToScreen(miscTranslucentTexture.width, miscTranslucentTexture.height, false); + RenderSystem.enableDepthTest(); + } + blackHoles.clear(); RenderSystem.restoreProjectionMatrix(); } From b06a74095d986d53576a080878fd1c0ecdfba954 Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 18:04:53 +0300 Subject: [PATCH 5/7] mixin in a different place so black hole doesnt render over everything with shaders enabled --- .../monilabs/client/render/BlackHoleRenderer.java | 6 +++++- .../neganote/monilabs/mixin/GameRendererMixin.java | 12 +++++++----- src/main/resources/monilabs.mixins.json | 6 +++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index 11e972b3..a9d4dcad 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -270,7 +270,8 @@ private static void renderCore(PoseStack poseStack, Vec3 cameraPos, Matrix4f pro @SubscribeEvent public static void onRenderLevel(RenderLevelStageEvent event) { - if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null || + if (blackHoles.isEmpty() || event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || + MoniShaders.WORMHOLE_SHADER == null || ShadowRenderer.ACTIVE) { return; } @@ -285,6 +286,9 @@ public static void onRenderLevel(RenderLevelStageEvent event) { } public static void renderWithShadersOn() { + if (blackHoles.isEmpty()) { + return; + } Window w = Minecraft.getInstance().getWindow(); if (worldTexture.width != w.getWidth() || worldTexture.height != w.getHeight()) { diff --git a/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java index a1a90fb2..b656c22b 100644 --- a/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/GameRendererMixin.java @@ -5,21 +5,23 @@ import net.minecraft.client.renderer.GameRenderer; import net.neganote.monilabs.client.render.BlackHoleRenderer; +import com.mojang.blaze3d.vertex.PoseStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(value = GameRenderer.class) +@Mixin(value = GameRenderer.class, priority = 1) public class GameRendererMixin { - @Inject(method = "render", + @Inject(method = "renderLevel", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/renderer/LevelRenderer;doEntityOutline()V")) - public void moniLabs$renderBlackHoleWithShaders(float partialTicks, long nanoTime, boolean renderLevel, + target = "Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;)V", + shift = At.Shift.AFTER)) + public void moniLabs$renderBlackHoleWithShaders(float partialTicks, long finishTimeNano, PoseStack poseStack, CallbackInfo ci) { - if (Iris.getCurrentPack().isPresent() && renderLevel && !ShadowRenderer.ACTIVE) { + if (Iris.getCurrentPack().isPresent() && !ShadowRenderer.ACTIVE) { BlackHoleRenderer.renderWithShadersOn(); } } diff --git a/src/main/resources/monilabs.mixins.json b/src/main/resources/monilabs.mixins.json index 3204b2ce..1287420b 100644 --- a/src/main/resources/monilabs.mixins.json +++ b/src/main/resources/monilabs.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_17", "minVersion": "0.8", "plugin": "net.neganote.monilabs.mixin.MoniMixinPlugin", + "refmap": "mixins.monilabs.refmap.json", "mixins": [ "DataAccessHatchMixin", "KubeJSPluginsMixin", @@ -15,7 +16,10 @@ "aae.MixinEncodedPatternItemShim", "aae.MixinGuiTextShim", "aae.MixinPatternDetailsHelperShim", - "aae.MixinProcessingPatternItemShim", + "aae.MixinProcessingPatternItemShim" + ], + "client": + [ "TranslucentRenderMixin", "ShaderChunkRendererMixin", "ShaderLoaderMixin", From aa8fee17b7c4fc3713dd61b3c7074e805a309dec Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 21:35:46 +0300 Subject: [PATCH 6/7] now should actually work --- .../monilabs/client/render/BlackHoleRenderer.java | 11 ++++++++--- .../monilabs/mixin/DefaultChunkRendererMixin.java | 11 +++++++++-- .../neganote/monilabs/mixin/ShaderLoaderMixin.java | 6 +++--- .../monilabs/mixin/TranslucentRenderMixin.java | 3 ++- src/main/resources/monilabs.mixins.json | 2 +- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index a9d4dcad..85abc35e 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -139,12 +139,17 @@ public static void updateTextures() { } } + public static boolean hasBlackHoles() { + return !blackHoles.isEmpty(); + } public static void render(Vector3f position) { blackHoles.add(position); } public static void handleTranslucentPassBegin(int programHandle) { - if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer || Iris.getCurrentPack().isPresent()) { + if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer + || Iris.getCurrentPack().isPresent() + || !hasBlackHoles()) { return; } @@ -270,7 +275,7 @@ private static void renderCore(PoseStack poseStack, Vec3 cameraPos, Matrix4f pro @SubscribeEvent public static void onRenderLevel(RenderLevelStageEvent event) { - if (blackHoles.isEmpty() || event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || + if (!hasBlackHoles() || event.getStage() != RenderLevelStageEvent.Stage.AFTER_WEATHER || MoniShaders.WORMHOLE_SHADER == null || ShadowRenderer.ACTIVE) { return; @@ -286,7 +291,7 @@ public static void onRenderLevel(RenderLevelStageEvent event) { } public static void renderWithShadersOn() { - if (blackHoles.isEmpty()) { + if (!hasBlackHoles()) { return; } Window w = Minecraft.getInstance().getWindow(); diff --git a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java index b482080e..91eb910a 100644 --- a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java @@ -35,8 +35,13 @@ private static void executeDrawBatch(CommandList commandList, GlTessellation tes MultiDrawBatch batch, @Local(argsOnly = true) TerrainRenderPass renderPass) { DefaultChunkRenderer instance = (DefaultChunkRenderer) (Object) this; - if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent() || - Iris.getCurrentPack().isPresent()) { + if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent() + || Iris.getCurrentPack().isPresent() + || !BlackHoleRenderer.hasBlackHoles()) { + //we do that because iris overrides getActiveProgram to null + if (Iris.getCurrentPack().isEmpty()) + GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), + "uAnyBlackHoles"), 0); executeDrawBatch(commandList, tessellation, batch); @@ -46,6 +51,8 @@ private static void executeDrawBatch(CommandList commandList, GlTessellation tes Minecraft.getInstance().getMainRenderTarget().bindWrite(true); GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), "uDrawInFrontOfBlackHole"), 0); + GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), + "uAnyBlackHoles"), 1); executeDrawBatch(commandList, tessellation, batch); diff --git a/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java b/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java index 8d0a987b..2cf76d04 100644 --- a/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/ShaderLoaderMixin.java @@ -18,7 +18,7 @@ public class ShaderLoaderMixin { if (BlackHoleRendererHelpers.isTranslucentShader) { if (name.toString().endsWith(".fsh")) { String originalSource = cir.getReturnValue(); - String myUniform = "\nuniform sampler2D u_BlackHoleDepthTexture;\nuniform int uDrawInFrontOfBlackHole;\n"; + String myUniform = "\nuniform sampler2D u_BlackHoleDepthTexture;\nuniform int uDrawInFrontOfBlackHole;\nuniform int uAnyBlackHoles = 0;\n"; String regex = "(?s)(.*)(uniform sampler2D\\s+\\w+;)([^\r\n]*)"; var replaced = originalSource.replaceFirst(regex, "$1$2$3\n" + myUniform) @@ -27,9 +27,9 @@ public class ShaderLoaderMixin { void main() { float sphereDepth = texture(u_BlackHoleDepthTexture, gl_FragCoord.xy / vec2(textureSize(u_BlackHoleDepthTexture, 0))).r; bool isBehindBlackHole = gl_FragCoord.z >= sphereDepth; - if (uDrawInFrontOfBlackHole == 0 && !isBehindBlackHole && sphereDepth < 1.0) + if (uAnyBlackHoles == 1 && uDrawInFrontOfBlackHole == 0 && !isBehindBlackHole && sphereDepth < 1.0) discard; - if (uDrawInFrontOfBlackHole == 1 && (sphereDepth >= 1.0 || isBehindBlackHole)) + if (uAnyBlackHoles == 1 && uDrawInFrontOfBlackHole == 1 && (sphereDepth >= 1.0 || isBehindBlackHole)) discard; """); cir.setReturnValue(replaced); diff --git a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java index 461c2795..b25533b9 100644 --- a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java @@ -32,7 +32,8 @@ public class TranslucentRenderMixin { Matrix4f projectionMatrix, Operation original, @Local(argsOnly = true) Camera camera) { - if (renderType == RenderType.translucent() && Iris.getCurrentPack().isEmpty()) { + if (renderType == RenderType.translucent() && Iris.getCurrentPack().isEmpty() + && BlackHoleRenderer.hasBlackHoles()) { BlackHoleRenderer.preTranslucentPass(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix, original, camera); diff --git a/src/main/resources/monilabs.mixins.json b/src/main/resources/monilabs.mixins.json index 1287420b..417af85b 100644 --- a/src/main/resources/monilabs.mixins.json +++ b/src/main/resources/monilabs.mixins.json @@ -22,8 +22,8 @@ [ "TranslucentRenderMixin", "ShaderChunkRendererMixin", - "ShaderLoaderMixin", "DefaultChunkRendererMixin", + "ShaderLoaderMixin", "GameRendererMixin", "accessor.TerrainRenderPassAccessor", "accessor.ShaderChunkRendererAccessor" From d6730114c870cc48dd36924e3e05af78d9a1f813 Mon Sep 17 00:00:00 2001 From: Jenya Date: Sat, 11 Apr 2026 21:41:02 +0300 Subject: [PATCH 7/7] spotless --- .../monilabs/client/render/BlackHoleRenderer.java | 6 +++--- .../monilabs/mixin/DefaultChunkRendererMixin.java | 13 +++++++------ .../monilabs/mixin/TranslucentRenderMixin.java | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java index 85abc35e..3d820edd 100644 --- a/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java +++ b/src/main/java/net/neganote/monilabs/client/render/BlackHoleRenderer.java @@ -142,14 +142,14 @@ public static void updateTextures() { public static boolean hasBlackHoles() { return !blackHoles.isEmpty(); } + public static void render(Vector3f position) { blackHoles.add(position); } public static void handleTranslucentPassBegin(int programHandle) { - if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer - || Iris.getCurrentPack().isPresent() - || !hasBlackHoles()) { + if (!BlackHoleRendererHelpers.isRenderingMinecraftTranslucentLayer || Iris.getCurrentPack().isPresent() || + !hasBlackHoles()) { return; } diff --git a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java index 91eb910a..704f02f8 100644 --- a/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/DefaultChunkRendererMixin.java @@ -35,13 +35,14 @@ private static void executeDrawBatch(CommandList commandList, GlTessellation tes MultiDrawBatch batch, @Local(argsOnly = true) TerrainRenderPass renderPass) { DefaultChunkRenderer instance = (DefaultChunkRenderer) (Object) this; - if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent() - || Iris.getCurrentPack().isPresent() - || !BlackHoleRenderer.hasBlackHoles()) { - //we do that because iris overrides getActiveProgram to null + if (((TerrainRenderPassAccessor) renderPass).getLayer() != RenderType.translucent() || + Iris.getCurrentPack().isPresent() || !BlackHoleRenderer.hasBlackHoles()) { + // we do that because iris overrides getActiveProgram to null if (Iris.getCurrentPack().isEmpty()) - GL31.glUniform1i(GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), - "uAnyBlackHoles"), 0); + GL31.glUniform1i( + GL31.glGetUniformLocation(((ShaderChunkRendererAccessor) instance).getActiveProgram().handle(), + "uAnyBlackHoles"), + 0); executeDrawBatch(commandList, tessellation, batch); diff --git a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java index b25533b9..92357bce 100644 --- a/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java +++ b/src/main/java/net/neganote/monilabs/mixin/TranslucentRenderMixin.java @@ -32,8 +32,8 @@ public class TranslucentRenderMixin { Matrix4f projectionMatrix, Operation original, @Local(argsOnly = true) Camera camera) { - if (renderType == RenderType.translucent() && Iris.getCurrentPack().isEmpty() - && BlackHoleRenderer.hasBlackHoles()) { + if (renderType == RenderType.translucent() && Iris.getCurrentPack().isEmpty() && + BlackHoleRenderer.hasBlackHoles()) { BlackHoleRenderer.preTranslucentPass(instance, renderType, poseStack, camX, camY, camZ, projectionMatrix, original, camera);