如何使用 JavaFX 中的 JCSG 库将 MeshView 转换为 CSG 对象

How to convert a MeshView to a CSG object using JCSG library in JavaFX

我正在为 JavaFX 使用 JCSG 库。

我有一些 MeshView 个对象,我想将它们转换成 CSG 个对象,有没有办法实现这个?

如果您有 TriangleMesh,将 javafx.scene.shape.Mesh 对象与 CSG 对象组合的最简单方法是将三角形面转换为多边形 (eu.mihosoft.vrl.v3d.Polygon)。

一旦你有了一个 CSG 对象,你就可以对其执行常规操作,然后你可以将它导出回 MeshView 例如。

原始形状(BoxSphere、...)的问题是您无法访问它们的 TriangleMesh。因此,您可以转到 F(X)yz 库并选择任何可用的 3D 形状。

例如,让我们使用一个 FrustumMesh 对象。

您可以轻松创建一个:

FrustumMesh cone = new FrustumMesh(1,0.2,4,2);

您将可以访问其网格:cone.getMesh()

现在我们需要将这个 TriangleMesh 转换成 List<Polygon>。为此,我们可以创建此实用程序 class:

public class Mesh2CSG {
    /**
     * Loads a CSG from TriangleMesh.
     * @param mesh
     * @return CSG
     * @throws IOException if loading failed
     */
    public static CSG mesh2CSG(MeshView mesh) throws IOException {
        return mesh2CSG(mesh.getMesh());
    }
    public static CSG mesh2CSG(Mesh mesh) throws IOException {

        List<Polygon> polygons = new ArrayList<>();
        List<Vector3d> vertices = new ArrayList<>();
        if(mesh instanceof TriangleMesh){
            // Get faces
            ObservableFaceArray faces = ((TriangleMesh)mesh).getFaces();
            int[] f=new int[faces.size()];
            faces.toArray(f);

            // Get vertices
            ObservableFloatArray points = ((TriangleMesh)mesh).getPoints();
            float[] p = new float[points.size()];
            points.toArray(p);

            // convert faces to polygons
            for(int i=0; i<faces.size()/6; i++){
                int i0=f[6*i], i1=f[6*i+2], i2=f[6*i+4];
                vertices.add(new Vector3d(p[3*i0], p[3*i0+1], p[3*i0+2]));
                vertices.add(new Vector3d(p[3*i1], p[3*i1+1], p[3*i1+2]));
                vertices.add(new Vector3d(p[3*i2], p[3*i2+1], p[3*i2+2]));
                polygons.add(Polygon.fromPoints(vertices));
                vertices = new ArrayList<>();
            }
        }

        return CSG.fromPolygons(new PropertyStorage(),polygons);
    }
}

用这个方法,你可以获得一个CSG圆锥体:

CSG coneCSG = Mesh2CSG.mesh2CSG(cone.getMesh());

因此您可以将其与其他 CSG 形式结合使用:

CSG cube = new Cube(2).toCSG().color(Color.RED);
CSG union = cube.union(coneCSG);

然后返回到 JavaFX 网格进行查看:

MeshView unionMesh = coneCSG.toJavaFXMesh().getAsMeshViews().get(0);

这是完整示例 class(前提是您的 class 路径上有 FXyzLib.jar 和 JCSG.jar 依赖项):

public class FXyzJCSG 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(-20, Rotate.Y_AXIS);

    @Override
    public void start(Stage primaryStage) throws IOException {

        FrustumMesh cone = new FrustumMesh(1,0.2,4,2);
        cone.setDrawMode(DrawMode.LINE);
        cone.setTextureModeNone(Color.ROYALBLUE);

        CSG coneCSG = Mesh2CSG.mesh2CSG(cone.getMesh());

        CSG cube = new Cube(2).toCSG().color(Color.RED);
        CSG union = cube.union(coneCSG);

        MeshView unionMesh = union.toJavaFXMesh().getAsMeshViews().get(0);
//        unionMesh.setDrawMode(DrawMode.LINE);
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -10));

        Group root3D = new Group(camera,unionMesh);

        SubScene subScene = new SubScene(root3D, 600, 400, true, SceneAntialiasing.BALANCED);
        subScene.setFill(Color.AQUAMARINE);
        subScene.setCamera(camera);

        Scene scene = new Scene(new StackPane(subScene), 600, 400);
        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.setTitle("FXyz & JCSG - JavaFX 3D");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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