domingo, 19 de junio de 2011

Panorama poco informativo - Jugando con el 3D

Hace un par de semanas, paseando con la familia, fuimos a la afamada placita honda de Rafaela y estuvimos sacando algunas fotos.
La idea era hacer algunas pruebas para un proyecto futuro, asi que jugamos un poco.
Hoy procesamos las fotos y creamos una panoramica usando Hugin. Tengo que reconocer que es impresionante como mejoró Hugin. Ademas de una interfaz mas sencilla de usar y estable, tiene varias carácteristicas nuevas que fueron muy utiles para crear este panorama.



Como no habíamos ido pensando en hacer esto, las fotos se hicieron a mano alzada, sin trípode, elemento esencial para estos trabajos. Esto se nota en las áreas blancas, que no tienen contenido.
A pesar de esto, la prueba salió muy bien. Todos los problemas de union pudieron ser solucionados agregando nuevos puntos de control, o usando la nueva pestaña de máscara, donde podemos definir áreas que deben ser incluidas o excluidas. Esto resultó muy util a la hora de asegurarnos que los chicos fueran incluidos si o si.

Como hoy es un domingo de lluvia y no pudimos hacer el viaje que teníamos planeado, decidí probar hacer un sencillo visualizador de panorámicas usando Flash y Away3D.
Away3D es un excelente librería 3D para flash. Si bien la última versión es la 4 alpha, está pensada para el reproductor que esta en incubación, con soporte para Molehill.
Para no complicar la cosa y porque no voy a necesitar tanta potencia, bajé la 3.6.0 desde acá.

Todo el código del proyecto se puede bajar desde github.

Lo primero es crear un proyecto nuevo en su editor favorito, el mío es FlashDevelop, la beta de la versión 4 anda muy bien.
Despues agregamos los archivos de Away3D, que simplemente hay que copiar y ya empezamos a crear nuestra aplicación.

Primero definimos las variables que vamos a necesitar. Notar que estoy embebiendo la imagen directamente porque es una prueba.

  [Embed(source = '../lib/panorama.jpg')]
  private var textura:Class;
  private var camara:HoverCamera3D;
  private var vista:View3D;


Lo siguiente es preparar la camara y la vista 3D que se encargan de mostrar lo que hagamos.

  private function setupCamara():void {
   camara = new HoverCamera3D();
   camara.panAngle = 20;
   camara.tiltAngle = 0;
   camara.hover(true);
   camara.zoom = 8;
   camara.maxPanAngle = 210;
   camara.minPanAngle = -30;
   
   vista = new View3D();
   vista.camera = camara;
   vista.x = stage.stageWidth / 2;
   vista.y = stage.stageHeight / 2;
   addChild(vista);
  }

Uso una HoverCamera3D porque no necesito gran complejidad en los movimientos y el suavizado que tiene es ideal para lo que hacemos.
Los ángulos maximos y minimos de paneo, se deben a que no es un panorama completo el que estoy usando, entonces detengo el movimiento de camara antes de llegar a los limites. Con una imagen que tenga 360 grados, no es necesario.
La vista simplemente contiene la camara y se acomoda en el centro de la pelicula.

A continuación, preparo los objetos que se van a visualizar.

  private function setupObjetos():void {
   //var ejes:Trident = new Trident();
   //vista.scene.addChild(ejes);
   var plano:Plane = new Plane()
   plano.width = 2500;
   plano.height = 2500;
   plano.segmentsH = 10;
   plano.segmentsW = 10;
   plano.moveDown(550);
   plano.material = new ColorMaterial(0x000000);
   vista.scene.addChild(plano)
   
   var cilindro:Cylinder = new Cylinder();
   cilindro.radius = 1000;
   cilindro.height = 1000;
   cilindro.segmentsW = 20;
   cilindro.invertFaces();
   var bmp:Bitmap = new textura() as Bitmap;
   var matriz:Matrix = new Matrix();
   matriz.scale( -1, 1)
   matriz.translate(bmp.width, 0);
   var bmpd_invertida:BitmapData = new BitmapData(bmp.width, bmp.height);
   bmpd_invertida.draw(bmp, matriz);
   
   var material:BitmapMaterial = new BitmapMaterial(bmpd_invertida)
   material.smooth = true;
   cilindro.material = material;
   cilindro.openEnded = true;
   vista.scene.addChild(cilindro);
  }

Lo primero que hago es setear un plano que me va a servir como base. Esto es opcional, pero como la imagen no tiene los limites bien definidos, queria tener un elemento de referencia.
Luego, creo el cilindro que contiene el panorama. Basicamente es un gran cilindro, sin los extremos, al que invertimos las caras para que la textura se aplique dentro y no afuera. Como textura, uso la imagen que embebo, pero antes de aplicarla la invierto. Esto se debe a que las caras del cilindro estan invertidas, obligandome a realizar esta operación.
Si la imagen que tuviesemos fuese un panorama completo con el suelo y cielo, podríamos usar una esfera en lugar de un cilindro.


private function actualizar(e:Event):void {
   if (stage.mouseX < 100) {
    camara.panAngle -= 1;
   } else if ( stage.mouseX > stage.stageWidth - 100) {
    camara.panAngle += 1;
   }
   camara.hover();
   vista.render();
  }

Por último, en cada frame, actualizamos la posicion de la camara y renderizamos la vista.
De ser necesario, muevo la cámara en base a la posición del mouse.

Acá esta el archivo generado. Fue bastante entretenido generar primero la imagen y luego el visualizado, asi que espero ansioso el momento de hacer una versión mas pulida.

1 comentario:

  1. Che está buenísmo!!! Hace unas semana pensaba en la posibilidad de hacerme una pagina del consultorio... sí, leíste bien. Mi idea era la de una página que muestre la entrada y el consultorio, que enfoque distintos objetos que den cuenta del trabajo ahí realizado (entrevistas preliminares adultos, adolescentes, hora de juego diagnóstico con niños, ludoterapia, etc) y que funcione como una pag de publicidad de paso. Parece que esas fotos que giran tienen esa onda. ¿Eso significa que después podés generar "toques de puntero" que te desplieguen texto o algo así? Una onda así: http://www.porliniers.com/

    ResponderEliminar