2015-04-28 3 views

Répondre

5

La meilleure façon de combiner un objet javafx.scene.shape.Mesh avec un CSG une, à condition d'avoir une TriangleMesh est de convertir les faces triangulaires de polygones (eu.mihosoft.vrl.v3d.Polygon).

Une fois que vous avez un objet CSG, vous pouvez y effectuer les opérations habituelles, puis vous pouvez l'exporter vers un MeshView par exemple.

Le problème avec les formes primitives (Box, Sphere, ...) est que vous n'avez pas accès à leur TriangleMesh. Vous pouvez donc aller à la bibliothèque F(X)yz et choisir l'une des formes 3D disponibles.

Par exemple, utilisons un objet FrustumMesh.

Vous pouvez facilement créer un:

FrustumMesh cone = new FrustumMesh(1,0.2,4,2); 

Cone

Et vous aurez accès à son maillage: cone.getMesh(). Maintenant nous devons convertir ce TriangleMesh en List<Polygon>. Pour cela, nous pouvons créer cette classe utilitaire:

public class Mesh2CSG { 
    /** 
    * Loads a CSG from TriangleMesh. 
    * @param mesh 
    * @return CSG 
    * @throws IOException if loading failed 
    */ 
    public static CSG mesh2CSG(MeshView mesh) throws IOException { 
     return mesh2CSG(mesh.getMesh()); 
    } 
    public static CSG mesh2CSG(Mesh mesh) throws IOException { 

     List<Polygon> polygons = new ArrayList<>(); 
     List<Vector3d> vertices = new ArrayList<>(); 
     if(mesh instanceof TriangleMesh){ 
      // Get faces 
      ObservableFaceArray faces = ((TriangleMesh)mesh).getFaces(); 
      int[] f=new int[faces.size()]; 
      faces.toArray(f); 

      // Get vertices 
      ObservableFloatArray points = ((TriangleMesh)mesh).getPoints(); 
      float[] p = new float[points.size()]; 
      points.toArray(p); 

      // convert faces to polygons 
      for(int i=0; i<faces.size()/6; i++){ 
       int i0=f[6*i], i1=f[6*i+2], i2=f[6*i+4]; 
       vertices.add(new Vector3d(p[3*i0], p[3*i0+1], p[3*i0+2])); 
       vertices.add(new Vector3d(p[3*i1], p[3*i1+1], p[3*i1+2])); 
       vertices.add(new Vector3d(p[3*i2], p[3*i2+1], p[3*i2+2])); 
       polygons.add(Polygon.fromPoints(vertices)); 
       vertices = new ArrayList<>(); 
      } 
     } 

     return CSG.fromPolygons(new PropertyStorage(),polygons); 
    } 
} 

Avec cette méthode, vous pouvez obtenir un cône de CSG:

CSG coneCSG = Mesh2CSG.mesh2CSG(cone.getMesh()); 

donc vous pouvez combiner avec d'autres formes CSG:

CSG cube = new Cube(2).toCSG().color(Color.RED); 
CSG union = cube.union(coneCSG); 

et revenir à un maillage JavaFX pour l'afficher:

MeshView unionMesh = coneCSG.toJavaFXMesh().getAsMeshViews().get(0); 

Cone and Box

Ceci est la classe de l'échantillon complet (à condition d'avoir sur votre classpath les dépendances FXyzLib.jar et JCSG.jar):

public class FXyzJCSG extends Application { 
    private double mousePosX, mousePosY; 
    private double mouseOldX, mouseOldY; 
    private final Rotate rotateX = new Rotate(-20, Rotate.X_AXIS); 
    private final Rotate rotateY = new Rotate(-20, Rotate.Y_AXIS); 

    @Override 
    public void start(Stage primaryStage) throws IOException { 

     FrustumMesh cone = new FrustumMesh(1,0.2,4,2); 
     cone.setDrawMode(DrawMode.LINE); 
     cone.setTextureModeNone(Color.ROYALBLUE); 

     CSG coneCSG = Mesh2CSG.mesh2CSG(cone.getMesh()); 

     CSG cube = new Cube(2).toCSG().color(Color.RED); 
     CSG union = cube.union(coneCSG); 

     MeshView unionMesh = union.toJavaFXMesh().getAsMeshViews().get(0); 
//  unionMesh.setDrawMode(DrawMode.LINE); 
     PerspectiveCamera camera = new PerspectiveCamera(true); 
     camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -10)); 

     Group root3D = new Group(camera,unionMesh); 

     SubScene subScene = new SubScene(root3D, 600, 400, true, SceneAntialiasing.BALANCED); 
     subScene.setFill(Color.AQUAMARINE); 
     subScene.setCamera(camera); 

     Scene scene = new Scene(new StackPane(subScene), 600, 400); 
     scene.setOnMousePressed(me -> { 
      mouseOldX = me.getSceneX(); 
      mouseOldY = me.getSceneY(); 
     }); 
     scene.setOnMouseDragged(me -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY)); 
      rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX)); 
      mouseOldX = mousePosX; 
      mouseOldY = mousePosY; 
     }); 

     primaryStage.setTitle("FXyz & JCSG - JavaFX 3D"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

Belle réponse! La méthode du convertisseur devrait être ajoutée à JCSG. – miho

+0

Merci @miho, les deux frameworks (FXyz et JCSG) pourraient bénéficier d'une interface qui permet une interaction facile entre les deux. Les opérations booléennes sont vraiment une fonctionnalité intéressante pour FXyz, tandis que JCSG pourrait bénéficier de sa collection de formes 3D améliorées. –

+0

Merci beaucoup José Pereda, je l'apprécie vraiment. Merci aussi à miho pour le travail incroyable sur CSG. @ José vous avez dit que JCSG pourrait bénéficier de la collection améliorée de formes 3D de FXyz, eh bien nous avons fait une demande de traction sur github pour ajouter de nouvelles formes 3D à FXyz –