inmensia |
Flash
Juan Mellado, 22 Noviembre, 2011 - 22:51
Siguiendo mi costumbre, he elaborado una pequeña cheat sheet para que me sirva de referencia, igual que la que hice para WebGL. Lo primero que llama la atención es que es una API de muy bajo nivel. Los que hayan utilizado alguna vez OpenGL, WebGL o DirectX se sentirán cómodos. Pero sinceramente, me esperaba una jerarquía de clases que ofreciera una funcionalidad de más alto nivel para la gestión de escenas, cámaras, colisiones o carga de modelos. Pero no, las clases que hay son para el acceso a bastante bajo nivel. De hecho, ni siquiera han incluido en el runtime el compilador de shaders. Pero vayamos por partes, las clases básicas de entrada al API son Stage3D y Context3D. La primera clase representa la superficie sobre la que se dibuja, de forma similar al Stage de toda la vida, y que permite además instanciar la segunda clase a través de un evento (para las situaciones de pérdida de contexto). El contexto 3D es el que permite instanciar al resto de clases como los buffers de índices, vértices, texturas o shaders. public class Example extends Sprite{Context3D es la clase base, muy similar a otras APIs, y permite, entre cosas, establecer el estado del render con las clásicas opciones de configuración del z-buffer, blending o stencil, y el envío al driver de la orden de dibujado de triángulos. Otras clases básicas son VertexBuffer3D, IndexBuffer3D, Texture, CubeTexture y Program3D. Pero tienen muy poca funcionalidad, apenas dos o tres métodos para inicializar su contenido desde fuentes de distintos tipos como arrays o matrices. El resto de clases son básicamente enumerados con las constantes típicas como Context3DTextureFormat, Context3DVertexBufferFormat, Context3DBlendFactor o Context3DStencilAction. En total son unas nueve clases de este último tipo, pero no ofrecen mayor funcionalidad aparte de exponer las constantes. var triangles:Vector.<uint> = Vector.<uint>( [ ... ] );Por lo que respecta a los shaders, Adobe ha definido un lenguaje propio (otro más) de muy bajo nivel llamado AGAL (Adobe Graphics Assembly Language). Es realmente ensamblador, por lo que las operaciones son de muy bajo nivel. Las instrucciones son opcodes que manipulan directamente los distintos tipos de registros habituales (attribute, constant, temporary, output, varying, sampler). private const VERTEX_SHADER:String =El array de bytecodes correspondiente a un shader puede generarse en tiempo de diseño mediante Pixel Bender 3D, que es una ampliación de la versión 2D de Pixel Bender, una tecnología de Adobe para el procesamiento óptimo de imágenes y vídeos independiente de la plataforma hardware utilizada basada en el uso de ficheros XML. Aunque afortunadamente los shaders también pueden compilarse de una forma más conveniente en tiempo de ejecución mediante una clase de utilidad externa llamada AGALMiniAssembler. private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();Por lo que respecta al bucle principal habitual de Flash, no parece requerir modificación, pudiéndose seguir utilizando el evento ENTER_FRAME por ejemplo. ...En definitiva, una API más, una opción más a tener en cuenta a la hora de representar 3D en el navegador. Quizás de muy bajo nivel para el concepto que suele tenerse en la cabeza de Flash, percepción que la aparición de ActionScript 3 empezó a modificar y que Stage3D no hace más que confirmar. Para terminar, revisando la web de Flash, he encontrado un enlace a un proyecto de la propia Adobe llamado Proscenium. Una librería gráfica de alto nivel, a modo de engine 3D, que están desarrollando sobre Stage3D. El inconveniente es que está aún en fase de desarrollo y no tiene soporte, aunque ya permite crear primitivas básicas, cargar modelos de objetos, e incluso gestionar colisiones. No sé como acabará, pero supongo que pretenderá ser una alternativa a motores desarrollados de forma independiente, como por ejemplo el popular Away3D y otros, que la propia Adobe parece estar apoyando.
Juan Mellado, 12 Junio, 2011 - 10:32
Demo online:
Juan Mellado, 11 Junio, 2011 - 14:30
Después de unas cortas, pero merecidas vacaciones, he retomado el proyecto de realidad aumentada para darle los últimos toques finales. En la lista del TODO me quedaron unas cuantas cosas por hacer que creía importante revisar. Al final he conseguido quitarme las más grandes de en medio, aunque alguna de ellas me han dado algún que otro dolor de cabeza. Memoria ![]() Como se observa en la primera imagen, la memoria empieza con unos valores iniciales aceptables. No obstante, el problema viene cuando a partir de ahí la memoria reservada no hace más que crecer y crecer, hasta que al alcanzar el límite de 2GB se cuelga la pestaña del navegador. Un error que ya había detectado antes, y que me tenía algo mosqueado. ![]() En la segunda imagen se ve la memoria a punto de alcanzar el máximo y provocar que el proceso aborte. No obstante, en esa imagen hay algo aún más importante en lo que fijarse. Y es en el hecho de que la memoria reservada por JavaScript y Flash sigue siendo del mismo orden de magnitud que al principio. La buena noticia es que todo apunta a que el problema no lo está generando el programa, ya que ni JavaScript ni Flash aparentan ser los culpables. Y la mala es que entonces surge la duda: ¿quién diablos está reservando toda esa memoria? Después de revisar todo una y otra vez, al final me he dado cuenta de que la memoria sólo crece de esa forma cuando tengo abierta la ventana de depuración de Chrome. O sea, que el problema es del navegador, no mía (\o/). Cuando tengo abierta la ventana de depuración (lo que en mi caso es prácticamente el 100% de las veces) la memoria no hace más que crecer y crecer. Pero cuando la tengo cerrada, haciendo una navegación normal, la memoria mantiene sus valores iniciales. ¡Aclarado el misterio! Rendimiento
Mi webcam, la más barata que encontré, es capaz de tomar imágenes a un ritmo de 15 fotogramas por segundo. Lo que da un tiempo de proceso de unos 67 (= 1000 / 15) milisegundos entre un fotograma y otro, mientras que librería estaba tardando 300 milisegundos por fotograma. La buena noticia es que al desplegar el detalle de los tiempos se observaba que en realidad el proceso de detección de marcadores apenas demoraba 40 milisegundos. Así que volvía a surgir una nueva pregunta: ¿en qué se estaba yendo el resto del tiempo? Pues resulta que todo el tiempo se consume en enviar los fotogramas desde Flash a JavaScript. Y por desgracia estoy obligado a utilizar Flash para capturar el vídeo, ya que todavía no puede hacer directamente desde JavaScript. Resulta que el paso de información entre Flash y JavaScript es bastante lento en general por culpa del proceso de serialización. Cuando implementé la librería de captura de vídeo en Flash me limité a guardar la imagen capturada en un Array y pasárselo a JavaScript, pero eso a la larga ha resultado ser muy sencillo de implementar pero muy poco eficiente.
Para acelerar el proceso de transferencia de datos entre Flash y JavaScript he realizado un montón de pruebas. Al final, la mejor implementación que he conseguido realizar, en cuanto a rendimiento, ha consistido en convertir todos los pixels de la imagen a cadena de caracteres y concatenarlos en un String separados por comas. Muy tosco, pero efectivo. Para disminuir el tamaño de la cadena de caracteres lo que he hecho es enviar la diferencia de un pixel con respecto al anterior, ya que normalmente tienden a parecerse. Y para reducir un poco más el número de caracteres los he codificado en base 36. Esto último puede sonar raro, pero es que esa es la mayor conversión de base que realizan de forma nativa tanto como Flash como JavaScript. De esta forma he encontrado un equilibrio entre la cantidad de información a intercambiar y el tiempo necesario para procesarla. He subido la clase ActionScript en un nuevo proyecto que he creado llamado flashcam. Por último, y entrando un poco más en detalle acerca de los tiempos de proceso de la librería, la función que más tarda con diferencia es la que realiza el filtro gaussiano, ya que ella sola se lleva el 75% del tiempo de ejecución. Curioso que al final una función "auxiliar" sea la que más tiempo tarde. Habrá que buscarle una alternativa.
Juan Mellado, 30 Mayo, 2011 - 07:37
He subido a un repositorio público todo el código JavaScript que he ido generando estos últimos días resultado de portar ArUco, una librería para la construcción de aplicaciones de realidad aumentada escrita en C++ utilizando OpenCV. He llamado js-aruco al proyecto, espero que el nombre no me cause problemas, pero me parecía el más adecuado. En contra de mi costumbre, he creado una pequeña demo, que tiene la particularidad de que es capaz de obtener imágenes de una webcam a través de una pequeña librería que he escrito en Flash, y que es capaz de capturar vídeo y enviar las imágenes a JavaScript. La demo requiere un ordenador bastante rápido, un navegador moderno actualizado (Chrome o Firefox), Flash para la captura de vídeo, y una webcam. ![]() Demo online: La demo detecta los marcadores y dibuja un borde rojo alrededor de los mismos, muestra en azul los números identificadores de cada uno de ellos, y destaca las esquinas superiores izquierda con un pequeño cuadro verde para poder hacer un seguimiento de su orientación real con respecto a la cámara. Los marcadores deben ser matrices de 7x7, con un borde negro de 1 celda de ancho. La matriz más interna de 5x5 puede tener filas con cualquiera de las siguiente combinaciones válidas: TODO Realidad Aumentada
Juan Mellado, 31 Mayo, 2010 - 09:08
Por el momento no resulta muy espectacular, ya que las películas Flash que requieren más proceso se ejecutan de una forma bastante lenta. Va requerir un poco más de optimización. Para lo que sirven en realidad este tipo de proyectos es para darse cuenta de que muchas cosas que se hacen "por inercia" con Flash se pueden hacer también con otras tecnologías. El principal problema es que no existen herramientas tan sencillas y productivas como Flash para hacerlas. Hay es donde se tienen que poner las pilas los desarrolladores. Y evidentemente falta que Internet Explorer empiece a soportar todas estas tecnologías. Microsoft debería tomar nota para la versión 9 de su navegador, que ya le toca. Silverlight y HTML5 pueden coexistir. Según la web del proyecto, el código fuente de Smokescreen se liberará dentro de un tiempo. No obstante, a dia de hoy se puede analizar el JavaScript que se ejecuta en la página de las demos: http://smokescreen.us/demos/js/smokescreen.0.1.3-min.js Leyendo entre líneas, se puede ver que han implementado un parser de ficheros SWF, de igual forma que se observa algunos nombres de clases del core del runtime de Flash para el player. Lo que no parece tener soporte el reproductor es para ActionScript, al menos en su versión 3, aunque teniendo sólo el código "minificado" es bastante complicado de saber a ciencia cierta. En cualquier caso, si bien estos "experimentos" resultan interesantes, la guerra entre Flash y HTML5 se ha enfriado un poco con la liberación de la versión Flash 10.1 (beta) que ya se puede ejecutar en móviles con Android 2.2 (Froyo). Google lo tiene claro: dar soporte para Flash, y otros ingenios como Unity por ejemplo. Si los usuarios no quieren utilizarlo que no lo hagan, es algo opcional. En la pasada Google I/O 2010 se pudieron ver bastantes cosas relativas a este tema, incluida una presentación de una aplicación de Adobe, aún en pañales, para generar animaciones directamente en HTML5 de forma similar a como se hace actualmente en Flash. |