ともさんのHP >プロブラミング >自作JavaLibrary >JavaFXでPhong shading
JavaFXでフォーンシェーディング(Phong shading)
3Dポリゴンを普通に表示させると、ポリゴンを構成する三角形がゴツゴツして表示されてしまいます。
三角形を小さくすると目立たなくなりますが、今度は計算に時間がかかってしまいます。
洋裁CADではJavaFXを利用して三次元の布を表示できるようにしていますが、ポリゴンの荒さが気になっていました。
てっきりJavaFX楽天 ではフォーンシェーディング(Phong shading)はできないと思っていたのですが、やっとできるようになったので方法を記述しておきます。
Java
楽天 FXでのフォーンシェーディングの方法についてはネット検索しても情報がなく、むしろ誤った情報が出てきたりして色々と翻弄されました。
フォーンシェーディング(Phong shading)の原理
フォーンシェーディングは光の反射方向を連続的に変化させて滑らかに見せる方法です。実際の3Dモデルに角は存在するのですが、分かりにくくなります。
光の反射方向を変えるには物体の法線方向をベクトル化して、これを場所によって滑らかに変更することで光の加減を変えます
JavaFXで実装する方法
JavaFXでポリゴンを表示させる場合はTriangleMeshを用います。
まずTriangleMeshオブジェクトに下記の情報を入れます
構成する点の3D座標
4つの点を設定しました。
float[] points = new float[] {
-10,0,10,
10,0,10,
-10,0,-10,
10,0,-10
};
mesh.getPoints().addAll( points );
構成点の法線3Dベクトル
float[] housen = new float[12];
housen = new float[] {
0,-1,0 ,
1,-1,1 ,
1,-1,1 ,
0,-1,0
};
mesh.getNormals().addAll( housen );
貼り付けるイメージの2D座標
ポリゴンに画像を貼り付ける場合は、使用するイメージ画像の2次元座標を設定します。
画像サイズにかかわらず、0~1を入れます。
イメージの設定も必要です。
float[] texCoords = new float[] {
0,1,
1,1,
0,0,
1,0,
};
mesh.getTexCoords().addAll( texCoords );
PhongMaterial material = new PhongMaterial();
image img = new Image("file:d:/sakura.png");
material.setDiffuseMap( img );
meshView.setMaterial(material);
三角形を構成する点の情報
三角形を構成する点情報を設定します。
3D点、2D点、ベクトルの順で設定します。
2,2,2,は、2番めの3D点、2番めの2D点、2番めのベクトルを示します。
2,2,2,
1,1,1,
0,0,0,
で、1つの三角形の設定になります。
int[] faces = new int[]{
2,2,2,
1,1,1,
0,0,0,
2,2,2,
3,3,3,
1,1,1,
};
mesh.VertexFormat( VertexFormat.POINT_NORMAL_TEXCOORD );
法線ベクトルを設定しない場合は、
int[] faces = new int[]{
2,2,
1,1,
0,0,
2,2,
3,3,
1,1
};
mesh.VertexFormat( VertexFormat.POINT_TEXCOORD );
と書きます。
サンプルプログラム
法線ベクトルを設定しないと、ポリゴンの法線がそのまま設定されます。
下の例では法線の設定した場合としない場合の実行結果を書いています
法線ベクトルあり
法線ベクトルなし
import javafx.application.Application;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.shape.VertexFormat;
import javafx.stage.Stage;
import tomojavalib.threedstage.ThreeDStage;
public class TriangleMeshTest2 extends Application {
//ステージ
public ThreeDStage stage = null;
//---メイン---
public static void main(String[] args) { Application.launch(args); }
@Override
public void start( Stage stage ) throws Exception {
this.stage = new ThreeDStage();
this.stage.camTransZ( -100 );
this.stage.light.setTranslateX( 500.0 );
this.stage.light.setTranslateY(-500.0 );
this.stage.light.setTranslateZ(110.0 );
this.stage.group.getChildren().add( this.createTriangleMesh1() );
return;
}
//法線ベクトルを設定する場合
public MeshView createTriangleMesh1( ){
MeshView meshView = new MeshView();
TriangleMesh mesh = new TriangleMesh();
//点の3D座標
float[] points = new float[] {
-10,0,10,
10,0,10,
-10,0,-10,
10,0,-10
};
//貼り付けるイメージ上の2D座標
float[] texCoords = new float[] {
0,1,
1,1,
0,0,
1,0,
};
//三角形を構成する3D点とイメージ上の座標点、3D点の座標
int[] faces = new int[]{
2,2,2,
1,1,1,
0,0,0,
2,2,2,
3,3,3,
1,1,1,
};
//3D点のベクトル
float[] housen = new float[12];
//housen = new float[] {0,-1,0 , 0,-1,0 , 0,-1,0 , 0,-1,0};
housen = new float[] {0,-1,0 , 1,-1,1 , 1,-1,1 , 0,-1,0};
mesh.getPoints().addAll( points );
mesh.getTexCoords().addAll( texCoords );
mesh.getNormals().addAll( housen );
mesh.getFaces().addAll( faces );
mesh.setVertexFormat( VertexFormat.POINT_NORMAL_TEXCOORD );
meshView.setMesh( mesh );
meshView.setCullFace(CullFace.NONE);
meshView.setDrawMode( DrawMode.FILL);
meshView.setDrawMode( DrawMode.LINE);
PhongMaterial material = new PhongMaterial();
//material.setDiffuseColor( Color.RED );
//Image img = new Image("file:d:/work/洋裁/テキスタイル/sakura.png");
//material.setDiffuseMap( img );
meshView.setMaterial(material);
return meshView;
}
//法線べく取りを設定しない場合
public MeshView createTriangleMesh2( ){
MeshView meshView = new MeshView();
TriangleMesh mesh = new TriangleMesh();
//点の3D座標
float[] points = new float[] {
-10,0,10,
10,0,10,
-10,0,-10,
10,0,-10
};
//貼り付けるイメージ上の2D座標
float[] texCoords = new float[] {
0,1,
1,1,
0,0,
1,0,
};
//三角形を構成する3D点とイメージ上の座標点、3D点の座標
int[] faces = new int[]{
2,2,
1,1,
0,0,
2,2,
3,3,
1,1
};
mesh.getPoints().addAll( points );
mesh.getTexCoords().addAll( texCoords );
mesh.getFaces().addAll( faces );
mesh.setVertexFormat( VertexFormat.POINT_TEXCOORD );
meshView.setMesh( mesh );
meshView.setCullFace(CullFace.NONE);
meshView.setDrawMode( DrawMode.FILL);
// meshView.setDrawMode( DrawMode.LINE);
PhongMaterial material = new PhongMaterial();
//material.setDiffuseColor( Color.RED );
//Image img = new Image("file:d:/work/洋裁/テキスタイル/sakura.png");
//material.setDiffuseMap( img );
meshView.setMaterial(material);
return meshView;
}
}
法線ベクトルの計算方法
ある点の法線ベクトルを計算するには、その点が属しているポリゴンを全て取り出し、ポリゴンの法線ベクトルを足し合わせます。このベクトルを使うと、ポリゴン全体が滑らかな曲面になります。
3D-CAD出の表示
洋裁CADの3Dクロスシミュレーションではこんな感じになりました。
最終更新日: 2021-12-10 11:27:37
ともさんのHP >プロブラミング >自作JavaLibrary >JavaFXでPhong shading
ツイート