はじめての JavaFX 3D

今回はちょっと背伸びをして、3D を試してみたいと思います。

先日、シリンダーをちょこっと作ってみて割と簡単に作れるんだと思い調子ぶっこく私です。

実は Getting Started with JavaFX 3D Graphics と言うチュートリアルが出ました。

しかし、バリバリの英語なので良く解りません。

いつものことですがそれは置いといて、あーでもない、こーでもない、と JavaFX 3D API と戯れてみました。

そういうことなので適当なことをいつもと同じようにしてます。(^_^;)

今回は下の画像のようなものを作って、スライダーでグリグリ動かせるようにしてみました。

1

2

3

4

また、X軸とY軸だけですけどレイアウトの変更もスライダーでできるようにしてみました。

ついでにライトと反射光も設定できるようにしました。

リセットスイッチとカメラ関係もと思いましたがめんどくさくなってきたので止めにしました。(ヲヒ

それではいい加減で適当なプログラムですが載せておきますね。

間違い等ありましたら優しく御教示くださいませ!

package jp.yucchi.cylinder_3d;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Cylinder_3D extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        // FXMLDocumentController に Scene を渡す。
        // もっとスマートな方法があるかもしれない。
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        Parent root = (Parent) loader.load();
        FXMLDocumentController c = loader.getController();
        Scene scene = new Scene(root);
        c.setThisScene(scene);

//        // こっちでも問題は無い。
//        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
//        Scene scene = new Scene(root);
//        PerspectiveCamera cam = new PerspectiveCamera(false);
//        scene.setCamera(cam);
        stage.setTitle("はじめての JavaFX 3D");
        stage.setScene(scene);
        stage.show();
    }

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

}

package jp.yucchi.cylinder_3d;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.AmbientLight;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Slider;
import javafx.scene.control.TitledPane;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Shape3D;
import javafx.scene.transform.Rotate;

public class FXMLDocumentController implements Initializable {

    @FXML
    private AnchorPane ap;

    @FXML
    private AnchorPane ap_3d;

    @FXML
    private TitledPane Transforms;

    @FXML
    private TitledPane Layout;

    @FXML
    private TitledPane Light;

    @FXML
    private Slider Transform_X;

    @FXML
    private Slider Transform_Y;

    @FXML
    private Slider Transform_Z;

    @FXML
    private Slider Layout_X;

    @FXML
    private Slider Layout_Y;

    @FXML
    private ComboBox DiffuseColorCombo;

    @FXML
    private ComboBox SpecularColorCombo;

    @FXML
    private ComboBox AmbientLightCombo;

    @FXML
    private ComboBox PointLightCombo;

    @FXML
    private Slider Ambient_slider;

    @FXML
    private Slider Point_slider;

    private Color diffuseColor;

    private Color specularColor;

    private AmbientLight ambient;

    private PointLight point;

    @FXML
    public void handleDiffuse(ActionEvent event) {

        switch (DiffuseColorCombo.getValue()) {
            case "WHITE":
                diffuseColor = Color.WHITE;
                break;
            case "AQUA":
                diffuseColor = Color.AQUA;
                break;
            case "YELLOW":
                diffuseColor = Color.YELLOW;
                break;
            case "RED":
                diffuseColor = Color.RED;
                break;
            case "PINK":
                diffuseColor = Color.PINK;
                break;
            case "VIOLET":
                diffuseColor = Color.VIOLET;
                break;
            case "GREEN":
                diffuseColor = Color.GREEN;
                break;
            case "ORANGE":
                diffuseColor = Color.ORANGE;
                break;
            case "BLACK":
                diffuseColor = Color.BLACK;
                break;
            default:
                diffuseColor = Color.GHOSTWHITE;
        }

        material.setDiffuseColor(diffuseColor);

    }

    @FXML
    public void handleSpecular(ActionEvent event) {

        switch (SpecularColorCombo.getValue()) {
            case "WHITE":
                specularColor = Color.WHITE;
                break;
            case "AQUA":
                specularColor = Color.AQUA;
                break;
            case "YELLOW":
                specularColor = Color.YELLOW;
                break;
            case "RED":
                specularColor = Color.RED;
                break;
            case "PINK":
                specularColor = Color.PINK;
                break;
            case "VIOLET":
                specularColor = Color.VIOLET;
                break;
            case "GREEN":
                specularColor = Color.GREEN;
                break;
            case "ORANGE":
                specularColor = Color.ORANGE;
                break;
            case "BLACK":
                specularColor = Color.BLACK;
                break;
            default:
                specularColor = Color.GHOSTWHITE;
        }

        material.setSpecularColor(specularColor);

    }

    @FXML
    public void handleAmbientLight(ActionEvent event) {

        switch (AmbientLightCombo.getValue()) {
            case "WHITE":
                ambient.setColor(Color.rgb(255, 255, 255, Ambient_slider.getValue()));
                break;
            case "AQUA":
                ambient.setColor(Color.rgb(0, 255, 255, Ambient_slider.getValue()));
                break;
            case "YELLOW":
                ambient.setColor(Color.rgb(255, 255, 0, Ambient_slider.getValue()));
                break;
            case "RED":
                ambient.setColor(Color.rgb(255, 0, 0, Ambient_slider.getValue()));
                break;
            case "PINK":
                ambient.setColor(Color.rgb(255, 192, 203, Ambient_slider.getValue()));
                break;
            case "VIOLET":
                ambient.setColor(Color.rgb(238, 130, 238, Ambient_slider.getValue()));
                break;
            case "GREEN":
                ambient.setColor(Color.rgb(0, 128, 0, Ambient_slider.getValue()));
                break;
            case "ORANGE":
                ambient.setColor(Color.rgb(255, 165, 0, Ambient_slider.getValue()));
                break;
            case "BLACK":
                ambient.setColor(Color.rgb(0, 0, 0, Ambient_slider.getValue()));
                break;
            default:
                ambient.setColor(Color.rgb(184, 134, 11, Ambient_slider.getValue()));
        }

    }

    @FXML
    public void handlePointtLight(ActionEvent event) {

        switch (PointLightCombo.getValue()) {
            case "WHITE":
                point.setColor(Color.rgb(255, 255, 255, Point_slider.getValue()));
                break;
            case "AQUA":
                point.setColor(Color.rgb(0, 255, 255, Point_slider.getValue()));
                break;
            case "YELLOW":
                point.setColor(Color.rgb(255, 255, 0, Point_slider.getValue()));
                break;
            case "RED":
                point.setColor(Color.rgb(255, 0, 0, Point_slider.getValue()));
                break;
            case "PINK":
                point.setColor(Color.rgb(255, 192, 203, Point_slider.getValue()));
                break;
            case "VIOLET":
                point.setColor(Color.rgb(238, 130, 238, Point_slider.getValue()));
                break;
            case "GREEN":
                point.setColor(Color.rgb(0, 128, 0, Point_slider.getValue()));
                break;
            case "ORANGE":
                point.setColor(Color.rgb(255, 165, 0, Point_slider.getValue()));
                break;
            case "BLACK":
                point.setColor(Color.rgb(0, 0, 0, Point_slider.getValue()));
                break;
            default:
                point.setColor(Color.rgb(184, 134, 11, Point_slider.getValue()));
        }

    }

    private Scene scene;
    private PerspectiveCamera cam;
    private Cylinder cylinder;
    private PhongMaterial material;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // 3Dオブジェクトを生成。
        Shape3D cl = make3DObject(500, 350, 80, 250);
        // 周囲の光源オブジェクトを定義します。
        ambient = new AmbientLight();
        ambient.setColor(Color.rgb(184, 134, 11, 0.5));

        // 点光源を設定。
        point = new PointLight();
        point.setColor(Color.rgb(255, 255, 255, 1));
        // レイアウト設定。
        point.setLayoutX(400);
        point.setLayoutY(100);
        point.setTranslateZ(-1100);
        point.getScope().add(cl);
        ap_3d.getChildren().addAll(cl, point, ambient);

        // これより設定値変更処理
        Transform_X.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            cylinder.getTransforms().add(new Rotate(newValue.doubleValue() - oldValue.doubleValue(), Rotate.X_AXIS));
        });

        Transform_Y.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            cylinder.getTransforms().add(new Rotate(newValue.doubleValue() - oldValue.doubleValue(), Rotate.Y_AXIS));
        });

        Transform_Z.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            cylinder.getTransforms().add(new Rotate(newValue.doubleValue() - oldValue.doubleValue(), Rotate.Z_AXIS));
        });

        Layout_X.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            cylinder.setLayoutX(newValue.doubleValue());
        });

        Layout_Y.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            cylinder.setLayoutY(newValue.doubleValue());
        });

        Ambient_slider.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            if (AmbientLightCombo.getValue() != null) {
                switch (AmbientLightCombo.getValue()) {
                    case "WHITE":
                        ambient.setColor(Color.rgb(255, 255, 255, newValue.doubleValue()));
                        break;
                    case "AQUA":
                        ambient.setColor(Color.rgb(0, 255, 255, newValue.doubleValue()));
                        break;
                    case "YELLOW":
                        ambient.setColor(Color.rgb(255, 255, 0, newValue.doubleValue()));
                        break;
                    case "RED":
                        ambient.setColor(Color.rgb(255, 0, 0, newValue.doubleValue()));
                        break;
                    case "PINK":
                        ambient.setColor(Color.rgb(255, 192, 203, newValue.doubleValue()));
                        break;
                    case "VIOLET":
                        ambient.setColor(Color.rgb(238, 130, 238, newValue.doubleValue()));
                        break;
                    case "GREEN":
                        ambient.setColor(Color.rgb(0, 128, 0, newValue.doubleValue()));
                        break;
                    case "ORANGE":
                        ambient.setColor(Color.rgb(255, 165, 0, newValue.doubleValue()));
                        break;
                    case "BLACK":
                        ambient.setColor(Color.rgb(0, 0, 0, newValue.doubleValue()));
                        break;
                    default:
                        ambient.setColor(Color.rgb(184, 134, 11, newValue.doubleValue()));
                }
            } else {
                ambient.setColor(Color.rgb(184, 134, 11, newValue.doubleValue()));
            }
        });

        Point_slider.valueProperty().addListener((ObservableValue observable, Number oldValue, Number newValue) -> {
            if (PointLightCombo.getValue() != null) {
                switch (PointLightCombo.getValue()) {
                    case "WHITE":
                        point.setColor(Color.rgb(255, 255, 255, newValue.doubleValue()));
                        break;
                    case "AQUA":
                        point.setColor(Color.rgb(0, 255, 255, newValue.doubleValue()));
                        break;
                    case "YELLOW":
                        point.setColor(Color.rgb(255, 255, 0, newValue.doubleValue()));
                        break;
                    case "RED":
                        point.setColor(Color.rgb(255, 0, 0, newValue.doubleValue()));
                        break;
                    case "PINK":
                        point.setColor(Color.rgb(255, 192, 203, newValue.doubleValue()));
                        break;
                    case "VIOLET":
                        point.setColor(Color.rgb(238, 130, 238, newValue.doubleValue()));
                        break;
                    case "GREEN":
                        point.setColor(Color.rgb(0, 128, 0, newValue.doubleValue()));
                        break;
                    case "ORANGE":
                        point.setColor(Color.rgb(255, 165, 0, newValue.doubleValue()));
                        break;
                    case "BLACK":
                        point.setColor(Color.rgb(0, 0, 0, newValue.doubleValue()));
                        break;
                    default:
                        point.setColor(Color.rgb(255, 255, 255, newValue.doubleValue()));
                }
            } else {
                point.setColor(Color.rgb(255, 255, 255, newValue.doubleValue()));
            }
        });

    }

    private Shape3D make3DObject(double x, double y, double radius, double height) {
        // シリンダーオブジェクトを生成。
        cylinder = new Cylinder(radius, height);
        // フォンシェーディングを設定。
        material = new PhongMaterial();
        // テクスチャを貼る。
        Image diffuseMap = new Image(getClass().getResource("Duke.jpg").toString());
        material.setDiffuseMap(diffuseMap);
        cylinder.setMaterial(material);
        // 散乱光による色の設定
        material.setDiffuseColor(Color.GHOSTWHITE);
        // スペキュラカラー(反射光の色)の設定。
        material.setSpecularColor(Color.BLACK);
        cylinder.setMaterial(material);
        cylinder.setLayoutX(x);
        cylinder.setLayoutY(y);
        cylinder.getTransforms().add(new Rotate(0, Rotate.X_AXIS));
        cylinder.getTransforms().add(new Rotate(0, Rotate.Y_AXIS));
        cylinder.getTransforms().add(new Rotate(0, Rotate.Z_AXIS));
        return cylinder;

    }

    void setThisScene(Scene scene) {
        this.scene = scene;
        cam = new PerspectiveCamera(false);
        scene.setCamera(cam);
    }

}











  
    
    
      
        
          
            
              
                
                
                
                
            
          
        
      
      
        
        
          
            
              
                
                
                
            
          
        
        
          
            
              
                
            
          
        
      
    
  


いつものように動画もサービスです!

余計なお世話でしょうが Java 8 実行環境の勇者様にはこちらをお試しでします。

Webstart: click to launch this app as webstart (Java 8 実行環境必須)

Hatena タグ:

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です