Ascii Art Shader

Very simple shader utilising the same method that I used in the Lemminvade and Flappy Bird shader to draw the pixel images (WebGL, pure fragment shader, sourcecode on Shadertoy).

If you want to use other characters, here's a little tool: thrill-project.com/archiv/coding/bitmap/

This shader is now part of pixi.js, a  2D webGL framework for JavaScript.

Shadertoy (annoying sound!)

I've asked ChatGPT to explain the character function of the shader and it did a really good job:

Related Topics:

Shadertoy

10 thoughts on “Ascii Art Shader

  1. Kashif

    Great Work. Excellent...! I love your script i use one from github in javscript but it was in greyscale your one is color but i am new to shadertoy or webgl, will you please tell me how i can use this code in html, i try to read this page (https://morioh.com/p/5199bcb845af) but i can't get success.
    i mean how i can add a mp4 file to this code and use it in html. your help will be appreaciated. will you make a html page with your shadertoy code embed mp4 video file. email me in comment profile.

    Reply
    1. movAX13h

      Post author

      Thank you!
      Unfortunately I don't have time to make a complete example with video for you.
      The shaders of shadertoy are used to color a polygon, a rectangle (made of 2 triangles). You have to set up quite a lot to get it working and adding a video is also not that trivial.

      I suggest:
      1. learn how to make a rectangle (or triangle) in WebGL
      2. learn about UV coordinates and show a texture (image) on the rectangle
      3. learn how to use a video instead of a texture

      Let me know how it goes.

      Reply
  2. asciiRenderQ&A

    Hi, I'm a student from south korea. I was searching for ascii rendering and I found your work. It is pretty awsome so I tried it out for myself. However, I'm kind of having some trouble of understanding your source code. I can understand the bitmap value from the previous comments, but the rest of the code is hard to understand. For example, I don't get of the equation of this:
    vec2 p = mod(uv/4.0, 2.0) - vec2(1.0);
    if (iMouse.z > 0.5) col = gray*vec3(character(n, p));
    else col = col*character(n, p);

    or this:
    p = floor(p*vec2(4.0, -4.0) + 2.5);
    if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
    {
    if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;
    }

    Can you explain me what are these codes used for??
    Thanks.

    Reply
    1. movAX13h

      Post author

      Hi!
      I'm glad if I can help!

      line 32:
      vec2 p = mod(uv/4.0, 2.0) - vec2(1.0);
      This splits the area into pieces of 8x8px and normalizes to values from -1 to +1.
      If you change the second value of the mod call (from 2.0 to 4.0 for example), you will see what it does.

      lines 8-12:
      p = floor(p*vec2(4.0, -4.0) + 2.5);
      if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
      {
      if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;
      }

      First p gets scaled to match our character width and height and shifted to a positive region. p.y is inverted (-4.0) because the characters are encoded in this order.
      The if-clamp-line (9) is just a simple way of checking if p.x and p.y are in the range of 0.0 to 4.0.
      The most complicated line 11 is calculating the binary AND this way because GLSL ES did not support the AND bit operation back then so I am using: (n/2^k)%2, assuming n and k integer which in GLSL is: mod(n/(pow(2.0,k)),2.0)

      This could be simplified because the &-operator is supported now.

      I hope that helped to understand the code. Feel free to ask if you have more questions.

      Reply
      1. Ayush

        can you explain what the character function does? I really don't understand how you are rendering characters without a texture or font atlas.

        Reply
        1. movAX13h

          Post author

          Sure. The character function takes every bit of the number passed in as 'n', interprets the stream of bits as a 5x5 grid and returns 0 or 1 depending on the bit at the location of the currently rendered point 'p'.
          It does the reverse of this little tool with which you can make new characters: https://thrill-project.com/archiv/coding/bitmap/

          Reply
  3. itstilldoesntmatter

    Hey, massive THANK YOU! For the code and for the really quick answer on Shadertoy. Still I couldn't find your e-mail, so I'm writing here hehe. To be honest, I'm a multimedia artist but I started to learn using software not so long ago, so I'm not sure if I will reach the point when I will be able to write a complete shader. Anyway, for now I hope you wont mind if I'll use your code as a part of the visualisation of my digital performance:)) And also I really liked that you gave me just a hint so I had to get to know this bitmap process a little closer.

    Reply
    1. movAX13h

      Post author

      Hi, you're welcome. I hope you have seen the link to the little tool that does the bitmapping for you. Just in case, here's the link again: http://www.thrill-project.com/archiv/coding/bitmap/

      "Bitmap" is exactly what it is. Since the characters are monochrome, 1 bit is enough to describe 1 pixel. A number in a shader consists of 32bits but only about 25 can be safely used for the mapping process because of precision issues. This means that we can encode 5x5 pixels in these 25 bits (1 number). And this is what the shader does.

      Reply
      1. itstilldoesntmatter

        Thank you for the explanation and the tool. I got to the answer pretty intuitively when I opened your bitmapping link, well maybe also after reading a little:)

        Reply

Leave a Reply to movAX13h Cancel reply

Your email address will not be published. Required fields are marked *