package collada2; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.scene.Group; import javafx.scene.LightBase; import javafx.scene.Parent; import javafx.scene.PerspectiveCamera; import javafx.scene.PointLight; import javafx.scene.Scene; import javafx.scene.SubScene; import javafx.scene.control.Button; import javafx.scene.control.Slider; import javafx.scene.control.ToggleButton; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.Box; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; import javafx.scene.transform.Translate; import javafx.stage.Stage; public class Test3DModelImport extends Application { public static void main(String[] args) { // フォント色がおかしくなることへの対処 System.setProperty( "prism.lcdtext" , "false" ); // メインスレッドを起動 launch( args ); } // 3Dオブジェクト ColladaData collada = null; PerspectiveCamera camera = new PerspectiveCamera( true ); LightBase light = new PointLight(); // 軸のカラーリング設定 Color[] axisColor = { Color.RED , Color.BLUE , Color.GREEN }; /** * 【シーングラフ構成】 * root * ┣ Group(model1) * ┃ ┣ メッシュ1 * ┃ ┣ … * ┃ ┗ メッシュn */ @Override public void start(Stage primaryStage) throws Exception { // Colladaデータを取り込み String[] fileNames = { "3dmodel/Luka/luka1_0_1.dae" , "3dmodel/Miku/miku_ver1_1_1.dae" , "3dmodel/KioMiku_blender_20091010/Miku_1_5_1_20091010.dae" }; String fileName = fileNames[0] ; collada = Dae141FileLoader.load( fileName ); // シーングラフの構成 Group root = new Group(); // シーンの作成 Scene scene = new Scene( root , 1000 , 780 , Color.LIGHTGRAY ); // サブシーン(3D)の構成 SubScene x3Scene = createSubScene3D(); // 2次元シーンのサブシーンの構成 Parent x2Group = createControlNode( 0 , 0 , 2 , -90 , 0 , 0 ); SubScene x2Scene = new SubScene( x2Group , 1000 , 80 ); x2Scene.setLayoutY( 700 ); // シーングラフに登録 root.getChildren().addAll( x3Scene , x2Scene ); // ウィンドウ表示 primaryStage.setScene( scene ); primaryStage.show(); } /** * 3次元オブジェクトを投射するサブシーンを作成 * @return */ public SubScene createSubScene3D() { // 3次元シーンのルート・ノードを作成 Group root = new Group(); // サブシーンの作成。3Dシーンの奥行きを表現するため、Zバッファを有効にする SubScene x3Scene = new SubScene( root , 1000 , 700 , true , null ); // 中心軸を表示 double[] axisSize = { 10.0 , 0.005 , 0.005 , 0.005 , 10.0 , 0.005 , 0.005 , 0.005 , 10 }; for( int i = 0 ; i < 3 ; i++ ) { // 軸船を作成 Box axis = new Box(); axis.setWidth( axisSize[ i*3 ] ); axis.setHeight( axisSize[ i*3 + 1 ] ); axis.setDepth( axisSize[ i*3 + 2 ] ); // 色を設定 PhongMaterial material = new PhongMaterial(); material.setDiffuseColor( axisColor[i] ); axis.setMaterial( material ); root.getChildren().add( axis ); } // ジョイント・ボーンデータの表示 root.getChildren().add( collada.getJointsNode() ); // 光源設定 light.setTranslateX( 0 ); light.setTranslateY( 0 ); light.setTranslateZ( -10 ); root.getChildren().add( light ); // アンビエント光 //final AmbientLight ambientLight = new AmbientLight(Color.rgb(80, 80, 80, 0.1)); //x3Group.getChildren().add(ambientLight); // カメラ設定 camera.setFarClip( 3000 ); camera.setTranslateX( light.getTranslateX() ); camera.setTranslateY( light.getTranslateY() ); camera.setTranslateZ( light.getTranslateZ() ); x3Scene.setCamera( camera ); return x3Scene; } /** * コントロール用のパネルを作成する * @param xTrans * @param yTrans * @param zTrans * @param xRotate * @param yRotate * @param zRotate * @return */ public Parent createControlNode( double xTrans , double yTrans , double zTrans , double xRotate , double yRotate , double zRotate ) { // ルートノード作成 VBox root = new VBox(); // X軸スライダーの追加 HBox xBox = new HBox(); Text xAxisNote = new Text( "x軸" ); Slider xTransAxisSlider = new Slider(); Slider xRotateAxisSlider = new Slider(); xAxisNote.setFill( axisColor[0] ); xTransAxisSlider.setMinWidth( 500 ); xTransAxisSlider.setMin( -100 ); xTransAxisSlider.setMax( 100 ); xTransAxisSlider.setValue( xTrans ); xRotateAxisSlider.setMin( -180 ); xRotateAxisSlider.setMax( 180 ); xRotateAxisSlider.setValue( xRotate ); xBox.getChildren().addAll( xAxisNote , xTransAxisSlider , xRotateAxisSlider ); // Y軸スライダーの追加 HBox yBox = new HBox(); Text yAxisNote = new Text( "y軸" ); Slider yTransAxisSlider = new Slider(); Slider yRotateAxisSlider = new Slider(); yAxisNote.setFill( axisColor[1] ); yTransAxisSlider.setMinWidth( 500 ); yTransAxisSlider.setMin( -100 ); yTransAxisSlider.setMax( 100 ); yTransAxisSlider.setValue( yTrans ); yRotateAxisSlider.setMin( -180 ); yRotateAxisSlider.setMax( 180 ); yRotateAxisSlider.setValue( yRotate ); yBox.getChildren().addAll( yAxisNote , yTransAxisSlider , yRotateAxisSlider ); // Z軸スライダーの追加 HBox zBox = new HBox(); Text zAxisNote = new Text( "z軸" ); Slider zTransAxisSlider = new Slider(); Slider zRotateAxisSlider = new Slider(); zAxisNote.setFill( axisColor[2] ); zTransAxisSlider.setMinWidth( 500 ); zTransAxisSlider.setMin( -100 ); zTransAxisSlider.setMax( 100 ); zTransAxisSlider.setValue( zTrans ); zRotateAxisSlider.setMin( -180 ); zRotateAxisSlider.setMax( 180 ); zRotateAxisSlider.setValue( zRotate ); zBox.getChildren().addAll( zAxisNote , zTransAxisSlider , zRotateAxisSlider ); // スライダ初期設定 changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ); // スライダイベント登録 xTransAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); yTransAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); zTransAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); xRotateAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); yRotateAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); zRotateAxisSlider.valueProperty().addListener( ( ov , old , current ) -> changeTransform( xTransAxisSlider.getValue() , yTransAxisSlider.getValue() , zTransAxisSlider.getValue() , xRotateAxisSlider.getValue() , yRotateAxisSlider.getValue() , zRotateAxisSlider.getValue() ) ); // ボタンボックス HBox buttonBox = new HBox(); // リセットボタン Button resetButton = new Button("reset"); resetButton.addEventHandler( ActionEvent.ACTION , e -> { xTransAxisSlider.setValue( xTrans ); yTransAxisSlider.setValue( yTrans ); zTransAxisSlider.setValue( zTrans ); xRotateAxisSlider.setValue( xRotate ); yRotateAxisSlider.setValue( yRotate ); zRotateAxisSlider.setValue( zRotate ); } ); buttonBox.getChildren().add( resetButton ); // ジョイント表示切替 ToggleButton drawJointsButton = new ToggleButton( "ジョイント表示切替" ); drawJointsButton.setSelected( true ); drawJointsButton.selectedProperty().addListener( ( ov , old , current ) -> { collada.setJointVisible( drawJointsButton.isSelected() ); } ); buttonBox.getChildren().add( drawJointsButton ); // レイアウトへ登録 root.getChildren().addAll( xBox , yBox , zBox , buttonBox ); return root; } /** * モデル変換を行う関数 * @param xTrans * @param yTrans * @param zTrans * @param xRotate * @param yRotate * @param zRotate */ public void changeTransform( double xTrans , double yTrans , double zTrans , double xRotate , double yRotate , double zRotate ) { // 変換を適用 // 回転はワールド座標系[0,0,0]をピボット・ポイント(回転中心)に指定する camera.getTransforms().clear(); camera.getTransforms().add( new Translate( xTrans , yTrans , zTrans ) ); camera.getTransforms().add( new Rotate( xRotate , -camera.getTranslateX() , -camera.getTranslateY() , -camera.getTranslateZ() , Rotate.X_AXIS ) ); camera.getTransforms().add( new Rotate( yRotate , -camera.getTranslateX() , -camera.getTranslateY() , -camera.getTranslateZ() , Rotate.Y_AXIS ) ); camera.getTransforms().add( new Rotate( zRotate , -camera.getTranslateX() , -camera.getTranslateY() , -camera.getTranslateZ() , Rotate.Z_AXIS ) ); light.getTransforms().clear(); light.getTransforms().add( new Translate( xTrans , yTrans , zTrans ) ); light.getTransforms().add( new Rotate( xRotate , -light.getTranslateX() , -light.getTranslateY() , -light.getTranslateZ() , Rotate.X_AXIS ) ); light.getTransforms().add( new Rotate( yRotate , -light.getTranslateX() , -light.getTranslateY() , -light.getTranslateZ() , Rotate.Y_AXIS ) ); light.getTransforms().add( new Rotate( zRotate , -light.getTranslateX() , -light.getTranslateY() , -light.getTranslateZ() , Rotate.Z_AXIS ) ); } }