Problem with adding multiple triangle meshes to a scene in javafx

1.4k views Asked by At

I hope someone can help me with this problem.

I am using javafx and triangle mesh to construct a sphere-like object out of triangles (like a football). The different tiles of the shape are distinguished by color but I want to add lines between the tiles. Like in this football:

The provided 2D lines of javafx bring terrible performance in the 3D space. Therefore I found the FXyzLib that provides a PolyLine3D. This is actually just another triangle mesh that creates a line in a 3D space.

With this I can create 3D lines. But if I want to add them to my original triangle mesh everything else turns black. It is also the other way around. I experimented with the provided example of the Libary found here. It creats a fancy 3D line but when I tried to add a simple red colored sphere to the scene the sphere was just black like this:

this.

I am no expert in this and new to javafx and couldn't find the problem in the code of the PolyLine3D. It shouldn't be a problem to add mutliple triangle mesh to a scene. Are there some light or camera effects I am not aware of?

1

There are 1 answers

4
José Pereda On

While there is nothing wrong about adding multiple triangle meshes to a scene, there is a more straightforward approach when you want to create a mesh like one from the football picture, so you can have the effect of highlighting some edges but not all the triangles from the mesh.

It can be done with a PolygonMesh that takes any valid close polygon as face.

This implementation already exists, in the 3DViewer project, which is open source and can be found here. There is a PolygonMeshView control that can render a PolygonMesh.

Note that if you use those two classes only in your project, you'll have to skip the subdivision mesh for now.

This answer already uses a quadrilateral mesh for a rendering a Box without the diagonal edges of a triangle mesh.

Under the hood, the Polygon mesh uses a triangle mesh, and internally converts the polygons you provide to triangles.

Truncated Icosahedron Mesh

So we can do something similar to generate the mesh of a truncated icosahedron, which is the name of the geometric figure that we can use to generate a simplified football model.

It has 12 regular pentagonal faces, 20 regular hexagonal faces and 60 vertices.

We need the 3D coordinates of those vertices, the 2D coordinates of the textures, and the indices of vertices and textures for each of the 32 faces.

I've used the free online sandbox WolframCloud resource to retrieve those values.

For instance, you can run:

Flatten[PolyhedronData["TruncatedIcosahedron","VertexCoordinates"]//N]

to get the list of vertex coordinates:

Out[1]= {-0.16246,-2.11803,1.27598,-0.16246,2.11803,...}

and, you can get the faces:

PolyhedronData["TruncatedIcosahedron","FaceIndices"]
Out[2]= {{53,11,24,23,9},{51,39,40,52,30},...}

Finally, you need the textures coordinates and indices, and that can be retrieved through the Net of the icosahedron:

PolyhedronData["TruncatedIcosahedron","Net"]
PolyhedronData["TruncatedIcosahedron","NetCoordinates"]

In this case, you get the 2D coordinates of the 32 faces. Given that we want to have the same texture for all the pentagons and the same for all hexagons, I've dome some manipulation of those coordinates to come up with this texture image:

with only 9 vertices, and their coordinates (in the JavaFX coordinate system).

This method contains the required information to create the mesh:

private PolygonMesh getTruncatedIcosahedron() {
    float[] points = new float[]{
        -0.16246f,-2.11803f,1.27598f,       -0.16246f,2.11803f,1.27598f, 
        0.16246f,-2.11803f,-1.27598f,       0.16246f,2.11803f,-1.27598f,
        -0.262866f,-0.809017f,-2.32744f,    -0.262866f,-2.42705f,-0.425325f,
        -0.262866f,0.809017f,-2.32744f,     -0.262866f,2.42705f,-0.425325f,
        0.262866f,-0.809017f,2.32744f,      0.262866f,-2.42705f,0.425325f, 
        0.262866f,0.809017f,2.32744f,       0.262866f,2.42705f,0.425325f,
        0.688191f,-0.5f,-2.32744f,          0.688191f,0.5f,-2.32744f,
        1.21392f,-2.11803f,0.425325f,       1.21392f,2.11803f,0.425325f,
        -2.06457f,-0.5f,1.27598f,           -2.06457f,0.5f,1.27598f,
        -1.37638f,-1.f,1.80171f,            -1.37638f,1.f,1.80171f,
        -1.37638f,-1.61803f,-1.27598f,      -1.37638f,1.61803f,-1.27598f,
        -0.688191f,-0.5f,2.32744f,          -0.688191f,0.5f,2.32744f,
        1.37638f,-1.f,-1.80171f,            1.37638f,1.f,-1.80171f,
        1.37638f,-1.61803f,1.27598f,        1.37638f,1.61803f,1.27598f,
        -1.7013f,0.f,-1.80171f,             1.7013f,0.f,1.80171f,
        -1.21392f,-2.11803f,-0.425325f,     -1.21392f,2.11803f,-0.425325f,
        -1.96417f,-0.809017f,-1.27598f,     -1.96417f,0.809017f,-1.27598f,
        2.06457f,-0.5f,-1.27598f,           2.06457f,0.5f,-1.27598f,
        2.22703f,-1.f,-0.425325f,           2.22703f,1.f,-0.425325f,
        2.38949f,-0.5f,0.425325f,           2.38949f,0.5f,0.425325f,
        -1.11352f,-1.80902f,1.27598f,       -1.11352f,1.80902f,1.27598f,
        1.11352f,-1.80902f,-1.27598f,       1.11352f,1.80902f,-1.27598f,
        -2.38949f,-0.5f,-0.425325f,         -2.38949f,0.5f,-0.425325f,
        -1.63925f,-1.80902f,0.425325f,      -1.63925f,1.80902f,0.425325f,
        1.63925f,-1.80902f,-0.425325f,      1.63925f,1.80902f,-0.425325f,
        1.96417f,-0.809017f,1.27598f,       1.96417f,0.809017f,1.27598f,
        0.850651f,0.f,2.32744f,             -2.22703f,-1.f,0.425325f,
        -2.22703f,1.f,0.425325f,            -0.850651f,0.f,-2.32744f,
        -0.525731f,-1.61803f,-1.80171f,     -0.525731f,1.61803f,-1.80171f,
        0.525731f,-1.61803f,1.80171f,       0.525731f,1.61803f,1.80171f};

    float[] texCoords = new float[]{0.904508f,0.820298f, 0.75f,0.529535f, 0.25f,0.529535f, 0.0954915f,0.820298f, 0.5f,1f, 
                                    1f,0.264767f, 0.75f,0f, 0.25f,0f, 0f,0.264767f};

    int faces[][] = new int[][]{{52,0,10,1,23,2,22,3,8,4},
                        {50,0,38,1,39,2,51,3,29,4},
                        {59,0,27,1,15,2,11,3,1,4},
                        {19,0,41,1,47,2,54,3,17,4},
                        {18,0,16,1,53,2,46,3,40,4},
                        {0,0,9,1,14,2,26,3,58,4},
                        {35,0,25,1,43,2,49,3,37,4},
                        {3,0,57,1,21,2,31,3,7,4},
                        {33,0,28,1,32,2,44,3,45,4},
                        {20,0,56,1,2,2,5,3,30,4},
                        {36,0,48,1,42,2,24,3,34,4},
                        {12,0,4,1,55,2,6,3,13,4},
                        {8,1,58,5,26,6,50,7,29,8,52,2},
                        {52,1,29,5,51,6,27,7,59,8,10,2},
                        {10,1,59,5,1,6,41,7,19,8,23,2},
                        {23,1,19,5,17,6,16,7,18,8,22,2},
                        {22,1,18,5,40,6,0,7,58,8,8,2},
                        {12,1,24,5,42,6,2,7,56,8,4,2},
                        {4,1,56,5,20,6,32,7,28,8,55,2},
                        {55,1,28,5,33,6,21,7,57,8,6,2},
                        {6,1,57,5,3,6,43,7,25,8,13,2},
                        {13,1,25,5,35,6,34,7,24,8,12,2},
                        {39,1,37,5,49,6,15,7,27,8,51,2},
                        {15,1,49,5,43,6,3,7,7,8,11,2},
                        {11,1,7,5,31,6,47,7,41,8,1,2},
                        {47,1,31,5,21,6,33,7,45,8,54,2},
                        {54,1,45,5,44,6,53,7,16,8,17,2},
                        {53,1,44,5,32,6,20,7,30,8,46,2},
                        {46,1,30,5,5,6,9,7,0,8,40,2},
                        {9,1,5,5,2,6,42,7,48,8,14,2},
                        {14,1,48,5,36,6,38,7,50,8,26,2},
                        {38,1,36,5,34,6,35,7,37,8,39,2}};

    int[] smooth = new int[] {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
        11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
        21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 
        31, 32
    };

    PolygonMesh mesh = new PolygonMesh(points, texCoords, faces);
    mesh.getFaceSmoothingGroups().addAll(smooth);
    return mesh;
}

Now you can easily add it to an scene:

private double mouseOldX, mouseOldY = 0;
private final Rotate rotateX = new Rotate(0, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(0, Rotate.Y_AXIS);

@Override
public void start(Stage primaryStage) {

    PolygonMeshView meshView = new PolygonMeshView(getTruncatedIcosahedron());

    final PhongMaterial phongMaterial = new PhongMaterial();
    meshView.setDrawMode(DrawMode.LINE);
    meshView.setMaterial(phongMaterial);
    final Group group = new Group(meshView);
    group.getTransforms().add(new Scale(50, 50, 50));
    Scene scene = new Scene(group, 500, 300, true, SceneAntialiasing.BALANCED);
    scene.setOnMousePressed(event -> {
        mouseOldX = event.getSceneX();
        mouseOldY = event.getSceneY();
    });

    scene.setOnMouseDragged(event -> {
        rotateX.setAngle(rotateX.getAngle() - (event.getSceneY() - mouseOldY));
        rotateY.setAngle(rotateY.getAngle() + (event.getSceneX() - mouseOldX));
        mouseOldX = event.getSceneX();
        mouseOldY = event.getSceneY();
    });

    PerspectiveCamera camera = new PerspectiveCamera(false);
    camera.setNearClip(0.1);
    camera.setFarClip(1000.0);
    camera.getTransforms().addAll(rotateX, rotateY, new Translate(-250, -150, 0));
    scene.setCamera(camera);

    primaryStage.setTitle("JavaFX 3D - Truncated Icosahedron");
    primaryStage.setScene(scene);
    primaryStage.show();
}

Will give you the wireframe:

wireframe

And if you add the image of the texture, you will get your football:

phongMaterial.setDiffuseMap(new Image(getClass().getResourceAsStream("net3.png")));
meshView.setDrawMode(DrawMode.FILL);       

football

Now it's up to you to manipulate to your convenience this information, and modify this mesh into the one you are looking for.