Finished GeometryManager and added AABB raster support

This commit is contained in:
mcrcortex
2024-01-29 12:35:09 +10:00
parent d499a19d4e
commit 787dc88c43
11 changed files with 69 additions and 77 deletions

View File

@@ -361,6 +361,6 @@ public class ModelManager {
} }
public void addDebugInfo(List<String> info) { public void addDebugInfo(List<String> info) {
info.add("BlockModels registered: " + this.modelTexture2id.size() + "/" + (1<<16));
} }
} }

View File

@@ -6,7 +6,6 @@ package me.cortex.zenith.client.core.rendering;
import me.cortex.zenith.client.core.gl.GlBuffer; import me.cortex.zenith.client.core.gl.GlBuffer;
import me.cortex.zenith.client.core.model.ModelManager; import me.cortex.zenith.client.core.model.ModelManager;
import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSection;
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
import me.cortex.zenith.client.core.rendering.util.UploadStream; import me.cortex.zenith.client.core.rendering.util.UploadStream;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;

View File

@@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import me.cortex.zenith.client.core.gl.GlBuffer; import me.cortex.zenith.client.core.gl.GlBuffer;
import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSection;
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
import me.cortex.zenith.client.core.rendering.util.BufferArena; import me.cortex.zenith.client.core.rendering.util.BufferArena;
import me.cortex.zenith.client.core.rendering.util.UploadStream; import me.cortex.zenith.client.core.rendering.util.UploadStream;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
@@ -33,7 +32,7 @@ public class GeometryManager {
void uploadResults() { void uploadResults() {
while (!this.buildResults.isEmpty()) { while (!this.buildResults.isEmpty()) {
var result = this.buildResults.pop(); var result = this.buildResults.pop();
boolean isDelete = result.opaque == null && result.translucent == null; boolean isDelete = result.geometryBuffer == null;
if (isDelete) { if (isDelete) {
int id = -1; int id = -1;
if ((id = this.pos2id.remove(result.position)) != -1) { if ((id = this.pos2id.remove(result.position)) != -1) {
@@ -142,36 +141,29 @@ public class GeometryManager {
//TODO: pack the offsets of each axis so that implicit face culling can work //TODO: pack the offsets of each axis so that implicit face culling can work
//Note! the opaquePreDataCount and translucentPreDataCount are never writen to the meta buffer, as they are indexed in reverse relative to the base opaque and translucent geometry //Note! the opaquePreDataCount and translucentPreDataCount are never writen to the meta buffer, as they are indexed in reverse relative to the base opaque and translucent geometry
private record SectionMeta(long position, int aabb, int opaqueGeometryPtr, int count, int translucentGeometryPtr) { private record SectionMeta(long position, int aabb, int geometryPtr, int size, int[] offsets) {
public void writeMetadata(long ptr) { public void writeMetadata(long ptr) {
//THIS IS DUE TO ENDIANNESS and that we are splitting a long into 2 ints //THIS IS DUE TO ENDIANNESS and that we are splitting a long into 2 ints
MemoryUtil.memPutInt(ptr, (int) (this.position>>32)); ptr += 4; MemoryUtil.memPutInt(ptr, (int) (this.position>>32)); ptr += 4;
MemoryUtil.memPutInt(ptr, (int) this.position); ptr += 4; MemoryUtil.memPutInt(ptr, (int) this.position); ptr += 4;
MemoryUtil.memPutInt(ptr, (int) this.aabb); ptr += 4; MemoryUtil.memPutInt(ptr, (int) this.aabb); ptr += 4;
ptr += 4; MemoryUtil.memPutInt(ptr, this.geometryPtr + this.offsets[0]); ptr += 4;
MemoryUtil.memPutInt(ptr, this.opaqueGeometryPtr); ptr += 4; MemoryUtil.memPutInt(ptr, (this.offsets[1]-this.offsets[0])|((this.offsets[2]-this.offsets[1])<<16)); ptr += 4;
MemoryUtil.memPutInt(ptr, this.count); ptr += 4; MemoryUtil.memPutInt(ptr, (this.offsets[3]-this.offsets[2])|((this.offsets[4]-this.offsets[3])<<16)); ptr += 4;
MemoryUtil.memPutInt(ptr, (this.offsets[5]-this.offsets[4])|((this.offsets[6]-this.offsets[5])<<16)); ptr += 4;
//MemoryUtil.memPutInt(ptr, (int) this.translucentGeometryPtr + this.translucentPreDataCount); ptr += 4; MemoryUtil.memPutInt(ptr, (this.offsets[7]-this.offsets[6])|((this.size -this.offsets[7])<<16)); ptr += 4;
//MemoryUtil.memPutInt(ptr, this.translucentQuadCount); ptr += 4;
} }
} }
private SectionMeta createMeta(BuiltSection geometry) { private SectionMeta createMeta(BuiltSection geometry) {
int geometryPtr = (int) this.geometryBuffer.upload(geometry.opaque.buffer()); int geometryPtr = (int) this.geometryBuffer.upload(geometry.geometryBuffer);
return new SectionMeta(geometry.position, geometry.aabb, geometryPtr, (int) (geometry.geometryBuffer.size/8), geometry.offsets);
//TODO: support translucent geometry
//return new SectionMeta(geometry.position, 0, geometryPtr, (int) (geometry.opaque.buffer().size/8), 0, -1,0, 0);
return new SectionMeta(geometry.position, 0, geometryPtr, (int) (geometry.opaque.buffer().size/8), -1);
} }
private void freeMeta(SectionMeta meta) { private void freeMeta(SectionMeta meta) {
if (meta.opaqueGeometryPtr != -1) { if (meta.geometryPtr != -1) {
this.geometryBuffer.free(meta.opaqueGeometryPtr); this.geometryBuffer.free(meta.geometryPtr);
}
if (meta.translucentGeometryPtr != -1) {
this.geometryBuffer.free(meta.translucentGeometryPtr);
} }
} }

View File

@@ -1,7 +1,6 @@
package me.cortex.zenith.client.core.rendering; package me.cortex.zenith.client.core.rendering;
import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSection;
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
import me.cortex.zenith.client.core.rendering.building.RenderGenerationService; import me.cortex.zenith.client.core.rendering.building.RenderGenerationService;
import me.cortex.zenith.common.world.WorldEngine; import me.cortex.zenith.common.world.WorldEngine;
import me.cortex.zenith.common.world.WorldSection; import me.cortex.zenith.common.world.WorldSection;
@@ -42,7 +41,7 @@ public class RenderTracker {
//Removes a lvl 0 section from the world renderer //Removes a lvl 0 section from the world renderer
public void remLvl0(int x, int y, int z) { public void remLvl0(int x, int y, int z) {
this.activeSections.remove(WorldEngine.getWorldSectionId(0, x, y, z)); this.activeSections.remove(WorldEngine.getWorldSectionId(0, x, y, z));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(0, x, y, z), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(0, x, y, z)));
this.renderGen.removeTask(0, x, y, z); this.renderGen.removeTask(0, x, y, z);
} }
@@ -64,14 +63,14 @@ public class RenderTracker {
this.renderGen.enqueueTask(lvl, x, y, z, this::shouldStillBuild, this::getBuildFlagsOrAbort); this.renderGen.enqueueTask(lvl, x, y, z, this::shouldStillBuild, this::getBuildFlagsOrAbort);
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1))));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1)));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1))));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1)));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1))));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1)));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1))));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1)));
this.renderGen.removeTask(lvl-1, (x<<1), (y<<1), (z<<1)); this.renderGen.removeTask(lvl-1, (x<<1), (y<<1), (z<<1));
@@ -96,7 +95,7 @@ public class RenderTracker {
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), O); this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), O);
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl, x, y, z)); this.activeSections.remove(WorldEngine.getWorldSectionId(lvl, x, y, z));
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl, x, y, z), null, null)); this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl, x, y, z)));
this.renderGen.removeTask(lvl, x, y, z); this.renderGen.removeTask(lvl, x, y, z);
this.renderGen.enqueueTask(lvl - 1, (x<<1), (y<<1), (z<<1), this::shouldStillBuild, this::getBuildFlagsOrAbort); this.renderGen.enqueueTask(lvl - 1, (x<<1), (y<<1), (z<<1), this::shouldStillBuild, this::getBuildFlagsOrAbort);

View File

@@ -1,29 +1,43 @@
package me.cortex.zenith.client.core.rendering.building; package me.cortex.zenith.client.core.rendering.building;
import me.cortex.zenith.common.util.MemoryBuffer;
import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
//TODO: also have an AABB size stored //TODO: also have an AABB size stored
public final class BuiltSection { public final class BuiltSection {
public final long position; public final long position;
public final BuiltSectionGeometry opaque; public final int aabb;
public final BuiltSectionGeometry translucent; public final MemoryBuffer geometryBuffer;
public final int[] offsets;
public BuiltSection(long position, BuiltSectionGeometry opaque, BuiltSectionGeometry translucent) { public BuiltSection(long position) {
this(position, -1, null, null);
}
public BuiltSection(long position, int aabb, MemoryBuffer geometryBuffer, int[] offsets) {
this.position = position; this.position = position;
this.opaque = opaque; this.aabb = aabb;
this.translucent = translucent; this.geometryBuffer = geometryBuffer;
this.offsets = offsets;
if (offsets != null) {
for (int i = 0; i < offsets.length-1; i++) {
int delta = offsets[i+1] - offsets[i];
if (delta<0||delta>=(1<<16)) {
throw new IllegalArgumentException("Offsets out of range");
}
}
}
} }
public BuiltSection clone() { public BuiltSection clone() {
return new BuiltSection(this.position, this.opaque != null ? this.opaque.clone() : null, this.translucent != null ? this.translucent.clone() : null); return new BuiltSection(this.position, this.aabb, this.geometryBuffer!=null?this.geometryBuffer.copy():null, this.offsets!=null?Arrays.copyOf(this.offsets, this.offsets.length):null);
} }
public void free() { public void free() {
if (this.opaque != null) { if (this.geometryBuffer != null) {
this.opaque.free(); this.geometryBuffer.free();
}
if (this.translucent != null) {
this.translucent.free();
} }
} }
} }

View File

@@ -1,21 +0,0 @@
package me.cortex.zenith.client.core.rendering.building;
import me.cortex.zenith.common.util.MemoryBuffer;
import java.util.Arrays;
/**
* @param startOffsets Will be converted to ending offsets when doing data computation
*/
public record BuiltSectionGeometry(MemoryBuffer buffer, short[] startOffsets) {
public BuiltSectionGeometry clone() {
return new BuiltSectionGeometry(this.buffer != null ? this.buffer.copy() : null, Arrays.copyOf(this.startOffsets, this.startOffsets.length));
}
public void free() {
if (this.buffer != null) {
this.buffer.free();
}
}
}

View File

@@ -297,7 +297,7 @@ public class RenderDataFactory {
//MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,1,0,0,2,159,0, 0));//92 515 //MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,1,0,0,2,159,0, 0));//92 515
//MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,1,0,0,2,159,0, 0));//92 515 //MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,1,0,0,2,159,0, 0));//92 515
if (outData.isEmpty()) { if (outData.isEmpty()) {
return new BuiltSection(section.getKey(), null, null); return new BuiltSection(section.getKey());
} }
//outData.clear(); //outData.clear();
@@ -317,7 +317,7 @@ public class RenderDataFactory {
MemoryUtil.memPutLong(ptr, data); ptr+=8; MemoryUtil.memPutLong(ptr, data); ptr+=8;
} }
return new BuiltSection(section.getKey(), new BuiltSectionGeometry(buff, new short[0]), null); return new BuiltSection(section.getKey(), (31<<15)|(31<<20)|(31<<25), buff, new int[]{0, outData.size(), outData.size(), outData.size(), outData.size(), outData.size(), outData.size(), outData.size()});
} }

View File

@@ -21,11 +21,11 @@ struct SectionMeta {
uint posA; uint posA;
uint posB; uint posB;
uint AABB; uint AABB;
uint _padA;
uint ptr; uint ptr;
uint cnt; uint cntA;
uint _padB; uint cntB;
uint _padC; uint cntC;
uint cntD;
}; };
//TODO: see if making the stride 2*4*4 bytes or something cause you get that 16 byte write //TODO: see if making the stride 2*4*4 bytes or something cause you get that 16 byte write

View File

@@ -55,11 +55,13 @@ void main() {
} }
if (shouldRender) { if (shouldRender) {
uint basePtr = extractQuadStart(meta);
DrawCommand cmd; DrawCommand cmd;
cmd.count = extractQuadCount(meta) * 6; cmd.count = (meta.cntA&0xFFFF) * 6;
cmd.instanceCount = 1; cmd.instanceCount = 1;
cmd.firstIndex = 0; cmd.firstIndex = 0;
cmd.baseVertex = int(extractQuadStart(meta))<<2; cmd.baseVertex = int(basePtr)<<2;
cmd.baseInstance = encodeLocalLodPos(detail, ipos); cmd.baseInstance = encodeLocalLodPos(detail, ipos);
cmdBuffer[atomicAdd(opaqueDrawCount, 1)] = cmd; cmdBuffer[atomicAdd(opaqueDrawCount, 1)] = cmd;
} }

View File

@@ -14,12 +14,15 @@ void main() {
uint detail = extractDetail(section); uint detail = extractDetail(section);
ivec3 ipos = extractPosition(section); ivec3 ipos = extractPosition(section);
ivec3 aabbOffset = extractAABBOffset(section);
ivec3 size = extractAABBSize(section);
//Transform ipos with respect to the vertex corner //Transform ipos with respect to the vertex corner
ipos += ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1); ivec3 pos = (((ipos<<detail)-baseSectionPos)<<5);
pos += aabbOffset;
pos += (ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1)*size)*(1<<detail);
vec3 cornerPos = vec3(((ipos<<detail)-baseSectionPos)<<5); gl_Position = MVP * vec4(vec3(pos),1);
gl_Position = MVP * vec4(cornerPos,1);
//Write to this id //Write to this id
id = sid; id = sid;

View File

@@ -16,6 +16,10 @@ uint extractQuadStart(SectionMeta meta) {
return meta.ptr; return meta.ptr;
} }
uint extractQuadCount(SectionMeta meta) { ivec3 extractAABBOffset(SectionMeta meta) {
return meta.cnt; return (ivec3(meta.AABB)>>ivec3(0,5,10))&31;
}
ivec3 extractAABBSize(SectionMeta meta) {
return ((ivec3(meta.AABB)>>ivec3(15,20,25))&31)+1;//The size is + 1 cause its always at least 1x1x1
} }