JavaFX Gráficos 3D
JavaFX nos ofrece la posibilidad de agregar gráficos tridimensionales en la aplicación que estemos desarrollando, JavaFX cuenta con un grupo de figuras prediseñadas como: cubo, esfera, cilindro, etc., además podemos crear nuestras propias figuras, contamos también con las clases correspondientes para el manejo de luces y cámaras.
Antes de hacer algo primero debemos verificar si nuestra plataforma soporta JavaFX 3D, el código de verificación es sencillo y se muestra a continuación:
Un punto en el espacio 3D está representado por sus coordenadas en las componentes (x, y, z), el sistema de coordenadas usado por JavaFX 3D ubica el punto (0, 0, 0) en la parte superior izquierda de la ventana, del siguiente modo:

Las clases Box, Sphere y Cylinder representan las figuras prediseñadas que podemos agregar a la escena, para visualizar correctamente la escena debemos agregar una fuente de luz, la clase PointLight nos crea una luz puntual, requerimos también agregar una cámara, para ello tenemos la clase PerspectiveCamera, cada una de estas clases cuenta con los métodos setTranslate(X/Y/Z) que nos permiten cambiar su posición.

Para obtener este resultado se han aplicado rotaciones en X e Y, usando en método box.setRotate(45); para indicar el ángulo de rotación y box.setRotationAxis(new Point3D(1, 1, 0)); para indicar los ejes sobre los que se hará la rotación.
Podemos indicar que tipo de material conforma nuestro objeto 3D, para ello contamos con la clase PhongMaterial usada para establecer los materiales de un objeto utilizando el modelo de iluminación Phong podemos establecer las siguientes propiedades: diffuseColor, diffuseMap, specularColor, specularMap, selfIlluminationMap, specularPower, bumpMap, con los correspondientes métodos setter.

En lugar de aplicar un simple color veamos cómo podemos utilizar mapas de texturas para establecer las componentes difusa y especular, aplicamos solo la primera en este ejemplo, además veremos cómo utilizar normal map o bump map.

La clase MeshView nos permite definir formas personalizas, esta clase requiere un objeto TriangleMesh para definir como se forma la figura, debemos indicar cada uno de los vértices usando triangulación, las coordenada de texturas y las caras del modelo.
Normalmente no definimos manualmente esta información, por lo general nos apoyamos en software de diseño 3D como: Blender, Maya, 3D Max, etc., generamos la figura y la almacenamos en un archivo en formato: .obj, .fbx, .dae, etc,.
Utilizaremos la librería creada para la aplicación de ejemplo JavaFX 3D Viewer, cargaremos un archivo .obj con sus materiales.
Este código genera la siguiente salida:
Puedes descargar este proyecto en su versión para IntelliJ IDE en: JavaFX Gráficos 3D.
Verificar Soporte Gráfico 3D
Antes de hacer algo primero debemos verificar si nuestra plataforma soporta JavaFX 3D, el código de verificación es sencillo y se muestra a continuación:
package sample; import javafx.application.Application; import javafx.application.ConditionalFeature; import javafx.application.Platform; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception { boolean supported = Platform.isSupported(ConditionalFeature.SCENE3D); if (supported) System.out.println("JavaFX 3D Listo"); else System.out.println("Esta plataforma no soporta JavaFX 3D"); } public static void main(String[] args) { launch(args); } }
Sistema de Coordenadas
Las clases Box, Sphere y Cylinder representan las figuras prediseñadas que podemos agregar a la escena, para visualizar correctamente la escena debemos agregar una fuente de luz, la clase PointLight nos crea una luz puntual, requerimos también agregar una cámara, para ello tenemos la clase PerspectiveCamera, cada una de estas clases cuenta con los métodos setTranslate(X/Y/Z) que nos permiten cambiar su posición.
private void createScene3D(Stage stage) { // crear un cubo 3D, anchura, altura y profundidad Box box = new Box(100, 100, 100); // crear una luz puntual PointLight light = new PointLight(); light.setTranslateX(-350); light.setTranslateY(-180); light.setTranslateZ(-500); Group root = new Group(box, light); // crear la escena, true para activar el buffer de profindidad Scene scene = new Scene(root, 1280, 768, true, SceneAntialiasing.BALANCED); // crear una camara en perspectiva PerspectiveCamera camera = new PerspectiveCamera(); camera.setTranslateX(scene.getWidth() / -2.0); camera.setTranslateY((scene.getHeight() / -2.0) - 150); scene.setCamera(camera); stage.setTitle("JavaFX Graficos 3D"); stage.setScene(scene); stage.show(); }
Para obtener este resultado se han aplicado rotaciones en X e Y, usando en método box.setRotate(45); para indicar el ángulo de rotación y box.setRotationAxis(new Point3D(1, 1, 0)); para indicar los ejes sobre los que se hará la rotación.
Especificar Materiales
Podemos indicar que tipo de material conforma nuestro objeto 3D, para ello contamos con la clase PhongMaterial usada para establecer los materiales de un objeto utilizando el modelo de iluminación Phong podemos establecer las siguientes propiedades: diffuseColor, diffuseMap, specularColor, specularMap, selfIlluminationMap, specularPower, bumpMap, con los correspondientes métodos setter.
PhongMaterial mat = new PhongMaterial(Color.RED); mat.setSpecularColor(Color.BLUE); mat.setSpecularPower(128); // crear un cubo 3D, anchura, altura y profundidad Box box = new Box(300, 300, 300); box.setRotate(45); box.setRotationAxis(new Point3D(1, 1, 0)); box.setMaterial(mat);
En lugar de aplicar un simple color veamos cómo podemos utilizar mapas de texturas para establecer las componentes difusa y especular, aplicamos solo la primera en este ejemplo, además veremos cómo utilizar normal map o bump map.
Image image_diffuse = new Image(getClass().getResource("muro_diffuse.jpg").toExternalForm()); Image image_normal = new Image(getClass().getResource("muro_normal.jpg").toExternalForm()); PhongMaterial mat = new PhongMaterial(); mat.setSpecularColor(color_luz); mat.setSpecularPower(64); mat.setDiffuseMap(image_diffuse); mat.setBumpMap(image_normal);
Creación de Objetos 3D
La clase MeshView nos permite definir formas personalizas, esta clase requiere un objeto TriangleMesh para definir como se forma la figura, debemos indicar cada uno de los vértices usando triangulación, las coordenada de texturas y las caras del modelo.
Normalmente no definimos manualmente esta información, por lo general nos apoyamos en software de diseño 3D como: Blender, Maya, 3D Max, etc., generamos la figura y la almacenamos en un archivo en formato: .obj, .fbx, .dae, etc,.
Utilizaremos la librería creada para la aplicación de ejemplo JavaFX 3D Viewer, cargaremos un archivo .obj con sus materiales.
private void loadScene3D(Stage stage) throws IOException { PointLight light1 = new PointLight(); light1.setTranslateZ(-500); Node model = Importer3D.load(getClass().getResource("obj-model/cyborg.obj").toExternalForm()); model.setScaleX(150.0); model.setScaleY(150.0); model.setScaleZ(150.0); Group root = new Group(model, light1); Scene scene = new Scene(root, 1280, 768, true, SceneAntialiasing.BALANCED); PerspectiveCamera camera = new PerspectiveCamera(); camera.setTranslateX(scene.getWidth() / -2.0); camera.setTranslateY(scene.getHeight() / -2.0); RotateTransition rt = new RotateTransition(Duration.seconds(10), model); rt.setCycleCount(Animation.INDEFINITE); rt.setFromAngle(0); rt.setToAngle(360); rt.setAxis(new Point3D(0, 1, 0)); rt.play(); scene.setFill(Color.CORNFLOWERBLUE); scene.setCamera(camera); stage.setTitle("JavaFX Graficos 3D - Cargar Modelo"); stage.setScene(scene); stage.show(); }
Este código genera la siguiente salida:
Puedes descargar este proyecto en su versión para IntelliJ IDE en: JavaFX Gráficos 3D.
Muchas gracias por el post!!
ResponderEliminarmuy bien explicado
puedes darme alguna información, sobre como cambiar la ubicación de un gráfico, es decir si cargas por defecto un cubo o un objeto .obj con mtl y .jpg este sale por defecto en el centro del frame, como puedo cambiar estas posiciones en X, Y, Z.
ResponderEliminarDe antemano gracias
Hola, con esta instrucción después de cargar el obj
Eliminarcubo.setTranslateX(valor);
cubo.setTranslateY(valor);
cubo.setTranslateZ(valor);
¿Qué librería es la que utilizas para importar los modelos 3D? Estuve buscando y no encontré sendas librerías.
ResponderEliminar