aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormakamys <makamys@outlook.com>2023-12-02 17:59:34 +0100
committermakamys <makamys@outlook.com>2023-12-03 00:48:45 +0100
commit2f4979260b60f90ef0fce1b9305b74bcd9fb8af5 (patch)
tree1faa8cc83615e167d7eba206b0c24a6a599e33dd /src
parent1b32e6e42aa0d377ee7556b504130e37e26463bf (diff)
downloadNeodymium-2f4979260b60f90ef0fce1b9305b74bcd9fb8af5.tar.gz
Neodymium-2f4979260b60f90ef0fce1b9305b74bcd9fb8af5.tar.bz2
Neodymium-2f4979260b60f90ef0fce1b9305b74bcd9fb8af5.zip
Fix camera shake at high distances
- Made chunk meshes use region-relative coordinates - Moved mesh tracking to NeoRegion - Regions are now drawn separately, allowing a different translation to be set for each
Diffstat (limited to 'src')
-rw-r--r--src/main/java/makamys/neodymium/renderer/ChunkMesh.java2
-rw-r--r--src/main/java/makamys/neodymium/renderer/Comparators.java26
-rw-r--r--src/main/java/makamys/neodymium/renderer/Mesh.java1
-rw-r--r--src/main/java/makamys/neodymium/renderer/NeoRegion.java46
-rw-r--r--src/main/java/makamys/neodymium/renderer/NeoRenderer.java66
-rw-r--r--src/main/java/makamys/neodymium/util/Util.java6
-rw-r--r--src/main/resources/shaders/chunk.vert8
7 files changed, 125 insertions, 30 deletions
diff --git a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
index 5bd38f6..24acc30 100644
--- a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
+++ b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
@@ -114,7 +114,7 @@ public class ChunkMesh extends Mesh {
for(int quadI = 0; quadI < t.vertexCount / verticesPerPrimitive; quadI++) {
MeshQuad quad = quadBuf.next();
- quad.setState(t.rawBuffer, tessellatorVertexSize, quadI * (verticesPerPrimitive * tessellatorVertexSize), FLAGS, t.drawMode, (float)-t.xOffset, (float)-t.yOffset, (float)-t.zOffset);
+ quad.setState(t.rawBuffer, tessellatorVertexSize, quadI * (verticesPerPrimitive * tessellatorVertexSize), FLAGS, t.drawMode, NeoRegion.toRelativeOffset(-t.xOffset), NeoRegion.toRelativeOffset(-t.yOffset), NeoRegion.toRelativeOffset(-t.zOffset));
if(quad.deleted) {
quadBuf.remove();
}
diff --git a/src/main/java/makamys/neodymium/renderer/Comparators.java b/src/main/java/makamys/neodymium/renderer/Comparators.java
index f72cad9..0863b17 100644
--- a/src/main/java/makamys/neodymium/renderer/Comparators.java
+++ b/src/main/java/makamys/neodymium/renderer/Comparators.java
@@ -4,6 +4,7 @@ import java.util.Comparator;
public class Comparators {
public static final MeshDistanceComparator MESH_DISTANCE_COMPARATOR = new MeshDistanceComparator();
+ public static final RegionDistanceComparator REGION_DISTANCE_COMPARATOR = new RegionDistanceComparator();
public static class MeshDistanceComparator implements Comparator<Mesh> {
double x, y, z;
@@ -44,4 +45,29 @@ public class Comparators {
}
}
+
+ public static class RegionDistanceComparator implements Comparator<NeoRegion> {
+ double x, y, z;
+
+ public RegionDistanceComparator setOrigin(double x, double y, double z) {
+ this.x = x / (NeoRegion.SIZE * 16.0);
+ this.y = y / (NeoRegion.SIZE * 16.0);
+ this.z = z / (NeoRegion.SIZE * 16.0);
+ return this;
+ }
+
+ @Override
+ public int compare(NeoRegion a, NeoRegion b) {
+ double distSqA = a.distSq(x, y, z);
+ double distSqB = b.distSq(x, y, z);
+
+ if(distSqA > distSqB) {
+ return 1;
+ } else if(distSqA < distSqB) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
}
diff --git a/src/main/java/makamys/neodymium/renderer/Mesh.java b/src/main/java/makamys/neodymium/renderer/Mesh.java
index 6c70523..1fe5003 100644
--- a/src/main/java/makamys/neodymium/renderer/Mesh.java
+++ b/src/main/java/makamys/neodymium/renderer/Mesh.java
@@ -18,6 +18,7 @@ public abstract class Mesh {
public int pass;
int x, y, z;
public QuadNormal normal = QuadNormal.NONE;
+ public NeoRegion containingRegion;
public double distSq(double x2, double y2, double z2) {
return Util.distSq(x + 0.5, y + 0.5, z + 0.5, x2, y2, z2);
diff --git a/src/main/java/makamys/neodymium/renderer/NeoRegion.java b/src/main/java/makamys/neodymium/renderer/NeoRegion.java
index 36f5909..7e85138 100644
--- a/src/main/java/makamys/neodymium/renderer/NeoRegion.java
+++ b/src/main/java/makamys/neodymium/renderer/NeoRegion.java
@@ -1,11 +1,19 @@
package makamys.neodymium.renderer;
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import makamys.neodymium.util.Util;
import net.minecraft.entity.Entity;
public class NeoRegion {
- public static final int SIZE = 32;
+ public static final int SIZE = 64;
private NeoChunk[][] data = new NeoChunk[SIZE][SIZE];
+ @Getter
+ private RenderData renderData;
int regionX, regionZ;
@@ -16,6 +24,7 @@ public class NeoRegion {
public NeoRegion(int regionX, int regionZ) {
this.regionX = regionX;
this.regionZ = regionZ;
+ this.renderData = new RenderData(regionX * SIZE * 16, 0, regionZ * SIZE * 16);
for(int i = 0; i < SIZE; i++) {
for(int j = 0; j < SIZE; j++) {
@@ -76,13 +85,42 @@ public class NeoRegion {
}
+ public double distSq(double x, double y, double z) {
+ return Util.distSq(regionX + 0.5, 0, regionZ + 0.5, x, y, z);
+ }
+
+ public static float toRelativeOffset(double d) {
+ return (float)(d - (Math.floor(d / (SIZE * 16.0)) * SIZE * 16.0));
+ }
+
@Override
public String toString() {
return "LODRegion(" + regionX + ", " + regionZ + ")";
}
- public boolean shouldDelete() {
- return emptyTicks > 100;
+ public boolean shouldDelete() {
+ return emptyTicks > 100;
+ }
+
+ @RequiredArgsConstructor
+ public static class RenderData {
+ public final double originX, originY, originZ;
+
+ private List<Mesh>[] sentMeshes = (List<Mesh>[])new ArrayList[] {new ArrayList<Mesh>(), new ArrayList<Mesh>()};
+ public int[] batchLimit = new int[2];
+ public int[] batchFirst = new int[2];
+
+ public void sort(double eyePosX, double eyePosY, double eyePosZ, boolean pass0, boolean pass1) {
+ if(pass0) {
+ sentMeshes[0].sort(Comparators.MESH_DISTANCE_COMPARATOR.setOrigin(eyePosX, eyePosY, eyePosZ).setInverted(false));
+ }
+ if(pass1) {
+ sentMeshes[1].sort(Comparators.MESH_DISTANCE_COMPARATOR.setOrigin(eyePosX, eyePosY, eyePosZ).setInverted(true));
+ }
+ }
+
+ public List<Mesh> getSentMeshes(int i) {
+ return sentMeshes[i];
+ }
}
-
}
diff --git a/src/main/java/makamys/neodymium/renderer/NeoRenderer.java b/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
index 1caf301..6c0b015 100644
--- a/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
+++ b/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
@@ -12,14 +12,11 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import makamys.neodymium.Compat;
import makamys.neodymium.renderer.attribs.AttributeSet;
@@ -72,11 +69,11 @@ public class NeoRenderer {
private int[] shaderProgramsNoFog = {0, 0};
private IntBuffer[] piFirst = new IntBuffer[2];
private IntBuffer[] piCount = new IntBuffer[2];
- private List<Mesh>[] sentMeshes = (List<Mesh>[])new ArrayList[] {new ArrayList<Mesh>(), new ArrayList<Mesh>()};
GPUMemoryManager mem;
private AttributeSet attributes;
private Map<ChunkCoordIntPair, NeoRegion> loadedRegionsMap = new HashMap<>();
+ private List<NeoRegion> loadedRegionsList = new ArrayList<>();
public World world;
@@ -181,27 +178,34 @@ public class NeoRenderer {
}
private void sort(boolean pass0, boolean pass1) {
- if(pass0) {
- sentMeshes[0].sort(Comparators.MESH_DISTANCE_COMPARATOR.setOrigin(eyePosX, eyePosY, eyePosZ).setInverted(false));
- }
- if(pass1) {
- sentMeshes[1].sort(Comparators.MESH_DISTANCE_COMPARATOR.setOrigin(eyePosX, eyePosY, eyePosZ).setInverted(true));
+ for(NeoRegion r : loadedRegionsMap.values()) {
+ r.getRenderData().sort(eyePosX, eyePosY, eyePosZ, pass0, pass1);
}
}
private void initIndexBuffers() {
+ loadedRegionsList.clear();
+ loadedRegionsList.addAll(loadedRegionsMap.values());
+ loadedRegionsList.sort(Comparators.REGION_DISTANCE_COMPARATOR.setOrigin(eyePosX, eyePosY, eyePosZ));
+
for(int i = 0; i < 2; i++) {
piFirst[i].limit(MAX_MESHES);
piCount[i].limit(MAX_MESHES);
- for(Mesh mesh : sentMeshes[i]) {
- WorldRenderer wr = ((ChunkMesh)mesh).wr;
- if(mesh.visible && wr.isVisible && shouldRenderMesh(mesh)) {
- int meshes = mesh.writeToIndexBuffer(piFirst[i], piCount[i], eyePosXTDiv, eyePosYTDiv, eyePosZTDiv, i);
- renderedMeshes += meshes;
- for(int j = piCount[i].position() - meshes; j < piCount[i].position(); j++) {
- renderedQuads += piCount[i].get(j) / 4;
+ int order = i == 0 ? 1 : -1;
+ for(int regionI = order == 1 ? 0 : loadedRegionsList.size() - 1; regionI >= 0 && regionI < loadedRegionsList.size(); regionI += order) {
+ NeoRegion.RenderData region = loadedRegionsList.get(regionI).getRenderData();
+ region.batchFirst[i] = piFirst[i].position();
+ for(Mesh mesh : region.getSentMeshes(i)) {
+ WorldRenderer wr = ((ChunkMesh)mesh).wr;
+ if(mesh.visible && wr.isVisible && shouldRenderMesh(mesh)) {
+ int meshes = mesh.writeToIndexBuffer(piFirst[i], piCount[i], eyePosXTDiv, eyePosYTDiv, eyePosZTDiv, i);
+ renderedMeshes += meshes;
+ for(int j = piCount[i].position() - meshes; j < piCount[i].position(); j++) {
+ renderedQuads += piCount[i].get(j) / 4;
+ }
}
}
+ region.batchLimit[i] = piFirst[i].position();
}
piFirst[i].flip();
piCount[i].flip();
@@ -296,7 +300,23 @@ public class NeoRenderer {
if(isWireframeEnabled()) {
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
}
- glMultiDrawArrays(GL_QUADS, piFirst[pass], piCount[pass]);
+
+ int u_renderOffset = glGetUniformLocation(getShaderProgram(pass), "renderOffset");
+
+ int oldLimit = piFirst[pass].limit();
+
+ int order = pass == 0 ? 1 : -1;
+ for(int regionI = order == 1 ? 0 : loadedRegionsList.size() - 1; regionI >= 0 && regionI < loadedRegionsList.size(); regionI += order) {
+ NeoRegion.RenderData region = loadedRegionsList.get(regionI).getRenderData();
+ Util.setPositionAndLimit(piFirst[pass], region.batchFirst[pass], region.batchLimit[pass]);
+ Util.setPositionAndLimit(piCount[pass], region.batchFirst[pass], region.batchLimit[pass]);
+
+ glUniform3f(u_renderOffset, (float)(region.originX - eyePosX), (float)(region.originY - eyePosY), (float)(region.originZ - eyePosZ));
+ glMultiDrawArrays(GL_QUADS, piFirst[pass], piCount[pass]);
+ }
+ Util.setPositionAndLimit(piFirst[pass], 0, oldLimit);
+ Util.setPositionAndLimit(piCount[pass], 0, oldLimit);
+
if(isWireframeEnabled()) {
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
}
@@ -363,7 +383,7 @@ public class NeoRenderer {
glUniform2(u_fogStartEnd, fogStartEnd);
glUniform1i(u_fogMode, glGetInteger(GL_FOG_MODE));
glUniform1f(u_fogDensity, glGetFloat(GL_FOG_DENSITY));
-
+
glUniform3f(u_playerPos, (float)eyePosX, (float)eyePosY, (float)eyePosZ);
if (Compat.RPLE()) {
@@ -606,7 +626,9 @@ public class NeoRenderer {
if(mesh.gpuStatus == GPUStatus.UNSENT) {
mem.sendMeshToGPU(mesh);
- sentMeshes[mesh.pass].add(mesh);
+ NeoRegion region = getRegionContaining(mesh.x, mesh.z);
+ region.getRenderData().getSentMeshes(mesh.pass).add(mesh);
+ mesh.containingRegion = region;
}
}
}
@@ -615,7 +637,9 @@ public class NeoRenderer {
if(mesh == null) return;
mem.deleteMeshFromGPU(mesh);
- sentMeshes[mesh.pass].remove(mesh);
+ if(mesh.containingRegion != null) {
+ mesh.containingRegion.getRenderData().getSentMeshes(mesh.pass).remove(mesh);
+ }
setMeshVisible(mesh, false);
}
@@ -669,4 +693,4 @@ public class NeoRenderer {
public static enum WorldRendererChange {
VISIBLE, INVISIBLE, DELETED
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/makamys/neodymium/util/Util.java b/src/main/java/makamys/neodymium/util/Util.java
index cd43358..46cd0f0 100644
--- a/src/main/java/makamys/neodymium/util/Util.java
+++ b/src/main/java/makamys/neodymium/util/Util.java
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
+import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
@@ -110,4 +111,9 @@ public class Util {
public static int createBrightness(int sky, int block) {
return sky << 20 | block << 4;
}
+
+ public static void setPositionAndLimit(Buffer buffer, int position, int limit) {
+ buffer.position(position);
+ buffer.limit(limit);
+ }
}
diff --git a/src/main/resources/shaders/chunk.vert b/src/main/resources/shaders/chunk.vert
index 9988605..56bc2d6 100644
--- a/src/main/resources/shaders/chunk.vert
+++ b/src/main/resources/shaders/chunk.vert
@@ -19,7 +19,7 @@ uniform vec2 fogStartEnd;
uniform int fogMode;
uniform float fogDensity;
-uniform vec3 playerPos;
+uniform vec3 renderOffset;
out vec2 TexCoord;
#ifdef RPLE
@@ -38,7 +38,8 @@ out float FogFactor; // -1 means: disable fog
void main()
{
- gl_Position = proj * modelView * (vec4(aPos - playerPos, 1.0) + vec4(0, 0.12, 0, 0));
+ vec4 untransformedPos = (vec4(aPos, 1.0) + vec4(renderOffset.x, renderOffset.y + 0.12, renderOffset.z, 0));
+ gl_Position = proj * modelView * untransformedPos;
TexCoord = aTexCoord;
#ifdef RPLE
BTexCoordR = aBTexCoordR;
@@ -56,8 +57,7 @@ void main()
if(fogStartEnd.x >= 0 && fogStartEnd.y >= 0){
float s = fogStartEnd.x;
float e = fogStartEnd.y;
- vec4 eyePos = (modelView * (vec4(aPos - playerPos, 1.0) + vec4(0, 0.12, 0, 0)));
- float c = length(eyePos);
+ float c = length(untransformedPos);
float fogFactor = fogMode == 0x2601
? clamp((e - c) / (e - s), 0, 1) /* GL_LINEAR */