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.
This commit is contained in:
James Seibel
2021-09-06 22:51:46 -05:00
parent 139867d4b8
commit 53a66268cb
3 changed files with 82 additions and 35 deletions
@@ -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<Callable<Boolean>> 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;
}
}
/**
@@ -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)
@@ -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. <br><br>
*
* 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;
}
/**