Work on the funny
This commit is contained in:
@@ -68,6 +68,10 @@ public class VoxelCore {
|
||||
|
||||
//Trigger the shared index buffer loading
|
||||
SharedIndexBuffer.INSTANCE.id();
|
||||
if (true) {
|
||||
this.renderer = new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||
System.out.println("Using Gl46MeshletFarWorldRendering");
|
||||
} else {
|
||||
if (VoxyConfig.CONFIG.useMeshShaders()) {
|
||||
this.renderer = new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||
System.out.println("Using NvMeshFarWorldRenderer");
|
||||
@@ -75,6 +79,7 @@ public class VoxelCore {
|
||||
this.renderer = new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||
System.out.println("Using Gl46FarWorldRenderer");
|
||||
}
|
||||
}
|
||||
this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport);
|
||||
System.out.println("Renderer initialized");
|
||||
|
||||
|
||||
@@ -40,11 +40,11 @@ import static org.lwjgl.opengl.GL30.*;
|
||||
|
||||
|
||||
//Todo: tinker with having the compute shader where each thread is a position to render? maybe idk
|
||||
public abstract class AbstractFarWorldRenderer <T extends Viewport> {
|
||||
public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends AbstractGeometryManager> {
|
||||
public static final int STATIC_VAO = glGenVertexArrays();
|
||||
|
||||
protected final GlBuffer uniformBuffer;
|
||||
protected final GeometryManager geometry;
|
||||
protected final J geometry;
|
||||
protected final ModelManager models;
|
||||
protected final GlBuffer lightDataBuffer;
|
||||
|
||||
@@ -63,11 +63,11 @@ public abstract class AbstractFarWorldRenderer <T extends Viewport> {
|
||||
|
||||
private final ConcurrentLinkedDeque<Mapper.StateEntry> blockStateUpdates = new ConcurrentLinkedDeque<>();
|
||||
private final ConcurrentLinkedDeque<Mapper.BiomeEntry> biomeUpdates = new ConcurrentLinkedDeque<>();
|
||||
public AbstractFarWorldRenderer(int geometrySize, int maxSections) {
|
||||
this.maxSections = maxSections;
|
||||
public AbstractFarWorldRenderer(J geometry) {
|
||||
this.maxSections = geometry.getMaxSections();
|
||||
this.uniformBuffer = new GlBuffer(1024);
|
||||
this.lightDataBuffer = new GlBuffer(256*4);//256 of uint
|
||||
this.geometry = new GeometryManager(geometrySize*8L, maxSections);
|
||||
this.geometry = geometry;
|
||||
this.models = new ModelManager(16);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package me.cortex.voxy.client.core.rendering;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
public abstract class AbstractGeometryManager {
|
||||
protected int sectionCount = 0;
|
||||
protected final int maxSections;
|
||||
protected final ConcurrentLinkedDeque<BuiltSection> buildResults = new ConcurrentLinkedDeque<>();
|
||||
|
||||
protected AbstractGeometryManager(int maxSections) {
|
||||
this.maxSections = maxSections;
|
||||
}
|
||||
|
||||
abstract IntArrayList uploadResults();
|
||||
|
||||
int getMaxSections() {
|
||||
return this.maxSections;
|
||||
}
|
||||
|
||||
public void enqueueResult(BuiltSection sectionGeometry) {
|
||||
this.buildResults.add(sectionGeometry);
|
||||
}
|
||||
|
||||
public abstract float getGeometryBufferUsage();
|
||||
|
||||
public int getSectionCount() {
|
||||
return this.sectionCount;
|
||||
}
|
||||
|
||||
public abstract void free();
|
||||
|
||||
}
|
||||
@@ -14,11 +14,8 @@ import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
public class GeometryManager {
|
||||
public class DefaultGeometryManager extends AbstractGeometryManager {
|
||||
private static final int SECTION_METADATA_SIZE = 32;
|
||||
|
||||
private final ConcurrentLinkedDeque<BuiltSection> buildResults = new ConcurrentLinkedDeque<>();
|
||||
private int sectionCount = 0;
|
||||
private final Long2IntOpenHashMap pos2id = new Long2IntOpenHashMap();
|
||||
private final LongArrayList id2pos = new LongArrayList();
|
||||
private final ObjectArrayList<SectionMeta> sectionMetadata = new ObjectArrayList<>();
|
||||
@@ -27,7 +24,8 @@ public class GeometryManager {
|
||||
private final GlBuffer sectionMetaBuffer;
|
||||
private final BufferArena geometryBuffer;
|
||||
|
||||
public GeometryManager(long geometryBufferSize, int maxSections) {
|
||||
public DefaultGeometryManager(long geometryBufferSize, int maxSections) {
|
||||
super(maxSections);
|
||||
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE);
|
||||
this.geometryBuffer = new BufferArena(geometryBufferSize, 8);
|
||||
this.pos2id.defaultReturnValue(-1);
|
||||
@@ -120,14 +118,6 @@ public class GeometryManager {
|
||||
return this.markSectionIds;
|
||||
}
|
||||
|
||||
public void enqueueResult(BuiltSection sectionGeometry) {
|
||||
this.buildResults.add(sectionGeometry);
|
||||
}
|
||||
|
||||
public int getSectionCount() {
|
||||
return this.sectionCount;
|
||||
}
|
||||
|
||||
public void free() {
|
||||
while (!this.buildResults.isEmpty()) {
|
||||
this.buildResults.pop().free();
|
||||
@@ -156,7 +146,7 @@ public class GeometryManager {
|
||||
|
||||
//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
|
||||
private record SectionMeta(long position, int aabb, int geometryPtr, int size, int[] offsets) {
|
||||
protected record SectionMeta(long position, int aabb, int geometryPtr, int size, int[] offsets) {
|
||||
public void writeMetadata(long ptr) {
|
||||
//THIS IS DUE TO ENDIANNESS and that we are splitting a long into 2 ints
|
||||
MemoryUtil.memPutInt(ptr, (int) (this.position>>32)); ptr += 4;
|
||||
@@ -171,7 +161,7 @@ public class GeometryManager {
|
||||
}
|
||||
}
|
||||
|
||||
private SectionMeta createMeta(BuiltSection geometry) {
|
||||
protected SectionMeta createMeta(BuiltSection geometry) {
|
||||
int geometryPtr = (int) this.geometryBuffer.upload(geometry.geometryBuffer);
|
||||
if (geometryPtr == -1) {
|
||||
String msg = "Buffer arena out of memory, please increase it in settings or decrease LoD quality";
|
||||
@@ -182,10 +172,9 @@ public class GeometryManager {
|
||||
return new SectionMeta(geometry.position, geometry.aabb, geometryPtr, (int) (geometry.geometryBuffer.size/8), geometry.offsets);
|
||||
}
|
||||
|
||||
private void freeMeta(SectionMeta meta) {
|
||||
protected void freeMeta(SectionMeta meta) {
|
||||
if (meta.geometryPtr != -1) {
|
||||
this.geometryBuffer.free(meta.geometryPtr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package me.cortex.voxy.client.core.rendering;
|
||||
|
||||
public class FrustumLoDComputation {
|
||||
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
||||
import static org.lwjgl.opengl.GL45.glClearNamedBufferData;
|
||||
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
||||
|
||||
public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport> {
|
||||
public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport, DefaultGeometryManager> {
|
||||
private final Shader commandGen = Shader.make()
|
||||
.add(ShaderType.COMPUTE, "voxy:lod/gl46/cmdgen.comp")
|
||||
.compile();
|
||||
@@ -55,7 +55,7 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport>
|
||||
private final GlBuffer glCommandCountBuffer;
|
||||
|
||||
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
|
||||
super(geometryBuffer, maxSections);
|
||||
super(new DefaultGeometryManager(geometryBuffer*8L, maxSections));
|
||||
this.glCommandBuffer = new GlBuffer(maxSections*5L*4 * 6);
|
||||
this.glCommandCountBuffer = new GlBuffer(4*2);
|
||||
nglClearNamedBufferData(this.glCommandBuffer.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package me.cortex.voxy.client.core.rendering;
|
||||
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL30C.GL_R8UI;
|
||||
import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
|
||||
import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
|
||||
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
||||
|
||||
public class Gl46MeshletViewport extends Viewport<Gl46MeshletViewport> {
|
||||
GlBuffer visibilityBuffer;
|
||||
public Gl46MeshletViewport(Gl46MeshletsFarWorldRenderer renderer) {
|
||||
super(renderer);
|
||||
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L);
|
||||
nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
|
||||
}
|
||||
|
||||
protected void delete0() {
|
||||
this.visibilityBuffer.free();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package me.cortex.voxy.client.core.rendering;
|
||||
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
import me.cortex.voxy.client.core.gl.shader.Shader;
|
||||
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import static org.lwjgl.opengl.ARBIndirectParameters.GL_PARAMETER_BUFFER_ARB;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate;
|
||||
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.GL30C.GL_RED_INTEGER;
|
||||
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
|
||||
import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
|
||||
import static org.lwjgl.opengl.GL33.glBindSampler;
|
||||
import static org.lwjgl.opengl.GL40.glDrawElementsIndirect;
|
||||
import static org.lwjgl.opengl.GL40C.GL_DRAW_INDIRECT_BUFFER;
|
||||
import static org.lwjgl.opengl.GL42.GL_FRAMEBUFFER_BARRIER_BIT;
|
||||
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
||||
import static org.lwjgl.opengl.GL43.*;
|
||||
import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
||||
import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData;
|
||||
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
||||
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
|
||||
import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FRAGMENT_TEST_NV;
|
||||
|
||||
public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46MeshletViewport, DefaultGeometryManager> {
|
||||
private final Shader meshletGenerator = Shader.make()
|
||||
.add(ShaderType.COMPUTE, "voxy:lod/gl46mesh/cmdgen.comp")
|
||||
.compile();
|
||||
|
||||
private final Shader lodShader = Shader.make()
|
||||
.add(ShaderType.VERTEX, "voxy:lod/gl46mesh/quads.vert")
|
||||
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/quads.frag")
|
||||
.compile();
|
||||
|
||||
private final Shader cullShader = Shader.make()
|
||||
.add(ShaderType.VERTEX, "voxy:lod/gl46mesh/cull.vert")
|
||||
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/cull.frag")
|
||||
.compile();
|
||||
|
||||
private final GlBuffer glDrawIndirect;
|
||||
private final GlBuffer meshletBuffer;
|
||||
|
||||
public Gl46MeshletsFarWorldRenderer(int geometrySize, int maxSections) {
|
||||
super(new DefaultGeometryManager(geometrySize*8L, maxSections));
|
||||
this.glDrawIndirect = new GlBuffer(4*5);
|
||||
this.meshletBuffer = new GlBuffer(4*1000000);//TODO: Make max meshlet count configurable
|
||||
}
|
||||
|
||||
protected void bindResources(Gl46MeshletViewport viewport) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.geometry.geometryId());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.glDrawIndirect.id);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.meshletBuffer.id);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.geometry.metaId());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, viewport.visibilityBuffer.id);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.models.getBufferId());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.models.getColourBufferId());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, this.lightDataBuffer.id);//Lighting LUT
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, this.glDrawIndirect.id);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
|
||||
|
||||
//Bind the texture atlas
|
||||
glBindSampler(0, this.models.getSamplerId());
|
||||
glBindTextureUnit(0, this.models.getTextureId());
|
||||
}
|
||||
|
||||
private void updateUniformBuffer(Gl46MeshletViewport viewport) {
|
||||
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, this.uniformBuffer.size());
|
||||
|
||||
var mat = new Matrix4f(viewport.projection).mul(viewport.modelView);
|
||||
var innerTranslation = new Vector3f((float) (viewport.cameraX-(this.sx<<5)), (float) (viewport.cameraY-(this.sy<<5)), (float) (viewport.cameraZ-(this.sz<<5)));
|
||||
mat.translate(-innerTranslation.x, -innerTranslation.y, -innerTranslation.z);
|
||||
mat.getToAddress(ptr); ptr += 4*4*4;
|
||||
MemoryUtil.memPutInt(ptr, this.sx); ptr += 4;
|
||||
MemoryUtil.memPutInt(ptr, this.sy); ptr += 4;
|
||||
MemoryUtil.memPutInt(ptr, this.sz); ptr += 4;
|
||||
MemoryUtil.memPutInt(ptr, this.geometry.getSectionCount()); ptr += 4;
|
||||
var planes = ((AccessFrustumIntersection)this.frustum).getPlanes();
|
||||
for (var plane : planes) {
|
||||
plane.getToAddress(ptr); ptr += 4*4;
|
||||
}
|
||||
innerTranslation.getToAddress(ptr); ptr += 4*3;
|
||||
MemoryUtil.memPutInt(ptr, viewport.frameId++); ptr += 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFarAwayOpaque(Gl46MeshletViewport viewport) {
|
||||
if (this.geometry.getSectionCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
{//Mark all of the updated sections as being visible from last frame
|
||||
for (int id : this.updatedSectionIds) {
|
||||
long ptr = UploadStream.INSTANCE.upload(viewport.visibilityBuffer, id * 4L, 4);
|
||||
MemoryUtil.memPutInt(ptr, viewport.frameId - 1);//(visible from last frame)
|
||||
}
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
this.updateUniformBuffer(viewport);
|
||||
UploadStream.INSTANCE.commit();
|
||||
glBindVertexArray(AbstractFarWorldRenderer.STATIC_VAO);
|
||||
|
||||
nglClearNamedBufferSubData(this.glDrawIndirect.id, GL_R32UI, 4, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
||||
|
||||
this.meshletGenerator.bind();
|
||||
this.bindResources(viewport);
|
||||
glDispatchCompute((this.geometry.getSectionCount()+63)/64, 1, 1);
|
||||
|
||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT);
|
||||
|
||||
this.lodShader.bind();
|
||||
this.bindResources(viewport);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, 0);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT);
|
||||
|
||||
this.cullShader.bind();
|
||||
this.bindResources(viewport);
|
||||
glDepthMask(false);
|
||||
glColorMask(false, false, false, false);
|
||||
glDrawElementsInstanced(GL_TRIANGLES, 6 * 2 * 3, GL_UNSIGNED_BYTE, (1 << 16) * 6 * 2, this.geometry.getSectionCount());
|
||||
glColorMask(true, true, true, true);
|
||||
glDepthMask(true);
|
||||
|
||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void renderFarAwayTranslucent(Gl46MeshletViewport viewport) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Gl46MeshletViewport createViewport0() {
|
||||
return new Gl46MeshletViewport(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
super.shutdown();
|
||||
this.meshletGenerator.free();
|
||||
this.lodShader.free();
|
||||
this.cullShader.free();
|
||||
|
||||
this.glDrawIndirect.free();
|
||||
this.meshletBuffer.free();
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
|
||||
import static org.lwjgl.opengl.GL45C.glClearNamedBufferData;
|
||||
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
||||
|
||||
public class Gl46Viewport extends Viewport<Gl46Viewport, Gl46FarWorldRenderer> {
|
||||
public class Gl46Viewport extends Viewport<Gl46Viewport> {
|
||||
GlBuffer visibilityBuffer;
|
||||
public Gl46Viewport(Gl46FarWorldRenderer renderer) {
|
||||
super(renderer);
|
||||
|
||||
@@ -34,7 +34,7 @@ import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
||||
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
|
||||
import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FRAGMENT_TEST_NV;
|
||||
|
||||
public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewport> {
|
||||
public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewport, DefaultGeometryManager> {
|
||||
private final Shader terrain = Shader.make()
|
||||
.add(ShaderType.TASK, "voxy:lod/nvmesh/primary.task")
|
||||
.add(ShaderType.MESH, "voxy:lod/nvmesh/primary.mesh")
|
||||
@@ -53,7 +53,7 @@ public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewp
|
||||
.compile();
|
||||
|
||||
public NvMeshFarWorldRenderer(int geometrySize, int maxSections) {
|
||||
super(geometrySize, maxSections);
|
||||
super(new DefaultGeometryManager(geometrySize*8L, maxSections));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
|
||||
import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
|
||||
import static org.lwjgl.opengl.GL45C.glClearNamedBufferData;
|
||||
|
||||
public class NvMeshViewport extends Viewport<NvMeshViewport, NvMeshFarWorldRenderer> {
|
||||
public class NvMeshViewport extends Viewport<NvMeshViewport> {
|
||||
GlBuffer visibilityBuffer;
|
||||
public NvMeshViewport(NvMeshFarWorldRenderer renderer) {
|
||||
super(renderer);
|
||||
|
||||
@@ -2,8 +2,8 @@ package me.cortex.voxy.client.core.rendering;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public abstract class Viewport <A extends Viewport<A,T>, T extends AbstractFarWorldRenderer<A>> {
|
||||
private final T renderer;
|
||||
public abstract class Viewport <A extends Viewport<A>> {
|
||||
private final AbstractFarWorldRenderer renderer;
|
||||
|
||||
int frameId;
|
||||
Matrix4f projection;
|
||||
@@ -12,7 +12,7 @@ public abstract class Viewport <A extends Viewport<A,T>, T extends AbstractFarWo
|
||||
double cameraY;
|
||||
double cameraZ;
|
||||
|
||||
protected Viewport(T renderer) {
|
||||
protected Viewport(AbstractFarWorldRenderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
struct BlockModel {
|
||||
uint faceData[6];
|
||||
uint flagsA;
|
||||
uint colourTint;
|
||||
uint _pad[8];
|
||||
};
|
||||
|
||||
struct SectionMeta {
|
||||
uint posA;
|
||||
uint posB;
|
||||
uint AABB;
|
||||
uint ptr;
|
||||
uint cntA;
|
||||
uint cntB;
|
||||
uint cntC;
|
||||
uint cntD;
|
||||
};
|
||||
|
||||
//TODO: see if making the stride 2*4*4 bytes or something cause you get that 16 byte write
|
||||
struct DrawCommand {
|
||||
uint count;
|
||||
uint instanceCount;
|
||||
uint firstIndex;
|
||||
int baseVertex;
|
||||
uint baseInstance;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform sampler2D blockModelAtlas;
|
||||
|
||||
#ifndef Quad
|
||||
#define Quad ivec2
|
||||
#endif
|
||||
layout(binding = 1, std430) readonly restrict buffer QuadBuffer {
|
||||
Quad quadData[];
|
||||
};
|
||||
|
||||
layout(binding = 2, std430) restrict buffer DrawBuffer {
|
||||
DrawCommand drawCmd;
|
||||
};
|
||||
|
||||
#ifndef Quad
|
||||
#define MESHLET_ACCESS readonly writeonly
|
||||
#endif
|
||||
layout(binding = 3, std430) MESHLET_ACCESS restrict buffer MeshletListData {
|
||||
uint meshlets[];
|
||||
};
|
||||
|
||||
layout(binding = 4, std430) readonly restrict buffer SectionBuffer {
|
||||
SectionMeta sectionData[];
|
||||
};
|
||||
|
||||
#ifndef VISIBILITY_ACCESS
|
||||
#define VISIBILITY_ACCESS readonly
|
||||
#endif
|
||||
layout(binding = 5, std430) VISIBILITY_ACCESS restrict buffer VisibilityBuffer {
|
||||
uint visibilityData[];
|
||||
};
|
||||
|
||||
layout(binding = 6, std430) readonly restrict buffer ModelBuffer {
|
||||
BlockModel modelData[];
|
||||
};
|
||||
|
||||
layout(binding = 7, std430) readonly restrict buffer ModelColourBuffer {
|
||||
uint colourData[];
|
||||
};
|
||||
|
||||
layout(binding = 8, std430) readonly restrict buffer LightingBuffer {
|
||||
uint lightData[];
|
||||
};
|
||||
|
||||
vec4 getLighting(uint index) {
|
||||
uvec4 arr = uvec4(lightData[index]);
|
||||
arr = arr>>uvec4(16,8,0,24);
|
||||
arr = arr & uvec4(0xFF);
|
||||
return vec4(arr)*vec4(1.0f/255.0f);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#version 450
|
||||
#define MESHLET_ACCESS writeonly
|
||||
#import <voxy:lod/quad_format.glsl>
|
||||
#import <voxy:lod/gl46mesh/bindings.glsl>
|
||||
#import <voxy:lod/section.glsl>
|
||||
#define extractMeshletStart extractQuadStart
|
||||
layout(local_size_x = 64) in;
|
||||
#define QUADS_PER_MESHLET 126
|
||||
|
||||
void emitMeshlets(inout uint mli, inout uint meshletPtr, uint mskedCnt, uint cnt) {
|
||||
for (;mskedCnt != 0; mskedCnt--,mli++) {
|
||||
meshlets[mli] = meshletPtr + (mskedCnt-1);
|
||||
}
|
||||
meshletPtr += cnt;
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (gl_GlobalInvocationID.x == 0) {
|
||||
//Setup the remaining state of the drawElementsIndirect command
|
||||
drawCmd.count = QUADS_PER_MESHLET*6;
|
||||
drawCmd.firstIndex = 0;
|
||||
drawCmd.baseVertex = 0;
|
||||
drawCmd.baseInstance = 0;
|
||||
}
|
||||
if (gl_GlobalInvocationID.x >= sectionCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Check the occlusion data from last frame
|
||||
bool shouldRender = visibilityData[gl_GlobalInvocationID.x] == frameId - 1;
|
||||
if (shouldRender) {
|
||||
SectionMeta meta = sectionData[gl_GlobalInvocationID.x];
|
||||
uint detail = extractDetail(meta);
|
||||
ivec3 ipos = extractPosition(meta);
|
||||
|
||||
ivec3 relative = ipos-(baseSectionPos>>detail);
|
||||
|
||||
uint a = ((meta.cntA>>16)&0xFFFF);
|
||||
uint u = (meta.cntB &0xFFFF) * uint(relative.y>-1);
|
||||
uint d = ((meta.cntB>>16)&0xFFFF) * uint(relative.y<1 );
|
||||
uint s = (meta.cntC &0xFFFF) * uint(relative.z>-1);
|
||||
uint n = ((meta.cntC>>16)&0xFFFF) * uint(relative.z<1 );
|
||||
uint w = (meta.cntD &0xFFFF) * uint(relative.x>-1);
|
||||
uint e = ((meta.cntD>>16)&0xFFFF) * uint(relative.x<1 );
|
||||
uint total = a + u + d + s + n + w + e;
|
||||
|
||||
uint mli = atomicAdd(drawCmd.instanceCount, total);//meshletListIndex
|
||||
|
||||
uint meshletPtr = extractMeshletStart(meta);
|
||||
|
||||
emitMeshlets(mli, meshletPtr, a, a);
|
||||
emitMeshlets(mli, meshletPtr, u, (meta.cntB &0xFFFF));
|
||||
emitMeshlets(mli, meshletPtr, d, ((meta.cntB>>16)&0xFFFF));
|
||||
emitMeshlets(mli, meshletPtr, s, (meta.cntC &0xFFFF));
|
||||
emitMeshlets(mli, meshletPtr, n, ((meta.cntC>>16)&0xFFFF));
|
||||
emitMeshlets(mli, meshletPtr, w, (meta.cntD &0xFFFF));
|
||||
emitMeshlets(mli, meshletPtr, e, ((meta.cntD>>16)&0xFFFF));
|
||||
//TODO: also increment a secondary atomic buffer that can be used to do a compute pass over all meshlets (need to basicly divide the meshletCounter by the computes workGroup size)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#version 450
|
||||
void main() {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#version 450
|
||||
void main() {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#version 460 core
|
||||
layout(location = 0) out vec4 outColour;
|
||||
void main() {
|
||||
outColour = vec4(1,0,0,1);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#version 450
|
||||
#define MESHLET_ACCESS readonly
|
||||
#define QUADS_PER_MESHLET 126
|
||||
//There are 16 bytes of metadata at the start of the meshlet
|
||||
#define MESHLET_SIZE (QUADS_PER_MESHLET+2)
|
||||
#import <voxy:lod/quad_format.glsl>
|
||||
#import <voxy:lod/gl46mesh/bindings.glsl>
|
||||
#import <voxy:lod/section.glsl>
|
||||
|
||||
uvec2 meshletPosition;
|
||||
Quad quad;
|
||||
bool setupMeshlet() {
|
||||
gl_CullDistance[0] = 1;
|
||||
//TODO: replace with vertexAttribute that has a divisor of 1
|
||||
uint data = meshlets[gl_InstanceID];
|
||||
if (data == uint(-1)) {//Came across a culled meshlet
|
||||
gl_CullDistance[0] = -1;
|
||||
//Since the primative is culled, dont need to do any more work or set any values as the primative is discarded
|
||||
// we dont need to care about undefined values
|
||||
return true;
|
||||
}
|
||||
|
||||
uint baseId = (data*QUADS_PER_MESHLET);
|
||||
uint quadIndex = baseId + (gl_VertexID>>2) + 2;
|
||||
meshletPosition = geometryPool[baseId];
|
||||
quad = geometryPool[quadIndex];
|
||||
if (isQuadEmpty(quad)) {
|
||||
gl_CullDistance[0] = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (setupMeshlet()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,10 @@ uint extractLightId(uint64_t quad) {
|
||||
return Eu32(quad, 8, 55);
|
||||
}
|
||||
|
||||
bool isQuadEmpty(uint64_t quad) {
|
||||
return quad == uint64_t(0);
|
||||
}
|
||||
|
||||
#else
|
||||
//TODO: FIXME, ivec2 swaps around the data of the x and y cause its written in little endian
|
||||
|
||||
@@ -69,4 +73,8 @@ uint extractBiomeId(ivec2 quad) {
|
||||
uint extractLightId(ivec2 quad) {
|
||||
return Eu32v(quad, 8, 55);
|
||||
}
|
||||
|
||||
bool isQuadEmpty(ivec2 quad) {
|
||||
return all(equal(quad, ivec2(0)));
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user