**since this screenshot is displayed in ascii format**
*++==---::::::. %**+++====--.. @%**++++-----..... @@###++++------..... @@%###+++++-----:..... @@@####+++++-=====...... . @@%%%%%*****=======...... ... @@@%%%%******======-....::.... @@@%%%%******======+::::::.... @@@%%%%***###*++++++=:::::..-- @@@@@@@######+++++++::::=--- @@@@@@#######++++++=====-- %%@@@@###%%@******+====* %@@@@@@@@@@******### %%%@@@@@%%%%%# .................. .................... ........................ .......................... ............................ .............................. ................................ .................................. 58 FPS (58-58)
Moving to some implementation details:
1. JS Ascii Libraries
Originally I ambitiously wanted to complete the proof of concept in 15 minutes, so the first thing was to look existing ascii libraries in JS out there. Turns out there were a few libraries out there such as this and this, but I decided on nihilogic’s jsascii library which seems to provide a little more options despite being written a longer time before.
2. Extracting Image Data
Since jsascii and the similar libraries uses images as an input, the first integration approach extract the base64 encoded image data via the Canvas’s toDataURL() from CanvasRenderer, and import the image to the library and pull the Ascii output. Doesn’t take too long to realize its pretty silly wasting cycles when we could process the image data directly without encoding and decoding the image data by using canvas.getImageData().
So I started modifying jascii library to tap straight into the domElement of CanvasRenderer. I worked but performance was still horrible, so I being more tweakings, particularly the text resolution. By having a lower resolution, a larger font size would be use, resulting greater performance but less clarity. After making these adjustments, I found there certain ratios where there was good performance with reasonable clarity. In fact, the framerates were also on par or sometimes faster than rendering the canvas to screen. It ran well on Chrome, and ran even faster in Firefox.
3. Swapping WebGLRender with CanvasRenderer
The next little experiment was to use WebGLRenderer instead of CanvasRender for rasterizing the scene. Turns out that rendering ASCII with WebGLRenderer was slower than the CanvasRenderer. Alteredq suggest that it was probably more expensive to pull data out of the webgl context. Perhaps gl.readPixels might be a more efficient way of extracting data, but I haven’t tried that yet.
4. More Settings
Here’s another area to explore for the adventurous. JSAscii supports various options like enabling colors, inverting them, using blocks, and its pretty interesting to see some of these effects although some of these options have a big penalty on performance.
At the least, the reader might want to have some fun and try custom character sets. The ASCII library works by converting a pixel block into text by measuring its brightness and using an ascii character which represents that brightness. One could also try looking up and utilize unicode characters. In my experiments, I realized the use of even really simple pallets, for example one made of different sizes of dots, are interesting and effective too. (for example: start with something simple like ” .*%”)
5. Ascii Renderer -> Effects
In r49, the previously Anaglyph, Crosseyed, ParallaxBarrier Renderers were refactored to Effects, and are located in /examples/js/effects. AsciiRenderer follows the style and gets refactored to AsciiEffect. In r50dev, mrdoob works on several new software renderers, I did a couple of tests of the AsciiEffect with the new rasterizers, and they work too. Now in theory, with some modifications to the software renderer and ascii effect, one can effectively render a three.js scene in old non-canvas supported browsers, such as IE6, using ASCII output.
Finally, to throw out more ideas, one could create ASCII stereogram, combining the styles of Crosseyed and Ascii effect. ASCII stereograms may look like they would give a big headache, but they’re pretty cool!
Summing up, I hope the additional of the Ascii Effect provides a really simple way to do interesting 3d scenes and animation in Ascii, and probably a good way to relax when you get tired of writing glsl shaders.
Who knows if I’ll be writing up more text experiments again, but till then, it’d be interesting what else you may come up with!