如何在 JavaFX 8 中创建自定义 3d 模型? [英] How to create custom 3d model in JavaFX 8?

查看:38
本文介绍了如何在 JavaFX 8 中创建自定义 3d 模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Image diifuseMap = new Image(getClass().getResource("t.jpg").toExternalForm());TriangleMesh planeMesh = new TriangleMesh();浮动[]点= {-5, 5, 0,-5, -5, 0,5, 5, 0,5, -5, 0};浮动[] texCoords = {0, 0,0, 1,1, 0,1, 1};int[] 人脸 = {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 平面 = new Group3D(new MeshView(planeMesh));

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

解决方案

现场什么都没出现

您的示例网格对我来说效果不错.

也许你的相机设置不正确,或者你的网格没有被缩放以使其可见.

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

<块引用>

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

是的,将网格视图的 DrawMode 设置为 线.

示例程序说明

我改变了你的脸的顺序,使它们都面向相同的方向,这样你就会得到一个面向观众的正方形,而不是一个面向观众而一个背向观众的三角形:

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.*;导入 javafx.application.Application;导入 javafx.beans.binding.Bindings;导入 javafx.geometry.Insets;导入 javafx.scene.*;导入 javafx.scene.control.CheckBox;导入 javafx.scene.image.Image;导入 javafx.scene.layout.VBox;导入 javafx.scene.paint.*;导入 javafx.scene.shape.*;导入 javafx.scene.transform.Rotate;导入 javafx.stage.Stage;导入 javafx.util.Duration;公共类 InlineModelViewer 扩展应用程序 {私有静态最终 int VIEWPORT_SIZE = 800;私人静态最终双 MODEL_SCALE_FACTOR = 40;私人静态最终双 MODEL_X_OFFSET = 0;私人静态最终双 MODEL_Y_OFFSET = 0;私有静态最终双 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";私有图像纹理;私有 PhongMaterial 纹理材料 = 新 PhongMaterial();私有 MeshView meshView = loadMeshView();私有 MeshView loadMeshView() {浮动[]点= {-5, 5, 0,-5, -5, 0,5, 5, 0,5, -5, 0};浮动[] texCoords = {1, 1,1, 0,0, 1,0, 0};int[] 人脸 = {2, 2, 1, 1, 0, 0,2, 2, 3, 3, 1, 1};TriangleMesh 网格 = new TriangleMesh();mesh.getPoints().setAll(points);mesh.getTexCoords().setAll(texCoords);mesh.getFaces().setAll(faces);返回新的网格视图(网格);}私人组 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);返回新组(meshView);}@覆盖公共无效开始(阶段阶段){纹理 = 新图像(textureLoc);texturedMaterial.setDiffuseMap(texture);组 group = buildScene();RotateTransition 旋转 =rotate3dGroup(group);VBox 布局 = 新 VBox(创建控件(旋转),createScene3D(群展));stage.setTitle("模型查看器");场景场景 = 新场景(布局,Color.CORNSILK);stage.setScene(场景);舞台表演();}私有子场景 createScene3D(组组){SubScene scene3d = new SubScene(group, VIEWPORT_SIZE, VIEWPORT_SIZE * 9.0/16, true, SceneAntialiasing.BALANCED);Scene3d.setFill(Color.rgb(10, 10, 40));场景3d.setCamera(新透视相机());返回scene3d;}私有 VBox createControls(RotateTransition rotateTransition) {CheckBox 剔除 = new CheckBox("Cull Back");meshView.cullFaceProperty().bind(绑定.when(剔除.selectedProperty()).then(CullFace.BACK).否则(CullFace.NONE));CheckBox 线框 = new CheckBox("Wireframe");meshView.drawModeProperty().bind(绑定.when(线框.selectedProperty()).then(DrawMode.LINE).否则(DrawMode.FILL));CheckBox 旋转 = new CheckBox("Rotate");rotate.selectedProperty().addListener(observable -> {如果(旋转.isSelected()){rotateTransition.play();} 别的 {rotateTransition.pause();}});CheckBox 纹理 = new CheckBox("Texture");meshView.materialProperty().bind(绑定.when(纹理.selectedProperty()).then(纹理材料).否则((PhongMaterial)空));VBox 控件 = new VBox(10, 旋转, 纹理, 剔除, 线框);control.setPadding(new Insets(10));退货控制;}私人 RotateTransition rotate3dGroup(组组){RotateTransitionrotate = new RotateTransition(Duration.seconds(10), group);旋转.setAxis(Rotate.Y_AXIS);旋转.setFromAngle(0);旋转.setToAngle(360);rotate.setInterpolator(Interpolator.LINEAR);rotate.setCycleCount(RotateTransition.INDEFINITE);返回旋转;}公共静态无效主(字符串 [] args){System.setProperty("prism.dirtyopts", "false");发射(参数);}}

<块引用>

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

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

<块引用>

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

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

I tried to make a plane in JavaFX application using official tutorial and has the next code:

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));

But, unfortunately, nothing appeared in the scene. Can anybody explain how to create my own 3d models in JavaFX? And is it possible to create them without texture(I want wireframe model)?

解决方案

nothing appeared in the scene

Your sample mesh rendered OK for me.

Perhaps you didn't have your camera setup correctly or have your mesh scaled so that it was visible.

Your sample mesh doesn't do much, it is one triangle facing towards the camera and a second triangle facing away from the camera.

And is it possible to create them without texture(I want wireframe model)?

Yes, set the DrawMode for your mesh view to Line.

Sample Program Explanation

I changed the order of your faces so that they both face the same direction so that you get a square facing the viewer rather than one triangle facing towards the viewer and one away from the viewer:

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

Also the texture map needs to change (for the above face array to get the right orientation on the texture so it is not upside down).

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

I set up a cull back control and animated rotating the model so that you could see the "back" sides of the triangles (in black) and it is clear what is being rendered. I also added the ability to toggle a diffuse map (some marble) for a texture or a wireframe mode.

Sample Program Output

Sample Program

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);
  }
}

Can anybody explain how to create my own 3d models

That is too broad a question for StackOverflow. There are universities and art colleges that hand out diplomas in that kind of stuff.

Can anyone explain why Mesh.setAll takes float[] while the rest of API uses double?

The JavaFX 3D implementation provides a wrapper around native APIs that communicate with graphics hardware (e.g. DirectX and OpenGL). These APIs work with float precision rather than double precision. Using float[] directly in the API means that the mesh model data can be stored more efficiently and directly mapped to the underlying graphics APIs than if double[] or an ObservableList<Double> were used.

这篇关于如何在 JavaFX 8 中创建自定义 3d 模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆