Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create 3d shape from STL in JavaFX 8?

I have class STLFile which returns two arrays: one with coordinates of normals and another one with vertices coords. So now I want to create 3d shape with these coordinates in my JavaFX app. The problem is that how can I do this without textures. Using the official guide I've made TriangleMesh with coordinates and add it to MeshView. But unfortunately nothing appeared in the scene. So can anybody explain me how to do this, because the description in official guide couldn't be called sufficient?

like image 367
Eugene Avatar asked Oct 19 '13 05:10

Eugene


1 Answers

You can load STL files using the Interactive Mesh JavaFX STL Model Importer.

jewel

JewelViewer.java

import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Mesh;
import javafx.scene.shape.MeshView;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

import java.io.File;

public class JewelViewer extends Application {

  private static final String MESH_FILENAME =
    "/Users/lilyshard/Downloads/Perfect Diamond/Perfect Diamond.STL";

  private static final double MODEL_SCALE_FACTOR = 400;
  private static final double MODEL_X_OFFSET = 0; // standard
  private static final double MODEL_Y_OFFSET = 0; // standard

  private static final int VIEWPORT_SIZE = 800;

  private static final Color lightColor = Color.rgb(244, 255, 250);
  private static final Color jewelColor = Color.rgb(0, 190, 222);

  private Group root;
  private PointLight pointLight;

  static MeshView[] loadMeshViews() {
    File file = new File(MESH_FILENAME);
    StlMeshImporter importer = new StlMeshImporter();
    importer.read(file);
    Mesh mesh = importer.getImport();

    return new MeshView[] { new MeshView(mesh) };
  }

  private Group buildScene() {
    MeshView[] meshViews = loadMeshViews();
    for (int i = 0; i < meshViews.length; i++) {
      meshViews[i].setTranslateX(VIEWPORT_SIZE / 2 + MODEL_X_OFFSET);
      meshViews[i].setTranslateY(VIEWPORT_SIZE / 2 + MODEL_Y_OFFSET);
      meshViews[i].setTranslateZ(VIEWPORT_SIZE / 2);
      meshViews[i].setScaleX(MODEL_SCALE_FACTOR);
      meshViews[i].setScaleY(MODEL_SCALE_FACTOR);
      meshViews[i].setScaleZ(MODEL_SCALE_FACTOR);

      PhongMaterial sample = new PhongMaterial(jewelColor);
      sample.setSpecularColor(lightColor);
      sample.setSpecularPower(16);
      meshViews[i].setMaterial(sample);

      meshViews[i].getTransforms().setAll(new Rotate(38, Rotate.Z_AXIS), new Rotate(20, Rotate.X_AXIS));
    }

    pointLight = new PointLight(lightColor);
    pointLight.setTranslateX(VIEWPORT_SIZE*3/4);
    pointLight.setTranslateY(VIEWPORT_SIZE/2);
    pointLight.setTranslateZ(VIEWPORT_SIZE/2);
    PointLight pointLight2 = new PointLight(lightColor);
    pointLight2.setTranslateX(VIEWPORT_SIZE*1/4);
    pointLight2.setTranslateY(VIEWPORT_SIZE*3/4);
    pointLight2.setTranslateZ(VIEWPORT_SIZE*3/4);
    PointLight pointLight3 = new PointLight(lightColor);
    pointLight3.setTranslateX(VIEWPORT_SIZE*5/8);
    pointLight3.setTranslateY(VIEWPORT_SIZE/2);
    pointLight3.setTranslateZ(0);

    Color ambientColor = Color.rgb(80, 80, 80, 0);
    AmbientLight ambient = new AmbientLight(ambientColor);

    root = new Group(meshViews);
    root.getChildren().add(pointLight);
    root.getChildren().add(pointLight2);
    root.getChildren().add(pointLight3);
    root.getChildren().add(ambient);

    return root;
  }

  private PerspectiveCamera addCamera(Scene scene) {
    PerspectiveCamera perspectiveCamera = new PerspectiveCamera();
    System.out.println("Near Clip: " + perspectiveCamera.getNearClip());
    System.out.println("Far Clip:  " + perspectiveCamera.getFarClip());
    System.out.println("FOV:       " + perspectiveCamera.getFieldOfView());

    scene.setCamera(perspectiveCamera);
    return perspectiveCamera;
  }

  @Override
  public void start(Stage primaryStage) {
    Group group = buildScene();
    group.setScaleX(2);
    group.setScaleY(2);
    group.setScaleZ(2);
    group.setTranslateX(50);
    group.setTranslateY(50);

    Scene scene = new Scene(group, VIEWPORT_SIZE, VIEWPORT_SIZE, true);
    scene.setFill(Color.rgb(10, 10, 40));
    addCamera(scene);
    primaryStage.setTitle("Jewel Viewer");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public static void main(String[] args) {
    System.setProperty("prism.dirtyopts", "false");
    launch(args);
  }
}

STL source model information

-- Model information --

Model Name : Perfect Diamond
Author : Scott Allen
Publisher : mtgtopdeck

You can view this model here :
http://www.3dvia.com/content/024BE6380A1C2E00
More models about this author :
http://www.3dvia.com/mtgtopdeck


-- Attached license --

A license is attached to the Perfect Diamond model and all related media.
You must agree with this licence before using the enclosed media.

License : Attribution-NonCommercial 2.5
Detailed license : http://creativecommons.org/licenses/by-nc/2.5/

The licenses used by 3dvia are based on Creative Commons Licenses.
More info: http://creativecommons.org/about/licenses/meet-the-licenses

FAQ

I've tried to use your code but importing a different STL [did not work correctly] (that shows up in other viewers)

When I wrote this example, if I recall, I tweaked a few settings like object scale, location, lighting camera positioning, etc. by trial and error until I got a rendering which I liked.

I doubt the settings I used would be generic to work well (or perhaps even at all for all models).

Perhaps the camera, object positioning, clip settings or lighting is wrong for your model.

Or perhaps it is just failing on the import due to limited functionality.

You could try the interactive mesh model viewer and see if it imports your models. If not, then your model isn't supported by the importer.

You could also see the FXyz lib which has model imports and try them, though you may need to convert to another format (e.g. obj) to use that.

Additionally, certain model features such as transparencies and flipped normals aren't currently supported, so the failure to render could also be due to the JavaFX 3D implementation rather than the model importer or camera/scene settings, in which case your model will not render correctly no matter what importer you use.

Expectations for JavaFX 3D

In general, JavaFX 3D isn't as widely used and actively developed as other Java based 3D libraries such as LWJGL, so don't expect as wide a functional base and displayable model set as other potential 3D solutions.

Still, the basic Phong rendering, texturing, hardware acceleration, camera and lighting in JavaFX 3D does work for many models and is usable for certain applications if you have the appropriate skill set and time.

like image 54
jewelsea Avatar answered Nov 01 '22 00:11

jewelsea