2

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?

user4157124
  • 2,809
  • 13
  • 27
  • 42
Erdbeer0815
  • 155
  • 8
  • >>> if I want to add them to my original triangle mesh everything else turns black. Jose's answer is the best way for you to get the exact effect you are looking for and even as the person who wrote the PolyLine3D class I would recommend you switch to Jose's implementation. However I am curious as to the problem you are seeing. Are you adding the PolyLine3D mesh to the scene or to the original Sphere node itself? Could you please post the code you are using for this effect? – Birdasaur Sep 29 '18 at 14:02
  • If you mean the picture above I am just adding the PolyLine3D to the scene. Code can be found here: https://codeshare.io/G70dYk But it is just the Polyline3D test from the library metioned above and I just added a sphere in the code above from line 66 to 69. Might be your library because I probably have it from your github. Would be still nice to resolve the problem because with the polygon mesh I cannot change the size of the lines between the tiles which is necessary for my problem. Thank you for your help. – Erdbeer0815 Sep 30 '18 at 22:07
  • @Erdbeer0815 Do not include solution to question please (post a separate answer instead). – user4157124 Aug 23 '23 at 02:05

1 Answers1

2

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.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Thank you for your help. It is a nice idea I haven't thought about but as far as I can see with polygonmesh it is not poossible to change the size of the lines that distinguish the tiles? – Erdbeer0815 Sep 30 '18 at 22:12
  • That is entirely up to you, as you can modify the image ("net3.png" in this case) that you use for the texture: use thick lines, change colors, ... – José Pereda Sep 30 '18 at 22:15
  • is there any documentation of polygonmesh? I can't find one – Erdbeer0815 Sep 30 '18 at 22:41
  • No, but you can have a look at the code, which is easy to follow. There are two use cases for the PolygonMeshView: wireframe and solid. Each case creates a different TriangleMesh. So it is just a custom (and smart) TriangleMesh after all. – José Pereda Sep 30 '18 at 22:48