diff --git a/client/src/main/java/core/engine/Engine.java b/client/src/main/java/core/engine/Engine.java index fdf5cf0..bfc9661 100644 --- a/client/src/main/java/core/engine/Engine.java +++ b/client/src/main/java/core/engine/Engine.java @@ -135,10 +135,15 @@ public class Engine { // Run the rendering loop until the user has attempted to close // the window or has pressed the ESCAPE key. MasterRenderer renderer = new MasterRenderer(); - MousePicker mousePicker = new MousePicker(camera, renderer.getProjectionMatrix()); + MousePicker mousePicker = new MousePicker(camera, renderer.getProjectionMatrix(), terrain); input(camera, renderer, mousePicker); while ( !glfwWindowShouldClose(window) ) { + DoubleBuffer posX = BufferUtils.createDoubleBuffer(1); + DoubleBuffer posY = BufferUtils.createDoubleBuffer(1); + glfwGetCursorPos(window, posX, posY); + mousePicker.update((float) posX.get(0), (float) posY.get(0)); renderer.processTerrain(terrain); + //renderer.processEntity(hexagonEntity); renderer.render(light, camera); glfwSwapBuffers(window); // swap the color buffers diff --git a/client/src/main/java/core/engine/terrain/Terrain.java b/client/src/main/java/core/engine/terrain/Terrain.java index 2f369ef..ef48266 100644 --- a/client/src/main/java/core/engine/terrain/Terrain.java +++ b/client/src/main/java/core/engine/terrain/Terrain.java @@ -1,6 +1,7 @@ package core.engine.terrain; import core.engine.Loader; +import core.engine.entity.Camera; import core.engine.model.HexagonModel; import core.engine.model.RawModel; import core.engine.model.TexturedModel; @@ -33,8 +34,6 @@ public class Terrain { } } - - public List getTerrainTiles() { return terrainTiles; } diff --git a/client/src/main/java/core/engine/terrain/TerrainTile.java b/client/src/main/java/core/engine/terrain/TerrainTile.java index 95a6fc5..1778f59 100644 --- a/client/src/main/java/core/engine/terrain/TerrainTile.java +++ b/client/src/main/java/core/engine/terrain/TerrainTile.java @@ -1,6 +1,7 @@ package core.engine.terrain; import core.engine.Loader; +import core.engine.entity.Camera; import core.engine.model.RawModel; import core.engine.model.TexturedModel; import core.engine.textures.ModelTexture; diff --git a/client/src/main/java/core/engine/toolbox/MousePicker.java b/client/src/main/java/core/engine/toolbox/MousePicker.java index e25c6f3..948270f 100644 --- a/client/src/main/java/core/engine/toolbox/MousePicker.java +++ b/client/src/main/java/core/engine/toolbox/MousePicker.java @@ -2,24 +2,34 @@ package core.engine.toolbox; import core.engine.Engine; import core.engine.entity.Camera; +import core.engine.terrain.Terrain; import org.lwjgl.system.windows.MOUSEINPUT; import utils.MatrixGraphicUtils; -import utils.vectors.Matrix4f; -import utils.vectors.Vector2f; -import utils.vectors.Vector3f; -import utils.vectors.Vector4f; +import utils.vectors.*; public class MousePicker { - private Vector3f currentRay; + private static final int RECURSION_COUNT = 200; + private static final float RAY_RANGE = 600; + + private Vector3f currentRay = new Vector3f(); + private Matrix4f projectionMatrix; private Matrix4f viewMatrix; private Camera camera; - public MousePicker(Camera camera, Matrix4f projectionMatrix) { - this.camera = camera; - this.projectionMatrix = projectionMatrix; - this.viewMatrix = MatrixGraphicUtils.createViewMatrix(camera); + private Terrain terrain; + private Vector3f currentTerrainPoint; + + public MousePicker(Camera cam, Matrix4f projection, Terrain terrain) { + camera = cam; + projectionMatrix = projection; + viewMatrix = MatrixGraphicUtils.createViewMatrix(camera); + this.terrain = terrain; + } + + public Vector3f getCurrentTerrainPoint() { + return currentTerrainPoint; } public Vector3f getCurrentRay() { @@ -27,34 +37,93 @@ public class MousePicker { } public void update(float mouseX, float mouseY) { - this.viewMatrix = MatrixGraphicUtils.createViewMatrix(camera); - this.currentRay = calculateMouseRay(mouseX, mouseY); + viewMatrix = MatrixGraphicUtils.createViewMatrix(camera); + currentRay = calculateMouseRay(mouseX, mouseY); + if (intersectionInRange(0, RAY_RANGE, currentRay)) { + currentTerrainPoint = binarySearch(0, 0, RAY_RANGE, currentRay); + } else { + currentTerrainPoint = null; + } } - public Vector3f calculateMouseRay(float mouseX, float mouseY) { - Vector2f normalizedDeviceCoords = getNormalizedDeviceCoords(mouseX, mouseY); - Vector4f clipCoords = new Vector4f(normalizedDeviceCoords.x, normalizedDeviceCoords.y, -1f, 1f); + private Vector3f calculateMouseRay(float mouseX, float mouseY) { + + Vector2f normalizedCoords = getNormalisedDeviceCoordinates(mouseX, mouseY); + Vector4f clipCoords = new Vector4f(normalizedCoords.x, normalizedCoords.y, -1.0f, 1.0f); Vector4f eyeCoords = toEyeCoords(clipCoords); - return toWorldCoords(eyeCoords); + Vector3f worldRay = toWorldCoords(eyeCoords); + System.out.println(worldRay); + return worldRay; } - private Vector2f getNormalizedDeviceCoords(float mouseX, float mouseY) { - float x = (2f* mouseX) / Engine.WINDOW_WIDTH -1; - float y = (2f * mouseY) / Engine.WINDOW_HEIGHT -1; - return new Vector2f(x, y); + private Vector3f toWorldCoords(Vector4f eyeCoords) { + Matrix4f invertedView = Matrix4f.invert(viewMatrix, null); + Vector4f rayWorld = Matrix4f.transform(invertedView, eyeCoords, null); + Vector3f mouseRay = new Vector3f(rayWorld.x, rayWorld.y, rayWorld.z); + mouseRay.normalise(); + return mouseRay; } private Vector4f toEyeCoords(Vector4f clipCoords) { - Matrix4f invertedProjectionMatrix = Matrix4f.invert(projectionMatrix, null); - Vector4f eyeCoords = Matrix4f.transform(invertedProjectionMatrix, clipCoords, null); + Matrix4f invertedProjection = Matrix4f.invert(projectionMatrix, null); + Vector4f eyeCoords = Matrix4f.transform(invertedProjection, clipCoords, null); return new Vector4f(eyeCoords.x, eyeCoords.y, -1f, 0f); } - private Vector3f toWorldCoords (Vector4f eyeCoords) { - Matrix4f invertedViewMatrix = Matrix4f.invert(viewMatrix, null); - Vector4f rayWorld = Matrix4f.transform(invertedViewMatrix, eyeCoords, null); - Vector3f worldCoords = new Vector3f(rayWorld.x, rayWorld.y, rayWorld.z); - worldCoords.normalise(); - return worldCoords; + private Vector2f getNormalisedDeviceCoordinates(float mouseX, float mouseY) { + float x = (2.0f * mouseX) / Engine.WINDOW_WIDTH - 1f; + float y = (2.0f * mouseY) / Engine.WINDOW_HEIGHT - 1f; + return new Vector2f(x, y); + } + + //********************************************************** + + private Vector3f getPointOnRay(Vector3f ray, float distance) { + Vector3f camPos = camera.getPosition(); + Vector3f start = new Vector3f(camPos.x, camPos.y, camPos.z); + Vector3f scaledRay = new Vector3f(ray.x * distance, ray.y * distance, ray.z * distance); + return Vector3f.add(start, scaledRay, null); + } + + private Vector3f binarySearch(int count, float start, float finish, Vector3f ray) { + float half = start + ((finish - start) / 2f); + if (count >= RECURSION_COUNT) { + Vector3f endPoint = getPointOnRay(ray, half); + Terrain terrain = getTerrain(endPoint.getX(), endPoint.getZ()); + if (terrain != null) { + return endPoint; + } else { + return null; + } + } + if (intersectionInRange(start, half, ray)) { + return binarySearch(count + 1, start, half, ray); + } else { + return binarySearch(count + 1, half, finish, ray); + } + } + + private boolean intersectionInRange(float start, float finish, Vector3f ray) { + Vector3f startPoint = getPointOnRay(ray, start); + Vector3f endPoint = getPointOnRay(ray, finish); + if (!isUnderGround(startPoint) && isUnderGround(endPoint)) { + return true; + } else { + return false; + } + } + + private boolean isUnderGround(Vector3f testPoint) { + Terrain terrain = getTerrain(testPoint.getX(), testPoint.getZ()); + float height = 0; + if (testPoint.y < height) { + return true; + } else { + return false; + } + } + + private Terrain getTerrain(float worldX, float worldZ) { + return terrain; } }