Added min chunk bounds + fix other bugs in model baking and other places
This commit is contained in:
@@ -7,6 +7,7 @@ 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.ModelBakerySubsystem;
|
||||
import me.cortex.voxy.client.core.rendering.ChunkBoundRenderer;
|
||||
import me.cortex.voxy.client.core.rendering.RenderDistanceTracker;
|
||||
import me.cortex.voxy.client.core.rendering.RenderService;
|
||||
import me.cortex.voxy.client.core.rendering.building.RenderDataFactory45;
|
||||
@@ -22,6 +23,7 @@ import me.cortex.voxy.common.world.WorldEngine;
|
||||
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.ChunkRenderMatrices;
|
||||
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gl.GlBackend;
|
||||
@@ -29,6 +31,7 @@ import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.Frustum;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -45,6 +48,7 @@ public class VoxyRenderSystem {
|
||||
private final PostProcessing postProcessing;
|
||||
private final WorldEngine worldIn;
|
||||
private final RenderDistanceTracker renderDistanceTracker;
|
||||
public final ChunkBoundRenderer chunkBoundRenderer;
|
||||
|
||||
public VoxyRenderSystem(WorldEngine world, ServiceThreadPool threadPool) {
|
||||
//Trigger the shared index buffer loading
|
||||
@@ -62,6 +66,8 @@ public class VoxyRenderSystem {
|
||||
this.renderer::removeTopLevelNode);
|
||||
|
||||
this.renderDistanceTracker.setRenderDistance(VoxyConfig.CONFIG.sectionRenderDistance);
|
||||
|
||||
this.chunkBoundRenderer = new ChunkBoundRenderer();
|
||||
}
|
||||
|
||||
public void setRenderDistance(int renderDistance) {
|
||||
@@ -130,13 +136,14 @@ public class VoxyRenderSystem {
|
||||
}
|
||||
|
||||
//TODO: Make a reverse z buffer
|
||||
private static Matrix4f computeProjectionMat() {
|
||||
return new Matrix4f(RenderSystem.getProjectionMatrix()).mulLocal(
|
||||
makeProjectionMatrix(0.05f, MinecraftClient.getInstance().gameRenderer.getFarPlaneDistance()).invert()
|
||||
private static Matrix4f computeProjectionMat(Matrix4fc base) {
|
||||
return base.mulLocal(
|
||||
makeProjectionMatrix(0.05f, MinecraftClient.getInstance().gameRenderer.getFarPlaneDistance()).invert(),
|
||||
new Matrix4f()
|
||||
).mulLocal(makeProjectionMatrix(16, 16*3000));
|
||||
}
|
||||
|
||||
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
|
||||
public void renderOpaque(ChunkRenderMatrices matrices, double cameraX, double cameraY, double cameraZ) {
|
||||
if (IrisUtil.irisShadowActive()) {
|
||||
return;
|
||||
}
|
||||
@@ -165,17 +172,13 @@ public class VoxyRenderSystem {
|
||||
cameraY += (16+(256-32-sector*30))*16;
|
||||
}
|
||||
|
||||
matrices.push();
|
||||
matrices.translate(-cameraX, -cameraY, -cameraZ);
|
||||
matrices.pop();
|
||||
|
||||
var projection = computeProjectionMat();//RenderSystem.getProjectionMatrix();
|
||||
//var projection = RenderSystem.getProjectionMatrix();
|
||||
var projection = computeProjectionMat(matrices.projection());//RenderSystem.getProjectionMatrix();
|
||||
//var projection = new Matrix4f(matrices.projection());
|
||||
|
||||
var viewport = this.renderer.getViewport();
|
||||
viewport
|
||||
.setProjection(projection)
|
||||
.setModelView(matrices.peek().getPositionMatrix())
|
||||
.setModelView(new Matrix4f(matrices.modelView()))
|
||||
.setCamera(cameraX, cameraY, cameraZ)
|
||||
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight)
|
||||
.update();
|
||||
@@ -190,22 +193,25 @@ public class VoxyRenderSystem {
|
||||
if (boundFB == 0) {
|
||||
throw new IllegalStateException("Cannot use the default framebuffer as cannot source from it");
|
||||
}
|
||||
|
||||
this.chunkBoundRenderer.render(viewport);
|
||||
|
||||
//TODO: use the raw depth buffer texture instead
|
||||
//int boundDepthBuffer = glGetNamedFramebufferAttachmentParameteri(boundFB, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
|
||||
//TODO:FIXME!!! ??
|
||||
this.postProcessing.setup(target.textureWidth, target.textureHeight, boundFB);
|
||||
|
||||
this.renderer.renderFarAwayOpaque(viewport);
|
||||
this.renderer.renderFarAwayOpaque(viewport, this.chunkBoundRenderer.getDepthBoundTexture());
|
||||
|
||||
//Compute the SSAO of the rendered terrain, TODO: fix it breaking depth or breaking _something_ am not sure what
|
||||
this.postProcessing.computeSSAO(projection, matrices);
|
||||
this.postProcessing.computeSSAO(viewport.MVP);
|
||||
|
||||
//We can render the translucent directly after as it is the furthest translucent objects
|
||||
this.renderer.renderFarAwayTranslucent(viewport);
|
||||
this.renderer.renderFarAwayTranslucent(viewport, this.chunkBoundRenderer.getDepthBoundTexture());
|
||||
|
||||
|
||||
this.postProcessing.renderPost(projection, RenderSystem.getProjectionMatrix(), boundFB);
|
||||
this.postProcessing.renderPost(projection, matrices.projection(), boundFB);
|
||||
glBindFramebuffer(GlConst.GL_FRAMEBUFFER, oldFB);
|
||||
TimingStatistics.main.stop();
|
||||
TimingStatistics.all.stop();
|
||||
@@ -225,7 +231,7 @@ public class VoxyRenderSystem {
|
||||
Logger.info("Flushing download stream");
|
||||
DownloadStream.INSTANCE.flushWaitClear();
|
||||
Logger.info("Shutting down rendering");
|
||||
try {this.renderer.shutdown();} catch (Exception e) {Logger.error("Error shutting down renderer", e);}
|
||||
try {this.renderer.shutdown();this.chunkBoundRenderer.free();} catch (Exception e) {Logger.error("Error shutting down renderer", e);}
|
||||
Logger.info("Shutting down post processor");
|
||||
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {Logger.error("Error shutting down post processor", e);}}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,14 @@ public class ModelBakerySubsystem {
|
||||
long budget = Math.min(totalBudget-200_000, totalBudget-(this.factory.resultJobs.size()*20_000L))-200_000;
|
||||
if (budget > 50_000) {
|
||||
Integer i = this.blockIdQueue.poll();
|
||||
while (i != null && (System.nanoTime() - start < budget)) {
|
||||
this.factory.addEntry(i);
|
||||
i = this.blockIdQueue.poll();
|
||||
if (i != null) {
|
||||
do {
|
||||
this.factory.addEntry(i);
|
||||
i = this.blockIdQueue.poll();
|
||||
} while (i != null && (System.nanoTime() - start < budget));
|
||||
if (i != null) {//We timedout on our budget and we have an entry so we must add it back
|
||||
this.blockIdQueue.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,12 +619,12 @@ public class ModelFactory {
|
||||
for (var dir : Direction.values()) {
|
||||
var data = textures[dir.getIndex()];
|
||||
float fd = TextureUtils.computeDepth(data, TextureUtils.DEPTH_MODE_AVG, checkMode);//Compute the min float depth, smaller means closer to the camera, range 0-1
|
||||
int depth = Math.round(fd * MODEL_TEXTURE_SIZE);
|
||||
//int depth = Math.round(fd * MODEL_TEXTURE_SIZE);
|
||||
//If fd is -1, it means that there was nothing rendered on that face and it should be discarded
|
||||
if (fd < -0.1) {
|
||||
res[dir.ordinal()] = -1;
|
||||
} else {
|
||||
res[dir.ordinal()] = ((float) depth)/MODEL_TEXTURE_SIZE;
|
||||
res[dir.ordinal()] = fd;//((float) depth)/MODEL_TEXTURE_SIZE;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
@@ -187,6 +187,12 @@ public class ModelTextureBakery {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, originalFramebuffer);
|
||||
}
|
||||
|
||||
private static boolean shouldReturnAirForFluid(BlockPos pos, int face) {
|
||||
var fv = Direction.byIndex(face).getVector();
|
||||
int dot = fv.getX()*pos.getX() + fv.getY()*pos.getY() + fv.getZ()*pos.getZ();
|
||||
return dot >= 1;
|
||||
}
|
||||
|
||||
private final BufferAllocator allocator = new BufferAllocator(786432);
|
||||
private void rasterView(BlockState state, BlockStateModel model, Matrix4f transform, long randomValue, int face, boolean renderFluid, GpuTexture texture, boolean hasDiscard) {
|
||||
var bb = new BufferBuilder(this.allocator, VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) {
|
||||
@@ -244,7 +250,7 @@ public class ModelTextureBakery {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
if (pos.equals(Direction.byIndex(face).getVector())) {
|
||||
if (shouldReturnAirForFluid(pos, face)) {
|
||||
return Blocks.AIR.getDefaultState();
|
||||
}
|
||||
|
||||
@@ -262,7 +268,7 @@ public class ModelTextureBakery {
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
if (pos.equals(Direction.byIndex(face).getVector())) {
|
||||
if (shouldReturnAirForFluid(pos, face)) {
|
||||
return Blocks.AIR.getDefaultState().getFluidState();
|
||||
}
|
||||
//if (pos.getY() == 1) {
|
||||
|
||||
@@ -8,6 +8,8 @@ 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.SharedIndexBuffer;
|
||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||
import me.cortex.voxy.common.Logger;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3i;
|
||||
@@ -19,6 +21,7 @@ import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
|
||||
import static org.lwjgl.opengl.GL15.glBindBuffer;
|
||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL30C.*;
|
||||
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
|
||||
import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
|
||||
import static org.lwjgl.opengl.GL45.glClearNamedFramebufferfv;
|
||||
|
||||
@@ -49,7 +52,8 @@ public class ChunkBoundRenderer {
|
||||
throw new IllegalStateException("At capacity");
|
||||
}
|
||||
if (this.chunk2idx.containsKey(pos)) {
|
||||
throw new IllegalArgumentException("Chunk already in map");
|
||||
Logger.warn("Chunk already in map: " + new ChunkPos(pos));
|
||||
return;
|
||||
}
|
||||
int idx = this.chunk2idx.size();
|
||||
this.chunk2idx.put(pos, idx);
|
||||
@@ -65,9 +69,10 @@ public class ChunkBoundRenderer {
|
||||
public void removeChunk(long pos) {
|
||||
int idx = this.chunk2idx.remove(pos);
|
||||
if (idx == -1) {
|
||||
throw new IllegalArgumentException("Chunk pos not in map");
|
||||
Logger.warn("Chunk not in map: " + new ChunkPos(pos));
|
||||
return;
|
||||
}
|
||||
if (idx == this.chunk2idx.size()-1) {
|
||||
if (idx == this.chunk2idx.size()) {
|
||||
//Dont need to do anything as heap is already compact
|
||||
return;
|
||||
}
|
||||
@@ -92,6 +97,8 @@ public class ChunkBoundRenderer {
|
||||
|
||||
//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) {
|
||||
if (this.chunk2idx.isEmpty()) return;
|
||||
|
||||
if (this.depthBuffer.getWidth() != viewport.width || this.depthBuffer.getHeight() != viewport.height) {
|
||||
this.depthBuffer.free();
|
||||
this.depthBuffer = new GlTexture().store(GL_DEPTH_COMPONENT24, 1, viewport.width, viewport.height);
|
||||
@@ -129,7 +136,10 @@ public class ChunkBoundRenderer {
|
||||
glBindVertexArray(RenderService.STATIC_VAO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this.frameBuffer.id);
|
||||
this.rasterShader.bind();
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
|
||||
//TODO: BATCH with multiple cubes per instance, this helps fill the pipe and should greatly improve performance of this
|
||||
|
||||
glDrawElementsInstanced(GL_TRIANGLES, 6*2*3, GL_UNSIGNED_BYTE, SharedIndexBuffer.CUBE_INDEX_OFFSET, this.chunk2idx.size());
|
||||
|
||||
{
|
||||
@@ -139,10 +149,14 @@ public class ChunkBoundRenderer {
|
||||
|
||||
//TODO: check this is correct
|
||||
glEnable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.chunk2idx.clear();
|
||||
}
|
||||
|
||||
public void free() {
|
||||
this.depthBuffer.free();
|
||||
this.frameBuffer.free();
|
||||
@@ -151,4 +165,8 @@ public class ChunkBoundRenderer {
|
||||
this.uniformBuffer.free();
|
||||
this.chunkPosBuffer.free();
|
||||
}
|
||||
|
||||
public GlTexture getDepthBoundTexture() {
|
||||
return this.depthBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.netty.util.internal.MathUtil;
|
||||
import me.cortex.voxy.client.RenderStatistics;
|
||||
import me.cortex.voxy.client.TimingStatistics;
|
||||
import me.cortex.voxy.client.core.gl.Capabilities;
|
||||
import me.cortex.voxy.client.core.gl.GlTexture;
|
||||
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
|
||||
import me.cortex.voxy.client.core.model.ModelStore;
|
||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||
@@ -58,7 +59,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
|
||||
//Max geometry: 1 gb
|
||||
long geometryCapacity = Math.min((1L<<(64-Long.numberOfLeadingZeros(Capabilities.INSTANCE.ssboMaxSize-1)))<<1, 1L<<32)-1024/*(1L<<32)-1024*/;
|
||||
// geometryCapacity = 1<<24;
|
||||
//geometryCapacity = 1<<24;
|
||||
//Max sections: ~500k
|
||||
this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<20, geometryCapacity);
|
||||
Logger.info("Using renderer: " + this.sectionRenderer.getClass().getSimpleName());
|
||||
@@ -106,7 +107,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
this.modelService.tick();
|
||||
}
|
||||
|
||||
public void renderFarAwayOpaque(J viewport) {
|
||||
public void renderFarAwayOpaque(J viewport, GlTexture depthBoundTexture) {
|
||||
//LightMapHelper.tickLightmap();
|
||||
|
||||
//Render previous geometry with the abstract renderer
|
||||
@@ -117,7 +118,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
// the section renderer is as it might have different backends, but they all accept a buffer containing the section list
|
||||
|
||||
|
||||
this.sectionRenderer.renderOpaque(viewport);
|
||||
this.sectionRenderer.renderOpaque(viewport, depthBoundTexture);
|
||||
|
||||
|
||||
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
|
||||
@@ -174,11 +175,12 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
}
|
||||
this.traversal.doTraversal(viewport, depthBuffer);
|
||||
|
||||
this.sectionRenderer.buildDrawCallsAndRenderTemporal(viewport, this.traversal.getRenderListBuffer());
|
||||
this.sectionRenderer.buildDrawCalls(viewport, this.traversal.getRenderListBuffer());
|
||||
this.sectionRenderer.renderTemporal(depthBoundTexture);
|
||||
}
|
||||
|
||||
public void renderFarAwayTranslucent(J viewport) {
|
||||
this.sectionRenderer.renderTranslucent(viewport);
|
||||
public void renderFarAwayTranslucent(J viewport, GlTexture depthBoundTexture) {
|
||||
this.sectionRenderer.renderTranslucent(viewport, depthBoundTexture);
|
||||
}
|
||||
|
||||
public void addDebugData(List<String> debug) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
||||
import me.cortex.voxy.client.core.rendering.util.GlStateCapture;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.lwjgl.opengl.GL11C;
|
||||
|
||||
import static org.lwjgl.opengl.ARBComputeShader.glDispatchCompute;
|
||||
@@ -136,16 +137,14 @@ public class PostProcessing {
|
||||
|
||||
//Computes ssao on the current framebuffer data and updates it
|
||||
// this means that translucency wont be effected etc
|
||||
public void computeSSAO(Matrix4f projection, MatrixStack stack) {
|
||||
public void computeSSAO(Matrix4f mvp) {
|
||||
this.didSSAO = true;
|
||||
|
||||
this.ssaoComp.bind();
|
||||
float[] data = new float[4*4];
|
||||
var mat = new Matrix4f(projection).mul(stack.peek().getPositionMatrix());
|
||||
mat.get(data);
|
||||
mvp.get(data);
|
||||
glUniformMatrix4fv(3, false, data);//MVP
|
||||
mat.invert();
|
||||
mat.get(data);
|
||||
mvp.invert(new Matrix4f()).get(data);
|
||||
glUniformMatrix4fv(4, false, data);//invMVP
|
||||
|
||||
glBindImageTexture(0, this.colourSSAO.id, 0, false,0, GL_READ_WRITE, GL_RGBA8);
|
||||
@@ -159,7 +158,7 @@ public class PostProcessing {
|
||||
|
||||
|
||||
//Executes the post processing and emits to whatever framebuffer is currently bound via a blit
|
||||
public void renderPost(Matrix4f fromProjection, Matrix4f tooProjection, int outputFB) {
|
||||
public void renderPost(Matrix4f fromProjection, Matrix4fc tooProjection, int outputFB) {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.cortex.voxy.client.core.rendering.section;
|
||||
|
||||
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
import me.cortex.voxy.client.core.gl.GlTexture;
|
||||
import me.cortex.voxy.client.core.model.ModelStore;
|
||||
import me.cortex.voxy.client.core.rendering.Viewport;
|
||||
|
||||
@@ -16,9 +17,10 @@ public abstract class AbstractSectionRenderer <T extends Viewport<T>, J extends
|
||||
this.modelStore = modelStore;
|
||||
}
|
||||
|
||||
public abstract void renderOpaque(T viewport);
|
||||
public abstract void buildDrawCallsAndRenderTemporal(T viewport, GlBuffer sectionRenderList);
|
||||
public abstract void renderTranslucent(T viewport);
|
||||
public abstract void renderOpaque(T viewport, GlTexture depthBoundTexture);
|
||||
public abstract void buildDrawCalls(T viewport, GlBuffer sectionRenderList);
|
||||
public abstract void renderTemporal(GlTexture depthBoundTexture);
|
||||
public abstract void renderTranslucent(T viewport, GlTexture depthBoundTexture);
|
||||
public abstract T createViewport();
|
||||
public void free() {
|
||||
this.geometryManager.free();
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.cortex.voxy.client.core.rendering.section;
|
||||
|
||||
import me.cortex.voxy.client.RenderStatistics;
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
import me.cortex.voxy.client.core.gl.GlTexture;
|
||||
import me.cortex.voxy.client.core.gl.shader.Shader;
|
||||
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
||||
import me.cortex.voxy.client.core.model.ModelStore;
|
||||
@@ -100,27 +101,28 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
|
||||
}
|
||||
|
||||
|
||||
private void bindRenderingBuffers() {
|
||||
private void bindRenderingBuffers(GlTexture depthBoundTexture) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniform.id);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.geometryManager.getGeometryBufferId());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.geometryManager.getMetadataBufferId());
|
||||
this.modelStore.bind(3, 4, 0);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, this.positionScratchBuffer.id);
|
||||
LightMapHelper.bind(1);
|
||||
glBindTextureUnit(2, depthBoundTexture.id);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, this.drawCallBuffer.id);
|
||||
glBindBuffer(GL_PARAMETER_BUFFER_ARB, this.drawCountCallBuffer.id);
|
||||
}
|
||||
|
||||
private void renderTerrain(long indirectOffset, long drawCountOffset, int maxDrawCount) {
|
||||
private void renderTerrain(GlTexture depthBoundTexture, long indirectOffset, long drawCountOffset, int maxDrawCount) {
|
||||
//RenderLayer.getCutoutMipped().startDrawing();
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
this.terrainShader.bind();
|
||||
glBindVertexArray(RenderService.STATIC_VAO);//Needs to be before binding
|
||||
this.bindRenderingBuffers();
|
||||
this.bindRenderingBuffers(depthBoundTexture);
|
||||
|
||||
glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, indirectOffset, drawCountOffset, maxDrawCount, 0);
|
||||
|
||||
@@ -135,16 +137,16 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOpaque(MDICViewport viewport) {
|
||||
public void renderOpaque(MDICViewport viewport, GlTexture dbt) {
|
||||
if (this.geometryManager.getSectionCount() == 0) return;
|
||||
|
||||
this.uploadUniformBuffer(viewport);
|
||||
|
||||
this.renderTerrain(0, 4*3, Math.min((int)(this.geometryManager.getSectionCount()*4.4+128), 400_000));
|
||||
this.renderTerrain(dbt, 0, 4*3, Math.min((int)(this.geometryManager.getSectionCount()*4.4+128), 400_000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTranslucent(MDICViewport viewport) {
|
||||
public void renderTranslucent(MDICViewport viewport, GlTexture depthBoundTexture) {
|
||||
if (this.geometryManager.getSectionCount() == 0) return;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
@@ -153,7 +155,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
this.terrainShader.bind();
|
||||
glBindVertexArray(RenderService.STATIC_VAO);//Needs to be before binding
|
||||
this.bindRenderingBuffers();
|
||||
this.bindRenderingBuffers(depthBoundTexture);
|
||||
|
||||
glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, TRANSLUCENT_OFFSET*5*4, 4*4, Math.min(this.geometryManager.getSectionCount(), 100_000), 0);
|
||||
|
||||
@@ -168,7 +170,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildDrawCallsAndRenderTemporal(MDICViewport viewport, GlBuffer sectionRenderList) {
|
||||
public void buildDrawCalls(MDICViewport viewport, GlBuffer sectionRenderList) {
|
||||
if (this.geometryManager.getSectionCount() == 0) return;
|
||||
this.uploadUniformBuffer(viewport);
|
||||
//Can do a sneeky trick, since the sectionRenderList is a list to things to render, it invokes the culler
|
||||
@@ -243,8 +245,13 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTemporal(GlTexture dbt) {
|
||||
if (this.geometryManager.getSectionCount() == 0) return;
|
||||
//Render temporal
|
||||
this.renderTerrain(TEMPORAL_OFFSET*5*4, 4*5, Math.min(this.geometryManager.getSectionCount(), 100_000));
|
||||
this.renderTerrain(dbt, TEMPORAL_OFFSET*5*4, 4*5, Math.min(this.geometryManager.getSectionCount(), 100_000));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.cortex.voxy.client.core.rendering.util;
|
||||
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
import me.cortex.voxy.client.core.util.IndexUtil;
|
||||
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
@@ -16,7 +15,7 @@ public class SharedIndexBuffer {
|
||||
|
||||
public SharedIndexBuffer() {
|
||||
this.indexBuffer = new GlBuffer((1<<16)*6*2 + 6*2*3);
|
||||
var quadIndexBuff = IndexUtil.generateQuadIndicesShort(16380);
|
||||
var quadIndexBuff = generateQuadIndicesShort(16380);
|
||||
var cubeBuff = generateCubeIndexBuffer();
|
||||
|
||||
long ptr = UploadStream.INSTANCE.upload(this.indexBuffer, 0, this.indexBuffer.size());
|
||||
@@ -30,7 +29,7 @@ public class SharedIndexBuffer {
|
||||
|
||||
private SharedIndexBuffer(boolean type2) {
|
||||
this.indexBuffer = new GlBuffer((1<<8)*6 + 6*2*3);
|
||||
var quadIndexBuff = IndexUtil.generateQuadIndicesByte(63);
|
||||
var quadIndexBuff = generateQuadIndicesByte(63);
|
||||
var cubeBuff = generateCubeIndexBuffer();
|
||||
|
||||
long ptr = UploadStream.INSTANCE.upload(this.indexBuffer, 0, this.indexBuffer.size());
|
||||
@@ -97,6 +96,60 @@ public class SharedIndexBuffer {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static MemoryBuffer generateQuadIndicesByte(int quadCount) {
|
||||
if ((quadCount*4) >= 1<<8) {
|
||||
throw new IllegalArgumentException("Quad count to large");
|
||||
}
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutByte(ptr + (0), (byte) (i + 1));
|
||||
MemoryUtil.memPutByte(ptr + (1), (byte) (i + 2));
|
||||
MemoryUtil.memPutByte(ptr + (2), (byte) (i + 0));
|
||||
MemoryUtil.memPutByte(ptr + (3), (byte) (i + 1));
|
||||
MemoryUtil.memPutByte(ptr + (4), (byte) (i + 3));
|
||||
MemoryUtil.memPutByte(ptr + (5), (byte) (i + 2));
|
||||
|
||||
ptr += 6;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
public static MemoryBuffer generateQuadIndicesShort(int quadCount) {
|
||||
if ((quadCount*4) >= 1<<16) {
|
||||
throw new IllegalArgumentException("Quad count to large");
|
||||
}
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L * 2);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutShort(ptr + (0*2), (short) (i + 1));
|
||||
MemoryUtil.memPutShort(ptr + (1*2), (short) (i + 2));
|
||||
MemoryUtil.memPutShort(ptr + (2*2), (short) (i + 0));
|
||||
MemoryUtil.memPutShort(ptr + (3*2), (short) (i + 1));
|
||||
MemoryUtil.memPutShort(ptr + (4*2), (short) (i + 3));
|
||||
MemoryUtil.memPutShort(ptr + (5*2), (short) (i + 2));
|
||||
|
||||
ptr += 6 * 2;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static MemoryBuffer generateQuadIndicesInt(int quadCount) {
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L * 2);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutInt(ptr + (0*4), i);
|
||||
MemoryUtil.memPutInt(ptr + (1*4), (i + 1));
|
||||
MemoryUtil.memPutInt(ptr + (2*4), (i + 2));
|
||||
MemoryUtil.memPutInt(ptr + (3*4), (i + 1));
|
||||
MemoryUtil.memPutInt(ptr + (4*4), (i + 3));
|
||||
MemoryUtil.memPutInt(ptr + (5*4), (i + 2));
|
||||
ptr += 6 * 4;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return this.indexBuffer.id;
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package me.cortex.voxy.client.core.util;
|
||||
|
||||
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public class IndexUtil {
|
||||
public static MemoryBuffer generateQuadIndicesByte(int quadCount) {
|
||||
if ((quadCount*4) >= 1<<8) {
|
||||
throw new IllegalArgumentException("Quad count to large");
|
||||
}
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutByte(ptr + (0), (byte) (i + 1));
|
||||
MemoryUtil.memPutByte(ptr + (1), (byte) (i + 2));
|
||||
MemoryUtil.memPutByte(ptr + (2), (byte) (i + 0));
|
||||
MemoryUtil.memPutByte(ptr + (3), (byte) (i + 1));
|
||||
MemoryUtil.memPutByte(ptr + (4), (byte) (i + 3));
|
||||
MemoryUtil.memPutByte(ptr + (5), (byte) (i + 2));
|
||||
|
||||
ptr += 6;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
public static MemoryBuffer generateQuadIndicesShort(int quadCount) {
|
||||
if ((quadCount*4) >= 1<<16) {
|
||||
throw new IllegalArgumentException("Quad count to large");
|
||||
}
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L * 2);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutShort(ptr + (0*2), (short) (i + 1));
|
||||
MemoryUtil.memPutShort(ptr + (1*2), (short) (i + 2));
|
||||
MemoryUtil.memPutShort(ptr + (2*2), (short) (i + 0));
|
||||
MemoryUtil.memPutShort(ptr + (3*2), (short) (i + 1));
|
||||
MemoryUtil.memPutShort(ptr + (4*2), (short) (i + 3));
|
||||
MemoryUtil.memPutShort(ptr + (5*2), (short) (i + 2));
|
||||
|
||||
ptr += 6 * 2;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static MemoryBuffer generateQuadIndicesInt(int quadCount) {
|
||||
MemoryBuffer buffer = new MemoryBuffer(quadCount * 6L * 2);
|
||||
long ptr = buffer.address;
|
||||
for(int i = 0; i < quadCount*4; i += 4) {
|
||||
MemoryUtil.memPutInt(ptr + (0*4), i);
|
||||
MemoryUtil.memPutInt(ptr + (1*4), (i + 1));
|
||||
MemoryUtil.memPutInt(ptr + (2*4), (i + 2));
|
||||
MemoryUtil.memPutInt(ptr + (3*4), (i + 1));
|
||||
MemoryUtil.memPutInt(ptr + (4*4), (i + 3));
|
||||
MemoryUtil.memPutInt(ptr + (5*4), (i + 2));
|
||||
ptr += 6 * 4;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public abstract class MixinWorldRenderer implements IGetVoxyRenderSystem {
|
||||
return this.renderer;
|
||||
}
|
||||
|
||||
@Inject(method = "reload()V", at = @At("TAIL"))
|
||||
@Inject(method = "reload()V", at = @At("RETURN"), order = 900)//We want to inject before sodium
|
||||
private void reloadVoxyRenderer(CallbackInfo ci) {
|
||||
this.shutdownRenderer();
|
||||
if (this.world != null) {
|
||||
|
||||
@@ -24,10 +24,7 @@ public class MixinDefaultChunkRenderer {
|
||||
if (renderPass == DefaultTerrainRenderPasses.CUTOUT) {
|
||||
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
|
||||
if (renderer != null) {
|
||||
var stack = new MatrixStack();
|
||||
stack.loadIdentity();
|
||||
stack.multiplyPositionMatrix(new Matrix4f(matrices.modelView()));
|
||||
renderer.renderOpaque(stack, camera.x, camera.y, camera.z);
|
||||
renderer.renderOpaque(matrices, camera.x, camera.y, camera.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package me.cortex.voxy.client.mixin.sodium;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import me.cortex.voxy.client.VoxyClientInstance;
|
||||
import me.cortex.voxy.client.config.VoxyConfig;
|
||||
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||
import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
|
||||
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -17,12 +20,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public class MixinRenderSectionManager {
|
||||
@Shadow @Final private ClientWorld level;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void voxy$resetChunkTracker(ClientWorld level, int renderDistance, CommandList commandList, CallbackInfo ci) {
|
||||
if (level.worldRenderer != null) {
|
||||
var system = ((IGetVoxyRenderSystem)(level.worldRenderer)).getVoxyRenderSystem();
|
||||
if (system != null) {
|
||||
system.chunkBoundRenderer.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onChunkAdded", at = @At("HEAD"))
|
||||
private void voxy$trackChunkAdd(int x, int z, CallbackInfo ci) {
|
||||
if (this.level.worldRenderer != null) {
|
||||
var system = ((IGetVoxyRenderSystem)(this.level.worldRenderer)).getVoxyRenderSystem();
|
||||
if (system != null) {
|
||||
|
||||
system.chunkBoundRenderer.addChunk(ChunkPos.toLong(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +45,7 @@ public class MixinRenderSectionManager {
|
||||
if (this.level.worldRenderer != null) {
|
||||
var system = ((IGetVoxyRenderSystem)(this.level.worldRenderer)).getVoxyRenderSystem();
|
||||
if (system != null) {
|
||||
|
||||
system.chunkBoundRenderer.removeChunk(ChunkPos.toLong(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,4 +65,13 @@ public class MixinRenderSectionManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ModifyReturnValue(method = "getSearchDistance", at = @At("RETURN"))
|
||||
private float voxy$increaseSearchDistanceFix(float searchDistance) {
|
||||
if (((IGetVoxyRenderSystem)(this.level.worldRenderer)).getVoxyRenderSystem() == null) {
|
||||
return searchDistance;
|
||||
}
|
||||
return searchDistance + 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ layout(binding = 1, std430) restrict readonly buffer ChunkPosBuffer {
|
||||
};
|
||||
|
||||
void main() {
|
||||
ivec3 origin = ivec3(chunkPos[gl_InstanceID], 0).xzy;
|
||||
origin -= section.xyz;
|
||||
|
||||
ivec3 cubeCornerI = ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1);
|
||||
cubeCornerI.xz += chunkPos[gl_InstanceID];
|
||||
//Expand the y height to be big (will be +- 8192)
|
||||
//TODO: make it W.R.T world height and offsets
|
||||
cubeCornerI.y = cubeCornerI.y*1024-512;
|
||||
cubeCornerI -= section.xyz;
|
||||
gl_Position = MVP * vec4(vec3(cubeCornerI*16), 1);
|
||||
cubeCornerI.y = cubeCornerI.y*32-16;
|
||||
gl_Position = MVP * vec4(vec3(cubeCornerI+origin)*16, 1);
|
||||
gl_Position.z -= 0.0001f;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#version 460 core
|
||||
layout(binding = 0) uniform sampler2D blockModelAtlas;
|
||||
layout(binding = 2) uniform sampler2D depthTex;
|
||||
|
||||
//#define DEBUG_RENDER
|
||||
|
||||
@@ -19,6 +20,10 @@ layout(location = 6) in flat uint quadDebug;
|
||||
#endif
|
||||
layout(location = 0) out vec4 outColour;
|
||||
void main() {
|
||||
//Check the minimum bounding texture and ensure we are greater than it
|
||||
if (gl_FragCoord.z < texelFetch(depthTex, ivec2(gl_FragCoord.xy), 0).r) {
|
||||
discard;
|
||||
}
|
||||
vec2 uv = mod(uv, vec2(1.0))*(1.0/(vec2(3.0,2.0)*256.0));
|
||||
//vec4 colour = solidColour;
|
||||
vec4 colour = texture(blockModelAtlas, uv + baseUV, ((flags>>1)&1u)*-4.0);
|
||||
|
||||
Reference in New Issue
Block a user