Wu Pixels

Wu Pixels


Star Fields. Remember the golden olden days of demos? They all had a starfield and some scrolly text. In the traditional resolution of 320x200, these stars could look really terrible. The distant stars, moving very slowly, would wiggle their way from the centre of the screen, hopping discreetly from one pixel to the next. The low resolution of the screen made the slow movement of the pixels quite ugly. What is needed is some way to overcome this finite resolution. The answer is Antialiasing.

Note:In this article I will distinguish between pixels on the screen, and the Wupixels we are trying to render. I shall use the term 'Pixels' to refer to pixels on the screen. 'Particles' will refer to the Wupixels we are trying to render using 'pixels'.


Here is a small program I wrote a long time ago in BASIC to demonstrate the wu pixels. Apologies for the fact that it is quite slow. A new demo, written in C, will be available soon.


On the left we have the particles in the positions we would like to render them. On the right are the antialiased versions.

Up this close, these antialiased particles don't look like anything special. However, when you use them to plot a large number of slowly moving pixels, the effect is really quite pleasing.

Properties
The Wupixels have the following properties:

  • The total brightness of the pixels plotted equals the brightness of the origional particle.
  • The centre of brightness of the Wupixel is located at the non-integer position of the origional particle.

    Method

    There are several ways to plot antialiased particles. You can plot square, unit size particles, which are the easiest. You can plot round unit sized particles which are slightly harder and look almost identical. You can also plot larger particles. In this case round versions look better.

    In any case, the brightness of any pixel plotted will be equal to the area covered by the particle.


    Unit Squares

    These are the easiest to plot. For each pixel covered by the particle, calculate the area covered by the particle. Multiply this by the brightness of the particle, and plot that pixel. A unit square particle can cover a maximum of 4 pixels.

    
    Pseudocode to render a Wupixel at (wx, wy) with brightness wb
    
    Variables:
      INTEGER: x, y                         ' Integer coordinates of Wupixel
      FLOAT:   fx, fy                       ' The fraction part of the coordinates  
      INTEGER: btl, btr, bbl, bbr           ' Brightness of the 4 pixels covered by particle
                                            '   (top left, top right, bottom left, bottom right)
      
    
    x = int(wx)                               ' Calculate the coordinates of the top left pixel
    y = int(wy)                               ' 
    fx = wx - x                                ' Calculate the 
    fy = wy - y                                '
    
    btl = (1-fx) * (1-fy) * wb          ' Calculate the brightness of each of the 4 pixels
    btr =  (fx)  * (1-fy) * wb          ' and multiply bu the brightness
    bbl = (1-fx) *  (fy)  * wb          '
    bbr =  (fx)  *  (fy)  * wb          '
    
    plot pixel with brightness btl at (x,   y)        ' Plot those pixels
    plot pixel with brightness btr at (x+1, y)        '
    plot pixel with brightness bbl at (x,   y+1)      '
    plot pixel with brightness bbr at (x+1, y+1)      '
    

    That gives you the idea behind the method. I shall leave it up to you to optimise it. The best method I have found is simply to create a lookup table containing 256 wupixels. This only takes 1Kb.


    Other Shapes and Sizes

    You needn't limit yourself to unit squares. Almost any size and shape is possible, although the it is only really possible to distinguish different shapes when they are relative large. The best way to create arbitary shapes and sizes is to render them several times larger, then resample them down.

    For example, a three pixel wide, round particle. Render the particle much larger, and resample it down. Do this for several offsets of X and Y between 0 and 1 and store them in a lookup table.