package application_fx; import javafx.animation.AnimationTimer; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.LightBase; import javafx.scene.Node; import javafx.scene.PerspectiveCamera; import javafx.scene.PointLight; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.CullFace; import javafx.scene.shape.DrawMode; import javafx.scene.shape.MeshView; import javafx.scene.transform.Affine; import javafx.scene.transform.Rotate; import javafx.stage.Stage; public class TestBoneAnimation extends Application { public static void main(String[] args) { launch( args ); } @Override public void start(Stage primaryStage) throws Exception { // シーングラフの構成 Group root = new Group(); // モデルデータの取り込み root.getChildren().add( createTriangleMesh() ); // シーンの作成 // 3Dシーンの奥行きを表現するため、Zバッファを有効にする Scene scene = new Scene( root , 500 , 300 , true ); scene.setFill( Color.BLACK ); // カメラ設定 PerspectiveCamera camera = new PerspectiveCamera( true ); camera.setFarClip( 300 ); camera.setTranslateZ( -50 ); scene.setCamera( camera ); // 光源設定 LightBase light = new PointLight(); light.setTranslateZ( -50 ); root.getChildren().add( light ); // ウィンドウ表示 primaryStage.setScene( scene ); primaryStage.show(); } /** * トライアングル・メッシュを作成 * * 【メッシュ】 * * p6┏━┓p7 * ┃\┃ * p4┣━┫p5 * ┃\┃ * p2┣━┫p3 * ┃\┃ * p0┗━┛p1 * * 【ジョイント】 * j2 * ┃ * j1 * ┃ * j0 * * @return */ public Node createTriangleMesh() throws Exception { // メッシュビューを作成 MeshView meshView = new MeshView(); // メッシュを作成 SkinTriangleMesh mesh = new SkinTriangleMesh(); float[] points = { 0 ,0 ,0 , // p0 3 ,0 ,0 , // p1 0 ,-3 ,0 , // p2 3 ,-3 ,0 , // p3 0 ,-6 ,0 , // p4 3 ,-6 ,0 , // p5 0 ,-9 ,0 , // p6 3 ,-9 ,0 , // p7 }; float[] texCoords = { 0 , 0 }; int[] faces = { 0 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 2 , 0 , 2 , 0 , 3 , 0 , 4 , 0 , 3 , 0 , 5 , 0 , 4 , 0 , 4 , 0 , 5 , 0 , 6 , 0 , 5 , 0 , 7 , 0 , 6 , 0 }; // ボーンアニメーション用情報 int[] influenceCounts = { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }; Affine[] jointMatrixes = { new Affine( 1.0 , 0.0 , 0.0 , 1.5 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 ) , new Affine( 1.0 , 0.0 , 0.0 , 1.5 , 0.0 , 1.0 , 0.0 , -4.5 , 0.0 , 0.0 , 1.0 , 0.0 ) , new Affine( 1.0 , 0.0 , 0.0 , 1.5 , 0.0 , 1.0 , 0.0 , -9.0 , 0.0 , 0.0 , 1.0 , 0.0 ) }; float[] weights = { 1.0f }; int[] influences = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 2 , 0 , 2 , 0 , 2 , 0 };//jointとweightの組 mesh.setPoints( points ); mesh.getTexCoords().addAll( texCoords ); mesh.getFaces().addAll( faces ); mesh.setInfluenceCounts( influenceCounts ); mesh.setBindingJointMatrixes( jointMatrixes ); mesh.setWeights( weights ); mesh.setInfluences( influences ); // メッシュを登録 meshView.setMesh( mesh ); meshView.setDrawMode( DrawMode.LINE ); meshView.setCullFace( CullFace.NONE ); // アニメーション開始 AnimationTimer timer = new AnimationTimer() { // アニメーション間隔(nano sec) private long duration = 2000 * 1000000L; // 2000ミリ秒 private long startTime = 0; private double percent = 0.0; @Override public void handle( long now ) { // アニメーションの開始時間を取得 if( startTime == 0 ){ startTime = now; } long time = ( now - startTime ) % duration; percent = (double) time / duration; // ボーン(ジョイント)の移動 // 関節の回転角度を計算して、行列を作成 Affine[] newJoints = new Affine[ jointMatrixes.length ]; // ジョイント0はそのまま newJoints[0] = jointMatrixes[0]; // ジョイント1は、バインディング位置でZ軸回転させる newJoints[1] = new Affine(); newJoints[1].append( jointMatrixes[1]); Affine rotate = new Affine(); double angle = 360.0 * percent; rotate.append( new Rotate( angle , Rotate.Z_AXIS ) ); newJoints[1].append( rotate ); // ジョイント2は、ジョイント1にあわせて回転する newJoints[2] = new Affine(); newJoints[2].append( newJoints[1] ); newJoints[2].append( new Affine( 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , -4.5 , 0.0 , 0.0 , 1.0 , 0.0 ) ); // 関節を設定 mesh.setJointMatrixes( newJoints ); // デバッグ出力 System.out.println( "角度 = " + angle ); } }; timer.start(); return meshView; } }