1

是否有任何可能的方法将 JavaFX NodeGroup或转换Shape3DMesh

我需要这个来将我的场景导出到“.obj”,而我找到的唯一导出器(在 FXyz 库中)需要Mesh.

4

1 回答 1

2

使用内置Shape3D节点时的主要问题是SphereCylinder或者Box那些不公开它们的TriangleMesh.

如果您需要该网格,有几种选择:

  1. 创建您自己的形状实现,在其中提供网格
  2. 改为使用FXyz库等效形状,因此您将在所有形状中都拥有网格
  3. 如果需要,请坚持使用内置Shape3D节点,但在导出它们之前,将它们转换为 FXyz 库中的等效形状,以便您可以访问它们的网格。

在导出模型方面,ObjWriterFXyz 中的电流一次只导出一个网格,因此您可以:

  1. 将所有形状导出到自己的 .obj 文件
  2. 修改 ObjWriter 以便将网格列表导出到单个文件(如果您这样做,欢迎您向 FXyz 创建拉取请求)
  3. 用于MeshHelper创建单个网格(只能应用一种材质),并将其导出到单个 .obj 文件。

我将在这两种情况下假设第三种情况,即TexturedMesh根据场景中找到的所有 3D 形状创建一个新对象。这将有一个可以导出到 obj 文件的网格。注意你需要FXyzLib.jar.

class EquivalentMesh extends TexturedMesh {

    private MeshHelper mh = null;

    public EquivalentMesh(Parent root) {
        ArrayList<Node> nodes = new ArrayList<>();
        addShapes3D(root, nodes);

        transformAndMerge(nodes);
    }

    // Transform Built-in Shape3Ds to a single TexturedMesh
    private void transformAndMerge(ArrayList<Node> nodes) {

        nodes.stream().forEach(shape -> {
            TriangleMesh tm = null;
            if (shape instanceof Sphere) {
                Sphere sphere = (Sphere)shape;
                SegmentedSphereMesh sm = new SegmentedSphereMesh(sphere.getRadius());
                sm.setCenter(new Point3D((float)sphere.getTranslateX(), (float)sphere.getTranslateY(), (float)sphere.getTranslateZ()));
                tm = (TriangleMesh)sm.getMesh();
            } else if (shape instanceof Cylinder) {
                Cylinder cylinder = (Cylinder)shape;
                FrustumMesh fm = new FrustumMesh(cylinder.getRadius(), cylinder.getRadius(), cylinder.getHeight());
                Affine affine = new Affine();
                cylinder.getTransforms().forEach(affine::append);
                javafx.geometry.Point3D ini = affine.transform(new javafx.geometry.Point3D(0, cylinder.getHeight()/2, 0));
                javafx.geometry.Point3D end = affine.transform(new javafx.geometry.Point3D(0, - cylinder.getHeight()/2, 0));
                fm.setAxisOrigin(new Point3D((float)ini.getX(), (float)ini.getY(), (float)ini.getZ()));
                fm.setAxisEnd(new Point3D((float)end.getX(), (float)end.getY(), (float)end.getZ()));
                fm.setSectionType(TriangleMeshHelper.SectionType.CIRCLE);
                tm = (TriangleMesh)fm.getMesh();
            } else if (shape instanceof Box) {
                Box box = (Box)shape;
                CuboidMesh cm = new CuboidMesh(box.getWidth(), box.getHeight(), box.getDepth());
                cm.setCenter(new Point3D((float)box.getTranslateX(), (float)box.getTranslateY(), (float)box.getTranslateZ()));
                // TODO: apply rotations
                tm = (TriangleMesh)cm.getMesh();
            } else if (shape instanceof MeshView) {
               tm = (TriangleMesh)((MeshView)shape).getMesh();
               // TODO: apply transformations 
            }

            if (mh == null) {
                mh = new MeshHelper(tm);
            } else {
                mh.addMesh(new MeshHelper(tm));
            }
        });

        // create single mesh
        updateMesh(mh);
    }

    private void addShapes3D(Parent parent, ArrayList<Node> nodes) {
        for (Node node : parent.getChildrenUnmodifiable()) {
            if (node instanceof Shape3D) {
                nodes.add(node);
            }
            if (node instanceof Parent) {
                addShapes3D((Parent)node, nodes);
            }
        }
    }

    @Override
    protected void updateMesh() {
        // no-op
    }

    // export to obj and mtl
    public void export(String nameFile) {
        OBJWriter writer=new OBJWriter((TriangleMesh) getMesh(), nameFile);
        writer.setMaterialColor(Color.RED);
        writer.exportMesh();
    }

}

为了测试它,让我们创建一个简单的场景:

@Override
public void start(Stage primaryStage) {
    Sphere sphere = new Sphere(100);
    sphere.setMaterial(new PhongMaterial(Color.BLUE));
    Box box = new Box(50,50,50);
    box.setMaterial(new PhongMaterial(Color.RED));
    box.setTranslateX(300);
    Cylinder cylinder = new Cylinder(2, 300);
    cylinder.setMaterial(new PhongMaterial(Color.GREEN));
    // Transformations applied:
    cylinder.getTransforms().addAll(new Translate(150, 0, 0), new Rotate(90, Rotate.Z_AXIS));

    Group group = new Group(cylinder, sphere, box);
    StackPane root = new StackPane(group);

    Scene scene = new Scene(root, 600, 400);

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

    // export as single mesh
    EquivalentMesh equivalentMesh = new EquivalentMesh(root);
    equivalentMesh.export("group");
}

初始场景

请注意,通过创建 的新实例EquivalentMesh,现在我们有一个网格,我们可以导出它,生成group.objgroup.mtl文件。

最后,使用3DViewer导入 o​​bj 文件,你会得到:

3DViewer obj 文件

于 2016-01-03T12:56:28.690 回答