How to render front and back sides of triangles the same in JavaFX
I am starting to use JavaFX to render 3D unstructured meshes and I am facing a rendering issue.
As pointed out in [1], JavaFX only displays the front faces of triangles unless you use the CullFace.NONE option. But then the back faces are black.
Since 3D meshes are generated by external tools (such as Gmsh http://geuz.org/gmsh/ ), I have no control over the orientation of the face. Grid scientific software also does not require oriented grids.
So I don't want to reorient the meshes later, just to display the same front and back sides of the triangles. Is this possible with JavaFX 8? How?
Thank you for your responses.
Notably: I also posted a similar question on the Oracle forums [2], but they seem to be pretty empty. If some of you know where the JavaFX community is active, a link would be helpful. I will of course update both threads if I have any helpful answers to share.
respectfully
source to share
SOLUTION 1
You can solve the problem by drawing two sets of meshes with different orientations of the face. See Results and Code below. However, this doubles the amount of data and the processing time.
PS: There is an additional issue worth mentioning. It's unclear if in the current JavaFX version (@August 2014) you can color the mesh borders differently than the edges. This would be necessary if you need to make visible individual tiles of flat tiles. The solution will add two more sets of mesh objects again. But this quadruples the required resources.
Also, I would like to drop some of the edges that are not needed. In the picture below, only the edges of the floor should be selected, not the diagonals.
SOLUTION 2
Replace each mesh surface with a 3D mesh object, that is, instead of having, for example, a rectangular surface, you create a slab. Thus, an object with an open box will be made of five slabs, and the inside and outside of the box will be the same color. This solution, like the first, is still a hack and still generates processing overhead.
<strong> FIGURES
Comparison of actual JavaFX rendering and desired rendering (generated 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;
}
}
source to share