En 2º de carrera acabamos en la misma clase STenyaK, fmonkey y yo. Y claro, nos acabamos juntando para hacer prácticas... y en una (laboratorio de informática?) acabamos haciendo un juego: el Geekfibres (ya, el nombre no tiene sentido, pero es como llamé al repositorio en el svn, y el nombre se quedó).
Bueno, pues aquel proyecto (que por cierto nos dirigió Borja Sotomayor) quedó bastante bien, pero nunca lo había mostrado por el asunto de que los gráficos son todos "robados" del Metal Slug xD Pero bueno, el juego no estaba mal y era divertido, así que me he puesto a rebuscar entre archivos, y he acabado encontrando el código, que todavía compila!.
El desarrollo fue un caos absoluto, sin saber en ningún momento qué clase de juego queríamos hacer y cambiándolo todo cada 3 días, haciendo desarrollo ágil total (sin saber siquiera lo que era eso xD). STenyaK se curró un motor físico con Continuous Collision Detection en 2 o 3 días, yo programé casi todo lo demás y fmonkey básicamente dio apoyo moral xDD
Y nada, aquí os dejo un vídeo de la primera pantalla del jueguecillo este. La verdad es que mola hacer juegos (y jugarlos luego xD)
Ugg, el upload se ha cargado el sonido. Ya subiré otra versión con el sonido bien cuando pueda
Edit: Versión subida con la música puesta :)
Geekfibres from Jon Valdés on Vimeo.
En otra asignatura de la facultad, el profesor nos ha dado la opción de librarnos del examen a cambio de programar un algoritmo gráfico. Y yo me he apuntado a hacer uno de síntesis de texturas, que ya tengo en un estado bastante potable.
Para esto me he basado en este paper de Efros y Leung, que describe un algoritmo bastante sencillo para crear texturas no repetitivas generadas a partir de una más pequeña.
La idea es bastante simple.
Empezamos con una imagen origen cargada de algún sitio, y una imagen destino "vacía".
Ahora "llenamos" unos pocos píxeles de la imagen destino, copiando píxeles desde la imagen original.
A continuación repetimos lo siguiente mientras queden píxeles vacíos en la imagen:
1- Elegimos un píxel vacío adyacente a uno lleno
2- Definimos la vecindad a ese pixel como los píxeles llenos de la imagen que queden dentro de un cuadrado de lado V centrado en el pixel.
3- Comparamos la vecindad de este pixel con las vecindades de todos los píxeles de la imagen original
4- Seleccionamos el píxel de la imagen original con la vecindad más parecida y asignamos ese color al nuevo pixel de la imagen destino.
En resumen, vamos buscando para cada pixel un pixel de la imagen original que tenga vecinos parecidos, y tomamos su color. Esto hace que cuanto más grande sea el cuadrado de vecinos, mayor será el parecido entre la imagen inicial y la final :)
Este algoritmo tan sencillo tiene una parte buena y una mala. La buena es que es capaz de generar imágenes arbitrariamente grandes con una estructura similar a la imagen original, pero sin repetirla. La mala es que es terriblemente lento. La complejidad del algoritmo anda entre cuadrático y cúbico (depende de cómo se mire).
Vídeo al canto para mostrar un poco cómo funciona. Cuando entregue la aplicación en clase pondré por aquí la versión terminada (aunque si tenéis mucho interés, el código está ya en el servidor de Mercurial...)
Texture Synthesis App from Jon Valdés on Vimeo.
Como STenyaK quería saber un poco más del asunto de los filtros de audio, voy a explicar un poco lo que he estado mirando del tema.
Bueno, de primeras, cualquier teleco sabe más que yo sobre estos temas, así que si alguien ve algún fallo garrafal, que me pegue un porrazo en el colodrillo.
Y segundo, me ha quedado una chapa bestial que no interesará en absoluto a los que no quieran hacer nada de filtros de audio. Avisados estáis xD
Bien, el asunto de estos filtros de audio (y de imagen) se hace con lo que se llama una Convolución de la señal. Esto lo que hace es básicamente, para cada elemento de la señal (un pixel, un sample, lo que sea), hace una suma de ese elemento con unos cuantos elementos a la izquierda y a la derecha (para señales 2D habría que añadir también el eje vertical). Y cada elemento de esa suma está multiplicado por un valor que dependerá de la distancia al elemento central. Así que tenemos dos parámetros: la distancia hasta la que se hace la suma, y la función que calcula el factor de cada elemento en función de la distancia.
La distancia de la suma, según la teoría, lo perfecto sería que fuese infinita. Claro que como el 99.999% de las veces no hace falta que lo sea, podemos tirar con una aproximación usando una distancia menor. Por lo general, necesitaremos una distancia suficiente para que el efecto de nuestro filtro esté contenido completamente (o casi) dentro de esa distancia.
Y la función de intensidad de cada elemento es lo que se llama el kernel de la convolución. La forma del kernel provocará diferentes efectos en la señal. La más conocida es usar un kernel con forma de campana de Gauss, que provoca la suma de los elementos cercanos al centro, lo que elimina las frecuencias altas de la señal. En tratamiento de imagen, esto es exactamente un Gaussian Blur. En tratamiento de audio, esto es un filtro paso-bajo :)
Y por el contrario, la forma del kernel que provoca un filtro paso-alto es la que en tratamiento de imagen se usa para detectar bordes. La técnica es exactamente la misma.
Luego ya toqueteando el kernel se pueden sacar más efectos, pero la verdad es que no tengo mucha idea del asunto xD
Bueno, y luego STenyaK también preguntaba a ver qué tal va el asunto este de usar la GPU para tratar estas cosas.
En este tema... el asunto es que la señal de audio y la de imagen se parecen mucho, y en este caso los algoritmos exactamente iguales, con lo que es bastante directo. La limitación más importante es el tamaño de las texturas en el hardware actual, que te obligan a guardar el audio en texturas con lineas de como máximo 8096 elementos. Esto hace que tengas que tener bastante cuidado al hacer la convolución en los elementos cercanos a los bordes de la imagen :-S De todas formas, ahora que van a meter cosas como OpenCL o el Compute Shader de DX, acceder a datos de audio unidimenisonales de tamaño arbitrario va a ser mucho mas fácil, y debería tirar mucho mas rápido también :)
Otro problema importante es que OpenGL no soporta framebuffer objects con un sólo canal. Es decir, a la hora de escribir una imagen calculada en la GPU a una textura, sólo se puede hacer si la textura tiene los 3 componentes RGB. Esto lo que hace es que como para cada pixel sólo generas un valor de audio (la convolución sería jodidísima si no), así que te ves obligado a desperdiciar 2 de los canales de la textura, con lo que gastas 3 veces más memoria de la necesaria. Asunto peliagudo :-S
Aun así, las gráficas son tan potentes que a una canción de 3 minutos son capaces de pasarle el filtro en menos de 5 segundos, contando subir el audio a la gráfica como una textura, generar la textura de salida, extraer la textura final de la GPU, convertirlo a WAV y pasárselo a la tarjeta de audio. Creo que no está mal :)
Dudo que alguien haya llegado a leerse esto entero... pero en fin, así es la vida.
Alguien me ha puesto un comentario en una imagen de hace varios meses de a ver cómo descargar el código para generar imágenes fractales como las que puse por aquí. Y la verdad es que había pensado subir el programa, pero se me pasó. Así que nada, subido está.
Podeis ver la descripción, bajar el código y tal desde aquí. Aviso que el código sólo lo he probado en MacOS, pero debería compilar sin muchos problemas en Linux y Windows. Lo único que necesitareis para hacerlo tirar son las librerías QT4.5.
Y nada, aquí os dejo un vídeo que hice para clase para que os hagais una idea de lo que hace el programa. Al final del video aparece una imagen de las buenas, como las que puse aquí, y se muestra cómo generarlas :)
Attractor Fractals App from Jon Valdés on Vimeo.
Pos nada, que tengo una asignatura que va de procesadores digitales de señal (o procesadores de señal digital, no lo tengo claro), y como práctica teníamos que elegir algo que nosotros quisiéramos hacer relacionado con el tratamiento de señal o imagen.
Y como al profesor no le gustaba demasiado el asunto de tratamiento de imagen, pues he decidido hacer un programa de tratamiento de audio con convoluciones (vease: http://es.wikipedia.org/wiki/Convoluci%C3%B3n ). Filtros de paso alto, paso bajo, etc.
Lo empecé el martes, y ya tengo un prototipo bastante majo. Todavía sólo soporto diferentes tipos de filtros de paso bajo, pero ya lo mejoraré (para los filtros de paso alto hay que jugar con "respuestas impulsionales negativas", y para eso tengo que hacer un par de retoques).
Bien, el asunto de esta práctica es cargar en una textura de OpenGL los datos del audio, cargar en otra textura el kernel de la convolución, y hacer la convolución, que es una operación bastante simple (aunque computacionalmente costosa). Si alguna vez habéis difuminado una imagen con un gaussian blur, el proceso es exactamente el mismo, sólo que en la imagen se hace en las 2 dimensiones, y en el audio sólo en una.
De hecho, un gaussian blur aplicado al audio es exactamente lo que es el filtro de paso bajo. Sólo deja en el audio final los datos con frecuencias menores que una dada, igual que un difuminado elimina de la imagen las frecuencias altas.
Es curioso además poder ver el audio directamente en una textura. Es como ver los surcos de un disco de vinilo, sólo que en imágen :-P Aquí por ejemplo os pongo dos imágenes ampliadas, una que muestra varias lineas del audio original, y otra el mismo audio después de un filtro paso bajo. ¿Veis cómo es exactamente un difuminado? :)
Ya comentaré por aquí un poco más del asunto, de cómo crear el kernel, y de cómo manejarlo todo en la gráfica (que por cierto me las ha liado bastante gordas hasta que me ha dejado usar texturas de 4096x2000 para el audio...). Y bueno, subiré el código por aqui cuando lo termine.