3D-Grafik Rotationen

bronkowitz

Aktives Mitglied
Hallo zusammen,

ich arbeite mich grad in die 3D-Darstellung mit JavaFX ein. Der u.a. Code basiert auf der "MoleculeSampleApp", die es auf der Oracle-Seite als Einstieg gibt, ist aber stark vereinfacht. Er zeigt einfach eine Box mit einer roten Kugel vorn zur Orientierung.
Wenn man klickt, werden die zwei Drehungen der Kamera um 90° ausgeführt, außerdem kann man aber auch die Maus ziehen um die Kamera dynamisch zu drehen. (Zum Ausprobieren des Ziehens den Klickcode dann auskommentieren)

Mein Problem:

1. Wenn man die Maus zieht, wird zunächst die Drehung so ausgeführt wie man es auch erwartet: Ziehen nach links/rechts dreht die Ansicht um die Hochachse, als wenn man "vorne anfasst". Entsprechend ziehen nach oben unten um die horizontale Achse.
Aber je weiter man um die Hochachse gedreht hat, desto mehr verändert sich die Drehung quer dazu. Denn die Drehachsen werden mitgedreht. Das "MoleculeSampleApp"-Programm von Oracle verhält sich auch so - die Drehungen fühlen sich dadurch unnatürlich an. Kein CAD-Programm verhält sich meines Wissens nach so. Kennt einer da irgendeine Lösung?

2. Aber was ich überhaupt nicht kapiere ist folgendes: In der "setOnMousePressed"-Methode, ist das Verhalten völlig anders: Dort bleiben die Drehachsen immer konstant! Drehfolgen werden also immer um raumfeste Achsen ausgeführt, unabhängig von den vorherigen Drehungen (bzw. hier ist es nur eine) weil sich hier die Drehachsen NICHT mitdrehen.
Wenn man die beiden Drehungen im Code (oder irgendwelche anderen) mit einer Schachtel oder so von Hand nachdreht, kann man das nachvollziehen. Dabei muss man nur darauf achten, dass es sich um Drehungen der Kamera - nicht des Objektes - handelt. Also mit umgekehrtem Vorzeichen. (Sorry für die Mühe)

Wie kann das denn angehen? o_O

Gruß,
bronkowitz

Java:
package transformationen;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
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;

public class Transformationen extends Application {

    final Group root = new Group();
    final XformWorld world = new XformWorld();
    final PerspectiveCamera camera = new PerspectiveCamera(true);
    final XformCamera cameraXform = new XformCamera();
    private static final double CAMERA_INITIAL_DISTANCE = -1000;
    private static final double CAMERA_NEAR_CLIP = 0.1;
    private static final double CAMERA_FAR_CLIP = 10000.0;
    double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY;

    @Override
    public void start(Stage primaryStage) {
        root.getChildren().add(world);
        root.setDepthTest(DepthTest.ENABLE);
        buildCamera();
        buildBodySystem();
        Scene scene = new Scene(root, 800, 600, true);
        scene.setFill(Color.GREY);
        handleMouse(scene);
        primaryStage.setTitle("Transformationen");
        primaryStage.setScene(scene);
        primaryStage.show();
        scene.setCamera(camera);
    }

    private void buildCamera() {
        root.getChildren().add(cameraXform);
        cameraXform.getChildren().add(camera);
        camera.setNearClip(CAMERA_NEAR_CLIP);
        camera.setFarClip(CAMERA_FAR_CLIP);
        camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
    }

    private void buildBodySystem() {
        PhongMaterial whiteMaterial = new PhongMaterial();
        whiteMaterial.setDiffuseColor(Color.WHITE);
        whiteMaterial.setSpecularColor(Color.LIGHTBLUE);
        Box box = new Box(400, 200, 100);
        box.setMaterial(whiteMaterial);
        PhongMaterial redMaterial = new PhongMaterial();
        redMaterial.setDiffuseColor(Color.DARKRED);
        redMaterial.setSpecularColor(Color.RED);
        Sphere sphere = new Sphere(5);
        sphere.setMaterial(redMaterial);
        sphere.setTranslateZ(-50.0);
        world.getChildren().addAll(box);
        world.getChildren().addAll(sphere);
    }

    private void handleMouse(Scene scene) {
        scene.setOnMousePressed((MouseEvent me) -> {
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            mouseOldX = me.getSceneX();
            mouseOldY = me.getSceneY();
            // Diese Drehungen werden nach dem Klicken ausgeführt. Sie werden
            // offenbar immer um die UNVERDREHTEN Achsen vorgenommen.
            cameraXform.rx.setAngle(-90.0);
            cameraXform.ry.setAngle(180.0);
        });
        scene.setOnMouseDragged((MouseEvent me) -> {
            mouseOldX = mousePosX;
            mouseOldY = mousePosY;
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            mouseDeltaX = (mousePosX - mouseOldX);
            mouseDeltaY = (mousePosY - mouseOldY);
            if (me.isPrimaryButtonDown()) {
                // Diese Drehungen werden beim Ziehen der Maus ausgeführt. Sie
                // werden immer um die MITVERDREHTEN Achsen vorgenommen, stimmen
                // also nur anfänglich mit den obigen überein.
                cameraXform.ry.setAngle(cameraXform.ry.getAngle() + mouseDeltaX * 0.2);
                cameraXform.rx.setAngle(cameraXform.rx.getAngle() - mouseDeltaY * 0.2);
            }
        });
    }

    public static void main(String[] args) {
        launch(args);
    }

}

class XformWorld extends Group {

    final Translate t = new Translate(0.0, 0.0, 0.0);
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);

    public XformWorld() {
        super();
        this.getTransforms().addAll(t, rx, ry, rz);
    }

}

class XformCamera extends Group {

    final Translate t = new Translate(0.0, 0.0, 0.0);
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);

    public XformCamera() {
        super();
        this.getTransforms().addAll(t, rx, ry, rz);
    }

}
 

bronkowitz

Aktives Mitglied
ich weiß nicht, ob es jemanden interessiert, aber ich habe jetzt eine Lösung gefunden, wie es so funktioniert, wie ich es mir vorstellen würde.

Gruß,
bronkowitz

Java:
package trafotest;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Point3D;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
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.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class TrafoTest extends Application {
    final Group root = new Group();
    final XformWorld world = new XformWorld();
    final PerspectiveCamera camera = new PerspectiveCamera(true);
    final XformCamera cameraXform = new XformCamera();
    private static final double CAMERA_INITIAL_DISTANCE = -1000;
    private static final double CAMERA_NEAR_CLIP = 0.1;
    private static final double CAMERA_FAR_CLIP = 10000.0;
    double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY;
    double mouseFactorX, mouseFactorY;

    @Override
    public void start(Stage primaryStage) {
        root.getChildren().add(world);
        root.setDepthTest(DepthTest.ENABLE);
        buildCamera();
        buildBodySystem();
        Scene scene = new Scene(root, 800, 600, true);
        scene.setFill(Color.GREY);
        handleMouse(scene);
        primaryStage.setTitle("TrafoTest");
        primaryStage.setScene(scene);
        primaryStage.show();
        scene.setCamera(camera);
        mouseFactorX = 180.0 / scene.getWidth();
        mouseFactorY = 180.0 / scene.getHeight();
    }

    private void buildCamera() {
        root.getChildren().add(cameraXform);
        cameraXform.getChildren().add(camera);
        camera.setNearClip(CAMERA_NEAR_CLIP);
        camera.setFarClip(CAMERA_FAR_CLIP);
        camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
    }

    private void buildBodySystem() {
        PhongMaterial whiteMaterial = new PhongMaterial();
        whiteMaterial.setDiffuseColor(Color.WHITE);
        whiteMaterial.setSpecularColor(Color.LIGHTBLUE);
        Box box = new Box(400, 200, 100);
        box.setMaterial(whiteMaterial);
        PhongMaterial redMaterial = new PhongMaterial();
        redMaterial.setDiffuseColor(Color.DARKRED);
        redMaterial.setSpecularColor(Color.RED);
        Sphere sphere = new Sphere(5);
        sphere.setMaterial(redMaterial);
        sphere.setTranslateX(200.0);
        sphere.setTranslateY(-100.0);
        sphere.setTranslateZ(-50.0);
        world.getChildren().addAll(box);
        world.getChildren().addAll(sphere);
    }

    private void handleMouse(Scene scene) {
        scene.setOnMousePressed((MouseEvent me) -> {
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            mouseOldX = me.getSceneX();
            mouseOldY = me.getSceneY();
        });
        scene.setOnMouseDragged((MouseEvent me) -> {
            mouseOldX = mousePosX;
            mouseOldY = mousePosY;
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            mouseDeltaX = (mousePosX - mouseOldX);
            mouseDeltaY = (mousePosY - mouseOldY);
            if (me.isPrimaryButtonDown()) {
                cameraXform.ry(mouseDeltaX * 180.0 / scene.getWidth());
                cameraXform.rx(-mouseDeltaY * 180.0 / scene.getHeight());
            } else if (me.isSecondaryButtonDown()) {
                camera.setTranslateZ(camera.getTranslateZ() + mouseDeltaY);
            }
        });
    }

    public static void main(String[] args) {
        launch(args);
    }

}

class XformWorld extends Group {
    final Translate t = new Translate(0.0, 0.0, 0.0);
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);
   
    public XformWorld() {
        super();
        this.getTransforms().addAll(t, rx, ry, rz);
    }
}

class XformCamera extends Group {
    Point3D px = new Point3D(1.0, 0.0, 0.0);
    Point3D py = new Point3D(0.0, 1.0, 0.0);
    Rotate r;
    Transform t = new Rotate();
   
    public XformCamera() {
        super();
    }
   
    public void rx(double angle) {
        r = new Rotate(angle, px);
        this.t = t.createConcatenation(r);
        this.getTransforms().clear();
        this.getTransforms().addAll(t);
    }
   
    public void ry(double angle) {
        r = new Rotate(angle, py);
        this.t = t.createConcatenation(r);
        this.getTransforms().clear();
        this.getTransforms().addAll(t);
    }

}
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben