Skip to content

flash

Flash Stage3D Cheat Sheet

WebGL Cheat SheetEl lanzamiento de la versión definitiva de Flash 11 hace unas pocas semanas trajo consigo el tan esperado Stage3D, anteriormente conocido como Molehill. O lo que es lo mismo, la posibilidad de aprovechar las capacidades de las GPUs desde Flash. En principio es una alternativa más a otras opciones disponibles actualmente como WebGL, aunque el anuncio por parte de Adobe de renunciar a seguir desarrollando Flash para móviles en favor de su plataforma AIR nos ha dejado despistados a un montón de gente. Pero decisiones empresariales aparte, el API está ahí fuera y es hora de echarle un vistazo.

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.

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.

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).

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.

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.

js-aruco: Realidad Aumentada en JavaScript

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.

js-aruco

Demo online: http://inmensia.com/files/aruco/webcam/webcam.html

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 7×7, con un borde negro de 1 celda de ancho. La matriz más interna de 5×5 puede tener filas con cualquiera de las siguiente combinaciones válidas:
blanco – negro – negro – negro – negro
blanco – negro – blanco – blanco – blanco
negro – blanco – negro – negro – blanco
negro – blanco – blanco – blanco – negro

TODO
Optimizar. Para capturar imágenes a un mínimo de 20 fps se requiere ser capaz de procesar cada imagen en tan sólo 50 (= 1000/20) milisegundos, algo bastante alejado del rendimiento actual de la librería, incluso para resoluciones pequeñas de 320×240. [Solucionado]
Reducir el uso de memoria. Hay unas cuantas funciones que reservan memoria que luego no reutilizan ya que vuelven a hacer la misma reserva para cada imagen procesada. [Solucionado]
Implementar interpolación bilineal en el warp. En ángulos en torno a los 45 grados, para imágenes pequeñas, no se están detectando a veces los marcadores debido a que se forman “dientes de sierra” en la imagen que provocan que falle la cuenta de pixels para diferenciar los cuadrados blancos de los negros. [Implementado]
Después de varios minutos de funcionamiento la ventana del navegador da un error, aunque aún no sé si porque falla Flash o JavaScript. Posiblemente sea porque falla el mecanismo que he puesto para intercambiar datos entre Flash y JavaScript, o porque el proceso se queda sin memoria. [Solucionado]
Sustituir Flash por la futura función JavaScript “getUserMedia”, un estándar que aún se está definiendo y que espero que los navegadores implementen algún día. [Implementado]

Realidad Aumentada
1. Introducción
2. Escala de grises (Grayscale & Gaussian Blur)
3. Umbralización (Adaptive Thresholding)
4. Detección de contornos (Suzuki)
5. Aproximación a polígonos (Douglas-Peucker)
6. Transformación de perspectiva (Homography & Otsu)
7. Detección de marcadores
8. js-aruco: Realidad Aumentada en JavaScript

Smokescreen: (Otro) Reproductor de Flash escrito en JavaScript

Flash Apple Android Windows MobileSmokescreen es otro proyecto que trata de reproducir Flash en el navegador a través de un programa escrito completamente en JavaScript utilizando HTML5. En la web del proyecto se pueden ver algunas demos, e incluso un video con las demos ejecutándose sobre un iPad. Muy similar al proyecto Gordon, en bastantes aspectos.

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.

App My Ride

Volkswagen logoApp My Ride es un concurso que tiene actualmente en marcha Volkswagen. La idea es desarrollar una aplicación, o proponer una idea, que pueda ser utilizada a través de un sistema de información computerizado de un coche. Lo curioso del tema es que los programas se tienen que enviar escritos en formato SWF, es decir, escritos en Flash o Flex.

Lo que han hecho es crear un SDK que incluye un reproductor sobre el que se tiene que ejecutar la aplicación Flash generada. Es como el reproductor standalone normal de Adobe, pero con un peculiaridad añadida. Al tiempo que se reproduce la aplicación se reproduce un fichero con información real capturada por los sensores de un coche en dos trayectos distintos. Uno durante un desplazamiento por una ciudad, y otro durante un viaje por una autopista. Y esa información se hace llegar al programa Flash en forma de eventos. De forma similar a como se gestionan los eventos de ratón o teclado por ejemplo.

Todos los eventos disponibles están definidos en un paquete de clases ActionScript llamado “volkswagen.miniapps.interfaces”, que también se incluye dentro del SDK, y que hay que importar dentro de la aplicación. Para recibir notificaciones sobre un evento determinado basta con definir un handler sobre él de la forma acostumbrada. Por ejemplo, para ser notificado en todo momento de la velocidad del coche, basta con escribir el siguiente sencillo código:

La velocidad del coche, la marcha engranada, el consumo de combustible, la latitud, longitud y altura respecto al nivel del mar, la temperatura exterior, e incluso la apertura o cierre de las puertas, el abrochado o desabrochado de los cinturones de seguridad, el encendido o apagado de las luces, pasando por la aceleración lineal, lateral o la fuerza que se está ejerciendo sobre los pedales, son algunos de los eventos que se pueden monitorizar. Incluso hay un evento que avisa si se está pulsando la bocina.

El reproductor que incluye el SDK permite además simular eventos, introduciendo manualmente los valores que queramos, para poder probar las aplicaciones de una forma más precisa, ya que es imposible que los recorridos de ejemplo cubran todas las posibilidades.

El plazo de recepción del concurso empezó a primeros de mayo y terminará a finales de junio. En la web se pueden ver las ideas propuestas hasta la fecha y las aplicaciones enviadas. Incluso permiten enviar juegos ¡que no distraigan a los conductores!. El tamaño de las aplicaciones está limitado a 380×380, y se insiste en que los controles han de ser grandes y con un alto contraste debido a que van a visualizarse en pantallas normalmente pequeñas y expuestas a la luz ambiente.

Hay 6.000 euros en premios a repartir entre los tres primeros clasificados, más algún extra, como la posibilidad de optar a una beca si eres estudiante, o de disfrutar de un coche de la marca durante un fin de semana.

En las bases del concurso se explican los requerimientos para entrar concursar, la cesión de derechos y demás de la forma acostumbrada.

Ejecutando (un poco de) ActionScript 3 en JavaScript

Después de haber conseguido parsear con éxito un fichero Flash mediante un programa en JavaScript, me he animado a programar una máquina virtual, también en JavaScript, que ejecute el código ActionScript 3 leído del fichero SWF sin utilizar el plugin de Adobe.

La ventaja de hacerlo en JavaScript es que ambos lenguajes se basan en la misma especificación ECMA-262, por lo que muchas cosas pueden traducirse directamente de un lenguaje a otro. Pero eso es en un mundo ideal, en la vida real ocurre que cada cual implementa la especificación de una forma ligeramente distinta, aparte de que la propia especificación deja margen para que ciertas partes se implementen de forma arbitraria. De hecho, es algo bastante conocido que la implementación del propio JavaScript varía de un navegador a otro.

Para simplificar estoy suponiendo que el comportamiento del código ejecutado en JavaScript es lo suficientemente parecido al de ActionScript 3. Siempre habrá tiempo para ajustar las pequeñas diferencias que aparezcan. Para el código estándar que no fuerce la mezcla de tipos de forma innecesaria, ni se base en efectos laterales, debería bastar. Y de hecho, ya he conseguido ejecutar sin mayor problema pequeños programas ActionScript 3 compuestos por operaciones matemáticas, comparaciones y bucles.

Siguiendo las especificaciones de Adobe, la ejecución de una función en ActionScript 3 requiere que la máquina virtual instancie una estructura de datos locales a dicha ejecución compuesta por una pila de operandos, una pila de ámbitos (scope) y un conjunto de registros.

Para empezar me he centrado en los opcodes que manipulan los registros o la pila de operandos, ya que normalmente son los más fáciles de implementar en cualquier tipo de emulador, y permiten tener en muy poco tiempo un prototipo ejecutando código.

La estructura principal de la máquina vitual es un simple switch que determina el código a ejecutar en función del opcode actual sobre el contador de programa.

Dejo para más adelante las consideraciones acerca del rendimiento, y realizar pruebas para ver es si mejor, o no, tener una función para cada opcode con el objetivo de agilizar la localización e invocación del código asociado a cada opcode. De momento me he centrado en implementar la mayor cantidad de opcodes posibles, unos cincuenta en estos momentos, sobre un total de aproximadamente ciento cincuenta con los que cuenta la especificación.

Una de las cosas “divertidas” de este proyecto es que me permite depurar código ActionScript 3 directamente desde el propio navegador mediante Firebug. Un fichero SWF generado en modo debug incluye opcodes de depuración con nombres de ficheros, números de línea y nombres de variable. Cuando se produce un error, como el intento de ejecución de un opcode no implementado, me basta con poner un punto de parada y ver que línea concreta del código fuente original ha generado el error, e incluso el nombre de las variables que contiene cada registro local en ese momento.

Buscando proyectos similares por Internet me he encontrado con un fork de Gordon por Brian McKelvey. Tiene implementado el parser de ficheros abcFile (que contienen el código ActionScript 3 compilado) aprovechando la clase base de lectura de Gordon, pero aún poca cosa de la máquina virtual en si misma. De hecho, me ha dado la impresión de lo que pretende no es construir una máquina virtual que interprete el código en tiempo de ejecución, sino trasladar los opcodes a código JavaScript directamente en forma de texto para luego evaluar la cadena resultante. Habrá que seguirle la pista.