From b526d5a51aa2b4b6cac2c9d5bf1ea2ab1dee011c Mon Sep 17 00:00:00 2001
From: mcrcortex <18544518+MCRcortex@users.noreply.github.com>
Date: Wed, 30 Apr 2025 13:19:08 +1000
Subject: [PATCH] Wip fix overdraw
---
.../core/rendering/ChunkBoundRenderer.java | 97 +++++++++++++++++++
.../core/rendering/SharedIndexBuffer.java | 1 +
.../voxy/client/core/rendering/Viewport.java | 29 +++++-
.../core/rendering/VoxyRenderSystem.java | 8 +-
.../HierarchicalOcclusionTraverser.java | 12 +--
.../section/MDICSectionRenderer.java | 17 ++--
.../sodium/MixinRenderSectionManager.java | 10 ++
7 files changed, 142 insertions(+), 32 deletions(-)
create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/ChunkBoundRenderer.java
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/ChunkBoundRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/ChunkBoundRenderer.java
new file mode 100644
index 00000000..3381a106
--- /dev/null
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/ChunkBoundRenderer.java
@@ -0,0 +1,97 @@
+package me.cortex.voxy.client.core.rendering;
+
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
+import me.cortex.voxy.client.core.gl.GlBuffer;
+import me.cortex.voxy.client.core.rendering.util.UploadStream;
+import org.lwjgl.system.MemoryUtil;
+
+import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
+import static org.lwjgl.opengl.GL15.glBindBuffer;
+import static org.lwjgl.opengl.GL30.glBindBufferBase;
+import static org.lwjgl.opengl.GL30.glBindVertexArray;
+import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
+import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
+import static org.lwjgl.opengl.GL40C.GL_DRAW_INDIRECT_BUFFER;
+import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
+
+//This is a render subsystem, its very simple in what it does
+// it renders an AABB around loaded chunks, thats it
+public class ChunkBoundRenderer {
+ public static final int MAX_CHUNK_COUNT = 10_000;
+ private final GlBuffer chunkPosBuffer = new GlBuffer(MAX_CHUNK_COUNT*8);//Stored as ivec2
+ private final GlBuffer uniformBuffer = new GlBuffer(128);
+ private final Long2IntOpenHashMap chunk2idx = new Long2IntOpenHashMap(MAX_CHUNK_COUNT);
+ private final long[] idx2chunk = new long[MAX_CHUNK_COUNT];
+
+ public ChunkBoundRenderer() {
+ this.chunk2idx.defaultReturnValue(-1);
+ }
+
+ public void addChunk(long pos) {
+ if (this.chunk2idx.containsKey(pos)) {
+ throw new IllegalArgumentException("Chunk already in map");
+ }
+ int idx = this.chunk2idx.size();
+ this.chunk2idx.put(pos, idx);
+ this.idx2chunk[idx] = pos;
+
+ long ptr = UploadStream.INSTANCE.upload(this.chunkPosBuffer, 8L*idx, 8);
+ //Need to do it in 2 parts because ivec2 is 2 parts
+ MemoryUtil.memPutInt(ptr, (int)(pos&0xFFFFFFFFL)); ptr += 4;
+ MemoryUtil.memPutInt(ptr, (int)((pos>>>32)&0xFFFFFFFFL));
+ UploadStream.INSTANCE.commit();
+ }
+
+ public void removeChunk(long pos) {
+ int idx = this.chunk2idx.remove(pos);
+ if (idx == -1) {
+ throw new IllegalArgumentException("Chunk pos not in map");
+ }
+ if (idx == this.chunk2idx.size()-1) {
+ //Dont need to do anything as heap is already compact
+ return;
+ }
+ if (this.idx2chunk[idx] != pos) {
+ throw new IllegalStateException();
+ }
+
+ //Move last entry on heap to this index
+ long ePos = this.idx2chunk[this.chunk2idx.size()];// since is already removed size is correct end idx
+ if (this.chunk2idx.put(ePos, idx) == -1) {
+ throw new IllegalStateException();
+ }
+ this.idx2chunk[idx] = ePos;
+
+ //Put the end pos into the new idx
+ long ptr = UploadStream.INSTANCE.upload(this.chunkPosBuffer, 8L*idx, 8);
+ //Need to do it in 2 parts because ivec2 is 2 parts
+ MemoryUtil.memPutInt(ptr, (int)(ePos&0xFFFFFFFFL)); ptr += 4;
+ MemoryUtil.memPutInt(ptr, (int)((ePos>>>32)&0xFFFFFFFFL));
+ UploadStream.INSTANCE.commit();
+ }
+
+ //Bind and render, changing as little gl state as possible so that the caller may configure how it wants to render
+ public void render(Viewport> viewport) {
+ long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 128);
+ viewport.MVP.getToAddress(ptr); ptr += 4*4*4;
+ viewport.section.getToAddress(ptr); ptr += 4*4;
+ viewport.innerTranslation.getToAddress(ptr); ptr += 4*4;
+ UploadStream.INSTANCE.commit();
+
+ //TODO: NOTE: need to reverse the winding order since we want the back faces of the AABB, not the front
+ //this.cullShader.bind();
+ glBindVertexArray(RenderService.STATIC_VAO);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.chunkPosBuffer.id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
+ glDrawElementsInstanced(GL_TRIANGLES, 6*2*3, GL_UNSIGNED_BYTE, SharedIndexBuffer.CUBE_INDEX_OFFSET, this.chunk2idx.size());
+ }
+
+ public void free() {
+ this.uniformBuffer.free();
+ this.chunkPosBuffer.free();
+ }
+}
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/SharedIndexBuffer.java b/src/main/java/me/cortex/voxy/client/core/rendering/SharedIndexBuffer.java
index 30f9dc13..b583c52a 100644
--- a/src/main/java/me/cortex/voxy/client/core/rendering/SharedIndexBuffer.java
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/SharedIndexBuffer.java
@@ -9,6 +9,7 @@ import org.lwjgl.system.MemoryUtil;
//Has a base index buffer of 16380 quads, and also a 1 cube byte index buffer at the end
public class SharedIndexBuffer {
+ public static final int CUBE_INDEX_OFFSET = (1<<16)*6*2;
public static final SharedIndexBuffer INSTANCE = new SharedIndexBuffer();
public static final SharedIndexBuffer INSTANCE_BYTE = new SharedIndexBuffer(true);
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java b/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java
index 9e3432b2..054d449b 100644
--- a/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java
@@ -1,8 +1,7 @@
package me.cortex.voxy.client.core.rendering;
-import org.joml.FrustumIntersection;
-import org.joml.Matrix4f;
-import org.joml.Vector4f;
+import net.minecraft.util.math.MathHelper;
+import org.joml.*;
import java.lang.reflect.Field;
@@ -28,6 +27,10 @@ public abstract class Viewport > {
public double cameraY;
public double cameraZ;
+ public final Matrix4f MVP = new Matrix4f();
+ public final Vector3i section = new Vector3i();
+ public final Vector3f innerTranslation = new Vector3f();
+
protected Viewport() {
Vector4f[] planes = null;
try {
@@ -67,8 +70,24 @@ public abstract class Viewport > {
return (A) this;
}
- public A updateFrustum() {
- this.frustum.set(new Matrix4f(this.projection).mul(this.modelView), false);
+ public A update() {
+ //MVP
+ this.projection.mul(this.modelView, this.MVP);
+
+ //Update the frustum
+ this.frustum.set(this.MVP, false);
+
+ //Translation vectors
+ int sx = MathHelper.floor(this.cameraX)>>5;
+ int sy = MathHelper.floor(this.cameraY)>>5;
+ int sz = MathHelper.floor(this.cameraZ)>>5;
+ this.section.set(sx, sy, sz);
+
+ this.innerTranslation.set(
+ (float) (this.cameraX-(sx<<5)),
+ (float) (this.cameraY-(sy<<5)),
+ (float) (this.cameraZ-(sz<<5)));
+
return (A) this;
}
}
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/VoxyRenderSystem.java b/src/main/java/me/cortex/voxy/client/core/rendering/VoxyRenderSystem.java
index 0ba3a7a8..a47f37e5 100644
--- a/src/main/java/me/cortex/voxy/client/core/rendering/VoxyRenderSystem.java
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/VoxyRenderSystem.java
@@ -6,14 +6,11 @@ import me.cortex.voxy.client.TimingStatistics;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.gl.Capabilities;
import me.cortex.voxy.client.core.gl.GlBuffer;
-import me.cortex.voxy.client.core.model.ColourDepthTextureData;
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
-import me.cortex.voxy.client.core.model.bakery.ModelTextureBakery;
import me.cortex.voxy.client.core.rendering.building.RenderDataFactory45;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
-import me.cortex.voxy.client.core.rendering.util.RawDownloadStream;
import me.cortex.voxy.client.core.util.IrisUtil;
import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.thread.ServiceThreadPool;
@@ -22,7 +19,6 @@ import me.cortex.voxy.common.world.WorldSection;
import me.cortex.voxy.common.world.other.Mapper;
import me.cortex.voxy.commonImpl.VoxyCommon;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
-import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.GlBackend;
import net.minecraft.client.render.Camera;
@@ -30,9 +26,7 @@ import net.minecraft.client.render.Frustum;
import net.minecraft.client.util.math.MatrixStack;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
-import org.lwjgl.system.MemoryUtil;
-import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -180,7 +174,7 @@ public class VoxyRenderSystem {
.setModelView(matrices.peek().getPositionMatrix())
.setCamera(cameraX, cameraY, cameraZ)
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight)
- .updateFrustum();
+ .update();
viewport.frameId++;
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java
index b898efc0..b4f9733d 100644
--- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java
@@ -174,20 +174,14 @@ public class HierarchicalOcclusionTraverser {
private void uploadUniform(Viewport> viewport) {
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 1024);
- int sx = MathHelper.floor(viewport.cameraX)>>5;
- int sy = MathHelper.floor(viewport.cameraY)>>5;
- int sz = MathHelper.floor(viewport.cameraZ)>>5;
- new Matrix4f(viewport.projection).mul(viewport.modelView).getToAddress(ptr); ptr += 4*4*4;
+ viewport.MVP.getToAddress(ptr); ptr += 4*4*4;
- MemoryUtil.memPutInt(ptr, sx); ptr += 4;
- MemoryUtil.memPutInt(ptr, sy); ptr += 4;
- MemoryUtil.memPutInt(ptr, sz); ptr += 4;
+ viewport.section.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutFloat(ptr, viewport.width); ptr += 4;
- var innerTranslation = new Vector3f((float) (viewport.cameraX-(sx<<5)), (float) (viewport.cameraY-(sy<<5)), (float) (viewport.cameraZ-(sz<<5)));
- innerTranslation.getToAddress(ptr); ptr += 4*3;
+ viewport.innerTranslation.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4;
diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/section/MDICSectionRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/section/MDICSectionRenderer.java
index 2a37c605..4947478a 100644
--- a/src/main/java/me/cortex/voxy/client/core/rendering/section/MDICSectionRenderer.java
+++ b/src/main/java/me/cortex/voxy/client/core/rendering/section/MDICSectionRenderer.java
@@ -84,24 +84,19 @@ public class MDICSectionRenderer extends AbstractSectionRenderer>5;
- int sy = MathHelper.floor(viewport.cameraY)>>5;
- int sz = MathHelper.floor(viewport.cameraZ)>>5;
- var mat = new Matrix4f(viewport.projection).mul(viewport.modelView);
- var innerTranslation = new Vector3f((float) (viewport.cameraX-(sx<<5)), (float) (viewport.cameraY-(sy<<5)), (float) (viewport.cameraZ-(sz<<5)));
- mat.translate(-innerTranslation.x, -innerTranslation.y, -innerTranslation.z);
+ var mat = new Matrix4f(viewport.MVP);
+ mat.translate(-viewport.innerTranslation.x, -viewport.innerTranslation.y, -viewport.innerTranslation.z);
mat.getToAddress(ptr); ptr += 4*4*4;
- MemoryUtil.memPutInt(ptr, sx); ptr += 4;
- MemoryUtil.memPutInt(ptr, sy); ptr += 4;
- MemoryUtil.memPutInt(ptr, sz); ptr += 4;
+
+ viewport.section.getToAddress(ptr); ptr += 4*3;
+
if (viewport.frameId<0) {
Logger.error("Frame ID negative, this will cause things to break, wrapping around");
viewport.frameId &= 0x7fffffff;
}
MemoryUtil.memPutInt(ptr, viewport.frameId&0x7fffffff); ptr += 4;
- innerTranslation.getToAddress(ptr); ptr += 4*3;
+ viewport.innerTranslation.getToAddress(ptr); ptr += 4*3;
UploadStream.INSTANCE.commit();
}
diff --git a/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinRenderSectionManager.java b/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinRenderSectionManager.java
index 2d5e4b04..bcda2c46 100644
--- a/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinRenderSectionManager.java
+++ b/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinRenderSectionManager.java
@@ -16,6 +16,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinRenderSectionManager {
@Shadow @Final private ClientWorld level;
+ @Inject(method = "onChunkAdded", at = @At("HEAD"))
+ private void voxy$trackChunkAdd(int x, int z, CallbackInfo ci) {
+
+ }
+
+ @Inject(method = "onChunkRemoved", at = @At("HEAD"))
+ private void voxy$trackChunkRemove(int x, int z, CallbackInfo ci) {
+
+ }
+
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
private void injectIngest(int x, int z, CallbackInfo ci) {
//TODO: Am not quite sure if this is right