How to 3D-print scene JavaFX 3D?

I am working on this scientific application in JavaFX. The program basically generates data from the algorithm and visualizes them in areas that intersect. enter image description here

I would like to print a 3D part of this model (color shapes). Is there a way to export a JavaFX scene? Even if it means that it exports it to a file, such as .stl or .obj, and imports it into Blender for further refinement or conversion of the files.

+6
source share
1 answer

If you want to export your 3D model to .obj, you need to access the TriangleMesh each shape so that you can export vertices and faces.

Currently, using built-in JavaFX 3D forms such as Sphere is not possible because their grids are not displayed.

In addition, there is no built-in export method.

Thus, the solution will create your 3D forms from scratch and provide an export method or use third-party solutions.

If you look at the F (X) yz library, it solves some of your problems, as it already provides:

  • Multiple 3D forms with full access to their cell information
  • Export to .obj and .mtl for any given three-dimensional shape.

Unfortunately, it does not allow exporting multiple shapes to a single .obj file, but it is something that can be easily added.

This is a quick implementation of the Group exporter, which will export all the MeshView in the group and their diffuse color to one obj file and one mtl file.

 public class GroupOBJWriter { private final String newline = System.getProperty("line.separator"); private float[] points0, texCoord0; private int[] faces0, sm0; private BufferedWriter writer = null; private final String fileName; private String diffuseMap; private String diffuseColor = "0.0 0.0 0.0"; // black private final Group group; public GroupOBJWriter(Group group, String fileName){ this.group = group; this.fileName = fileName; } public void exportMesh(){ File objFile = new File(fileName + ".obj"); try{ writer = new BufferedWriter(new FileWriter(objFile)); writer.write("mtllib " + fileName + ".mtl" + newline); AtomicInteger counter = new AtomicInteger(); AtomicInteger vCounter = new AtomicInteger(); group.getChildren().stream() .filter(MeshView.class::isInstance) .map(s -> (TriangleMesh) ((MeshView) s).getMesh()) .forEach(mesh -> { try{ writer.write("# Material" + newline); int count = counter.getAndIncrement(); writer.write("usemtl " + fileName + "-" + count + ""+newline); points0 = new float[mesh.getPoints().size()]; mesh.getPoints().toArray(points0); List<Point3D> points1 = IntStream.range(0, points0.length/3) .mapToObj(i -> new Point3D(points0[3*i], points0[3*i+1], points0[3*i+2])) .collect(Collectors.toList()); writer.write("# Vertices (" + points1.size() + ") for shape " + count + "" + newline); points1.forEach(p -> { try { writer.write("v " + px + " " + py + " " + pz + "" + newline); } catch (IOException ex) { System.out.println("Error writting vertex "+ex); } }); writer.write(newline); texCoord0 = new float[mesh.getTexCoords().size()]; mesh.getTexCoords().toArray(texCoord0); List<Point2D> texCoord1 = IntStream.range(0, texCoord0.length/2) .mapToObj(i -> new Point2D(texCoord0[2*i], texCoord0[2*i+1])) .collect(Collectors.toList()); writer.write("# Textures Coordinates (" + texCoord1.size() + ") for shape " + count + "" + newline); texCoord1.forEach(t->{ try { // objimporter u->u, v->(1-v) writer.write("vt " + ((float) t.getX()) + " " + ((float) (1d - t.getY())) + "" +newline); } catch (IOException ex) { System.out.println("Error writting texture coordinate " + ex); } }); writer.write(newline); faces0 = new int[mesh.getFaces().size()]; mesh.getFaces().toArray(faces0); List<Integer[]> faces1 = IntStream.range(0, faces0.length/6) .mapToObj(i -> new Integer[]{faces0[6*i], faces0[6*i+1], faces0[6*i+2], faces0[6*i+3], faces0[6*i+4], faces0[6*i+5]}) .collect(Collectors.toList()); writer.write("# Faces (" + faces1.size() + ") for shape " + count + "" + newline); writer.write("# Material for shape " + count + "" + newline); writer.write("usemtl " + fileName + "-" + count + "" + newline); sm0 = new int[mesh.getFaces().size()]; mesh.getFaceSmoothingGroups().toArray(sm0); if (sm0[0] > 0) { writer.write("s " + sm0[0] + "" + newline); } AtomicInteger c = new AtomicInteger(); final int inc = vCounter.get() + 1; faces1.forEach(f->{ try { writer.write("f " + (f[0] + inc) + "/" + (f[1] + inc) + " " + (f[2] + inc) + "/" + (f[3] + inc) + " " + (f[4] + inc) + "/" + (f[5] + inc) + "" + newline); if (sm0[c.getAndIncrement()] != sm0[c.get()]) { writer.write("s " + (sm0[c.get()] > 0 ? sm0[c.get()] : "off" ) + "" + newline); } } catch (IOException ex) { System.out.println("Error writting face "+ex); } }); vCounter.addAndGet(points1.size()); writer.write(newline); } catch(IOException io){ System.out.println("Error creating writer obj " + io); } }); } catch(IOException io){ System.out.println("Error creating writer obj "+io); } finally { try { if(writer!=null){ writer.close(); } } catch (Exception e) {} } File mtlFile = new File(fileName+".mtl"); try{ writer = new BufferedWriter(new FileWriter(mtlFile)); AtomicInteger counter = new AtomicInteger(); group.getChildren().stream() .filter(MeshView.class::isInstance) .map(s -> ((PhongMaterial) ((MeshView) s).getMaterial()).getDiffuseColor()) .forEach(color -> { try{ diffuseColor=""+((float)(color.getRed()))+" "+((float)(color.getGreen()))+" "+((float)(color.getBlue())); int count = counter.getAndIncrement(); writer.write("# Material " + fileName + "-" + count + "" + newline); writer.write("newmtl " + fileName + "-" + count + "" + newline); writer.write("illum 4" + newline); // Illumination [0-10] writer.write("Kd " + diffuseColor + "" + newline); // diffuse color black writer.write("Ka 0.10 0.10 0.10" + newline); // ambient color writer.write("Tf 1.00 1.00 1.00" + newline); // Transmission filter if (diffuseMap != null) { writer.write("map_Kd " + diffuseMap + "" + newline); } writer.write("Ni 1.00" + newline); // optical density writer.write("Ks 1.00 1.00 1.00" + newline); // specular reflectivity writer.write("Ns 32.00" + newline); // specular exponent writer.write(newline); } catch(IOException io){ System.out.println("Error creating writer obj " + io); } }); } catch(IOException io){ System.out.println("Error creating writer mtl "+io); } finally { try { if(writer!=null){ writer.close(); } } catch (Exception e) {} } } } 

With SegmentedSphereMesh from F (X) yz, you can create a sphere, so this will be an example of how to build a group and export it:

 @Override public void start(Stage primaryStage) throws Exception { PerspectiveCamera camera = new PerspectiveCamera(true); camera.setTranslateZ(-20); Group sceneRoot = new Group(); Scene scene = new Scene(sceneRoot, 800, 600, true, SceneAntialiasing.BALANCED); scene.setCamera(camera); Group group = new Group(); for (int i = -5; i < 5; i++) { for (int j = -2; j < 2; j++) { for (int k = 0; k < 3; k++) { SegmentedSphereMesh sphere = new SegmentedSphereMesh(50, 0, 0, 0.75, new Point3D((float) i, (float) j, (float) k)); sphere.setTextureModeNone(Color.rgb(255 / 10 * (6 + i), 255 / 5 * (j + 3), 255 / 3 * (k + 1))); group.getChildren().add(sphere); } } } group.getTransforms().addAll(new Rotate(40, Rotate.X_AXIS), new Rotate(10, Rotate.Y_AXIS)); sceneRoot.getChildren().addAll(group); primaryStage.setTitle("F(X)yz - Segmented Spheres Group"); primaryStage.setScene(scene); primaryStage.show(); GroupOBJWriter writer=new GroupOBJWriter(group,"spheres"); writer.exportMesh(); } 

Group of spheres

If you import the resulting spheres.obj from 3DViewer , you will see:

3DViewer

+3
source

All Articles