Skip to content

Commit

Permalink
proper shadow frustum culling
Browse files Browse the repository at this point in the history
  • Loading branch information
FalsePattern committed Dec 27, 2024
1 parent e63bc3f commit 3a545c1
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 13 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ dependencies {
implementation("org.joml:joml:1.10.5")
implementation("it.unimi.dsi:fastutil:8.5.13")

compileOnly("makamys:neodymium-mc1.7.10:0.4.0-unofficial:dev")
compileOnly("makamys:neodymium-mc1.7.10:0.4.2-unofficial:dev")

compileOnly("com.github.GTNewHorizons:lwjgl3ify:2.1.5:dev")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
guiFactory = Tags.ROOT_PKG + ".config.FalseTweaksGuiFactory",
acceptableRemoteVersions = "*",
dependencies = "required-after:falsepatternlib@[1.5.5,);" +
"after:neodymium@[0.4.0,);" +
"after:neodymium@[0.4.2,);" +
"after:gtnhlib@[0.5.21,);"
)
public class FalseTweaks {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,32 @@
import com.falsepattern.falsetweaks.modules.occlusion.OcclusionCompat;
import com.falsepattern.falsetweaks.modules.occlusion.OcclusionHelpers;
import com.falsepattern.falsetweaks.modules.occlusion.WorldRendererOcclusion;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
import makamys.neodymium.renderer.Mesh;
import com.falsepattern.falsetweaks.modules.occlusion.shader.ShadowPassOcclusionHelper;
import lombok.val;
import makamys.neodymium.renderer.ChunkMesh;
import makamys.neodymium.renderer.GPUMemoryManager;
import makamys.neodymium.renderer.NeoRegion;
import makamys.neodymium.renderer.NeoRenderer;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
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.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import net.minecraft.client.renderer.WorldRenderer;

import java.util.List;

@Mixin(value = NeoRenderer.class,
remap = false)
public abstract class NeoRendererMixin {
@Shadow private List<GPUMemoryManager> mems;

@Shadow private List<NeoRegion> loadedRegionsList;

@Inject(method = "render",
at = @At(value = "INVOKE",
target = "Lorg/lwjgl/opengl/GL30;glBindVertexArray(I)V",
Expand All @@ -60,12 +67,35 @@ private void postRender(int pass, double alpha, CallbackInfoReturnable<Integer>
* @reason Compat
*/
@Overwrite
@Dynamic
private boolean isRendererVisible(WorldRenderer wr, boolean shadowPass) {
if (shadowPass) {
return ((WorldRendererOcclusion)wr).ft$isVisibleShadows();
} else {
if (!shadowPass) {
return wr.isVisible;
}
if (!((WorldRendererOcclusion) wr).ft$isVisibleShadows()) {
return false;
}
return ShadowPassOcclusionHelper.isShadowVisible(wr);
}

@Inject(method = "initIndexBuffers",
at = @At("HEAD"),
require = 1)
private void initIndexBuffers(boolean shadowPass, CallbackInfo ci) {
if (!shadowPass)
return;
ShadowPassOcclusionHelper.begin();
int regionsSize = loadedRegionsList.size();
for (val mem: mems) {
for (int regionI = 0; regionI < regionsSize; regionI++) {
val region = loadedRegionsList.get(regionI).getRenderData(mem);
for (val mesh: region.getSentMeshes()) {
val wr = ((ChunkMesh)mesh).wr();
if (wr.isVisible && wr.isInFrustum) {
ShadowPassOcclusionHelper.addShadowReceiver(wr);
}
}
}
}
ShadowPassOcclusionHelper.end();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* This file is part of FalseTweaks.
*
* Copyright (C) 2022-2024 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalseTweaks is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FalseTweaks is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FalseTweaks. If not, see <https://www.gnu.org/licenses/>.
*/

package com.falsepattern.falsetweaks.mixin.mixins.client.occlusion.optifine.shaders;

import com.falsepattern.falsetweaks.modules.occlusion.shader.ShadowPassOcclusionHelper;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import shadersmod.client.Shaders;

import java.nio.FloatBuffer;

@Mixin(value = Shaders.class,
remap = false)
public abstract class ShadersMixin {
@Shadow @Final static FloatBuffer shadowModelView;

@Inject(method = "setCameraShadow",
at = @At("RETURN"),
require = 1)
private static void onSetCameraShadow(CallbackInfo ci) {
shadowModelView.position(0);
ShadowPassOcclusionHelper.shadowModelViewMatrix.set(shadowModelView);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ public enum Mixin implements IMixin {
Occlusion_Optifine_Shaders_FrustrumMixin(Side.CLIENT,
THREADING.and(REQUIRE_OPTIFINE_WITH_SHADERS),
"occlusion.optifine.shaders.FrustrumMixin"),
Occlusion_Optifine_Shaders_ShadersMixin(Side.CLIENT,
THREADING.and(REQUIRE_OPTIFINE_WITH_SHADERS),
"occlusion.optifine.shaders.ShadersMixin"),


//FastCraft
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.falsepattern.falsetweaks.config.OcclusionConfig;
import com.falsepattern.falsetweaks.modules.debug.Debug;
import com.falsepattern.falsetweaks.modules.occlusion.interfaces.IRenderGlobalMixin;
import com.falsepattern.falsetweaks.modules.occlusion.shader.ShadowPassOcclusionHelper;
import com.falsepattern.falsetweaks.modules.threadedupdates.ThreadedChunkUpdateHelper;
import com.falsepattern.falsetweaks.modules.threadexec.FTWorker;
import com.falsepattern.falsetweaks.modules.threadexec.ThreadedTask;
Expand Down Expand Up @@ -1120,6 +1121,18 @@ public int sortAndRender(int start, int end, int pass, double tick) {

prof.startSection("setup_lists");
int glListsRendered = 0, allRenderListsLength = 0;

if (shadowPass) {
val renderers = rg.worldRenderers;
ShadowPassOcclusionHelper.begin();
for (int i = 0; i < renderers.length; i++) {
val wr = renderers[i];
if (wr != null && wr.isVisible && wr.isInFrustum && !wr.skipAllRenderPasses()) {
ShadowPassOcclusionHelper.addShadowReceiver(wr);
}
}
ShadowPassOcclusionHelper.end();
}
WorldRenderer[] sortedWorldRenderers = shadowPass ? rg.worldRenderers : rg.sortedWorldRenderers;

for (int i = loopStart; i != loopEnd; i += dir) {
Expand All @@ -1131,7 +1144,7 @@ public int sortAndRender(int start, int end, int pass, double tick) {
isVisible = rend.isVisible;
isInFrustum = rend.isInFrustum;
rend.isVisible = iwr.ft$isVisibleShadows();
rend.isInFrustum = true;
rend.isInFrustum = ShadowPassOcclusionHelper.isShadowVisible(rend);
}

if ((rend.isVisible && rend.isInFrustum) && !rend.skipRenderPass[pass]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* This file is part of FalseTweaks.
*
* Copyright (C) 2022-2024 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalseTweaks is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FalseTweaks is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FalseTweaks. If not, see <https://www.gnu.org/licenses/>.
*/

package com.falsepattern.falsetweaks.modules.occlusion.shader;

import org.joml.Matrix4f;
import org.joml.Vector3f;

import net.minecraft.client.renderer.WorldRenderer;

public class ShadowPassOcclusionHelper {
private static float minCamX, minCamY, minCamZ;
private static float maxCamX, maxCamY;

private static float minX, minY, minZ;
private static float maxX, maxY, maxZ;

private static Vector3f scratch = new Vector3f();
public static Matrix4f shadowModelViewMatrix = new Matrix4f();
public static void begin() {
minCamX = Float.POSITIVE_INFINITY;
minCamY = Float.POSITIVE_INFINITY;
minCamZ = Float.POSITIVE_INFINITY;
maxCamX = Float.NEGATIVE_INFINITY;
maxCamY = Float.NEGATIVE_INFINITY;
minX = Float.POSITIVE_INFINITY;
minY = Float.POSITIVE_INFINITY;
minZ = Float.POSITIVE_INFINITY;
maxX = Float.NEGATIVE_INFINITY;
maxY = Float.NEGATIVE_INFINITY;
maxZ = Float.NEGATIVE_INFINITY;
}

public static void addShadowReceiver(WorldRenderer wr) {
minX = Math.min(minX, wr.posX);
minY = Math.min(minY, wr.posY);
minZ = Math.min(minZ, wr.posZ);
maxX = Math.max(maxX, wr.posX + 16);
maxY = Math.max(maxY, wr.posY + 16);
maxZ = Math.max(maxZ, wr.posZ + 16);
}

public static void end() {
for (int i = 0; i < 8; i++) {
float x = (i & 1) == 0 ? minX : maxX;
float y = (i & 2) == 0 ? minY : maxY;
float z = (i & 4) == 0 ? minZ : maxZ;
shadowModelViewMatrix.transformPosition(x, y, z, scratch);
x = scratch.x;
y = scratch.y;
z = scratch.z;
minCamX = Math.min(minCamX, x);
minCamY = Math.min(minCamY, y);
minCamZ = Math.min(minCamZ, z);
maxCamX = Math.max(maxCamX, x);
maxCamY = Math.max(maxCamY, y);
}
if (Float.isNaN(minCamX))
minCamX = Float.NEGATIVE_INFINITY;
if (Float.isNaN(minCamY))
minCamY = Float.NEGATIVE_INFINITY;
if (Float.isNaN(minCamZ))
minCamZ = Float.NEGATIVE_INFINITY;
if (Float.isNaN(maxCamX))
maxCamX = Float.POSITIVE_INFINITY;
if (Float.isNaN(maxCamY))
maxCamY = Float.POSITIVE_INFINITY;
}

public static boolean isShadowVisible(WorldRenderer wr) {
float posX = wr.posX;
float posY = wr.posY;
float posZ = wr.posZ;

float minX = Float.POSITIVE_INFINITY, minY = Float.POSITIVE_INFINITY;
float maxX = Float.NEGATIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY, maxZ = Float.NEGATIVE_INFINITY;
for (int i = 0; i < 8; i++) {
float x = posX + ((i & 1) == 0 ? 0 : 16);
float y = posY + ((i & 2) == 0 ? 0 : 16);
float z = posZ + ((i & 4) == 0 ? 0 : 16);
shadowModelViewMatrix.transformPosition(x, y, z, scratch);
x = scratch.x;
y = scratch.y;
z = scratch.z;
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
maxZ = Math.max(maxZ, z);
}
return maxX > minCamX && minX < maxCamX && maxY > minCamY && minY < maxCamY && maxZ > minCamZ;
}
}

0 comments on commit 3a545c1

Please sign in to comment.