From 8ac9cf11049e07c3cda46e21b1dda4cbf5b17a8d Mon Sep 17 00:00:00 2001 From: James Ball Date: Mon, 4 Apr 2022 22:06:56 +0100 Subject: [PATCH] Implement toggle to remove hidden edges from objects --- pom.xml | 2 +- .../java/sh/ball/engine/CameraDrawKernel.java | 160 +++++++++--------- src/main/java/sh/ball/engine/WorldObject.java | 18 +- .../ball/gui/controller/MainController.java | 14 ++ .../sh/ball/gui/controller/ObjController.java | 4 + .../sh/ball/parser/obj/ObjFrameSettings.java | 4 +- .../sh/ball/parser/obj/ObjFrameSource.java | 5 +- .../ball/parser/obj/ObjSettingsFactory.java | 6 +- src/main/resources/fxml/main.fxml | 1 + 9 files changed, 126 insertions(+), 88 deletions(-) diff --git a/pom.xml b/pom.xml index 227f85f..a463bde 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sh.ball osci-render - 1.20.3 + 1.21.3 osci-render diff --git a/src/main/java/sh/ball/engine/CameraDrawKernel.java b/src/main/java/sh/ball/engine/CameraDrawKernel.java index b5d0f8d..a347186 100644 --- a/src/main/java/sh/ball/engine/CameraDrawKernel.java +++ b/src/main/java/sh/ball/engine/CameraDrawKernel.java @@ -28,6 +28,7 @@ public class CameraDrawKernel extends Kernel { private float cameraPosY; private float cameraPosZ; private float focalLength; + private int hideEdges = 0; public CameraDrawKernel() {} @@ -45,6 +46,7 @@ public class CameraDrawKernel extends Kernel { } } prevObject = object; + hideEdges = object.edgesHidden() ? 1 : 0; Vector3 rotation = object.getRotation(); Vector3 position = object.getPosition(); this.rotationX = (float) rotation.x; @@ -70,11 +72,15 @@ public class CameraDrawKernel extends Kernel { linesList = new ArrayList<>(); - for (int i = 0; i < vertices.length / 3; i += 2) { - if (!Float.isNaN(vertexResult[2 * i]) && !Float.isNaN(vertexResult[2 * i + 2])) { + for (int i = 0; i < vertices.length / 3; i++) { + int nextOffset = 0; + if (i < vertices.length / 3 - 1) { + nextOffset = 2 * i + 2; + } + if (!Float.isNaN(vertexResult[2 * i]) && !Float.isNaN(vertexResult[nextOffset])) { linesList.add(new Line( new Vector2(vertexResult[2 * i], vertexResult[2 * i + 1]), - new Vector2(vertexResult[2 * i + 2], vertexResult[2 * i + 3]) + new Vector2(vertexResult[nextOffset], vertexResult[nextOffset + 1]) )); } } @@ -127,95 +133,97 @@ public class CameraDrawKernel extends Kernel { float rotatedY = y3 + positionY; float rotatedZ = z3 + positionZ; - float rotatedCameraPosX = cameraPosX - positionX; - float rotatedCameraPosY = cameraPosY - positionY; - float rotatedCameraPosZ = cameraPosZ - positionZ; - - cosValue = cos(-rotationZ); - sinValue = sin(-rotationZ); - x2 = cosValue * rotatedCameraPosX - sinValue * rotatedCameraPosY; - y2 = sinValue * rotatedCameraPosX + cosValue * rotatedCameraPosY; - - cosValue = cos(-rotationY); - sinValue = sin(-rotationY); - rotatedCameraPosX = cosValue * x2 + sinValue * rotatedCameraPosZ; - z2 = -sinValue * x2 + cosValue * rotatedCameraPosZ; - - cosValue = cos(-rotationX); - sinValue = sin(-rotationX); - rotatedCameraPosY = cosValue * y2 - sinValue * z2; - rotatedCameraPosZ = sinValue * y2 + cosValue * z2; - - float dirx = rotatedCameraPosX - x1; - float diry = rotatedCameraPosY - y1; - float dirz = rotatedCameraPosZ - z1; - float length = sqrt(dirx * dirx + diry * diry + dirz * dirz); - dirx /= length; - diry /= length; - dirz /= length; - boolean intersects = false; - for (int j = 0; j < triangles.length / 9 && !intersects; j++) { - float v1x = triangles[9 * j]; - float v1y = triangles[9 * j + 1]; - float v1z = triangles[9 * j + 2]; - float v2x = triangles[9 * j + 3]; - float v2y = triangles[9 * j + 4]; - float v2z = triangles[9 * j + 5]; - float v3x = triangles[9 * j + 6]; - float v3y = triangles[9 * j + 7]; - float v3z = triangles[9 * j + 8]; + if (hideEdges == 1) { + float rotatedCameraPosX = cameraPosX - positionX; + float rotatedCameraPosY = cameraPosY - positionY; + float rotatedCameraPosZ = cameraPosZ - positionZ; - // vec3 edge1 = v2 - v1; - float edge1x = v2x - v1x; - float edge1y = v2y - v1y; - float edge1z = v2z - v1z; + cosValue = cos(-rotationZ); + sinValue = sin(-rotationZ); + x2 = cosValue * rotatedCameraPosX - sinValue * rotatedCameraPosY; + y2 = sinValue * rotatedCameraPosX + cosValue * rotatedCameraPosY; - // vec3 edge2 = v3 - v1; - float edge2x = v3x - v1x; - float edge2y = v3y - v1y; - float edge2z = v3z - v1z; + cosValue = cos(-rotationY); + sinValue = sin(-rotationY); + rotatedCameraPosX = cosValue * x2 + sinValue * rotatedCameraPosZ; + z2 = -sinValue * x2 + cosValue * rotatedCameraPosZ; - // vec3 p = cross(dir, edge2); - float px = crossX(dirx, diry, dirz, edge2x, edge2y, edge2z); - float py = crossY(dirx, diry, dirz, edge2x, edge2y, edge2z); - float pz = crossZ(dirx, diry, dirz, edge2x, edge2y, edge2z); + cosValue = cos(-rotationX); + sinValue = sin(-rotationX); + rotatedCameraPosY = cosValue * y2 - sinValue * z2; + rotatedCameraPosZ = sinValue * y2 + cosValue * z2; - float det = dot(edge1x, edge1y, edge1z, px, py, pz); + float dirx = rotatedCameraPosX - x1; + float diry = rotatedCameraPosY - y1; + float dirz = rotatedCameraPosZ - z1; + float length = sqrt(dirx * dirx + diry * diry + dirz * dirz); + dirx /= length; + diry /= length; + dirz /= length; - if (det > -EPSILON && det < EPSILON) { - continue; - } + for (int j = 0; j < triangles.length / 9 && !intersects; j++) { + float v1x = triangles[9 * j]; + float v1y = triangles[9 * j + 1]; + float v1z = triangles[9 * j + 2]; + float v2x = triangles[9 * j + 3]; + float v2y = triangles[9 * j + 4]; + float v2z = triangles[9 * j + 5]; + float v3x = triangles[9 * j + 6]; + float v3y = triangles[9 * j + 7]; + float v3z = triangles[9 * j + 8]; - float inv_det = 1.0f / det; + // vec3 edge1 = v2 - v1; + float edge1x = v2x - v1x; + float edge1y = v2y - v1y; + float edge1z = v2z - v1z; - // vec3 t = origin - v1; - float tx = x1 - v1x; - float ty = y1 - v1y; - float tz = z1 - v1z; + // vec3 edge2 = v3 - v1; + float edge2x = v3x - v1x; + float edge2y = v3y - v1y; + float edge2z = v3z - v1z; - float u = dot(tx, ty, tz, px, py, pz) * inv_det; + // vec3 p = cross(dir, edge2); + float px = crossX(dirx, diry, dirz, edge2x, edge2y, edge2z); + float py = crossY(dirx, diry, dirz, edge2x, edge2y, edge2z); + float pz = crossZ(dirx, diry, dirz, edge2x, edge2y, edge2z); - if (u < 0 || u > 1) { - continue; - } + float det = dot(edge1x, edge1y, edge1z, px, py, pz); - // vec3 q = cross(t, edge1); - float qx = crossX(tx, ty, tz, edge1x, edge1y, edge1z); - float qy = crossY(tx, ty, tz, edge1x, edge1y, edge1z); - float qz = crossZ(tx, ty, tz, edge1x, edge1y, edge1z); + if (det > -EPSILON && det < EPSILON) { + continue; + } - float v = dot(dirx, diry, dirz, qx, qy, qz) * inv_det; + float inv_det = 1.0f / det; - if (v < 0 || u + v > 1) { - continue; - } + // vec3 t = origin - v1; + float tx = x1 - v1x; + float ty = y1 - v1y; + float tz = z1 - v1z; - float mu = dot(edge2x, edge2y, edge2z, qx, qy, qz) * inv_det; + float u = dot(tx, ty, tz, px, py, pz) * inv_det; - if (mu > EPSILON) { - intersects = true; + if (u < 0 || u > 1) { + continue; + } + + // vec3 q = cross(t, edge1); + float qx = crossX(tx, ty, tz, edge1x, edge1y, edge1z); + float qy = crossY(tx, ty, tz, edge1x, edge1y, edge1z); + float qz = crossZ(tx, ty, tz, edge1x, edge1y, edge1z); + + float v = dot(dirx, diry, dirz, qx, qy, qz) * inv_det; + + if (v < 0 || u + v > 1) { + continue; + } + + float mu = dot(edge2x, edge2y, edge2z, qx, qy, qz) * inv_det; + + if (mu > EPSILON) { + intersects = true; + } } } diff --git a/src/main/java/sh/ball/engine/WorldObject.java b/src/main/java/sh/ball/engine/WorldObject.java index ca9e078..0d08051 100644 --- a/src/main/java/sh/ball/engine/WorldObject.java +++ b/src/main/java/sh/ball/engine/WorldObject.java @@ -22,6 +22,7 @@ public class WorldObject { private List vertexPath; private Vector3 position; private Vector3 rotation; + private boolean hideEdges = false; private WorldObject(List objVertices, List vertexPath, Vector3 position, Vector3 rotation) { @@ -56,8 +57,6 @@ public class WorldObject { Graph graph = new DefaultUndirectedWeightedGraph<>( DefaultWeightedEdge.class); - vertexPath = new ArrayList<>(); - // Add all lines in frame to graph as vertices and edges. Edge weight is determined by the // length of the line as this is directly proportional to draw time. for (Line3D edge : edges) { @@ -79,12 +78,7 @@ public class WorldObject { for (Set vertices : inspector.connectedSets()) { AsSubgraph subgraph = new AsSubgraph<>(graph, vertices); ChinesePostman cp = new ChinesePostman<>(); - List path = cp.getCPPSolution(subgraph).getVertexList(); - - for (int i = 1; i < path.size(); i++) { - vertexPath.add(path.get(i - 1)); - vertexPath.add(path.get(i)); - } + vertexPath.addAll(cp.getCPPSolution(subgraph).getVertexList()); } } @@ -215,4 +209,12 @@ public class WorldObject { return new WorldObject(new ArrayList<>(objVertices), new ArrayList<>(vertexPath), position, rotation); } + + public void hideEdges(boolean hideEdges) { + this.hideEdges = hideEdges; + } + + public boolean edgesHidden() { + return hideEdges; + } } diff --git a/src/main/java/sh/ball/gui/controller/MainController.java b/src/main/java/sh/ball/gui/controller/MainController.java index 31f5552..55ca8b5 100644 --- a/src/main/java/sh/ball/gui/controller/MainController.java +++ b/src/main/java/sh/ball/gui/controller/MainController.java @@ -122,6 +122,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis @FXML private CheckMenuItem flipYCheckMenuItem; @FXML + private CheckMenuItem hideHiddenMeshesCheckMenuItem; + @FXML private Spinner midiChannelSpinner; @FXML private Spinner translationIncrementSpinner; @@ -268,6 +270,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis flipXCheckMenuItem.selectedProperty().addListener((e, old, flip) -> audioPlayer.flipXChannel(flip)); flipYCheckMenuItem.selectedProperty().addListener((e, old, flip) -> audioPlayer.flipYChannel(flip)); + hideHiddenMeshesCheckMenuItem.selectedProperty().addListener((e, old, hidden) -> objController.hideHiddenMeshes(hidden)); + NumberFormat format = NumberFormat.getIntegerInstance(); UnaryOperator filter = c -> { if (c.isContentChange()) { @@ -404,6 +408,7 @@ public class MainController implements Initializable, FrequencyListener, MidiLis objController.updateFocalLength(); if (oldSettings instanceof ObjFrameSettings settings) { objController.setObjRotate(settings.baseRotation, settings.currentRotation); + objController.hideHiddenMeshes(settings.hideEdges); } executor.submit(producer); effectsController.restartEffects(); @@ -718,6 +723,10 @@ public class MainController implements Initializable, FrequencyListener, MidiLis root.appendChild(flipX); root.appendChild(flipY); + Element hiddenEdges = document.createElement("hiddenEdges"); + hiddenEdges.appendChild(document.createTextNode(String.valueOf(hideHiddenMeshesCheckMenuItem.isSelected()))); + root.appendChild(hiddenEdges); + Element translationIncrement = document.createElement("translationIncrement"); translationIncrement.appendChild(document.createTextNode(translationIncrementSpinner.getValue().toString())); root.appendChild(translationIncrement); @@ -814,6 +823,11 @@ public class MainController implements Initializable, FrequencyListener, MidiLis flipYCheckMenuItem.setSelected(Boolean.parseBoolean(flipY.getTextContent())); } + Element hiddenEdges = (Element) root.getElementsByTagName("hiddenEdges").item(0); + if (hiddenEdges != null) { + hideHiddenMeshesCheckMenuItem.setSelected(Boolean.parseBoolean(hiddenEdges.getTextContent())); + } + Element translationIncrement = (Element) root.getElementsByTagName("translationIncrement").item(0); if (translationIncrement != null) { translationIncrementSpinner.getValueFactory().setValue(Double.parseDouble(translationIncrement.getTextContent())); diff --git a/src/main/java/sh/ball/gui/controller/ObjController.java b/src/main/java/sh/ball/gui/controller/ObjController.java index 885cc48..218d646 100644 --- a/src/main/java/sh/ball/gui/controller/ObjController.java +++ b/src/main/java/sh/ball/gui/controller/ObjController.java @@ -121,6 +121,10 @@ public class ObjController implements Initializable, SubController { producer.setFrameSettings(ObjSettingsFactory.rotation(baseRotation, currentRotation)); } + public void hideHiddenMeshes(Boolean hidden) { + producer.setFrameSettings(ObjSettingsFactory.hideEdges(hidden)); + } + @Override public void initialize(URL url, ResourceBundle resourceBundle) { focalLengthSlider.valueProperty().addListener((source, oldValue, newValue) -> diff --git a/src/main/java/sh/ball/parser/obj/ObjFrameSettings.java b/src/main/java/sh/ball/parser/obj/ObjFrameSettings.java index 3325708..d5c4383 100644 --- a/src/main/java/sh/ball/parser/obj/ObjFrameSettings.java +++ b/src/main/java/sh/ball/parser/obj/ObjFrameSettings.java @@ -10,14 +10,16 @@ public class ObjFrameSettings { public Vector3 currentRotation; public Double rotateSpeed; public boolean resetRotation = false; + public Boolean hideEdges = null; - protected ObjFrameSettings(Double focalLength, Vector3 cameraPos, Vector3 baseRotation, Vector3 currentRotation, Double rotateSpeed, boolean resetRotation) { + protected ObjFrameSettings(Double focalLength, Vector3 cameraPos, Vector3 baseRotation, Vector3 currentRotation, Double rotateSpeed, boolean resetRotation, Boolean hideEdges) { this.focalLength = focalLength; this.cameraPos = cameraPos; this.baseRotation = baseRotation; this.currentRotation = currentRotation; this.rotateSpeed = rotateSpeed; this.resetRotation = resetRotation; + this.hideEdges = hideEdges; } protected ObjFrameSettings(double focalLength) { diff --git a/src/main/java/sh/ball/parser/obj/ObjFrameSource.java b/src/main/java/sh/ball/parser/obj/ObjFrameSource.java index 37540b6..c25702c 100644 --- a/src/main/java/sh/ball/parser/obj/ObjFrameSource.java +++ b/src/main/java/sh/ball/parser/obj/ObjFrameSource.java @@ -67,12 +67,15 @@ public class ObjFrameSource implements FrameSource> { if (obj.resetRotation) { object.resetRotation(); } + if (obj.hideEdges != null) { + object.hideEdges(obj.hideEdges); + } } } // TODO: Refactor! @Override public Object getFrameSettings() { - return ObjSettingsFactory.rotation(baseRotation, currentRotation); + return new ObjFrameSettings(null, null, baseRotation, currentRotation, null, false, object.edgesHidden()); } } diff --git a/src/main/java/sh/ball/parser/obj/ObjSettingsFactory.java b/src/main/java/sh/ball/parser/obj/ObjSettingsFactory.java index b4b706c..235ee9a 100644 --- a/src/main/java/sh/ball/parser/obj/ObjSettingsFactory.java +++ b/src/main/java/sh/ball/parser/obj/ObjSettingsFactory.java @@ -17,7 +17,7 @@ public class ObjSettingsFactory { } public static ObjFrameSettings rotation(Vector3 baseRotation, Vector3 currentRotation) { - return new ObjFrameSettings(null, null, baseRotation, currentRotation, null, false); + return new ObjFrameSettings(null, null, baseRotation, currentRotation, null, false, null); } public static ObjFrameSettings rotateSpeed(double rotateSpeed) { @@ -27,4 +27,8 @@ public class ObjSettingsFactory { public static ObjFrameSettings resetRotation() { return new ObjFrameSettings(true); } + + public static ObjFrameSettings hideEdges(Boolean hideEdges) { + return new ObjFrameSettings(null, null, null, null, null, false, hideEdges); + } } diff --git a/src/main/resources/fxml/main.fxml b/src/main/resources/fxml/main.fxml index a85bb34..3bce499 100644 --- a/src/main/resources/fxml/main.fxml +++ b/src/main/resources/fxml/main.fxml @@ -70,6 +70,7 @@ +