Specification

Renderer

to come later

Model Parser Proposal

Motivation

To motivate the need for a model parser, even a simple one as outlined below; advantages of a parser over a hard coded scene are given:
  1. A parser provides a clean separation of the radiosity solver and the actual data. By starting off with a simple parser we are leading the way for more complex parsing of DXF and 3DS files.
  2. Minor changes to hard coded scenes require recompiling of the project and wastes time.
  3. Hard coding data structures especially in C++ can be difficult which may give way to an easier data structure for hard coded scene but may not be well suited for parser driven model generation.
  4. Major enhancements can be made to the parser to preprocess and augment the input as to make the input file easier to generate and still provide more complex models.
  5. Hard coded scenes limit the amount of testing to that one scene. By allowing quick modification to an input file a wide variety of testing can be done.

Description

The parser takes as input the name of the file to be parsed and then builds an appropriate model from the input. The input file is assumed to be in the form of the grammar given below, and any errors found in the input are reported and the parse fails. As well as parsing the file syntactically the parser can also check other information to determine the validity of the input file. Such checks could include:
  1. Determining if the given normal for a patch is in the same direction as the normal calculated using the patch vertices.
  2. Checking to make sure that all the normals of an object point in the same direction.
  3. Determining whether an object is convex, concave or other properties that maybe yield inappropriate results from the radiosity solver.
  4. The vertex list given corresponds to valid vertices in the vertex list.
The grammar is designed so that first the set of points available to the model is given first. This allows common vertices to be shared and reduces the amount or data replication. The points are given as a 3-tuple where the three numbers represent the x, z and y coordinates in R3. Once all the points are listed then the objects within the scene are listed. An object is merely a group of patches tied together with a name. A patch is determined by a set of 4 vertices and some extra information to fully specify a patch. The 4 vertices are integer numbers that index into the point list given at the top of the file. The extra information given with a patch is as follows:
  1. subdiv – The amount the patch should be subdivided by when parsing. This allows for very easy subdivision of patches before the radiosity solver begins. This is an integer value
  2. reflectivity – The fraction of radiosity that this patch absorbs from other patches. Used in the radiosity calculations. This is a 3-tuple of floats where each value is between 0 and 1.
  3. emission – The initial emission values for this patch. These value will be zero except for the light source. This is a 3-tuple of float values.
  4. normal – This is the normal vector to the patch. This is an optional value since the normal can be determined from the vertices given. But since the direction of the normal is extremely important explicitly specifying it is sometimes easier. The value does not need to be a unit vector that will be done by the parser.
The render section of the grammar allows for a list of the object that's are to be rendered. This allows for specification of many objects but with the ability to render only a specified subset. By doing this it is very simple to remove and add objects from the scene with out large modifications.

An implementation of this spec can be done relatively easily using flex and bison. Flex being a lexical analyzer and bison being a parser generator. Unfortunately the interface to these tools is somewhat clumsy and strictly C orientated. Given below is a possible C++ interface that can wrap the C interface.

Parser Improvements

The parser input file as it stands is very simple and can only generate rectangle type of model without major effort on the part of the

  1. Addition of more complex object types. By specifying a center and radius a sphere could be generated use a variety of mesh generation techniques. An example may be:

    object "globe" { sphere { center (1, 1, 1) radius 5 } }

    This could be done for a variety of non-rectangular shapes (i.e. cone, torus, cylinder, etc.)

  2. Keeping the same interface we could write parsers for other predetermined format and use the correct parser by looking at file extensions (i.e. DXF files and 3DS files).
  3. Large number of improvements could be made to the pre and post processing of input files.

C++ Interface

class parser_t
   {
   public:
      parser_t(void);
      model_t* parse(char* filename);
   };

Grammar

model ->
   MODEL {
      POINTS { <point> {, <point> } }
      { <object> }
      RENDER { <string> {, <string> }
   }

object ->
   OBJECT <string> {
      <patch> { <patch> }
   }

patch ->
   PATCH {
      SUBDIV <integer>
      REFLECTIVITY <point>
      EMISSION  <point>
      VERTICES { <integer>, <integer>, <integer>, <integer> }
      [ NORMAL <point> ]
   }

point ->
      ( <float>, <float>, <float> )

integer ->
   INT

float ->
   INT | FLOAT

string ->
   STRING
Note: the bold and italicized {} and [] denote repetition and optional parts (i.e. BNF grammar)

Radiosity Solver & Geometry Library

Winged Edge Data Structure

A polygonal mesh data structure is necessary to represent connected polygons.

The winged edge data structure allows easy iteration over faces, edges, and vertices. In practice, half-edge is usually used because of its simpler implementation.

Note: Vertex and edge ordering is always counter-clockwise.

Mesh

Face

Edge

Vertex


Renderer

The renderer is responsible for actually displaying the radiosity solution and is based on OpenGL using the Mesa library.

The renderer can operate in two modes: flat shaded mode or Gouraud shaded mode. Gouraud shading interpolates vertex colours, and thus requires these colours to be pre-calculated.

The scene is manouvered through via a camera object. The camera is manipulated through its own interface.

Renderer


Geometry Library

The geometry library contains all objects necessary for high-level 2-D and 3-D operations.

3-D

Point3D

Vector3D

Matrix & Vector operations

Ray3D

2-D


Tri-quad tree

A tri-quad tree is used to recursively subdivide each face of the polygonal mesh into elements. Anchoring is done (and removed) automatically.

Each tri-quad tree is rooted in a face.

Note: Vertex and edge ordering is always counter-clockwise.

Vertex

Element

TQTree


Radiosity Solver

The radiosity solver does all the actual calculations through a single exposed method.

The input is the scene containing all polygonal surfaces. The output is the same scene, possibly subdivided, with radiosity values calculated for each face.

Radiosity


Camera

The renderer needs a camera object to view the resulting scene. Cameras have a standard interface borrowed from the motion picture industry. See the CS488 course notes (online).

Note that the camera should ALWAYS stay level with respect to the z axis, unless you want your audience nauseous.

Also note that you shouldn't change the field of view to zoom. Dolly in and out instead.

Camera


Scene

The scene is an object that encapsulates all model geometry.

Definitions:

Mesh
a solid object described by a collection of maximally connected faces
Face
a single facet of a polygonal solid (mesh)
faces are restricted to be quadrilaterals
Element
produced by subdivision of faces
each face is an element, but each element is not a face
elements are restricted to be quadrilaterals or triangles
Vertex
a corner of a face
Light
a face that emits radiosity
lights are not subdivided and thus consist of a single face
Receiver element
an element that is not part of a light

Scene


Iterators

An iterator is an object which allows you to enumerate a set. For example, the following is an iterator over integers from 1 to N:

for(int i = 1; i <= N; i++) {
     //
     // do stuff
     //
}

It makes sense to iterate over things other than numbers. It also makes sense to have a standard interface to iteration. The following is commonly used (see GNU C++ library, Microsoft Foundation Classes):

for(Iterator it = object.first(); it != NULL; object.next(it)) {
     doSomethingWith(object.get(it));
}

Iterator functions an object supporting iteration must implement are:

Optional iterator functionality is:

Using iterators neatly encapsulates iteration behaviour and avoids the need to access pointers directly. The Iterator type is usually a void pointer, but the user doesn't need to know that.

[Home]


Last updated March 23, 1998.
Maintained by Ming-Yee Iu
.