diff --git a/src/main/java/de/hft/stuttgart/citygml/viewer/Camera.java b/src/main/java/de/hft/stuttgart/citygml/viewer/Camera.java index 8c5a80bf0161cce5b4134f4ee4d404474faa5dec..c8715ec3309fc99ba1062060f3d8ed9541fc98c7 100644 --- a/src/main/java/de/hft/stuttgart/citygml/viewer/Camera.java +++ b/src/main/java/de/hft/stuttgart/citygml/viewer/Camera.java @@ -19,6 +19,7 @@ import java.nio.FloatBuffer; import org.joml.Math; import org.joml.Matrix4f; +import org.joml.Vector2f; import org.joml.Vector3f; import org.lwjgl.system.MemoryUtil; @@ -27,24 +28,21 @@ public class Camera { private static final float MIN_DISTANCE = 1f; private static final float PI = (float) Math.PI; - private Matrix4f projMatrix; + Matrix4f projMatrix; private Matrix4f viewMatrix; private Matrix4f projViewMatrix; - private float rotateAroundX = 2f; - private float rotateAroundZ = 3f; + private float rotateAroundZ = 0f; - private Vector3f eyeVec = new Vector3f(); - private Vector3f center = new Vector3f(); + private Vector3f eyePos = new Vector3f(); + private Vector3f centerPos = new Vector3f(); private Vector3f up = new Vector3f(); private float distance = 5; private static final float SCROLL_PERCENTAGE = 0.1f; - private UniformLocation uniformLocation; - private FloatBuffer matrixBuffer = MemoryUtil.memAllocFloat(16); - - private boolean isOrtho = false; + UniformLocation uniformLocation; + FloatBuffer matrixBuffer = MemoryUtil.memAllocFloat(16); public Camera(Shader shader) { uniformLocation = shader.getUniformLocation("projViewModel"); @@ -52,69 +50,60 @@ public class Camera { viewMatrix = new Matrix4f(); projMatrix = new Matrix4f(); up.z = 1; + eyePos.x = distance; } public void reshape(int width, int height, float distance) { - if (isOrtho) { - projMatrix.setOrtho(0, width, height, 0, 0, distance); - } else { - // 90 degree fow - float fow = PI / 2f; - float aspectRatio = (float) width / height; - projMatrix.setPerspective(fow, aspectRatio, MIN_DISTANCE, distance); - - } + // 90 degree fow + float fow = PI / 2f; + float aspectRatio = (float) width / height; + projMatrix.setPerspective(fow, aspectRatio, MIN_DISTANCE, distance); updateMatrix(); } - public void setOrtho(boolean isOrtho) { - this.isOrtho = isOrtho; - } - private void updateMatrix() { - // view matrix - if (isOrtho) { - projMatrix.get(matrixBuffer); - } else { - float sx = Math.sin(rotateAroundX); - float cx = Math.cos(rotateAroundX); - float sy = Math.sin(rotateAroundZ); - float cy = Math.cos(rotateAroundZ); - float sxDistance = distance * sx; - eyeVec.x = sxDistance * cy; - eyeVec.y = sxDistance * sy; - eyeVec.z = distance * cx; - viewMatrix.identity(); - viewMatrix.translate(0, 0, distance); - viewMatrix.lookAt(eyeVec, center, up); - projMatrix.mul(viewMatrix, projViewMatrix); - // model matrix is identity - projViewMatrix.get(matrixBuffer); - - } + viewMatrix.setLookAt(eyePos, centerPos, up); + projMatrix.mul(viewMatrix, projViewMatrix); + // model matrix is identity + projViewMatrix.get(matrixBuffer); uniformLocation.uploadMat4(matrixBuffer); } - public void drag(double dragDiffX, double dragDiffY) { - rotateAroundX += dragDiffY / 500f; - rotateAroundZ -= dragDiffX / 500f; - if (rotateAroundX > Math.PI) { - rotateAroundX = (float) Math.PI - 0.001f; - } else if (rotateAroundX < 0.001) { - rotateAroundX = (float) 0.001; + public void rotate(double dragDiffX, double dragDiffY) { + float rotationX = (float) (-dragDiffX / 500f); + float rotationZ = (float) (dragDiffY / 500f); + float tempRotationValue = rotateAroundZ + rotationZ; + if (tempRotationValue < -Math.PI / 2 + 0.0001 || tempRotationValue > Math.PI / 2 - 0.0001) { + // to close to 90 degree, stop rotation + rotationZ = 0; } + rotateAroundZ += rotationZ; + + Vector3f res = new Vector3f(); + eyePos.sub(centerPos, res); + res.rotateZ(rotationX); + + Vector3f rotAxis = new Vector3f(res.x, res.y, res.z + 5); + rotAxis.cross(res); + rotAxis.normalize(); + res.rotateAxis(rotationZ, rotAxis.x, rotAxis.y, rotAxis.z); + centerPos.add(res, eyePos); updateMatrix(); } public void setDistance(float distance) { this.distance = distance; + Vector3f res = new Vector3f(); + eyePos.sub(centerPos, res); + res.normalize().mul(distance); + centerPos.add(res, eyePos); updateMatrix(); } public void scroll(int scroll) { int addedDistance = (int) (distance * scroll * SCROLL_PERCENTAGE); distance += addedDistance; - updateMatrix(); + setDistance(distance); } public void free() { @@ -122,6 +111,27 @@ public class Camera { } public void move(double dragDiffX, double dragDiffY) { + Vector3f res = new Vector3f(); + centerPos.sub(eyePos, res); + Vector2f dir = new Vector2f(res.x, res.y); + dir.normalize(); + Vector2f yDrag = new Vector2f(); + dir.mul((float) -dragDiffY * 0.5f, yDrag); + + // handle diffY + centerPos.add(yDrag.x, yDrag.y, 0); + eyePos.add(yDrag.x, yDrag.y, 0); + + // handle diffX + float temp = dir.x; + dir.x = dir.y; + dir.y = -temp; + dir.mul((float) dragDiffX * 0.5f); + + centerPos.add(dir.x, dir.y, 0); + eyePos.add(dir.x, dir.y, 0); + + updateMatrix(); } } diff --git a/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java b/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java index f38157bca7aca41eb39463595917ba564a4b2209..d261c76cfd646572d799b04b78899f343c0dab85 100644 --- a/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java +++ b/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java @@ -68,8 +68,6 @@ import org.lwjgl.system.MemoryUtil; import org.lwjgl.util.nfd.NativeFileDialog; import org.xml.sax.SAXException; -import com.jogamp.opengl.GLException; - import de.hft.stuttgart.citygml.viewer.datastructure.BoundingBox; import de.hft.stuttgart.citygml.viewer.datastructure.Polygon; import de.hft.stuttgart.citygml.viewer.math.Vector3d; @@ -118,7 +116,7 @@ public class CityGMLViewer { public static void main(String[] args) { File f = null; f = parseArguments(args, f); - + try { setupWindow(f, useDebug); } catch (Exception e) { @@ -175,7 +173,7 @@ public class CityGMLViewer { } } } - + // default values for missing parameters if (colorsPath == null) { colorsPath = Paths.get("color.properties"); @@ -186,7 +184,7 @@ public class CityGMLViewer { if (f == null) { f = showFileChooserDialog(); } - + colorMapper = new PolygonColorMapper(mappingPath); colorHandler = new ColorHandler(colorsPath); return f; @@ -315,7 +313,7 @@ public class CityGMLViewer { } } else if (button == GLFW.GLFW_MOUSE_BUTTON_1 && action == GLFW.GLFW_RELEASE) { mouse1Down = false; - } else if (button == GLFW.GLFW_MOUSE_BUTTON_2 && action == GLFW.GLFW_PRESS) { + } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT && action == GLFW.GLFW_PRESS) { mouse2Down = true; try (MemoryStack stack = MemoryStack.stackPush()) { DoubleBuffer xBuffer = stack.mallocDouble(1); @@ -324,7 +322,7 @@ public class CityGMLViewer { x = xBuffer.get(0); y = yBuffer.get(0); } - } else if (button == GLFW.GLFW_MOUSE_BUTTON_2 && action == GLFW.GLFW_RELEASE) { + } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT && action == GLFW.GLFW_RELEASE) { mouse2Down = false; } } @@ -340,21 +338,17 @@ public class CityGMLViewer { GLFW.glfwSetCursorPosCallback(windowId, (window, xPos, yPos) -> { if (mouse1Down) { - try (MemoryStack stack = MemoryStack.stackPush()) { - double dragDiffX = xPos - x; - double dragDiffY = yPos - y; - camera.drag(dragDiffX, dragDiffY); - x = xPos; - y = yPos; - } + double dragDiffX = xPos - x; + double dragDiffY = yPos - y; + camera.rotate(dragDiffX, dragDiffY); + x = xPos; + y = yPos; } else if (mouse2Down) { - try (MemoryStack stack = MemoryStack.stackPush()) { - double dragDiffX = xPos - x; - double dragDiffY = yPos - y; - camera.move(dragDiffX, dragDiffY); - x = xPos; - y = yPos; - } + double dragDiffX = xPos - x; + double dragDiffY = yPos - y; + camera.move(dragDiffX, dragDiffY); + x = xPos; + y = yPos; } }); @@ -391,20 +385,25 @@ public class CityGMLViewer { Shader program = new Shader("vertex.vert", "fragment.frag", useDebug); program.use(); log.fine(() -> "OpenGL error code after shader loading: " + GL11.glGetError()); - camera = new Camera(program); - camera.setOrtho(true); + camera = new OrthogonalCamera(program); camera.reshape(width, height, cameraViewDistance); bar = new ProgressBar(windowId, width, height); bar.drawProgress(0); log.fine(() -> "OpenGL error code after drawing initial progress bar: " + GL11.glGetError()); - loadGmlFile(f); + double longestSide = loadGmlFile(f); log.fine(() -> "OpenGL error code after loading GML file: " + GL11.glGetError()); bar.free(); bar = null; - camera.setOrtho(false); + camera.free(); + camera = new Camera(program); camera.reshape(width, height, cameraViewDistance); + double d = longestSide / Math.tan(Math.toRadians(30) / 2); + double translateZ = -d; + camera.setDistance((float) translateZ); + cameraViewDistance = (float) longestSide * 20f; + camera.rotate(0, -300); clearColor = MemoryUtil.memAllocFloat(4); clearColor.put(0, 0.9411765f).put(1, 1f).put(2, 1f).put(3, 1f); @@ -429,6 +428,16 @@ public class CityGMLViewer { } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); + } catch (CityGMLContextException e) { + e.printStackTrace(); + } catch (CityGMLReadException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (SAXException e) { + e.printStackTrace(); } finally { MemoryUtil.memFree(clearColor); MemoryUtil.memFree(clearDepth); @@ -445,8 +454,7 @@ public class CityGMLViewer { GLFW.glfwTerminate(); } - private static void loadGmlFile(File f) { - try { + private static double loadGmlFile(File f) throws InterruptedException, CityGMLContextException, CityGMLReadException, IOException, ParserConfigurationException, SAXException { File file = f; ParserConfiguration config = new ParserConfiguration(); CityGMLParser.parseEpsgCodeFromFile(file, config); @@ -523,19 +531,10 @@ public class CityGMLViewer { viewing.add(lod4ViewInfo); } - double longestSide = bbox.getDiagonalLength() * 0.2; - double d = longestSide / Math.tan(Math.toRadians(30) / 2); - double translateZ = -d; - camera.setDistance((float) translateZ); - cameraViewDistance = (float) longestSide * 20f; - camera.reshape(width, height, cameraViewDistance); + return bbox.getDiagonalLength() * 0.2; } catch (InterruptedException e) { - Thread.currentThread().interrupt(); log.severe("Could not finish parsing file in 20 minutes, aborting"); + throw e; } - } catch (GLException | IOException | ParserConfigurationException | SAXException | CityGMLContextException - | CityGMLReadException e) { - e.printStackTrace(); - } } } diff --git a/src/main/java/de/hft/stuttgart/citygml/viewer/OrthogonalCamera.java b/src/main/java/de/hft/stuttgart/citygml/viewer/OrthogonalCamera.java new file mode 100644 index 0000000000000000000000000000000000000000..6b749ec9ab9fba6e0effa199765ec5b0f49d108d --- /dev/null +++ b/src/main/java/de/hft/stuttgart/citygml/viewer/OrthogonalCamera.java @@ -0,0 +1,32 @@ +package de.hft.stuttgart.citygml.viewer; + +public class OrthogonalCamera extends Camera { + + public OrthogonalCamera(Shader shader) { + super(shader); + } + + @Override + public void reshape(int width, int height, float distance) { + projMatrix.setOrtho(0, width, height, 0, 0, distance); + projMatrix.get(matrixBuffer); + uniformLocation.uploadMat4(matrixBuffer); + } + + @Override + public void rotate(double dragDiffX, double dragDiffY) { + } + + @Override + public void move(double dragDiffX, double dragDiffY) { + } + + @Override + public void scroll(int scroll) { + } + + @Override + public void setDistance(float distance) { + } + +}