From 53a66268cb558474f47809bf8de0605e5890c5b8 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 6 Sep 2021 22:51:46 -0500 Subject: [PATCH] Close issue #37 (z-fighting far from the origin) I'm not certain why in LodRenderer swapBuffers has to be called after the frame has been rendered, but otherwise it causes stuttering / rubber banding. --- .../seibel/lod/builders/LodBufferBuilder.java | 52 +++++++++++++------ .../lodTemplates/CubicLodTemplate.java | 19 ++++--- .../com/seibel/lod/render/LodRenderer.java | 46 +++++++++++----- 3 files changed, 82 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index 71cac492f..106f8b480 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -49,7 +49,7 @@ import net.minecraft.util.math.ChunkPos; * This object is used to create NearFarBuffer objects. * * @author James Seibel - * @version 8-24-2021 + * @version 9-6-2021 */ public class LodBufferBuilder { @@ -107,7 +107,13 @@ public class LodBufferBuilder private volatile Object[][] setsToRender; private volatile RegionPos center; - + + /** This is the ChunkPos the player was at the last time the buffers were built. + * IE the center of the buffers last time they were built */ + private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0,0); + private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0,0); + + public LodBufferBuilder() { @@ -159,11 +165,8 @@ public class LodBufferBuilder ArrayList> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length); startBuffers(fullRegen, lodDim); - - // =====================// - // RENDERING PART // - // =====================// - + + RegionPos playerRegionPos = new RegionPos(playerChunkPos); if (center == null) center = playerRegionPos; @@ -173,7 +176,10 @@ public class LodBufferBuilder if (setsToRender.length != lodDim.regions.length) setsToRender = new Object[lodDim.regions.length][lodDim.regions.length]; - + + // this will be the center of the VBOs once they have been built + buildableCenterChunkPos = playerChunkPos; + RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterX(), playerRegionPos.z - lodDim.getCenterZ()); if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0) @@ -293,8 +299,8 @@ public class LodBufferBuilder } } posToRender.changeParameters(detailLevel, posX, posZ); - - LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPos, lodData, adjData, + + LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, lodData, adjData, posToRender, renderer.previousDebugMode); } } catch (ArrayIndexOutOfBoundsException e) @@ -338,7 +344,7 @@ public class LodBufferBuilder // ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms" + '\n' + // "Tree cutting time: " + treeTime + " ms" + '\n' + // "Rendering time: " + renderingTime + " ms"); - + // mark that the buildable buffers as ready to swap switchVbos = true; } catch (Exception e) @@ -361,7 +367,7 @@ public class LodBufferBuilder } }); - + mainGenThread.execute(thread); return; @@ -571,7 +577,7 @@ public class LodBufferBuilder /** * Get the newly created VBOs */ - public VertexBuffer[][] getVertexBuffers() + public VertexBuffersAndOffset getVertexBuffers() { // don't wait for the lock to open // since this is called on the main render thread @@ -580,13 +586,29 @@ public class LodBufferBuilder VertexBuffer[][] tmp = drawableVbos; drawableVbos = buildableVbos; buildableVbos = tmp; - + + drawableCenterChunkPos = buildableCenterChunkPos; + // the vbos have been swapped switchVbos = false; bufferLock.unlock(); } - return drawableVbos; + return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos); + } + /** + * A simple container to pass multiple objects back in the getVertexBuffers method. + */ + public class VertexBuffersAndOffset + { + public VertexBuffer[][] vbos; + public ChunkPos drawableCenterChunkPos; + + public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos) + { + vbos = newVbos; + drawableCenterChunkPos = newDrawableCenterChunkPos; + } } /** diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java index dff5e5c0f..07b7e764f 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -35,7 +35,7 @@ import net.minecraft.util.math.BlockPos; * Builds LODs as rectangular prisms. * * @author James Seibel - * @version 8-10-2021 + * @version 9-6-2021 */ public class CubicLodTemplate extends AbstractLodTemplate { @@ -47,7 +47,7 @@ public class CubicLodTemplate extends AbstractLodTemplate } @Override - public void addLodToBuffer(BufferBuilder buffer, BlockPos playerBlockPos, short[] data, short[][][] adjData, + public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, short[] data, short[][][] adjData, LevelPos levelPos, DebugMode debugging) { AxisAlignedBB bbox; @@ -61,7 +61,8 @@ public class CubicLodTemplate extends AbstractLodTemplate width, levelPos.posX * width, 0, - levelPos.posZ * width); + levelPos.posZ * width, + bufferCenterBlockPos); int color = DataPoint.getColor(data); if (debugging != DebugMode.OFF) @@ -71,12 +72,12 @@ public class CubicLodTemplate extends AbstractLodTemplate if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, color, playerBlockPos, adjData); + addBoundingBoxToBuffer(buffer, bbox, color, bufferCenterBlockPos, adjData); } } - private AxisAlignedBB generateBoundingBox(int height, int depth, int width, double xOffset, double yOffset, double zOffset) + private AxisAlignedBB generateBoundingBox(int height, int depth, int width, double xOffset, double yOffset, double zOffset, BlockPos bufferCenterBlockPos) { // don't add an LOD if it is empty if (height == -1 && depth == -1) @@ -89,7 +90,13 @@ public class CubicLodTemplate extends AbstractLodTemplate height++; } - return new AxisAlignedBB(0, depth, 0, width, height, width).move(xOffset, yOffset, zOffset); + // offset the AABB by it's x/z position in the world since + // it uses doubles to specify its location, unlike the model view matrix + // which only uses floats + double x = -bufferCenterBlockPos.getX(); + double z = -bufferCenterBlockPos.getZ(); + + return new AxisAlignedBB(0, depth, 0, width, height, width).move(xOffset, yOffset, zOffset).move(x, 0, z); } private void addBoundingBoxToBuffer(BufferBuilder buffer, AxisAlignedBB bb, int c, BlockPos playerBlockPos, short[][][] adjData) diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index 83b42b707..a0e2c7e17 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -31,6 +31,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.seibel.lod.builders.LodBufferBuilder; +import com.seibel.lod.builders.LodBufferBuilder.VertexBuffersAndOffset; import com.seibel.lod.config.LodConfig; import com.seibel.lod.enums.DebugMode; import com.seibel.lod.enums.FogDistance; @@ -56,6 +57,7 @@ import net.minecraft.entity.Entity; import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Effects; import net.minecraft.profiler.IProfiler; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Matrix4f; @@ -68,7 +70,7 @@ import net.minecraft.util.math.vector.Vector3f; * This is where LODs are draw to the world. * * @author James Seibel - * @version 8-31-2021 + * @version 9-6-2021 */ public class LodRenderer { @@ -120,7 +122,7 @@ public class LodRenderer */ private VertexBuffer[][] vbos; public static final VertexFormat LOD_VERTEX_FORMAT = DefaultVertexFormats.POSITION_COLOR; - + private ChunkPos vbosCenter = new ChunkPos(0,0); /** * This is used to determine if the LODs should be regenerated @@ -228,14 +230,6 @@ public class LodRenderer // TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead) // ...ending here - // replace the buffers used to draw and build, - // this is only done when the createLodBufferGenerationThread - // has finished executing on a parallel thread. - if (lodBufferBuilder.newBuffersAvaliable()) - { - swapBuffers(); - } - //===========================// @@ -346,6 +340,18 @@ public class LodRenderer GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); + + // replace the buffers used to draw and build, + // this is only done when the createLodBufferGenerationThread + // has finished executing on a parallel thread. + if (lodBufferBuilder.newBuffersAvaliable()) + { + // this has to be called after the VBOs have been drawn + // otherwise rubber banding may occur + swapBuffers(); + } + + // end of internal LOD profiling profiler.pop(); } @@ -490,10 +496,17 @@ public class LodRenderer // generate the model view matrix MatrixStack matrixStack = new MatrixStack(); matrixStack.pushPose(); - // translate and rotate to the current camera location + // rotate to the current camera's direction matrixStack.mulPose(Vector3f.XP.rotationDegrees(renderInfo.getXRot())); matrixStack.mulPose(Vector3f.YP.rotationDegrees(renderInfo.getYRot() + 180)); - matrixStack.translate(-projectedView.x, -projectedView.y, -projectedView.z); + // translate the camera relative to the regions' center + // (AxisAlignedBoundingBoxes (LODs) use doubles and thus have a higher + // accuracy vs the model view matrix, which only uses floats) + BlockPos bufferPos = vbosCenter.getWorldPosition(); + Vector3d eyePos = mc.getPlayer().getEyePosition(partialTicks); + double xDiff = eyePos.x - bufferPos.getX(); + double zDiff = eyePos.z - bufferPos.getZ(); + matrixStack.translate(-xDiff, -projectedView.y, -zDiff); return matrixStack.last().pose(); } @@ -638,13 +651,18 @@ public class LodRenderer /** * Replace the current Vertex Buffers with the newly - * created buffers from the lodBufferBuilder. + * created buffers from the lodBufferBuilder.

+ * + * For some reason this has to be called after the frame has been rendered, + * otherwise visual stuttering/rubber banding may happen. I'm not sure why... */ private void swapBuffers() { // replace the drawable buffers with // the newly created buffers from the lodBufferBuilder - vbos = lodBufferBuilder.getVertexBuffers(); + VertexBuffersAndOffset result = lodBufferBuilder.getVertexBuffers(); + vbos = result.vbos; + vbosCenter = result.drawableCenterChunkPos; } /**