# ASCII Art in Pixel Shader
Today I'm going to show completely ugly and useless effect :) I have always been fascinated with ASCII art, so I'm glad I am now able to visualize it on GPU. Here is the final effect:
And here is how I've made it. First, I took a 3D scene with some untextured boxes.
Now I do pixelate effect to have my image looking like each 8 x 8 pixel group have same color. Optimally I should render whole scene into 8 x 8 times smaller render target and rewrite it with POINT filtering, but currently I'm just doing some processing during rewriting this image from render target texture to the back buffer. That processing is simply rounding texture coordinate down to a multiply of 8 texels:
// in float2 TexCoord : TEXCOORD0 // float2 g_PixelateParam = float2(BackBufSizeX / 8, BackBufSizeY / 8) TexCoord = floor(TexCoord * g_PixelateParam) / g_PixelateParam; float4 Color = tex2D(RenderTargetSampler, TexCoord);
Then for each pixel I calculate its luminance using weighted average of RGB values:
float Grayscale = dot(Color.rgb, float3(0.299, 0.587, 0.114));
And finally I'm doing a lookup into specially prepared volume texture. XY coordinates are taken from texel position in screen space, while Z (depth) coordinate is just the pixel luminance.
float2 TexXY = (Pos-float2(0.5,0.5))/g_VolumeLookupTextureSize.xy; float TexZ = Grayscale; float4 VolSample = tex3D(VolumeLookupSampler, float3(TexXY.x, TexXY.y, TexZ)); Color.rgb = VolSample.rgb;
The texture is prepared so that its subsequent slices contain ASCII characters: from empty black image, through dark gray dot on black background, dark gray comma, colon, until white hash on light gray background and finally blank white image. Here you can download this texture (I've made it using GIMP and DirectX Texture Tool): Atari Font.dds.
To make it pixel-perfect, I had to bias XY texture coordinate by (-0.5, -0.5) texels, as well as turn off texture filtering:
Dev->SetSamplerState(3, D3DSAMP_MINFILTER, D3DTEXF_POINT); Dev->SetSamplerState(3, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
It also turned off smooth transitioning between slices in volume texture (it means ASCII characters are not blended together), It's what I actually wanted to do, but by the way I realized that we cannot switch filtering for separate texture coordinate axes (e.g. only UV or only W), just like we do with addressing modes (D3DSAMP_ADDRESSU and so on). It could be useful sometimes... Anyway, we can achieve that with pixel shader.