Merging cubes
With the use of ScatterMesh
from the FXyz library you can merge all the individual meshes from your cube objects (I take each cube is a Box
), into one single big triangle mesh, while keeping their unique color.
Given that you have a set of 3D coordinates, each one defining a cube, and a given color per coordinate (cube), this small code snippet demonstrates how to do it. It is based on the use of CUBE
markers that will create a CuboidMesh
per each point in the scatter plot.
List<Double> coordinates = Arrays.asList(x0,y0,z0,...); // n points
List<Color> colors = Arrays.asList(new Color(),...); // n colors
// create org.fxyz3d.geometry.Point3D for each cube with x,y,z,f (index of color)
List<Point3D> cubes = new ArrayList<>();
AtomicInteger i = new AtomicInteger();
colors.stream()
.forEach(c -> cubes.add(new Point3D(coordinates.get(i.getAndIncrement()),
coordinates.get(i.getAndIncrement()),
coordinates.get(i.getAndIncrement()),
colors.indexOf(c))));
// create scatterMesh from cubes, each cube with a size of 20 pixels
ScatterMesh scatterMesh = new ScatterMesh(cubes, 20);
// apply `CUBE` marker
scatterMesh.setMarker(MarkerFactory.Marker.CUBE);
// apply same `f` value to all 8 vertices of each cube
scatterMesh.setFunctionData(cubes.stream()
.flatMap(p -> Collections.nCopies(8, p.f).stream()).collect(Collectors.toList()));
// Apply texture based on the list of colors
scatter.setTextureModeVertices3D(new Palette.ListColorPalette(colors), p -> p.f);
With this approach you will have as a result a single mesh. Accessing the cubes can be done with PickResult
and some logic to find the cube from the given coordinates.
Another option that could simplify identifying cubes of a given terrain height is to use a ScatterMesh
per given height (that will have the same color):
List<ScatterMesh> scatterMeshList = new ArrayList<>();
// Collect different heights
List<Float> heights = cubes.stream()
.map(b -> b.z)
.distinct()
.collect(Collectors.toList());
scatterMeshList = heights.stream()
.map(h -> {
List<Point3D> cubesPerH = cubes.stream()
.filter(p -> p.z == h)
.collect(Collectors.toList());
int colorIndex = (int)cubesPerH.get(0).f;
ScatterMesh scatterMesh = new ScatterMesh(cubesPerH, 20);
scatterMesh.setMarker(MarkerFactory.Marker.CUBE);
scatterMesh.setTextureModeNone(colors.get(colorIndex));
return scatterMesh;
})
.collect(Collectors.toList());
Artifacts
Having a single or a small number of scatter meshes instead of hundreds or thousands of cube meshes is obviously better in terms of performance.
However, this might not solve the issue with the artifacts that appear when rendering a JavaFX 3D shape with a given texture. This is a known issue, but I didn't find it filed though, so it should definitely be reported.