Wip fix overdraw

This commit is contained in:
mcrcortex
2025-04-30 13:19:08 +10:00
parent c209cc82af
commit b526d5a51a
7 changed files with 142 additions and 32 deletions

View File

@@ -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();
}
}

View File

@@ -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 //Has a base index buffer of 16380 quads, and also a 1 cube byte index buffer at the end
public class SharedIndexBuffer { 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 = new SharedIndexBuffer();
public static final SharedIndexBuffer INSTANCE_BYTE = new SharedIndexBuffer(true); public static final SharedIndexBuffer INSTANCE_BYTE = new SharedIndexBuffer(true);

View File

@@ -1,8 +1,7 @@
package me.cortex.voxy.client.core.rendering; package me.cortex.voxy.client.core.rendering;
import org.joml.FrustumIntersection; import net.minecraft.util.math.MathHelper;
import org.joml.Matrix4f; import org.joml.*;
import org.joml.Vector4f;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@@ -28,6 +27,10 @@ public abstract class Viewport <A extends Viewport<A>> {
public double cameraY; public double cameraY;
public double cameraZ; public double cameraZ;
public final Matrix4f MVP = new Matrix4f();
public final Vector3i section = new Vector3i();
public final Vector3f innerTranslation = new Vector3f();
protected Viewport() { protected Viewport() {
Vector4f[] planes = null; Vector4f[] planes = null;
try { try {
@@ -67,8 +70,24 @@ public abstract class Viewport <A extends Viewport<A>> {
return (A) this; return (A) this;
} }
public A updateFrustum() { public A update() {
this.frustum.set(new Matrix4f(this.projection).mul(this.modelView), false); //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; return (A) this;
} }
} }

View File

@@ -6,14 +6,11 @@ import me.cortex.voxy.client.TimingStatistics;
import me.cortex.voxy.client.config.VoxyConfig; import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.gl.Capabilities; import me.cortex.voxy.client.core.gl.Capabilities;
import me.cortex.voxy.client.core.gl.GlBuffer; 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.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.RenderDataFactory45;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService; 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.post.PostProcessing;
import me.cortex.voxy.client.core.rendering.util.DownloadStream; 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.client.core.util.IrisUtil;
import me.cortex.voxy.common.Logger; import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.thread.ServiceThreadPool; 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.common.world.other.Mapper;
import me.cortex.voxy.commonImpl.VoxyCommon; import me.cortex.voxy.commonImpl.VoxyCommon;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.GlBackend; import net.minecraft.client.gl.GlBackend;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
@@ -30,9 +26,7 @@ import net.minecraft.client.render.Frustum;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.system.MemoryUtil;
import java.lang.invoke.VarHandle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@@ -180,7 +174,7 @@ public class VoxyRenderSystem {
.setModelView(matrices.peek().getPositionMatrix()) .setModelView(matrices.peek().getPositionMatrix())
.setCamera(cameraX, cameraY, cameraZ) .setCamera(cameraX, cameraY, cameraZ)
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight) .setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight)
.updateFrustum(); .update();
viewport.frameId++; viewport.frameId++;

View File

@@ -174,20 +174,14 @@ public class HierarchicalOcclusionTraverser {
private void uploadUniform(Viewport<?> viewport) { private void uploadUniform(Viewport<?> viewport) {
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 1024); 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; viewport.section.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutInt(ptr, sy); ptr += 4;
MemoryUtil.memPutInt(ptr, sz); ptr += 4;
MemoryUtil.memPutFloat(ptr, viewport.width); ptr += 4; 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))); viewport.innerTranslation.getToAddress(ptr); ptr += 4*3;
innerTranslation.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4; MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4;

View File

@@ -84,24 +84,19 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
private void uploadUniformBuffer(MDICViewport viewport) { private void uploadUniformBuffer(MDICViewport viewport) {
long ptr = UploadStream.INSTANCE.upload(this.uniform, 0, 1024); long ptr = UploadStream.INSTANCE.upload(this.uniform, 0, 1024);
int sx = MathHelper.floor(viewport.cameraX)>>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 mat = new Matrix4f(viewport.MVP);
var innerTranslation = new Vector3f((float) (viewport.cameraX-(sx<<5)), (float) (viewport.cameraY-(sy<<5)), (float) (viewport.cameraZ-(sz<<5))); mat.translate(-viewport.innerTranslation.x, -viewport.innerTranslation.y, -viewport.innerTranslation.z);
mat.translate(-innerTranslation.x, -innerTranslation.y, -innerTranslation.z);
mat.getToAddress(ptr); ptr += 4*4*4; mat.getToAddress(ptr); ptr += 4*4*4;
MemoryUtil.memPutInt(ptr, sx); ptr += 4;
MemoryUtil.memPutInt(ptr, sy); ptr += 4; viewport.section.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutInt(ptr, sz); ptr += 4;
if (viewport.frameId<0) { if (viewport.frameId<0) {
Logger.error("Frame ID negative, this will cause things to break, wrapping around"); Logger.error("Frame ID negative, this will cause things to break, wrapping around");
viewport.frameId &= 0x7fffffff; viewport.frameId &= 0x7fffffff;
} }
MemoryUtil.memPutInt(ptr, viewport.frameId&0x7fffffff); ptr += 4; MemoryUtil.memPutInt(ptr, viewport.frameId&0x7fffffff); ptr += 4;
innerTranslation.getToAddress(ptr); ptr += 4*3; viewport.innerTranslation.getToAddress(ptr); ptr += 4*3;
UploadStream.INSTANCE.commit(); UploadStream.INSTANCE.commit();
} }

View File

@@ -16,6 +16,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinRenderSectionManager { public class MixinRenderSectionManager {
@Shadow @Final private ClientWorld level; @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")) @Inject(method = "onChunkRemoved", at = @At("HEAD"))
private void injectIngest(int x, int z, CallbackInfo ci) { private void injectIngest(int x, int z, CallbackInfo ci) {
//TODO: Am not quite sure if this is right //TODO: Am not quite sure if this is right