kopia lustrzana https://github.com/jameshball/osci-render
Implement toggle to remove hidden edges from objects
rodzic
a039583e68
commit
8ac9cf1104
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
|||
|
||||
<groupId>sh.ball</groupId>
|
||||
<artifactId>osci-render</artifactId>
|
||||
<version>1.20.3</version>
|
||||
<version>1.21.3</version>
|
||||
|
||||
<name>osci-render</name>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ public class WorldObject {
|
|||
private List<Vector3> vertexPath;
|
||||
private Vector3 position;
|
||||
private Vector3 rotation;
|
||||
private boolean hideEdges = false;
|
||||
|
||||
private WorldObject(List<Vector3> objVertices, List<Vector3> vertexPath, Vector3 position,
|
||||
Vector3 rotation) {
|
||||
|
@ -56,8 +57,6 @@ public class WorldObject {
|
|||
Graph<Vector3, DefaultWeightedEdge> 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<Vector3> vertices : inspector.connectedSets()) {
|
||||
AsSubgraph<Vector3, DefaultWeightedEdge> subgraph = new AsSubgraph<>(graph, vertices);
|
||||
ChinesePostman<Vector3, DefaultWeightedEdge> cp = new ChinesePostman<>();
|
||||
List<Vector3> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
|||
@FXML
|
||||
private CheckMenuItem flipYCheckMenuItem;
|
||||
@FXML
|
||||
private CheckMenuItem hideHiddenMeshesCheckMenuItem;
|
||||
@FXML
|
||||
private Spinner<Integer> midiChannelSpinner;
|
||||
@FXML
|
||||
private Spinner<Double> 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<TextFormatter.Change> 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()));
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -67,12 +67,15 @@ public class ObjFrameSource implements FrameSource<List<Shape>> {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
<items>
|
||||
<CheckMenuItem fx:id="flipXCheckMenuItem" mnemonicParsing="false" text="Flip X Direction" />
|
||||
<CheckMenuItem fx:id="flipYCheckMenuItem" mnemonicParsing="false" text="Flip Y Direction" />
|
||||
<CheckMenuItem fx:id="hideHiddenMeshesCheckMenuItem" mnemonicParsing="false" text="Hide Hidden Meshes" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Controls">
|
||||
|
|
Ładowanie…
Reference in New Issue