The Finitron Ray Tracer: Finray


This project was started based on 'C' code found in the book:

Practical RAY TRACING in C by Craig A. Lindley

Program source code and script samples are available on GitHub. Here


I've been looking at code and mathematics for ray-tracing from a number of sources.

Some of the back-end code from POV-ray has been ported over with significant modifications. The mathematics is common for all ray-tracers so the code should look roughly the same.

Finray scripts are similar to the most primitive forms of POV scene description files. The thought had crossed my mind to just re-use the POV-Ray language grammar which is very good. I wanted to understand things at a basic level by developing a grammar. I'm still debating with myself whether or not to incorporate POV ray compatibility, but at this point it isn't a goal.

Keywords are case-sensitive and must be lower case.

Three dimensional vectors are used in scripts and are denoted with angle brackets. So the point at X=10, Y=12 and Z=50 is represented as "<10,12,50>" in the scripts. Components of the vector must be separated by commas. Elements of a list of vectors and numbers are separated by commas.

Finray supports the following basic shapes:

Boxes and Cubes Boxes and cubes are currently implemented as an aggregated array of 12 triangles
Cones and Cylinders  
Object Aggregated object - composed of any number of objects

Objects may also be anti-objects (also called hollow objects). The presence of anti-objects causes ray-object intersection tests to fail which makes that part of a scene transparent. Anti-objects are specified using the keyword 'anti' before the object.


The following transforms are at least partially supported (I haven' tested everything for every object). The same transform will be applied to all objects contained in an aggregated object.

Rotation angles are specified in degrees

Parameters for the objects location and size may usually be specified as part of the object declaration. Parameters must be surrounded by round brackets. Other properties of the object are set in a language block which is identified with curly brackets.

The following declares a sphere of radius 7 at point x=10, y = 12, and z = 50 :

sphere (<10,12,50>, 7) { }

Note this is slightly different from POV-Ray.

The box object is specified as a point and a vector length. To create a box of width =8, height = 10 and depth = 15 at x = -10, y = 20, and z = -1 the following would do so:

box (<-10,20,-1>, <8,10,15>) {}

<8,10,15> is the distance from the point specified as the first parameter.



The ray tracer uses a slightly modified version of a 'C' pre-processor ( the pre-processor looks in the 'FINRAY' environment variable in order to locate script files rather than the 'INCLUDE' environment variable in order to keep the graphics separate from other code).  Otherwise it's a fairly standard 'C' pre-processor supporting #include's #define's #if / #else. The pre-processor is a bit dated, having been originally developed about 25 years ago.


Language Elements

Comments may be either to the end of the line with '//' or block comments denoted with /* and */ as in C.

Variables may be used to represent objects and properties of objects. The variables do not have to be #declared. For example the following creates a variable to hold texture elements:


texture {

    ambient 0.3

    diffuse 0.7

    brilliance 100.0

    specular 0.9

    roughness 100.0

    reflection 1.0



The variable may then be substituted as part of the texture element.


sphere (<x*3+1,1,1>, 1) {

    texture SURFACE

    color Green



A common use of this is to set colour definitions. The color property accepts a color vector for specification. This property may be supplied from a variable.





The ray tracer uses float singles (32 bits) for each color component. The goal here was better performance in color calculations. Whether it's better or not than using float doubles I don't know yet. The eye and most displays are limited to under 24 bits for color. About eight bits per component are usually sufficient. The extra 15 or 16 bits available in a float single can help provide insurance against rounding errors. When I first started the ray-tracer I was going to use 32 bit scaled integer arithmetic for colors as color varies only from 0 to 1. The exponent part of the float number is more or less wasted for colours.


For other calculations the ray-tracer uses double precision arithmetic.




It's slow :) Compared to POV-ray. It's fast to enough to render simple scenes. Performance is likely to improve in the future. Getting it to work at all is the first goal. The tracer doesn't support bounding objects yet.



Likely to change:


Likely to change is the generation of random numbers and vectors. Currently only a single channel is supported, and all numbers generated are based on using the time as a seed. This makes scenes with random elements in them non-repeatable.



Missing Elements:


As of now there is no support for pigments or image mapping. I'm currently researching these things.