March 8th, 2008

Tunnel effect

The Tunnel effect is probably the oldest effect ever. I think even Wozniak hacked one on Apple II. Nowaday, it's pretty easy to program, our machines have so much speed that you can brutecalcule everything on the fly. But how did they reach 30 frames per secondes on boxes as powerfull as a microwave?
The non technical answer is:

It's a trick ! Computer graphic is machiavelli's world: It doesn't matter how you do it as long as it looks Ok.

Perception IS reality...

Try it and source code


I discover demomaker's universe with a software considered one of the best in all time: Second Reality by Future Crew. It was running on a 486 DX2 and it was breathtaking. Released in 1994, more than 10 years later it still looks damn good and you can check it out on YouTube.

Since then I've always followed the scene, not programming myself but being an enthousiast.

How they did it.

Key world is: Precalculation.

There was no GPU or graphic card whatsoever at this time, everything was done with the CPU. This is called software rendition and it means you have to do EVERYTHING ! Namely it means that you start your loop wih an empty array, decide the color of every single pixels and then send the entiere thing to the screen.

It's the only "hard" part to get: the program precalculates the texture's coordinates only once and so for the entiere screen. With a screen resolution of 256*256, it's 65536 array raster (the pixels).

    // Pregenerating the mapping pixel/coordinate.
    for(int x = 0; x < scrWidth; x++)
        for(int y = 0; y < scrHeight; y++)
            distances[x][y] = (int)

            (	(30.0 * TEXTUREHEIGHT / 
                 Math.sqrt(x - scrWidth /2.0) * (x - scrWidth /2.0) + (y - scrHeight /2.0) * (y - scrHeight /2.0))
            ) % TEXTUREHEIGHT);
            angles[x][y] = (int)(0.5* TEXTUREWIDTH * Math.atan2(y - scrHeight /2.0, x - scrWidth /2.0) / Math.PI);

How do we get this perception of movement if nothing move then ? Well, you don't move, the tunnel is not moving either, but the texture is "slidding" on the Tunnel.
So the main program loop is very small because there we are only shifting the texture on the right and to the up:

    //calculate the shift values out of the animation value
    shiftX =  (int)(TEXTUREWIDTH  + animation);
    shiftY =  (int)(TEXTUREHEIGHT +movement);// / rotation);

    for(int y = 0,cursor=0; y < scrHeight; y++)
        for(int x = 0; x < scrWidth; x++,cursor++)
            static int c_x = (distances[x][y] + shiftX) % TEXTUREWIDTH;
            static int c_y = (angles[x][y] + shiftY) % TEXTUREHEIGHT;

            renderer.offScreenRaster[cursor] = texture[c_x + c_y * TEXTUREWIDTH] ;



Two excellent articles by Lode: The Tunnel effect. And the XOR Texture



Fabien Sanglard @2008