5

I am starting to use JavaFX for visualizing 3D unstructured meshes and I am facing a rendering issue.

As indicated in [1], JavaFX only renders the front faces of triangles unless you use the CullFace.NONE option. But then the back faces are black.

As the 3D meshes are generated by external tools (such as Gmsh http://geuz.org/gmsh/), I don't have the control of the faces orientation. The scientific software that use the mesh also do not require oriented meshes.

Thus I don't want to re-orient the meshes afterwards, only to render the front and back faces of triangles identically. Is this possible with JavaFX 8? How?

Thanks for your answers.

Noteworthy: I have also posted a similar question on Oracle forums [2], but they seem pretty empty. If some of you know where the JavaFX community is active, a link would be useful. I will of course update both threads if I have useful answers to share.

Kind regards

Sphere meshed in 3D

[1] How to make sense of JavaFX triangle mesh?

[2] https://community.oracle.com/thread/3593434

Community
  • 1
  • 1
Ben
  • 6,321
  • 9
  • 40
  • 76

1 Answers1

4

SOLUTION 1

You can solve the problem by drawing two sets of meshes with different face orientations. See the results and code below. However this doubles the amount of data and processing time.

PS: There is an additional issue worth mentioning. It is not clear if in the current Version of JavaFX (@August 2014) you can color mesh edges differently than the faces. This would be necessay if you need to make visible individual tiles of a planar tiling. The solution is again to add two more wire sets of mesh objects. But this quadruples the required resources.

Also, one would like to cull some of the edges which are not necessary. In the figure below only the floor edges need to be highlighted, not the diagonals.

SOLUTION 2

Replace each mesh face with a 3D mesh object, i.e. instead of having for example a rectangular surface you create a slab. An open box object will thus be made from five slabs and the inside and outside of the box will have the same color. This solution, like the first one, is still a hack and still produces processing overhead.

FIGURES

Comparison between the actual JavaFX rendering and the desired rendering (produced in Matlab):

http://s30.postimg.org/iuotogvgh/3d_tower.jpg

Partial solution:

http://s30.postimg.org/83dcwtpkx/3d_boxes.png

CODE

import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;

/**
// * Draw polygonal 3D box.
// * 
// * INPUT
// * - footprint: 2D polygon coordinates; 
// *   closed path (i.e. first and last coordinates are identical); ex:
// *   float[] footprint = {
// *       10, -1,
// *       -1, -1,
// *       -1, 5,
// *       10, 5,
// *       10, -1
// *   };
// * - zLevel: z-coordinate of actual floor level: int k; float zLevel = k * HEIGHT - HEIGHT;
// * - HEIGHT: height of the box: private static final float HEIGHT = (float) 50;
// * 
// * NOTE: we have to use the mesh method since the straightforward way
// * to construct a rectangle - "rectangle" method - produces blurry edges.
// *
// */
public class DrawPolygonalBox {

// Draw polygonal 3D box.
public static Group draw(float[] footprint, float zLevel, float HEIGHT) {

    Group box = new Group();
    int y = 0;

    // for each footprint coordinate make a rectangle
    int n = footprint.length - 2;

    // one side of the box
    for (int k = 0; k < n; k = k + 2) {

        float[] points = {
            footprint[k], y + zLevel, footprint[k + 1],
            footprint[k + 2], y + zLevel, footprint[k + 3],
            footprint[k + 2], y + zLevel + HEIGHT, footprint[k + 3],
            footprint[k], y + zLevel + HEIGHT, footprint[k + 1]
        };            
        float[] texCoords = {
            1, 1,
            1, 0,
            0, 1,
            0, 0
        };
        int[] faces = {
            0, 0, 2, 2, 1, 1,
            0, 0, 3, 3, 2, 2
        };
        int[] faces2 = {
            0, 0, 1, 1, 2, 2,
            0, 0, 2, 2, 3, 3
        };

        TriangleMesh mesh1 = new TriangleMesh();
        mesh1.getPoints().setAll(points);
        mesh1.getTexCoords().setAll(texCoords);
        mesh1.getFaces().setAll(faces);

        TriangleMesh mesh2 = new TriangleMesh();
        mesh2.getPoints().setAll(points);
        mesh2.getTexCoords().setAll(texCoords);
        mesh2.getFaces().setAll(faces2);

        final MeshView rectangle1 = new MeshView(mesh1);
        rectangle1.setMaterial(new PhongMaterial(Color.web("#FF0000",0.25)));
        rectangle1.setCullFace(CullFace.BACK);

        final MeshView rectangle2 = new MeshView(mesh2);
        rectangle2.setMaterial(new PhongMaterial(Color.web("#FF0000",0.25)));
        rectangle2.setCullFace(CullFace.BACK);

        final MeshView wire1 = new MeshView(mesh1);
        wire1.setMaterial(new PhongMaterial(Color.web("#000000",0.5)));
        wire1.setCullFace(CullFace.BACK);
        wire1.setDrawMode(DrawMode.LINE);

        final MeshView wire2 = new MeshView(mesh2);
        wire2.setMaterial(new PhongMaterial(Color.web("#000000",0.5)));
        wire2.setCullFace(CullFace.BACK);
        wire2.setDrawMode(DrawMode.LINE);

        // add to group
        box.getChildren().addAll(rectangle1, wire1, rectangle2, wire2);
    }

    return box;
}

}