Hace ya algún tiempo abordaba la problemática de la publicación y distribución de contenidos 3D ya que con frecuencia una buena parte de la documentación 3D generada, raras veces acaba viendo la luz por lo poco usual de las herramientas de visualización de contenidos 3D, el peso de muchos de los documentos y lo relativamente ajeno de ciertas estrategias de publicación web.
Aunque en los últimos años plataformas propietarias como Sketchfab o p3dj.in se han convertido en una interesante solución, los costes que su uso implica a largo plazo puede no ser especialmente sostenible para ciertos proyectos.
Como alternativa, tenemos el conocido el 3D PDF o el X3DOM para web, basado en el formato X3D, el cual se presenta como una fuerte apuesta para la estandarización en la publicación web.
El problema de la publicación en X3DOM es, por ahora, la dependencia de herramientas como AOPT de Instant Player, para realizar las conversiones a partir de documentos X3D a HTML5
Actualmente quizás una de las pocas alternativas maduras a X3DOM podría ser el proyecto Three.js, que como su nombre indica esta basado en Javascript y aprovecha igualmente las capacidades webGL de nuestros exploradores para renderizar modelos 3D a traves de la Web.
Quizás una de las posibilidades más interesantes de Three.js, frente al uso de X3DOM, es el uso directo de formatos de archivo como Wavefront (.obj) o Stanford Triangle Format (.ply) unos formato de archivo tremendamente comunes, por lo que no es necesario ninguna preparación previa del modelo, salvo, la evidente y necesaria simplificación del modelo, con el fin de reducir el tamaño de nuestros documentos lo suficiente, para su carga vía web sin aburrir al usuario en tiempos de espera eternos.
Three.js es un proyecto open-source liberado por Ricardo Cabello en 2010, casualmente en el mismo año que surge X3DOM. En la actualidad dicho proyecto posee un fuerte desarrollo y ha sido escalado con un buen número de librerías que aportan interesantes funcionalidades.
Nos podemos hacer una idea de las tremendas posibilidades de dicha librería a través de la web del Museo de Paleontología de la universidad de Michigan (http://umorf.ummp.lsa.umich.edu/wp/ )
Introducción al uso de Three.js
Podemos introducirnos fácilmente en el uso de dicha librería gracias a los numerosos ejemplos que podemos descargar de su web ( http://mrdoob.github.io/three.js/examples/ ). El siguiente código que vamos a ver, esta tomado del ejemplo de carga de documentos en formato Wavefront (obj Loader).
En este ejemplo se usan cuatro librerías:
- Three.js que es la librería principal encargada de generar el render de nuestro modelo vía webGL
- TrackballControls.js la cual como su nombre indica nos permite la rotación del modelo (control de cámaras)
- OBJLoader.js, encargada de la carga de modelos en formato Wavefront (.obj)
- Detector.js cuya misión es verificar si nuestro explorador de internet tiene soporte para webGL
El código fuente completo es el siguiente:
<script src="js/three.min.js"></script> <script src="js/TrackballControls.js"></script> <script src="js/OBJLoader.js"></script> <script src="js/Detector.js"></script> <script> var container, stats; var camera, scene, renderer; var mouseX = 0, mouseY = 0; var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); camera.position.z = 100; controls = new THREE.TrackballControls( camera ); controls.rotateSpeed = 5.0; controls.zoomSpeed = 5; controls.panSpeed = 2; controls.noZoom = false; controls.noPan = false; controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; // escena scene = new THREE.Scene(); // luz ambiente var ambient = new THREE.AmbientLight( 0xffffff ); scene.add( ambient ); // Carga textura var texture = new THREE.Texture(); var loader = new THREE.ImageLoader(); loader.addEventListener( 'load', function ( event ) { texture.image = event.content; texture.needsUpdate = true; texture.magFilter = THREE.NearestFilter; texture.minFilter = THREE.NearestMipMapLinearFilter; } ); loader.load( 'diosa_textura_low.png' ); // Carga modelo var loader = new THREE.OBJLoader(); loader.addEventListener( 'load', function ( event ) { var object = event.content; object.traverse( function ( child ) { if ( child instanceof THREE.Mesh ) { child.material.map = texture; } } ); object.scale = new THREE.Vector3(25,25,25 ); scene.add( object ); }); loader.load( 'diosa.0.mesh_low_low.textura.obj' ); // Renderiza con webGL renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); document.addEventListener( 'mousemove', onDocumentMouseMove, false ); window.addEventListener( 'resize', onWindowResize, false ); } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function onDocumentMouseMove( event ) { mouseX = ( event.clientX - windowHalfX ) / 2; mouseY = ( event.clientY - windowHalfY ) / 2; } function animate() { requestAnimationFrame( animate ); render(); } function render() { controls.update(); camera.lookAt( scene.position ); renderer.render( scene, camera ); } </script> <div> <canvas width="800" height="800" style="width: 800px; height: 800px;"></canvas> </div>
De este código es interesante destacar la carga de nuestra textura en:
loader.load( 'diosa_textura_low.png' );
Y finalmente la carga del archivo Wavefront
loader.load( 'diosa.0.mesh_low_low.textura.obj' );
Hay que tener presente que OBJLoader también puede cargar documentos .mtl para la referencia de materiales.
loader.load( 'diosa.0.mesh_low_low.textura.obj', 'diosa.0.mesh_low_low.textura.mtl')
A continuación podeis ver un pequeño modelo de 24.000 polígonos, con un peso total de 1.4Mb y una textura jpeg de 500Kb publicado con Three.js: The Queen of The Night