is a ray-tracer written in Haskell. It uses the ICFP 2000 GML scene specification in order to produce images.
The main program reads the input from the standard input and writes the output in the specified PPM files.
There is also a prototype interface written using GTK2Hs
The program was developed using the ICFP 2000 specification which can be found at http://www.cs.cornell.edu/icfp/task.htm
The program is structured in two major components:
- the GML evaluator
- the actual ray-tracer
The role of the GML evaluator is to interpret GML files and produce scene descriptions which are fed into the ray-tracer.
In order to process GML files the interpreter must first parse them.
We opted to implement the parser and lexer using Happy and Alex.
The parser is defined in GML/Parser.y and the lexer in GML/Lexer.x
The parser outputs an abstract syntax of GML which closelly follows the specification.
Definition of the abstract syntax is found in the module AbstractSyntax
The interpreter for GML is an stack machine which processes the abstract syntax in order to output multiple scene descriptions. The implementation
is contained in two modules:
- GML.Core, which contains the main data-types employed by the interpreter
- GML.Evaluate, which contains the main evaluator loop
As described in the specification the interpreter has a state which contains the environment, the value stack, and the code stack. The environment contains the values of all the defined bindings. The value stack represents the current values produced by the running GML program, and the code stack contains the un-evaluated part of the program. In the implementation this is modeled using the State monad. The effect of the render operation (namely the scene descriptions) are stored in the state. Since GML operations can fail, the computations of the interpreter monad are transformed using ErrorT
The main part of the evaluator is implemented in GML.Evaluate. The evaluator function takes a state and performs the reductions on the code stack. The modifications of the operators are performed on the current scene. All the input to trigonometric operations is first converted to radians and the result of such operations is converted back to degrees.
The most intresting aspect is how the surface functions are implemented. The surface function is a closure which is evaluated outside of the interpreter loop, during the ray-tracing stage. Thus the surface function is evaluated into a "mini"-eval loop which produces the texture coordinates.
The ray tracer takes as input a scene description and renders it. The scene description can be found in GML.Data.Scene.
The implementation is split into several modules:
- GML.Render, which contains the top-level tracing functions
- GML.Intersection, which contains the code for intersection testing
- GML.Lighting, which contains the lighting calculations
In order to deal with the geometric operations some helper functions are defined in the GML.Data.Geometry.
Because of constructive solid geometry the intersections are represented as intervals, using the Ranged-Set library.
The source code is available at:
Libraries and Tools
- Cabal for building
- HLint for checking code
- Haddock for documentation
- Alex for generating the lexer
- Happy for generating the parser
* Hay Tracer:
* Dice in GHay-tracer:
* More results can be viewed: at http://sorinara.org/hay/
The team is composed of:
-- Andreas Resios - 23 Feb 2010
- 14 Apr 2010