¿Cómo crear un modelo 3D personalizado en JavaFX 8?

Traté de hacer un avión en la aplicación JavaFX usando el tutorial oficial y tengo el siguiente código:

Image diifuseMap = new Image(getClass().getResource("t.jpg").toExternalForm()); TriangleMesh planeMesh = new TriangleMesh(); float[] points = { -5, 5, 0, -5, -5, 0, 5, 5, 0, 5, -5, 0 }; float[] texCoords = { 0, 0, 0, 1, 1, 0, 1, 1 }; int[] faces = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1 }; planeMesh.getPoints().addAll(points); planeMesh.getTexCoords().addAll(texCoords); planeMesh.getFaces().addAll(faces); MeshView meshView = new MeshView(planeMesh); meshView.setMaterial(new PhongMaterial(Color.BLACK, diifuseMap, null, null, null)); Group3D plane = new Group3D(new MeshView(planeMesh)); 

Pero, desafortunadamente, nada apareció en la escena. ¿Alguien puede explicar cómo crear mis propios modelos 3D en JavaFX? ¿Y es posible crearlos sin textura (quiero el modelo de estructura alámbrica)?

nada apareció en la escena

Tu malla de muestra se procesó para mí.

Quizás no haya configurado la cámara correctamente o haya cambiado su malla para que esté visible.

Su malla de muestra no hace mucho, es un triángulo orientado hacia la cámara y un segundo triángulo que mira hacia la cámara.

¿Y es posible crearlos sin textura (quiero el modelo de estructura alámbrica)?

Sí, configure DrawMode para su vista de malla en Line .

Ejemplo de Explicación del Progtwig

Cambié el orden de tus rostros para que ambos encaren en la misma dirección, de modo que obtienes un cuadrado frente al espectador en lugar de un triángulo orientado hacia el espectador y otro del espectador:

 int[] faces = { 2, 2, 1, 1, 0, 0, 2, 2, 3, 3, 1, 1 }; 

Además, el mapa de texturas debe cambiar (para que la matriz de caras anterior obtenga la orientación correcta en la textura para que no quede al revés).

 float[] texCoords = { 1, 1, 1, 0, 0, 1, 0, 0 }; 

Configuré un control de recuperación y animé la rotación del modelo para que pudieras ver los lados “posteriores” de los triangularjs (en negro) y queda claro lo que se está renderizando. También agregué la capacidad de alternar un mapa difuso (algo de mármol) para una textura o un modo de estructura alámbrica.

Muestra de salida del progtwig

llanuraestructura metálicatextura

Progtwig de muestra

 import javafx.animation.*; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.geometry.Insets; import javafx.scene.*; import javafx.scene.control.CheckBox; import javafx.scene.image.Image; import javafx.scene.layout.VBox; import javafx.scene.paint.*; import javafx.scene.shape.*; import javafx.scene.transform.Rotate; import javafx.stage.Stage; import javafx.util.Duration; public class InlineModelViewer extends Application { private static final int VIEWPORT_SIZE = 800; private static final double MODEL_SCALE_FACTOR = 40; private static final double MODEL_X_OFFSET = 0; private static final double MODEL_Y_OFFSET = 0; private static final double MODEL_Z_OFFSET = VIEWPORT_SIZE / 2; private static final String textureLoc = "https://www.sketchuptextureclub.com/public/texture_f/slab-marble-emperador-cream-light-preview.jpg"; private Image texture; private PhongMaterial texturedMaterial = new PhongMaterial(); private MeshView meshView = loadMeshView(); private MeshView loadMeshView() { float[] points = { -5, 5, 0, -5, -5, 0, 5, 5, 0, 5, -5, 0 }; float[] texCoords = { 1, 1, 1, 0, 0, 1, 0, 0 }; int[] faces = { 2, 2, 1, 1, 0, 0, 2, 2, 3, 3, 1, 1 }; TriangleMesh mesh = new TriangleMesh(); mesh.getPoints().setAll(points); mesh.getTexCoords().setAll(texCoords); mesh.getFaces().setAll(faces); return new MeshView(mesh); } private Group buildScene() { meshView.setTranslateX(VIEWPORT_SIZE / 2 + MODEL_X_OFFSET); meshView.setTranslateY(VIEWPORT_SIZE / 2 * 9.0 / 16 + MODEL_Y_OFFSET); meshView.setTranslateZ(VIEWPORT_SIZE / 2 + MODEL_Z_OFFSET); meshView.setScaleX(MODEL_SCALE_FACTOR); meshView.setScaleY(MODEL_SCALE_FACTOR); meshView.setScaleZ(MODEL_SCALE_FACTOR); return new Group(meshView); } @Override public void start(Stage stage) { texture = new Image(textureLoc); texturedMaterial.setDiffuseMap(texture); Group group = buildScene(); RotateTransition rotate = rotate3dGroup(group); VBox layout = new VBox( createControls(rotate), createScene3D(group) ); stage.setTitle("Model Viewer"); Scene scene = new Scene(layout, Color.CORNSILK); stage.setScene(scene); stage.show(); } private SubScene createScene3D(Group group) { SubScene scene3d = new SubScene(group, VIEWPORT_SIZE, VIEWPORT_SIZE * 9.0/16, true, SceneAntialiasing.BALANCED); scene3d.setFill(Color.rgb(10, 10, 40)); scene3d.setCamera(new PerspectiveCamera()); return scene3d; } private VBox createControls(RotateTransition rotateTransition) { CheckBox cull = new CheckBox("Cull Back"); meshView.cullFaceProperty().bind( Bindings.when( cull.selectedProperty()) .then(CullFace.BACK) .otherwise(CullFace.NONE) ); CheckBox wireframe = new CheckBox("Wireframe"); meshView.drawModeProperty().bind( Bindings.when( wireframe.selectedProperty()) .then(DrawMode.LINE) .otherwise(DrawMode.FILL) ); CheckBox rotate = new CheckBox("Rotate"); rotate.selectedProperty().addListener(observable -> { if (rotate.isSelected()) { rotateTransition.play(); } else { rotateTransition.pause(); } }); CheckBox texture = new CheckBox("Texture"); meshView.materialProperty().bind( Bindings.when( texture.selectedProperty()) .then(texturedMaterial) .otherwise((PhongMaterial) null) ); VBox controls = new VBox(10, rotate, texture, cull, wireframe); controls.setPadding(new Insets(10)); return controls; } private RotateTransition rotate3dGroup(Group group) { RotateTransition rotate = new RotateTransition(Duration.seconds(10), group); rotate.setAxis(Rotate.Y_AXIS); rotate.setFromAngle(0); rotate.setToAngle(360); rotate.setInterpolator(Interpolator.LINEAR); rotate.setCycleCount(RotateTransition.INDEFINITE); return rotate; } public static void main(String[] args) { System.setProperty("prism.dirtyopts", "false"); launch(args); } } 

¿Alguien puede explicar cómo crear mis propios modelos 3D

Esa es una pregunta demasiado amplia para StackOverflow. Hay universidades y escuelas de arte que entregan diplomas en ese tipo de cosas.

¿Alguien puede explicar por qué Mesh.setAll toma float [] mientras que el rest de la API usa double?

La implementación 3D de JavaFX proporciona una envoltura alrededor de las API nativas que se comunican con el hardware de gráficos (por ejemplo, DirectX y OpenGL). Estas API funcionan con precisión flotante en lugar de precisión doble. El uso de float[] directamente en la API significa que los datos del modelo de malla se pueden almacenar de manera más eficiente y se pueden asignar directamente a las API de gráficos subyacentes que si se utilizara double[] o una ObservableList .

Paso 1: enumera los puntos

Paso 1

 cube.getPoints().addAll( 0, 0, 100, //P0 100, 0, 100, //P1 0, 100, 100, //P2 100, 100, 100, //P3 0, 0, 0, //P4 100, 0, 0, //P5 0, 100, 0, //P6 100, 100, 0 //P7 ); 

Paso 2: enumera los puntos de textura

Paso 2

 cube.getTexCoords().addAll( 0.25f, 0, //T0 0.5f, 0, //T1 0, 0.25f, //T2 0.25f, 0.25f, //T3 0.5f, 0.25f, //T4 0.75f, 0.25f, //T5 1, 0.25f, //T6 0, 0.5f, //T7 0.25f, 0.5f, //T8 0.5f, 0.5f, //T9 0.75f, 0.5f, //T10 1, 0.5f, //T11 0.25f, 0.75f, //T12 0.5f, 0.75f //T13 ); 

Paso 3: enumere las caras (puntos mixtos 3D y puntos de textura en sentido antihorario (o regla de la mano derecha))

 cube.getFaces().addAll( 5,1,4,0,0,3 //P5,T1 ,P4,T0 ,P0,T3 ,5,1,0,3,1,4 //P5,T1 ,P0,T3 ,P1,T4 ,0,3,4,2,6,7 //P0,T3 ,P4,T2 ,P6,T7 ,0,3,6,7,2,8 //P0,T3 ,P6,T7 ,P2,T8 ,1,4,0,3,2,8 //P1,T4 ,P0,T3 ,P2,T8 ,1,4,2,8,3,9 //P1,T4 ,P2,T8 ,P3,T9 ,5,5,1,4,3,9 //P5,T5 ,P1,T4 ,P3,T9 ,5,5,3,9,7,10 //P5,T5 ,P3,T9 ,P7,T10 ,4,6,5,5,7,10 //P4,T6 ,P5,T5 ,P7,T10 ,4,6,7,10,6,11 //P4,T6 ,P7,T10 ,P6,T11 ,3,9,2,8,6,12 //P3,T9 ,P2,T8 ,P6,T12 ,3,9,6,12,7,13 //P3,T9 ,P6,T12 ,P7,T13 );