2

問題

MeshView に拡散反射光マップを適用したいと思います。拡散反射光マップを含むマテリアルを MeshView に適用すると、表示されません。ただし、ボックスに適用された同じマテリアルが表示されます。

質問

拡散反射光マップを MeshView に適用するにはどうすればよいですか?

コード

このコードは、ランダム ノイズを含む Image を生成します。画像は PhongMaterial の拡散マップとして使用されます。画像が表示され、その上にマテリアルが適用されたボックスが表示され、ボックスの上にマテリアルが適用された MeshView (ピラミッド) が表示されます。マテリアルはピラミッドに表示されません。回転にはマウスドラッグを使用できます。

import java.util.Random;

import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class Test extends Application {

    private double mousePosX, mousePosY;
    private double mouseOldX, mouseOldY;
    private final Rotate rotateX = new Rotate(20, Rotate.X_AXIS);
    private final Rotate rotateY = new Rotate(-45, Rotate.Y_AXIS);

    @Override
    public void start(Stage primaryStage) {

        // cube
        Group group = new Group();

        // size of the cube
        double size = 400;
        group.getTransforms().addAll(rotateX, rotateY);

        Image diffuseMap = createImage( size);

        // show noise image
        ImageView iv = new ImageView( diffuseMap);
        iv.setTranslateX(-0.5*size);
        iv.setTranslateY(-0.20*size);
        iv.setRotate(90);
        iv.setRotationAxis(new Point3D(1,0,0));
        group.getChildren().add( iv);

        // create material out of the noise image
        PhongMaterial material = new PhongMaterial();
        material.setDiffuseMap(diffuseMap);

        // create box with noise diffuse map
        Box box = new Box( 100,100,100);
        box.setMaterial(material);
        group.getChildren().add( box);

        // create pyramid with diffuse map
        float h = 150;                    // Height
        float s = 150;                    // Side

        TriangleMesh pyramidMesh = new TriangleMesh();

        pyramidMesh.getTexCoords().addAll(1,1,1,0,0,1,0,0);

        pyramidMesh.getPoints().addAll(
                0,    0,    0,            // Point 0 - Top
                0,    h,    -s/2,         // Point 1 - Front
                -s/2, h,    0,            // Point 2 - Left
                s/2,  h,    0,            // Point 3 - Back
                0,    h,    s/2           // Point 4 - Right
            );

        pyramidMesh.getFaces().addAll(
          0,0,  2,0,  1,0,          // Front left face
          0,0,  1,0,  3,0,          // Front right face
          0,0,  3,0,  4,0,          // Back right face
          0,0,  4,0,  2,0,          // Back left face
          4,0,  1,0,  2,0,          // Bottom rear face
          4,0,  3,0,  1,0           // Bottom front face
        ); 


        MeshView pyramid = new MeshView(pyramidMesh);
        pyramid.setDrawMode(DrawMode.FILL);
        pyramid.setTranslateY(-250);

        // apply material
        // TODO: why is the diffuse map not displayed?
        pyramid.setMaterial(material);

        group.getChildren().add(pyramid);

        // scene
        StackPane root = new StackPane();
        root.getChildren().add(group);
        Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED);
        scene.setCamera(new PerspectiveCamera());

        // interaction listeners
        scene.setOnMousePressed(me -> {
            mouseOldX = me.getSceneX();
            mouseOldY = me.getSceneY();
        });
        scene.setOnMouseDragged(me -> {
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY));
            rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX));
            mouseOldX = mousePosX;
            mouseOldY = mousePosY;

        });

        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    /**
     * Create image with random noise
     */
    public Image createImage( double size) {

        Random rnd = new Random();

        int width = (int) size;
        int height = (int) size;

        WritableImage wr = new WritableImage(width, height);
        PixelWriter pw = wr.getPixelWriter();
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {

                Color color = Color.rgb(rnd.nextInt( 256), rnd.nextInt( 256), rnd.nextInt( 256));
                pw.setColor(x, y, color);

            }
        }

        return wr;

    }

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

スクリーンショット

ここに画像の説明を入力

助けてくれてどうもありがとう!

4

1 に答える 1

5

問題

この形状は、6 つの単一形状で構成されています。4 つの三角形はすべて点 A で交わります。また、一番下に長方形があります。これらは三角形であるため、長方形を作成するには 2 つの三角形が必要です。次の図は、その形状の平面図を示しています。

上面図

ご覧のとおり、ポイントは 5 つあります。そのため、それらを TriangleMesh のポイントに追加する必要があります。1 つのポイントは、3 つの float 値 (x、y、z) のタペルで構成されます。したがって、この配列は常に 3、6、9、...、15 などのサイズで構成されます。

テクスチャ

メッシュのマテリアルとして画像がある場合 (あなたのように)、テクスチャ座標を取得し、それらに画像座標を追加する必要があります。しかし、ここに何を追加しますか?これらは、マテリアルとして設定する画像の 2D 座標です。(0.0, 0.0) (u0, v0) から始まり、(1.0, 1.0) (u1, v1) まで上がります。これは、3D メッシュに表示したい画像ピースの 2D 座標です。ノイズの多い画像しかないので、0,0 から 1,1 を実行できますが、三角形には 3 つのポイントが必要です。

向いている

次に、面取りを行う必要があります。これは、シェイプの線の間のスペースにいくつかのプレートを配置するようなものです。すでに見たように、三角形に 4 つのピース、底に 2 つのピースを追加する必要があります。

フェーシングは 6 つの値のタプルです。三角形を描いているので、それは常に次のようなものです: 点から点へ、そして点へ。したがって、タプルは 6 つの値で構成されます。p0、t0、p1、t1、p2、t2。これらの値は、ポイントおよびテクスチャ配列へのインデックスです。p0 はポイント配列の最初のツリー タプルを指し、t0 はテクスチャ座標配列の最初の 2 つのタプルを指します。

(反) 時計回り

私の説明は完全に正しくないかもしれませんが、これは私がそれをどのように理解したかです:

JavaFX のデフォルトのカメラは反時計回りであるため、顔を反時計回りに配置すると、顔の正面がカメラに表示されます。顔は戻っていません。これは、パフォーマンスの問題のために JavaFX で内部的に行われます。カリングを背面に設定しない限り、背面はマテリアルでレンダリングされません。

この三角形の底を表示するには、カメラの視点を時計回りに変更する必要があります。そして、顔の前後で同じことを繰り返します。

あなたの例では、ポイントに名前を付けました。これは、最初にレンダリングした面と最後にレンダリングした面を確認できるためです。例えば:

ABC は私にとって最初の面です。ポイント A、B、C の間の三角形です。これらのポイントは、マテリアル イメージ座標からテクスチャを取得します。

これらの詳細については、José Pereda のブログ ( http://jperedadnr.blogspot.de/2015/01/creating-and-texturing-javafx-3d-shapes.html ) を参照してください。

うまくいけば、あなたはすべてを理解していると思います.

解決

import java.util.Random;

import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class Test extends Application {

    private double mousePosX, mousePosY;
    private double mouseOldX, mouseOldY;
    private final Rotate rotateX = new Rotate(20, Rotate.X_AXIS);
    private final Rotate rotateY = new Rotate(-45, Rotate.Y_AXIS);

    @Override
    public void start(Stage primaryStage) {

        // cube
        Group group = new Group();

        // size of the cube
        double size = 400;
        group.getTransforms().addAll(rotateX, rotateY);

        Image diffuseMap = createImage(size);

        // show noise image
        ImageView iv = new ImageView(diffuseMap);
        iv.setTranslateX(-0.5 * size);
        iv.setTranslateY(-0.20 * size);
        iv.setRotate(90);
        iv.setRotationAxis(new Point3D(1, 0, 0));
        group.getChildren().add(iv);

        // create material out of the noise image
        PhongMaterial material = new PhongMaterial();
        material.setDiffuseMap(diffuseMap);

        // create box with noise diffuse map
        Box box = new Box(100, 100, 100);
        box.setMaterial(material);
        group.getChildren().add(box);

        // create pyramid with diffuse map
        float h = 150; // Height
        float s = 150; // Side
        float hs = s / 2;

        // coordinates of the mapped image
        float x0 = 0.0f;
        float y0 = 0.0f;
        float x1 = 1.0f;
        float y1 = 1.0f;

        TriangleMesh pyramidMesh = new TriangleMesh();

        pyramidMesh.getPoints().addAll( //
                0.0f, 0.0f, 0.0f, // A 0 Top of Pyramid
                hs, h, -hs, // B 1
                hs, h, hs, // C 2
                -hs, h, hs, // D 3
                -hs, h, -hs // E 4
        );

        pyramidMesh.getTexCoords().addAll( //
                x0, y0, // 0
                x0, y1, // 1
                x1, y0, // 2
                x1, y1 // 3
        );

        pyramidMesh.getFaces().addAll(// index of point, index of texture, index of point, index of texture, index of point, index of texture
                0, 0, 1, 1, 2, 3, // ABC (counter clockwise)
                0, 0, 2, 1, 3, 3, // ACD (counter clockwise)
                0, 0, 3, 1, 4, 3, // ADE (counter clockwise)
                0, 0, 4, 1, 1, 3, // AEB (counter clockwise)
                4, 0, 3, 1, 2, 3, // EDC (Bottom first triangle clock wise)
                2, 0, 1, 1, 4, 3 // CBE (Bottom second triangle clock wise)
        );

        MeshView pyramid = new MeshView();
        pyramid.setMesh(pyramidMesh);
        pyramid.setDrawMode(DrawMode.FILL);
        pyramid.setTranslateY(-250);

        // apply material
        // TODO: why is the diffuse map not displayed?
        pyramid.setMaterial(material);
        group.getChildren().add(pyramid);

        // scene
        StackPane root = new StackPane();
        root.getChildren().add(group);
        Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED);
        scene.setCamera(new PerspectiveCamera());

        // interaction listeners
        scene.setOnMousePressed(me -> {
            mouseOldX = me.getSceneX();
            mouseOldY = me.getSceneY();
        });
        scene.setOnMouseDragged(me -> {
            mousePosX = me.getSceneX();
            mousePosY = me.getSceneY();
            rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
            rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
            mouseOldX = mousePosX;
            mouseOldY = mousePosY;

        });

        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    /**
     * Create image with random noise
     */
    public Image createImage(double size) {

        Random rnd = new Random();

        int width = (int) size;
        int height = (int) size;

        WritableImage wr = new WritableImage(width, height);
        PixelWriter pw = wr.getPixelWriter();
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                Color color = Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
                pw.setColor(x, y, color);
            }
        }
        return wr;
    }

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

ここに画像の説明を入力

于 2015-06-29T14:13:29.687 に答える