Los orígenes del Ascii Art, como los de tantas otras disciplinas, son remotos. Pueden rastrearse hasta fines del Siglo XIX, cuando aparecen las primeras máquinas de escribir y, con ellas, la idea de que se podían realizar diseños gráficos a partir de la tipografía.
Lewis Carrol, En 1898 dibujó con su máquina de escribir esta mariposa utilizando sólo corchetes, puntos, paréntesis, barras de dividir, asteriscos y letras o.
La técnica de arte Ascii Art es ampliamente utilizada por artistas, aficionados, hackers. Un ejemplo especialmente interesante de uso y desarrollo creativo del arte ASCII son las obras creadas por el grupo "ASCII Art Ensemble". El grupo, formado por Walter van der Cruijsen, Luka Frelih, Vuk Cosic, fue fundado en 1998. Los miembros del "ASCII Art Ensemble" crearon un software para "codificar" imágenes en movimiento en piezas de arte ASCII animadas (secuenciales).
Desde el punto de vista de evolución de la gráfica computarizada, el Arte ASCII replantea la observación tradicional de una imagen en base al conjunto de elementos pictóricos que la conforman, un efecto óptico similar al del puntillismo. Así pues, a una mayor distancia del observador, la imagen hecha en Arte ASCII adquiere mayor definición; exactamente lo opuesto a lo que sucede cuando, al observar con lupa una imagen impresa en un diario, la distancia entre los píxeles que la conforman se hace evidente y la imagen se desvirtúa.
No. | Descripción |
---|---|
1 | Precargar Shader para imagen con el vertex y fragment shader. |
2 | Crear canvas de WEBGL. |
3 | Crear el shader a partir del precargado. |
4 | Pasar datos de imagen base o cámara, y activación del Fragment Shader. |
5 | El fragment shader carga la textura |
6 | Calculo del LUMA en cada bloque de pixeles |
7 | Según el valor LUMA calculado se escoge el caracter a renderizar (dentro del conjunto previamente dado) |
8 | Renderizar el caracter correspondiente al valor de luminosidad calculado para cada bloque de pixeles. |
1linklet theShader;
2link// this variable will hold our webcam video
3linklet cam;
4linkfunction preload() {
5link // Precargar el shader
6link theShader = loadShader('/vc/docs/sketches/workshop2/texturaAscii.vert', '/vc/docs/sketches/workshop2/> > texturaAscii.frag');
7link}
8link
9linkfunction setup() {
10link // shaders require WEBGL mode to work
11link createCanvas(710, 400, WEBGL);
12link noStroke();
13link //Crea una aptura de video instantanea
14link cam = createCapture(VIDEO);
15link cam.size(710, 400);
16link //Esconde la captura para solo mostrar el renderizado final
17link cam.hide();
18link}
19link
20linkfunction draw() {
21link // shader() Activación del Shader con nuestro Shader
22link shader(theShader);
23link
24link // Se pasa la Cámara (cam) como textura
25link theShader.setUniform('tex', cam);
26link
27link // rect gives us some geometry on the screen
28link rect(0, 0, width, height);
29link}
30link
1link// Las modificaciones y ajustes fueron compartidos en clase por el compañero Camilo Gómez
2link// del código original: https://www.shadertoy.com/view/lssGDj
3link// código del compañero: https://drive.google.com/file/d/1Fg_p77X0wvyK4cY4txpmdsc743M2FCIz/view
4link
5link#ifdef GL_ES
6linkprecision mediump float;
7link#endif
8link
9linkuniform sampler2D tex;
10link// Implementación Operador a nivel de bits
11linkint getBit(int n, int a) {
12link float value = float(n);
13link for(float i = 27.0; i >= 0.0; i -= 1.0) {
14link float val = pow(2.0,i*1.0);
15link
16link if (val <= value) {
17link value -= val;
18link if(i == float(a)) return 1;
19link }
20link }
21link return 0;
22link}
23link// Reducción tamaño de 8x8 a 5x5 y activación brillo
24linkfloat character(int n, vec2 p)
25link{
26link p = floor(p*vec2(4.0, -4.0) + 2.5);
27link if (clamp(p.x, 0.0, 4.0) == p.x)
28link {
29link if (clamp(p.y, 0.0, 4.0) == p.y)
30link {
31link int a = int(floor(p.x+0.5) + 5.0 * floor(p.y+0.5));
32link if (getBit(n,a) == 1) return 1.0;
33link }
34link }
35link return 0.0;
36link}
37link
38linkvoid main() {
39link vec2 pix = gl_FragCoord.xy;
40link pix.y = 393.0*2.0 - pix.y;
41link vec2 resol = vec2(393.0*2.0, 393.0*2.0);
42link // Partición de la imagen en 8x8 pixeles
43link vec3 col = texture2D(tex, floor(pix/8.0)*8.0/resol).rgb;
44link // Calculo LUMA
45link float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;
46link // Máscaras a aplicar dependiendo del LUMA
47link // n = codificación del caracter en entero
48link // página para codificación de caracteres: http://thrill-project.com/archiv/coding/bitmap/
49link int n = 4096; // .
50link if (gray > 0.2) n = 65600; // :
51link if (gray > 0.3) n = 332772; // *
52link if (gray > 0.4) n = 15255086; // o
53link if (gray > 0.5) n = 23385164; // &
54link if (gray > 0.6) n = 15252014; // 8
55link if (gray > 0.7) n = 13199452; // @
56link if (gray > 0.8) n = 11512810; // #
57link
58link //Cálculo de separación entre caracteres
59link vec2 p = mod(pix/4.0, 2.0) - vec2(1.0);
60link
61link col = vec3(character(n, p));
62link
63link gl_FragColor = vec4(col, 1.0);
64link}
1link// vert file and comments from adam ferriss
2link// https://github.com/aferriss/p5jsShaderExamples
3link
4link#ifdef GL_ES
5linkprecision mediump float;
6link#endif
7link
8linkattribute vec3 aPosition;
9linkattribute vec2 aTexCoord;
10link
11link// lets get texcoords just for fun!
12linkvarying vec2 vTexCoord;
13link
14linkvoid main() {
15link // copy the texcoords
16link vTexCoord = aTexCoord;
17link // copy the position data into a vec4, using 1.0 as the w component
18link vec4 positionVec4 = vec4(aPosition, 1.0);
19link // scale the rect by two, and move it to the center of the screen
20link // if we don't do this, it will appear with its bottom left corner in the center of the sketch
21link // try commenting this line out to see what happens
22link positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
23link // send the vertex information on to the fragment shader
24link gl_Position = positionVec4;
25link}
En la implementación realizada del shader se particiona la imagen en bloques de 8x8 pixeles y se procede a hacer el cálculo del LUMA para cada uno de ellos. Posteriormente, teniendo el cuenta el cálculo del LUMA obtenido en cada bloque se determina que caracter ASCII se debe usar de acuerdo a la codificación realizada previamente de algunos caracteres ASCII. Posteriormente, el shader hace un barrido bloque a bloque y de acuerdo si es un bloque con brillo 1 es reemplazado por el caracter asignado, si el brillo de este bloque es 0, se deja el espacio.
Si bien, esta herramienta de mapeo de los caracteres facilita el proceso de la implementación del Ascii Art, limita el uso de caracteres a los que sean representables en la matriz de 5 x 5, es decir que caracteres de otros lenguajes que utilicen caracteres curvos o figuras abstractas no podrían ser utilizados en esta implementación.
El Ascii Art es utilizado cuando no es posible la transmisión o la impresión de imágenes en las configuraciones de equipos computarizados, tales como maquinillas, teletipos y equipos de visualización (consolas y terminales) que no cuentan con tarjetas de proceso gráfico. Además, el Ascii Art ha servido como lenguaje fuente para representar logos de compañías y productos, para crear diagramas procedimentales de flujo de operaciones y también en el diseño de los primeros videojuegos. Programas editores de texto especializados tal como IMG2TXT o JPG2TXT, están diseñados para dibujar figuras geométricas y rellenar áreas de luz y sombra con una combinación de caracteres basándose en algoritmos matemáticos.