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
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);

View File

@@ -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 <A extends Viewport<A>> {
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 <A extends Viewport<A>> {
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;
}
}

View File

@@ -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++;

View File

@@ -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;

View File

@@ -85,23 +85,18 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
private void uploadUniformBuffer(MDICViewport viewport) {
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 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();
}

View File

@@ -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