Ir al contenido principal

Cargar Un Modelo 3D De Blender En JavaFX

EL día de hoy he estado experimentando con las nuevas características del Preview del JDK8 y de JavaFX8 mas específicamente con 3D.

lo que vamos a ver hoy es como cargar en JavaFX un modelo 3D exportado desde Blender al formato Collada.

Lo primero son las herramientas, para este caso me encuentro utilizando el siguiente PC:

  • Windows 8.1 Preview de 64bits
  • Procesador AMD FX de 8 nucleos, con 4 GB de RAM.
Y tengo instalado el siguiente software:
  • JDK8 Early Access Build 101
  • Blender 2.6
  • Netbeans 7.4 Beta.
Ahora si podemos empezar. Lo primero que debemos hacer es crear un modelo básico en Blender o en su defecto descargar uno libre, para efectos de esta prueba incluso el básico cubo que trae por defecto una nueva escena de Blender nos puede servir.

Paso a seguir exportamos nuestro modelo al formato Collada, primero seleccionamos el objeto y luego accedemos a la opcion del menú file>export>Collada(.dae). En las opciones que nos nuestra marcamos el check "Selection Only" para que únicamente nos exporte el objeto seleccionado. Esto NO quiere decir que no se pueda exportar toda la escena, es posible exportarla toda pero para que sea un poco mas sencilla la lectura del archivo solo exportaremos el objeto seleccionado.



Collada es un formato XML que almacena los datos de nuestros modelos 3D, el formato completo lo pueden encontrar en la pagina http://collada.org/. de momento solo veremos algunos pocos aspectos del modelos que hemos exportado:

lo primero que vemos es que tenemos unas librerias, nos centraremos en esta ocasión en la librería que contiene la geometría:
Dentro de esa librería nos encontramos las geometrías en mi caso  solo tengo una geometría "Cube-mesh" y esta contiene unas fuentes, una definición de vértices y una definición de polígono:
nos centraremos en la lista de polígono "polylist", como vemos dentro de ella se encuentra un tag que se llama "vcount" que indica los grupos de vértices que forman cada polígono, en este caso blender nos exporta los polígonos en triángulos y por ello cada uno de los valores separados por espacio de este tag tiene el numero 3.

Luego tenemos una etiqueta "p" con una serie de números, para entender esta serie de números debemos fijarnos en las etiquetas que tenemos a su mismo nivel como vemos tenemos 2 etiquetas de tipo "input" y cada una de ella hace referencia a una fuente (source="#nombre-de-fuente"), esto quiere decir que su contenido va a estar definido en una etiqueta cuyo ID(id="id") sea el nombre que esta especificando. Para nuestro ejemplo se esta haciendo referencia a los vértices y a las normales que se encuentran definidos en las etiquetas "source" y  "vertices":

aunque nuestro "input semantic=VERTEX" hace referencia a una etiqueta tipo "vertices" esta luego hace referencia a una etiqueta de tipo source, asi que nos centraremos en este momento en la etiqueta source.

las etiquetas source que estamos observando contiene un array y una técnica con 3 parámetros X, Y y Z. estos 3 parámetros indican como esta dividido el array que esta describiendo, por ejemplo en la imagen en el source de id="Cube-mesh-positions-array" esta describiendo un array que cada posición contiene 3 valores "XYZ" de tal forma que el primer número del array (1) es el valor X de la primera posición, el segundo numero(1) es el valor Y de la primera posición, el tercer numero(-1) es el valor Z de la primera posición, el cuarto numero(1) es el valor X de la segunda posición y asi sucesivamente agrupamos ese array en grupos de 3 valores de manera que si de ese array queremos el valor Y de la tercera posición estaríamos trayendo el numero en la posición 8(-0.9999998).

una vez hemos entendido los "sources" volvemos a nuestra etiqueta "p" dentro del "polylist", los valores de esta etiqueta están definidos por el atributo "offset" que tienen los "input" dentro del "polylist" este "offset" indica que posición de la secuencia corresponde al "input", por ejemplo el "input" de "source=#Cube-mesh-vertices" tiene "offset=0" lo cual quiere decir que el primer valor de p(el numero 3) corresponde a la posicion del "source" "#Cube-mesh-vertices" y, como el otro "input" tiene "offset=1" quiere decir que el próximo numero (el numero 0) corresponderá a la posición del "source" "#Cube-mesh-normals". De esta manera continua la secuencia siendo el primer valor el vértice y el segundo valor la normal, el tercer valor el vértice y el cuarto valor la normal así sucesivamente hasta completar en este caso los 80 valores.

Entendido lo anterior los que hacemos es un código para obtener los puntos y la configuración de estos puntos del "polylist":

public class LoadDAE {

    private final Document doc;
    private Node mesh;

    private Node getMesh() {
        if (mesh == null) {
            NodeList libraryGeometries = doc.getDocumentElement().getElementsByTagName("library_geometries");
            Node geometry = libraryGeometries.item(0).getChildNodes().item(1);
            mesh = geometry.getChildNodes().item(1);
        }
        return mesh;
    }

    /**
     *
     * @return
     */
    public Float[] cargarPuntos() {
        Node meshNode = getMesh();
        Node cubeMeshPositionsArray = meshNode.getChildNodes().item(1).getChildNodes().item(1);
        String[] srtPuntos = cubeMeshPositionsArray.getFirstChild().getTextContent().split(" ");
        Float[] puntos = new Float[srtPuntos.length];
        for (int i = 0; i < srtPuntos.length; i++) {
            puntos[i] = Float.valueOf(srtPuntos[i]);
        }
        return puntos;
    }

    public Integer[] cargarPolyList() {
        Element meshNode = (Element) getMesh();

        Element polylist = (Element) meshNode.getElementsByTagName("polylist").item(0);
        Element p = (Element) polylist.getElementsByTagName("p").item(0);

        String[] srtPuntos = p.getTextContent().split(" ");
        Integer[] puntos = new Integer[srtPuntos.length];
        for (int i = 0; i < srtPuntos.length; i += 2) {
            puntos[i] = Integer.valueOf(srtPuntos[i]);
            puntos[i+1] = 0;
        }
        return puntos;
    }

    public LoadDAE() throws ParserConfigurationException, SAXException, IOException {
        File fXmlFile = new File("D:\\casarara.dae");
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        doc = dBuilder.parse(fXmlFile);

        doc.getDocumentElement().normalize();
    }
}

Luego de tener nuestra clase procedemos a utilizarla:
        //creamos el material
        PhongMaterial material = new PhongMaterial();
        material.setDiffuseColor(Color.LIGHTGRAY);
        material.setSpecularColor(Color.rgb(30, 30, 30));
        //cargamos los puntos a un nuevo objeto tipo TriangleMesh 
        LoadDAE loadDAE = new LoadDAE();
        TriangleMesh tm = new TriangleMesh();
        for (Float punto : loadDAE.cargarPuntos()) {
            tm.getPoints().addAll(punto * 100);
        }
        //adicionamos unas corrdenadas de textura al azar aunque aun no las utilizamos:
        tm.getTexCoords().addAll(
                0, 0,
                1, 0,
                0, 1,
                1, 1);
        //cargamos nuestras caras del polylist
        for (Integer punto : loadDAE.cargarPolyList()) {
            tm.getFaces().addAll(punto);
        }
y lo adicinamos a nuestro Shape3D:
        Shape3D meshView = new MeshView(tm);
        
        meshView.setMaterial(material);

Ejecutamos y el resultado debe ser algo como esto dependiendo de su figura 3d:


la anterior solución solo pretende mostrar como se puede comprender el formato para que se tome como punto de partida para luego hacer otra librería que sea un poco mas automática a la hora de cargar modelos COLLADA, espero les sea de provecho y experimenten con las nuevas características de JavaFX8


hasta una próxima.

Comentarios

Entradas populares de este blog

Character controller en Unity con el nuevo input system

Bienvenidos

BIENVENIDOS bienvenidos a mi blog donde colocaré todos mis avances, análisis, técnicas, concejos y recomendaciones que aplique en las áreas de: Desarrollo de software en ambiente web. Desarrollo de software Java Desarrollo de software para móviles. Desarrollo de software con interfaces 3d para web o escritorio. Desarrollo de de videojuegos, entornos virtuales y animaciones. Diseño y modelado de 3d. Noticias, curiosidades y opiniones de tecnología. cualquier otro tema pertinente Agradezco su colaboración siguiendo este blog, y sus opiniones :) . Fecha De lanzamiento: miércoles 06 de abril de 2011.