Skip to content

Instantly share code, notes, and snippets.

@Birdasaur
Created June 6, 2022 14:14
Show Gist options
  • Select an option

  • Save Birdasaur/ae9acb83315c69bb1c2d9eff5ec53ee2 to your computer and use it in GitHub Desktop.

Select an option

Save Birdasaur/ae9acb83315c69bb1c2d9eff5ec53ee2 to your computer and use it in GitHub Desktop.
package edu.jhuapl.trinity.javafx;
/*-
* #%L
* ******************************* UNCLASSIFIED *******************************
* LookAtTest.java
* trinity:trinity
* %%
* Copyright (C) 2021 - 2022 Johns Hopkins University Applied Physics Laboratory
* %%
* (c) Johns Hopkins University Applied Physics Laboratory. All Rights Reserved.
* This material may only be used, modified, or reproduced by or for the
* U.S. government pursuant to the license rights granted under FAR
* clause 52.227-14 or DFARS clauses 252.227-7013/7014.
* For any other permission, please contact the Legal Office at JHU/APL.
* #L%
*/
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import org.fxyz3d.geometry.MathUtils;
import org.fxyz3d.utils.CameraTransformer;
public class LookAtTest extends Application {
PerspectiveCamera camera = new PerspectiveCamera(true);
public Group sceneRoot = new Group();
public SubScene subScene;
public CameraTransformer cameraTransform = new CameraTransformer();
private double cameraDistance = -500;
private final double sceneWidth = 4000;
private final double sceneHeight = 4000;
private double mousePosX;
private double mousePosY;
private double mouseOldX;
private double mouseOldY;
private double mouseDeltaX;
private double mouseDeltaY;
@Override
public void start(Stage primaryStage) throws Exception {
subScene = new SubScene(sceneRoot, sceneWidth, sceneHeight, true, SceneAntialiasing.BALANCED);
//Start Tracking mouse movements only when a button is pressed
subScene.setOnMouseDragged((MouseEvent me) -> mouseDragCamera(me));
subScene.setOnScroll((ScrollEvent event) -> {
double modifier = 2.0;
double modifierFactor = 0.1;
if (event.isControlDown()) {
modifier = 1;
}
if (event.isShiftDown()) {
modifier = 50.0;
}
double z = camera.getTranslateZ();
double newZ = z + event.getDeltaY() * modifierFactor * modifier;
camera.setTranslateZ(newZ);
});
StackPane stackPane = new StackPane(subScene);
subScene.widthProperty().bind(stackPane.widthProperty());
subScene.heightProperty().bind(stackPane.heightProperty());
subScene.setFill(Color.BLACK);
camera = new PerspectiveCamera(true);
//setup camera transform for rotational support
cameraTransform.setTranslate(0, 0, 0);
cameraTransform.getChildren().add(camera);
camera.setNearClip(0.1);
camera.setFarClip(100000.0);
camera.setTranslateZ(cameraDistance);
cameraTransform.ry.setAngle(-45.0);
cameraTransform.rx.setAngle(-10.0);
subScene.setCamera(camera);
AmbientLight ambientLight = new AmbientLight(Color.WHITE);
Box center = new Box(2, 2, 2);
center.setMaterial(new PhongMaterial(Color.AQUA));
Sphere body = new Sphere(10);
Box pointer = new Box(2, 2, 20);
pointer.setMaterial(new PhongMaterial(Color.TOMATO));
pointer.setTranslateZ(10);
Group pointyGroup = new Group(body, pointer);
pointyGroup.setTranslateX(-100);
Sphere sphereX = new Sphere(5);
sphereX.setTranslateX(100);
sphereX.setMaterial(new PhongMaterial(Color.RED));
sphereX.setOnMouseClicked(e -> {
Point3D currentPoint3D = new Point3D(
pointyGroup.getTranslateX(),
pointyGroup.getTranslateY(),
pointyGroup.getTranslateZ());
Point3D lookAtPoint3D = new Point3D(
sphereX.getTranslateX(),
sphereX.getTranslateY(),
sphereX.getTranslateZ());
lookAt(pointyGroup, currentPoint3D, lookAtPoint3D);
});
Sphere sphereY = new Sphere(5);
sphereY.setTranslateY(-100);
sphereY.setMaterial(new PhongMaterial(Color.GREEN));
sphereY.setOnMouseClicked(e -> {
Point3D currentPoint3D = new Point3D(
pointyGroup.getTranslateX(),
pointyGroup.getTranslateY(),
pointyGroup.getTranslateZ());
Point3D lookAtPoint3D = new Point3D(
sphereY.getTranslateX(),
sphereY.getTranslateY(),
sphereY.getTranslateZ());
lookAt(pointyGroup, currentPoint3D, lookAtPoint3D);
});
Sphere sphereZ = new Sphere(5);
sphereZ.setTranslateZ(100);
sphereZ.setMaterial(new PhongMaterial(Color.BLUE));
sphereZ.setOnMouseClicked(e -> {
Point3D currentPoint3D = new Point3D(
pointyGroup.getTranslateX(),
pointyGroup.getTranslateY(),
pointyGroup.getTranslateZ());
Point3D lookAtPoint3D = new Point3D(
sphereZ.getTranslateX(),
sphereZ.getTranslateY(),
sphereZ.getTranslateZ());
lookAt(pointyGroup, currentPoint3D, lookAtPoint3D);
});
sceneRoot.getChildren().addAll(cameraTransform, ambientLight,
center, sphereX, sphereY, sphereZ, pointyGroup);
BorderPane bpOilSpill = new BorderPane(subScene);
stackPane.getChildren().clear();
stackPane.getChildren().addAll(bpOilSpill);
stackPane.setPadding(new Insets(10));
stackPane.setBackground(new Background(new BackgroundFill(Color.rgb(255, 255, 255), CornerRadii.EMPTY, Insets.EMPTY)));
Scene scene = new Scene(stackPane, 1000, 1000);
scene.setOnMouseEntered(event -> subScene.requestFocus());
primaryStage.setTitle("Multiple SpotLight Test");
primaryStage.setScene(scene);
primaryStage.show();
}
public void lookAt(Node node, javafx.geometry.Point3D currentPosition, javafx.geometry.Point3D lookAtPos) {
//Create direction vector
javafx.geometry.Point3D lookDirection = lookAtPos.subtract(currentPosition.getX(), currentPosition.getY(), currentPosition.getZ());
lookDirection = lookDirection.normalize();
double xRotation = Math.toDegrees(Math.asin(-lookDirection.getY()));
double yRotation = Math.toDegrees(Math.atan2( lookDirection.getX(), lookDirection.getZ()));
Rotate ry = new Rotate(yRotation, currentPosition.getX(), currentPosition.getY(), currentPosition.getZ(), Rotate.Y_AXIS);
Rotate rx = new Rotate(xRotation, currentPosition.getX(), currentPosition.getY(), currentPosition.getZ(), Rotate.X_AXIS);
node.getTransforms().setAll( ry, rx, new Translate(
currentPosition.getX(), currentPosition.getY(), currentPosition.getZ()));
}
private void mouseDragCamera(MouseEvent me) {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseDeltaX = (mousePosX - mouseOldX);
mouseDeltaY = (mousePosY - mouseOldY);
double modifier = 5.0;
double modifierFactor = 0.1;
if (me.isControlDown()) {
modifier = 1;
}
if (me.isShiftDown()) {
modifier = 10.0;
}
if (me.isPrimaryButtonDown()) {
if(me.isAltDown()) { //roll
cameraTransform.rz.setAngle(((cameraTransform.rz.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0) % 360 + 540) % 360 - 180); // +
} else {
cameraTransform.ry.setAngle(((cameraTransform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0) % 360 + 540) % 360 - 180); // +
cameraTransform.rx.setAngle(
MathUtils.clamp(-60,
(((cameraTransform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0) % 360 + 540) % 360 - 180),
60)); // -
}
} else if (me.isMiddleButtonDown() ) {
cameraTransform.t.setX(cameraTransform.t.getX() + mouseDeltaX * modifierFactor * modifier * 0.3); // -
cameraTransform.t.setY(cameraTransform.t.getY() + mouseDeltaY * modifierFactor * modifier * 0.3); // -
}
}
public static void main(String[] args){
Application.launch(LookAtTest.class, args);
}
}
@Birdasaur
Copy link
Author

@jperedadnr Hey I am trying to implement a lookAt function for a 3D node but I've screwed up the transforms some how.
I'm trying to follow the threads found here:
https://stackoverflow.com/questions/39215592/equivalent-for-glulookat-in-javafx-3d
and
https://community.oracle.com/tech/developers/discussion/3868043/javafx-perspective-camera-lookat-method

@Birdasaur
Copy link
Author

My goal with this test is to just point the sphere (via the pointer Box) towards and arbitrary Point3D.
This implementation seems close... but it seems to translate my PointyGroup to another point than I expected. Is this a Scene vs SubScene issue?
Is there a better way to do it?

@Birdasaur
Copy link
Author

image
If I place the pointy group at 0, 0, 0 (no translations) the lookAt rotation works

@Birdasaur
Copy link
Author

if i set the initial translation of the group to something other than 0,0,0 (arbitrary... image is translateX(-100) it seems to add the existing translation to the original?
image

@jperedadnr
Copy link

Not sure if I get it right... but have you tried adding the transforms of the parent?

node.getTransforms().setAll(...);
+ node.getTransforms().addAll(0, node.getParent().getTransforms());

@Birdasaur
Copy link
Author

this didn't work either... :-/

   node.getTransforms().setAll( ry, rx, new Translate( 
        currentPosition.getX(), currentPosition.getY(), currentPosition.getZ())); 
    node.getTransforms().addAll(0, node.getParent().getTransforms());  

@Birdasaur
Copy link
Author

its close... the problem is that its adding the original translation I think... and I'm not sure if its because the "node" is actually a Group?

@Birdasaur
Copy link
Author

So this worked:
Rotate ry = new Rotate(yRotation, 0, 0, 0, Rotate.Y_AXIS);
Rotate rx = new Rotate(xRotation, 0, 0, 0, Rotate.X_AXIS);

    node.getTransforms().setAll( ry, rx);

Doing the rotation around 0,0,0 as the pivot point but then not adding in a translate after

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment