THIRD

by Sandro Maffiodo

smaffer@gmail.com

www.assezeta.com/sandromaffiodo

OVERVIEW

This is not another Ray Tracer.

This is a classical 3D Software Rasterizer that supports:

The program reads an infinite list of frame descriptors from stdin and generate an infinite sequence of rendered frames to stdout.

BUILD

$(CC) prog.c -D_= -lm -o prog

The _ symbol is usefull if you want to build the program on Windows. MS Windows need this code to modifiy the open mode of stdout from text to binary:

setmode(fileno(stdout),O_BINARY);

Additional tools

If you want to view the rendering output you can pipe the output to any program that can understand BGRA raw images (like ffmpeg or imagemagick convert), otherwise you can use my simple SDL viewer (oview.c):

$(CC) oview.c -lSDL -o oview

The program require three parameters: WIDTH, HEIGHT and DELAY. The program reads frames from stdin and shows them to a window with DELAY milliseconds between one frame and the next. This tool require libSDL1.X.

If you like to experiment with the program, you can convert your Wavefront OBJ files to a frame descriptor, using my simple converter (oconvert.c):

$(CC) oconvert.c -o oconvert

The program require two parameters: INPUT and OUTPUT. INPUT is the OBJ file and OUTPUT will be a partial frame descriptor with the converted geometry of the input model (without textures). The OBJ file must use triangles (not quads) and must include vertex normals and textures coordinates.

RUN

When the program starts you can manually type inputs to the program, but this can take a lot of time. So i've writen some shell scripts that generate some examples, usefull to test the program and see what it does. To use those scripts you must make them executables:

$ chmod +x *.sh

Each script generate an infinite list of:

To view what one of these scripts does alone, you can type

$ ./cube.sh 320 200

By running cube.sh in pipe with the program you will get an infinite list of BGRA frames:

$ ./cube.sh 320 200 | ./prog 320 200

By running the same command in pipe with ffmpeg you will get a movie:

./cube.sh 320 200 | ./prog 320 200 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 320x200 -i - -y -t 5 -b 2M test.mpeg

Otherwise you can pipe the program output to my simple SDL viewer (oview):

./cube.sh 320 200 | ./prog 320 200 | ./oview 320 200 0

More examples:

using ffmpeg:

$ ./computer.sh 640 480 | ./prog 640 480 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 640x480 -i - -y -t 5 -b 2M computer.mpeg

$ ./cube.sh 320 200 | ./prog 320 200 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 320x200 -i - -y -t 5 -b 2M cube.mpeg

$ ./randomsphere.sh 320 240 | ./prog 320 240 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 320x240 -i - -y -t 5 -b 2M randomsphere.sh

$ ./smaffer.sh 800 600 | ./prog 800 600 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 800x600 -i - -y -t 5 -b 2M smaffer.mpeg

$ ./tribytri.sh 800 600 | ./prog 800 600 | ffmpeg -r 25 -f rawvideo -pix_fmt bgra -s 800x600 -i - -y -t 5 -b 2M tribytri.mpeg

using my SDL viewer:

$ ./computer.sh 640 480 | ./prog 640 480 | ./oview 640 480 0

$ ./cube.sh 320 200 | ./prog 320 200 | ./oview 320 200 0

$ ./randomsphere.sh 320 240 | ./prog 320 240 | ./oview 320 240 0

$ ./smaffer.sh 800 600 | ./prog 800 600 | ./oview 800 600 0

$ ./tribytri.sh 800 600 | ./prog 800 600 | ./oview 800 600 0

HOW IT WORK

The program starts reading the output resolution from the command line arguments; then reads a raw BGRA texture image from stdin.

Texture format

The texture format is very simple:

Frame Descriptor

After that, the program continue to reading an infinite list of frame descriptor from stdin. Each frame descriptor is encoded in ASCII and contain a list of float values, comma separated:

The list of float values must terminate with the "E" character. For each 3 vertices the renderer will generate a single triangle.

Example

This is an example of a descriptor for one coloured triangle:

-1.81066, 0, 0, 0,
0, -2.414213, 0, 0,
0, 0, -1.083333, -1,
0, 0, -8.333333, 0,

1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, -10, 1,

10, 10, 1, 1, 

0, 0, 1, 1,     1, 0, 0,    0, 0,   -1, -1, 1, 1,
0, 0, 1, 1,     1, 0, 1,    1, 0,   1, -1,  1, 1,
0, 0, 1, 1,     1, 1, 1,    1, 1,   1,  1,  1, 1,

E

This command will generate the same triangle in the file frame.bgra, using a white 2x2 texture:

$ printf "\001\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077 -1.81066, 0, 0, 0, 0, -2.414213, 0, 0, 0, 0, -1.083333, -1,0, 0, -8.333333, 0,1, 0, 0, 0,0, 1, 0, 0,0, 0, 1, 0,0, 0, -10, 1, 10, 10, 1, 1, 0, 0, 1, 1,1, 0, 0, 0, 0, -1, -1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, -1,  1, 1, 0, 0, 1, 1, 1, 1, 1,1, 1, 1,  1,  1, 1, E" | ./prog 320 200 > frame.bgra

To convert frame.bgra to JPG you can use this:

convert -size 320x200 -depth 8 frame.bgra frame.jpg

LIMITATION

The program does not set any limitations on the rendering output resolution. The maximum output resolution can be

width = INT_MAX 
height = INT_MAX 

On a 32bit machine this mean (2147483647 x 2147483647) pixels

The maximum texture resolution is limited to

width = 1<<SCHAR_MAX
height = 1<<SCHAR_MAX

This mean that the biggest loadable texture resolution is 9223372036854775807 x 9223372036854775807 pixels. Obviously this resolution can be reached only if you build and run the program on a system that have more than 64bits.

The texture resolution must be square: width and height must be equals.

The 3d scene can totally change in each frame but the texture data remains the same. For example you can pipe a frame descriptor with a spinning cube for 100 frames and then change the frame descriptor in a bouncing ball for the next 100 frames, but the texture used from the two descriptors cannot change. You must use one big texture to all your needs.

You can only change one MODELVIEW matrix for frame. This mean that you can only tranform all triangles of the scene with the given matrix. For example you can rotate and scale the scene (simulating a camera movement) but you cannot rotate a single object of the scene keeping all the others fixed.

REMARK

The example scripts require bc and the existence of the file /dev/urandom.

The additional tool oview.c requires libSDL1.X.

The build process will generate some warnings (40~ on clang) about: