How to revive spinning?

This is Hanukkah, and I'm trying to revive a spinning top (dreidel):

spinning top

I can make it spin on its own axis. Here is my code:

import static javafx.scene.paint.Color.*;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class DreidelAnim extends Application {

    private double bodyBase = 30;
    private double bodyHeight = bodyBase * 3 / 2;
    private double baseRadius = bodyBase / 2;

    @Override
    public void start(Stage stage) throws Exception {
        DoubleProperty spinAngle = new SimpleDoubleProperty();
        Rotate spin = new Rotate(0, Rotate.Z_AXIS);
        spin.angleProperty().bind(spinAngle);

        Timeline spinAnim = new Timeline(new KeyFrame(Duration.seconds(2), new KeyValue(spinAngle, 360)));
        spinAnim.setCycleCount(Timeline.INDEFINITE);
        spinAnim.play();

        Group dreidel = createDreidel();
        Translate zTrans = new Translate(0, 0, -(bodyHeight/2 + baseRadius));
        dreidel.getTransforms().addAll(spin, zTrans);

        Scene scene = new Scene(dreidel, 200, 200, true, SceneAntialiasing.BALANCED);
        scene.setFill(SKYBLUE);
        scene.setCamera(createCamera());

        stage.setScene(scene);
        stage.show();
    }

    private Group createDreidel() {
        double handleHeight = bodyBase * 3/4;
        Cylinder handle = new Cylinder(bodyBase / 6, handleHeight);
        handle.setTranslateZ(-(bodyHeight + handleHeight) / 2);
        handle.setRotationAxis(Rotate.X_AXIS);
        handle.setRotate(90);
        handle.setMaterial(new PhongMaterial(RED));

        Box body = new Box(bodyBase, bodyBase, bodyHeight);
        body.setMaterial(new PhongMaterial(BLUE));

        Sphere base = new Sphere(baseRadius);
        base.setTranslateZ(bodyHeight / 2);
        base.setMaterial(new PhongMaterial(GREEN));

        return new Group(handle, body, base);
    }

    private Camera createCamera() {
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFarClip(1000);

        int xy = 150;
        Translate trans = new Translate(-xy, xy, -120);
        Rotate rotXY = new Rotate(70, new Point3D(1, 1, 0));
        Rotate rotZ = new Rotate(45, new Point3D(0, 0, 1));
        camera.getTransforms().addAll(trans, rotXY, rotZ);

        return camera;
    }

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

I created a simple model by rotating it around its axis and translating it so that its tip is on (0, 0, 0). Here is the result:

enter image description here

How can I achieve something like the image above, where it also rotates around the axis of rotation?

+6
source share
2 answers

The rotation of the axis around which the spins of an object are called Precession . The movement of the rotating top requires 2 turns:

  • Rotation of an object around its internal axis (parallel to the red handle).
  • (z ).

2 Animation . . (0, 0, 0) ( zTrans), z, .

:

import static javafx.scene.paint.Color.*;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class FinalDreidelSpin extends Application {

    private double bodyBase = 30;
    private double bodyHeight = bodyBase * 3 / 2;
    private double baseRadius = bodyBase / 2;

    @Override
    public void start(Stage stage) throws Exception {
        double tiltAngle = 40;
        DoubleProperty spinAngle = new SimpleDoubleProperty();

        Rotate spin = new Rotate(0, Rotate.Z_AXIS);
        Rotate tilt = new Rotate(tiltAngle, Rotate.X_AXIS);

        spin.angleProperty().bind(spinAngle);

        Timeline spinAnim = new Timeline();
        spinAnim.getKeyFrames().add(new KeyFrame(Duration.seconds(2), new KeyValue(spinAngle, 360)));
        spinAnim.setCycleCount(Timeline.INDEFINITE);
        spinAnim.play();

        Group dreidel = createDreidel();
        Translate zTrans = new Translate(0, 0, -(bodyHeight/2 + baseRadius));
        dreidel.getTransforms().addAll(spin, tilt, spin, zTrans);

        Scene scene = new Scene(new Group(dreidel, createAxes()), 200, 200, true, SceneAntialiasing.BALANCED);
        scene.setFill(SKYBLUE);
        scene.setCamera(createCamera());

        stage.setScene(scene);
        stage.show();
    }

    private Group createDreidel() {
        double handleHeight = bodyBase * 3/4;
        Cylinder handle = new Cylinder(bodyBase / 6, handleHeight);
        handle.setTranslateZ(-(bodyHeight + handleHeight) / 2);
        handle.setRotationAxis(Rotate.X_AXIS);
        handle.setRotate(90);
        handle.setMaterial(new PhongMaterial(RED));

        Box body = new Box(bodyBase, bodyBase, bodyHeight);
        body.setMaterial(new PhongMaterial(BLUE));

        Sphere base = new Sphere(baseRadius);
        base.setTranslateZ(bodyHeight / 2);
        base.setMaterial(new PhongMaterial(GREEN));

        return new Group(handle, body, base);
    }

    private Camera createCamera() {
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFarClip(1000);

        int xy = 150;
        Translate trans = new Translate(-xy, xy, -100);
        Rotate rotXY = new Rotate(70, new Point3D(1, 1, 0));
        Rotate rotZ = new Rotate(45, new Point3D(0, 0, 1));
        camera.getTransforms().addAll(trans, rotXY, rotZ);

        return camera;
    }

    private Group createAxes() {
        int axisWidth = 1;
        int axisLength = 400;

        Cylinder xAxis = new Cylinder(axisWidth, axisLength);
        xAxis.setMaterial(new PhongMaterial(CYAN));

        Cylinder yAxis = new Cylinder(axisWidth, axisLength);
        yAxis.setRotationAxis(Rotate.Z_AXIS);
        yAxis.setRotate(90);
        yAxis.setMaterial(new PhongMaterial(MAGENTA));

        Cylinder zAxis = new Cylinder(axisWidth, axisLength);
        zAxis.setRotationAxis(Rotate.X_AXIS);
        zAxis.setRotate(90);
        zAxis.setMaterial(new PhongMaterial(YELLOW));

        return new Group(xAxis, yAxis, zAxis);
    }

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

. , getTransforms() , ( getChildren()), . , .

- x y.
tilt, spin, getTransforms().addAll(tilt, spin, zTrans), (. 1 ), :

spin

spin, tilt, getTransforms().addAll(spin, tilt, zTrans), (. 2):

precession

2, , :

full

+8

, @user1803551, , .

:

dreidel

, net dreidel, :

Fbnxv.png

.

, .

, TriangleMesh , 9 (3D-), 16 (2D) 14 , . width, - height. L = 4 * width, H = 2 * width + height.

, 0 0 - 2 - 1 8 - 3 - 7, 0 {width / 2, width / 2, width / 2}, 8 {width, 2 * width}, [0, 1]: {width / L, 2 * width / H}.

1fgB1.pngK97g4.png

:

float width = 375f;
float height = 351f;

3D-:

class DreidelMesh extends Group {

    float width = 375f;
    float height = 351f; 

    public DreidelMesh(){
        MeshView bodyMesh = new MeshView(createBodyMesh());
        PhongMaterial material = new PhongMaterial();
        material.setDiffuseMap(new Image(getClass().getResourceAsStream("3dreidel3d.png")));
        bodyMesh.setMaterial(material);

        Cylinder handle = new Cylinder(45, 260);
        handle.setTranslateY(-(handle.getHeight() + width) / 2);
        material = new PhongMaterial(Color.web("#daaf6d"));
        handle.setMaterial(material);

        getTransforms().add(new Rotate(90, Rotate.X_AXIS));
        getChildren().addAll(bodyMesh, handle);
    }

    private TriangleMesh createBodyMesh() {
        TriangleMesh m = new TriangleMesh();

        float L = 4f * width;
        float H = 2f * width + height;
        float w2 = width / 2f;

        // POINTS
        m.getPoints().addAll(
             w2,  w2,  w2, 
             w2,  w2, -w2, 
             w2, -w2,  w2, 
             w2, -w2, -w2, 
            -w2,  w2,  w2, 
            -w2,  w2, -w2, 
            -w2, -w2,  w2, 
            -w2, -w2, -w2, 
             0f,  w2 + height,  0f
        );

        // TEXTURES
        m.getTexCoords().addAll(
            width / L, 0f, 
            2f * width/ L, 0f, 
            0f, width / H,
            width / L, width / H, 
            2f * width/ L, width / H, 
            3f * width/ L, width / H, 
            1f, width / H, 
            0f, 2f * width / H,
            width / L, 2f * width / H, 
            2f * width/ L, 2f * width / H, 
            3f * width/ L, 2f * width / H, 
            1f, 2f * width / H, 
            width / 2f / L, 1f,
            3f * width / 2f / L, 1f,
            5f * width / 2f / L, 1f,
            7f * width / 2f / L, 1f
        );

        // FACES
        m.getFaces().addAll(
            0,  8, 2,  3, 1,  7,           
            2,  3, 3,  2, 1,  7,           
            4,  9, 5, 10, 6,  4,           
            6,  4, 5, 10, 7,  5,           
            0,  8, 1,  7, 8, 12,        
            4,  9, 0,  8, 8, 13,           
            5, 10, 4,  9, 8, 14,           
            1, 11, 5, 10, 8, 15,            
            2,  3, 6,  4, 3,  0,            
            3,  0, 6,  4, 7,  1,            
            0,  8, 4,  9, 2,  3,          
            2,  3, 4,  9, 6,  4,           
            1, 11, 3,  6, 5, 10,           
            5, 10, 3,  6, 7,  5
        );
        return m;
    }
}

dreidel

, , ( ), :

@Override
public void start(Stage stage) {
    double tiltAngle = 15;
    DoubleProperty spinAngle = new SimpleDoubleProperty();
    DoubleProperty precessionAngle = new SimpleDoubleProperty();

    Rotate spin = new Rotate(0, Rotate.Z_AXIS);
    Rotate precession = new Rotate(0, Rotate.Z_AXIS);
    Rotate tilt = new Rotate(tiltAngle, Rotate.X_AXIS);

    spin.angleProperty().bind(spinAngle);
    precession.angleProperty().bind(precessionAngle);

    Timeline spinAnim = new Timeline();
    spinAnim.getKeyFrames().add(new KeyFrame(Duration.seconds(1.5), new KeyValue(spinAngle, 360)));
    spinAnim.setCycleCount(Timeline.INDEFINITE);
    spinAnim.play();

    Timeline precessionAnim = new Timeline();
    precessionAnim.getKeyFrames().add(new KeyFrame(Duration.seconds(4), new KeyValue(precessionAngle, 360)));
    precessionAnim.setCycleCount(Timeline.INDEFINITE);
    precessionAnim.play();

    Group dreidel = new Group(new DreidelMesh());
    Translate zTrans = new Translate(0, 0, - dreidel.getBoundsInLocal().getMaxZ());
    dreidel.getTransforms().addAll(precession, tilt, spin, zTrans);

    Scene scene = new Scene(new Group(dreidel), 300, 300, true, SceneAntialiasing.BALANCED);
    scene.setFill(SKYBLUE);
    scene.setCamera(createCamera());

    stage.setScene(scene);
    stage.setTitle("JavaFX 3D - Dreidel");
    stage.show();
}

, .

+3

All Articles