【问题标题】:How to create custom 3d model in JavaFX 8?如何在 JavaFX 8 中创建自定义 3d 模型?
【发布时间】:2013-10-18 21:03:32
【问题描述】:

我尝试使用官方教程在 JavaFX 应用程序中制作飞机,并且有下一个代码:

Image diifuseMap = new Image(getClass().getResource("t.jpg").toExternalForm());
    TriangleMesh planeMesh = new TriangleMesh();
    float[] points = {
            -5, 5, 0,
            -5, -5, 0,
            5, 5, 0,
            5, -5, 0
    };
    float[] texCoords = {
            0, 0,
            0, 1,
            1, 0,
            1, 1
    };
    int[] faces = {
            0, 0, 1, 1, 2, 2,
            2, 2, 3, 3, 1, 1
    };
    planeMesh.getPoints().addAll(points);
    planeMesh.getTexCoords().addAll(texCoords);
    planeMesh.getFaces().addAll(faces);
    MeshView meshView =   new MeshView(planeMesh);
    meshView.setMaterial(new PhongMaterial(Color.BLACK, diifuseMap, null, null, null));
    Group3D plane = new Group3D(new MeshView(planeMesh));

但是,不幸的是,场景中什么都没有出现。任何人都可以解释如何在 JavaFX 中创建我自己的 3d 模型吗?是否可以在没有纹理的情况下创建它们(我想要线框模型)?

【问题讨论】:

    标签: 3d javafx-2 javafx-8


    【解决方案1】:

    场景中什么都没有出现

    您的示例网格对我来说渲染得很好。

    也许您的相机设置不正确,或者您的网格未缩放以使其可见。

    您的示例网格没有太多作用,它是一个面向相机的三角形和一个背对相机的三角形。

    是否可以在没有纹理的情况下创建它们(我想要线框模型)?

    是的,set the DrawMode 用于您的网格视图到Line

    示例程序说明

    我改变了你的脸的顺序,使它们都面向相同的方向,这样你得到一个面向观察者的正方形,而不是一个面向观察者和一个远离观察者的三角形:

    int[] faces = {
        2, 2, 1, 1, 0, 0,
        2, 2, 3, 3, 1, 1
    };
    

    纹理贴图也需要改变(为了让上面的面阵列在纹理上获得正确的方向,所以它不会倒置)。

    float[] texCoords = {
        1, 1,
        1, 0,
        0, 1,
        0, 0
    };
    

    我设置了一个剔除控件并动画旋转模型,以便您可以看到三角形的“背面”侧(黑色)并且很清楚正在渲染什么。我还添加了为纹理或线框模式切换漫反射贴图(一些大理石)的功能。

    示例程序输出

    示例程序

    import javafx.animation.*;
    import javafx.application.Application;
    import javafx.beans.binding.Bindings;
    import javafx.geometry.Insets;
    import javafx.scene.*;
    import javafx.scene.control.CheckBox;
    import javafx.scene.image.Image;
    import javafx.scene.layout.VBox;
    import javafx.scene.paint.*;
    import javafx.scene.shape.*;
    import javafx.scene.transform.Rotate;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class InlineModelViewer extends Application {
    
      private static final int VIEWPORT_SIZE = 800;
    
      private static final double MODEL_SCALE_FACTOR = 40;
      private static final double MODEL_X_OFFSET = 0;
      private static final double MODEL_Y_OFFSET = 0;
      private static final double MODEL_Z_OFFSET = VIEWPORT_SIZE / 2;
    
      private static final String textureLoc = "https://www.sketchuptextureclub.com/public/texture_f/slab-marble-emperador-cream-light-preview.jpg";
    
      private Image texture;
      private PhongMaterial texturedMaterial = new PhongMaterial();
    
      private MeshView meshView = loadMeshView();
    
      private MeshView loadMeshView() {
        float[] points = {
            -5, 5, 0,
            -5, -5, 0,
            5, 5, 0,
            5, -5, 0
        };
        float[] texCoords = {
            1, 1,
            1, 0,
            0, 1,
            0, 0
        };
        int[] faces = {
            2, 2, 1, 1, 0, 0,
            2, 2, 3, 3, 1, 1
        };
    
        TriangleMesh mesh = new TriangleMesh();
        mesh.getPoints().setAll(points);
        mesh.getTexCoords().setAll(texCoords);
        mesh.getFaces().setAll(faces);
    
        return new MeshView(mesh);
      }
    
      private Group buildScene() {
        meshView.setTranslateX(VIEWPORT_SIZE / 2 + MODEL_X_OFFSET);
        meshView.setTranslateY(VIEWPORT_SIZE / 2 * 9.0 / 16 + MODEL_Y_OFFSET);
        meshView.setTranslateZ(VIEWPORT_SIZE / 2 + MODEL_Z_OFFSET);
        meshView.setScaleX(MODEL_SCALE_FACTOR);
        meshView.setScaleY(MODEL_SCALE_FACTOR);
        meshView.setScaleZ(MODEL_SCALE_FACTOR);
    
        return new Group(meshView);
      }
    
      @Override
      public void start(Stage stage) {
        texture = new Image(textureLoc);
        texturedMaterial.setDiffuseMap(texture);
    
        Group group = buildScene();
    
        RotateTransition rotate = rotate3dGroup(group);
    
        VBox layout = new VBox(
            createControls(rotate),
            createScene3D(group)
        );
    
        stage.setTitle("Model Viewer");
    
        Scene scene = new Scene(layout, Color.CORNSILK);
        stage.setScene(scene);
        stage.show();
      }
    
      private SubScene createScene3D(Group group) {
        SubScene scene3d = new SubScene(group, VIEWPORT_SIZE, VIEWPORT_SIZE * 9.0/16, true, SceneAntialiasing.BALANCED);
        scene3d.setFill(Color.rgb(10, 10, 40));
        scene3d.setCamera(new PerspectiveCamera());
        return scene3d;
      }
    
      private VBox createControls(RotateTransition rotateTransition) {
        CheckBox cull      = new CheckBox("Cull Back");
        meshView.cullFaceProperty().bind(
            Bindings.when(
                cull.selectedProperty())
                  .then(CullFace.BACK)
                  .otherwise(CullFace.NONE)
        );
        CheckBox wireframe = new CheckBox("Wireframe");
        meshView.drawModeProperty().bind(
            Bindings.when(
                wireframe.selectedProperty())
                  .then(DrawMode.LINE)
                  .otherwise(DrawMode.FILL)
        );
    
        CheckBox rotate = new CheckBox("Rotate");
        rotate.selectedProperty().addListener(observable -> {
          if (rotate.isSelected()) {
            rotateTransition.play();
          } else {
            rotateTransition.pause();
          }
        });
    
        CheckBox texture = new CheckBox("Texture");
        meshView.materialProperty().bind(
            Bindings.when(
                texture.selectedProperty())
                  .then(texturedMaterial)
                  .otherwise((PhongMaterial) null)
        );
    
        VBox controls = new VBox(10, rotate, texture, cull, wireframe);
        controls.setPadding(new Insets(10));
        return controls;
      }
    
      private RotateTransition rotate3dGroup(Group group) {
        RotateTransition rotate = new RotateTransition(Duration.seconds(10), group);
        rotate.setAxis(Rotate.Y_AXIS);
        rotate.setFromAngle(0);
        rotate.setToAngle(360);
        rotate.setInterpolator(Interpolator.LINEAR);
        rotate.setCycleCount(RotateTransition.INDEFINITE);
    
        return rotate;
      }
    
      public static void main(String[] args) {
        System.setProperty("prism.dirtyopts", "false");
        launch(args);
      }
    }
    

    谁能解释如何创建我自己的 3d 模型

    对于 StackOverflow 来说,这个问题太宽泛了。有些大学和艺术学院会颁发这类东西的文凭。

    谁能解释一下为什么 Mesh.setAll 使用 float[] 而其他 API 使用 double?

    JavaFX 3D 实现为与图形硬件(例如 DirectX 和 OpenGL)通信的本机 API 提供了一个包装器。这些 API 使用浮点精度而不是双精度。在 API 中直接使用 float[] 意味着与使用 double[]ObservableList<Double> 相比,可以更有效地存储网格模型数据并直接映射到底层图形 API。

    【讨论】:

    • 脸是什么? texCoords 是什么?要点是什么?
    • 谁能解释一下为什么 Mesh.setAll 使用 float[] 而其他 API 使用 double?
    • 我相信因为这些值直接传递给 api bellow prism DirectX 或 OpenGL,所以类将是 com.sun.prism.d3d.D3DMeshView 和 com.sun.prism.es2.ES2MeshView。我假设 Java2D 也有一个实现,但我还没有找到它。
    • 我怀疑是否存在 MeshView 的 Java2D 实现。 JavaFX 中的 3D 是 ConditionalFeature,因此不运行 DirectX 或 OpenGL 等专用 3D 实现的平台可能只会禁用 SCENE3D ConditionalFeature。这几乎不是问题,因为大多数平台都支持 DirectX 或 OpenGL。
    • @jewelsea 您的示例代码结果错误。见this image
    【解决方案2】:

    第 1 步:列出要点

    cube.getPoints().addAll(
        0, 0, 100,      //P0
        100, 0, 100,    //P1
        0, 100, 100,    //P2
        100, 100, 100,  //P3
        0, 0, 0,        //P4
        100, 0, 0,      //P5
        0, 100, 0,      //P6
        100, 100, 0     //P7
    );
    

    第二步:列出纹理点

    cube.getTexCoords().addAll(
        0.25f, 0,       //T0
        0.5f, 0,        //T1
        0, 0.25f,       //T2
        0.25f, 0.25f,   //T3
        0.5f, 0.25f,    //T4
        0.75f, 0.25f,   //T5
        1, 0.25f,       //T6
        0, 0.5f,        //T7
        0.25f, 0.5f,    //T8
        0.5f, 0.5f,     //T9
        0.75f, 0.5f,    //T10
        1, 0.5f,        //T11
        0.25f, 0.75f,   //T12
        0.5f, 0.75f     //T13
    );
    

    第 3 步:列出面(逆时针(或右手法则)混合 3D 点和纹理点)

    cube.getFaces().addAll(
        5,1,4,0,0,3     //P5,T1 ,P4,T0  ,P0,T3
        ,5,1,0,3,1,4    //P5,T1 ,P0,T3  ,P1,T4
        ,0,3,4,2,6,7    //P0,T3 ,P4,T2  ,P6,T7
        ,0,3,6,7,2,8    //P0,T3 ,P6,T7  ,P2,T8
        ,1,4,0,3,2,8    //P1,T4 ,P0,T3  ,P2,T8
        ,1,4,2,8,3,9    //P1,T4 ,P2,T8  ,P3,T9
        ,5,5,1,4,3,9    //P5,T5 ,P1,T4  ,P3,T9
        ,5,5,3,9,7,10   //P5,T5 ,P3,T9  ,P7,T10
        ,4,6,5,5,7,10   //P4,T6 ,P5,T5  ,P7,T10
        ,4,6,7,10,6,11  //P4,T6 ,P7,T10 ,P6,T11
        ,3,9,2,8,6,12   //P3,T9 ,P2,T8  ,P6,T12
        ,3,9,6,12,7,13  //P3,T9 ,P6,T12 ,P7,T13
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-23
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 2017-02-11
      • 1970-01-01
      相关资源
      最近更新 更多