Added raycasting method! I think...

This commit is contained in:
Andrew Lalis 2022-07-15 17:10:23 +02:00
parent c2958e403b
commit c9b325da3a
4 changed files with 163 additions and 20 deletions

View File

@ -37,6 +37,10 @@ public class ChunkMesh {
return positionData; return positionData;
} }
public Chunk getChunk() {
return chunk;
}
/** /**
* Generates and loads this chunk's mesh into the allocated OpenGL buffers. * Generates and loads this chunk's mesh into the allocated OpenGL buffers.
*/ */

View File

@ -4,10 +4,9 @@ import nl.andrewl.aos2_client.Camera;
import nl.andrewl.aos_core.model.Chunk; import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.World; import nl.andrewl.aos_core.model.World;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Vector3i;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import static org.lwjgl.opengl.GL46.*; import static org.lwjgl.opengl.GL46.*;
@ -26,7 +25,7 @@ public class ChunkRenderer {
private int viewTransformUniform; private int viewTransformUniform;
private int chunkPositionUniform; private int chunkPositionUniform;
private final List<ChunkMesh> chunkMeshes = new ArrayList<>(); private final Map<Vector3i, ChunkMesh> chunkMeshes = new HashMap<>();
public void setupShaderProgram() { public void setupShaderProgram() {
this.shaderProgram = new ShaderProgram.Builder() this.shaderProgram = new ShaderProgram.Builder()
@ -53,18 +52,22 @@ public class ChunkRenderer {
public void draw(Camera cam, World world) { public void draw(Camera cam, World world) {
while (!meshGenerationQueue.isEmpty()) { while (!meshGenerationQueue.isEmpty()) {
chunkMeshes.add(new ChunkMesh(meshGenerationQueue.remove(), world, chunkMeshGenerator)); Chunk chunk = meshGenerationQueue.remove();
ChunkMesh mesh = new ChunkMesh(chunk, world, chunkMeshGenerator);
chunkMeshes.put(chunk.getPosition(), mesh);
} }
shaderProgram.use(); shaderProgram.use();
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData()); glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
for (var mesh : chunkMeshes) { for (var mesh : chunkMeshes.values()) {
glUniform3iv(chunkPositionUniform, mesh.getPositionData()); glUniform3iv(chunkPositionUniform, mesh.getPositionData());
mesh.draw(); mesh.draw();
} }
} }
public void free() { public void free() {
for (var mesh : chunkMeshes) mesh.free(); for (var mesh : chunkMeshes.values()) mesh.free();
chunkMeshes.clear();
meshGenerationQueue.clear();
shaderProgram.free(); shaderProgram.free();
} }
} }

View File

@ -82,23 +82,80 @@ public class World {
setBlockAt(new Vector3f(x, y, z), block); setBlockAt(new Vector3f(x, y, z), block);
} }
// public byte getBlockAt(int x, int y, int z) {
//// int chunkX = x / Chunk.SIZE;
//// int localX = x % Chunk.SIZE;
//// int chunkY = y / Chunk.SIZE;
//// int localY = y % Chunk.SIZE;
//// int chunkZ = z / Chunk.SIZE;
//// int localZ = z % Chunk.SIZE;
//// Vector3i chunkPos = new Vector3i(chunkX, chunkY, chunkZ);
//// Chunk chunk = chunkMap.get(chunkPos);
//// if (chunk == null) return 0;
//// return chunk.getBlockAt(localX, localY, localZ);
// }
public Chunk getChunkAt(Vector3i chunkPos) { public Chunk getChunkAt(Vector3i chunkPos) {
return chunkMap.get(chunkPos); return chunkMap.get(chunkPos);
} }
/**
* Gets the position that a system is looking at, within a distance limit.
* Usually used to determine where a player has interacted/clicked in the
* world.
* @param eyePos The origin point to look from.
* @param eyeDir The direction to look towards. This should be normalized.
* @param limit The radius out from the origin to look. Blocks outside this
* limit will not be returned.
* @return The location of the block that is looked at, or null if none
* could be found.
*/
public Vector3i getLookingAtPos(Vector3f eyePos, Vector3f eyeDir, float limit) {
if (eyeDir.lengthSquared() == 0 || limit <= 0) return null;
Vector3f pos = new Vector3f(eyePos);
Vector3f movement = new Vector3f(); // Pre-allocate this vector.
while (pos.distance(eyePos) < limit) {
// Find the coordinates of the next blocks on the x, y, and z axes.
float stepX = getNextStep(pos.x, eyeDir.x);
float stepY = getNextStep(pos.y, eyeDir.y);
float stepZ = getNextStep(pos.z, eyeDir.z);
// Get the distance from our current position to the next block on the x, y, and z axes.
float distX = Math.abs(pos.x - stepX);
float distY = Math.abs(pos.y - stepY);
float distZ = Math.abs(pos.z - stepZ);
// Get the factor required to multiply each component by to get to its next step.
float factorX = Math.abs(distX / eyeDir.x);
float factorY = Math.abs(distY / eyeDir.y);
float factorZ = Math.abs(distZ / eyeDir.z);
float minFactor = Float.MAX_VALUE;
if (factorX > 0 && factorX < minFactor) minFactor = factorX;
if (factorY > 0 && factorY < minFactor) minFactor = factorY;
if (factorZ > 0 && factorZ < minFactor) minFactor = factorZ;
// We should add dir * lowest factor to step to the first next block.
movement.set(eyeDir).mul(minFactor);
pos.add(movement);
if (getBlockAt(pos) > 0) {
return new Vector3i(
(int) Math.floor(pos.x),
(int) Math.floor(pos.y),
(int) Math.floor(pos.z)
);
}
}
return null;
}
/**
* Helper function to find the next whole number, given a current number and
* an indication of which direction the number is increasing.
* @param n The current number.
* @param sign An indication of which way the number is increasing.
* @return The next whole number up from the current number.
*/
private static float getNextStep(float n, float sign) {
if (sign > 0) {
if (Math.ceil(n) == n) {
return n + 1;
} else {
return Math.ceil(n);
}
} else if (sign < 0) {
if (Math.floor(n) == n) {
return n - 1;
} else {
return Math.floor(n);
}
}
return n;
}
/** /**
* Gets the coordinates of a chunk at a given world position. * Gets the coordinates of a chunk at a given world position.
* @param worldPos The world position. * @param worldPos The world position.

View File

@ -5,6 +5,7 @@ import org.joml.Vector3i;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class WorldTest { public class WorldTest {
@Test @Test
@ -31,4 +32,82 @@ public class WorldTest {
assertEquals(new Vector3i(1, 1, 1), World.getChunkPosAt(new Vector3f(Chunk.SIZE, Chunk.SIZE, Chunk.SIZE))); assertEquals(new Vector3i(1, 1, 1), World.getChunkPosAt(new Vector3f(Chunk.SIZE, Chunk.SIZE, Chunk.SIZE)));
assertEquals(new Vector3i(4, 4, 4), World.getChunkPosAt(new Vector3f(Chunk.SIZE * 5 - 1, Chunk.SIZE * 5 - 1, Chunk.SIZE * 5 - 1))); assertEquals(new Vector3i(4, 4, 4), World.getChunkPosAt(new Vector3f(Chunk.SIZE * 5 - 1, Chunk.SIZE * 5 - 1, Chunk.SIZE * 5 - 1)));
} }
@Test
public void testGetLookingAtPos() {
World world = Worlds.testingWorld();
// Spawn a block high in the air.
Vector3i blockPos = new Vector3i(20, 20, 20);
world.setBlockAt(blockPos.x, blockPos.y, blockPos.z, (byte) 5);
assertEquals( // Looking straight down onto block.
blockPos,
world.getLookingAtPos(
new Vector3f(20.5f, 25, 20.5f),
new Vector3f(0, -1, 0),
15
)
);
assertEquals( // Looking straight up.
blockPos,
world.getLookingAtPos(
new Vector3f(20.5f, 15, 20.5f),
new Vector3f(0, 1, 0),
15
)
);
assertEquals( // Looking towards -Z
blockPos,
world.getLookingAtPos(
new Vector3f(20.5f, 20.5f, 26f),
new Vector3f(0, 0, -1),
15
)
);
assertEquals( // Looking towards +Z
blockPos,
world.getLookingAtPos(
new Vector3f(20.5f, 20.5f, 15f),
new Vector3f(0, 0, 1),
15
)
);
assertEquals( // Looking towards -X
blockPos,
world.getLookingAtPos(
new Vector3f(26f, 20.5f, 20.5f),
new Vector3f(-1, 0, 0),
15
)
);
assertEquals( // Looking towards +X
blockPos,
world.getLookingAtPos(
new Vector3f(15f, 20.5f, 20.5f),
new Vector3f(1, 0, 0),
15
)
);
// Looking up into the void.
assertNull(world.getLookingAtPos(
new Vector3f(0, 30, 0),
new Vector3f(0, 1, 0),
10
));
// Looking straight down, but too far away.
assertNull(world.getLookingAtPos(
new Vector3f(0.5f, 20, 0.5f),
new Vector3f(0, -1, 0),
15
));
assertEquals( // Standing in the corner, looking into center of block.
blockPos,
world.getLookingAtPos(
new Vector3f(20f, 21f, 20f),
new Vector3f(1, -2, 1).normalize(),
15
)
);
}
} }