CPSC 424 Computer Graphics Fall 2025

CPSC 424 Scene Graph Project

Due: Mon 11/17 at the start of class

A scene graph provides a more user-friendly and platform-independent way to define a scene — the programmer can create a data structure representing the contents of the scene in terms of shapes, materials, transformations, lights, and so forth instead of having to issue specific OpenGL commands. A scene graph data structure can also be changed on the fly and can be written to — and read from — a file, making it possible to create general-purpose modeling and viewing programs that can work with any scene.

In this project, you will implement a WebGL renderer for XML-based scene description files and consider some design decisions for the scene description format.

Collaboration and Use of AI

This is an individual project. You may get technical help from others, but the effort and ideas that go into producing solutions should be yours.

You may use AI as outlined in the Use of AI policy — Copilot's inline coding suggestions, explain, fix, review and comment features but not code generation from English prompts. Also:

Handin

Hand in your writeup in class.

Hand in your code by copying your ~/cs424/scenegraph folder into your handin folder (/classes/cs424/handin/username, where username is your username). Make sure that your scenes and shader files are contained in scenes and shaders subdirectories, respectively.

Check that the result is that your files are contained in /classes/cs424/handin/username/scenegraph — if not, fix it!


Preliminaries

Setup

Make sure that your scenegraph and lib directories are named exactly like that and is at the same level in your workspace directory. This is important so that the relative path names used to access common files remain the same so your program doesn't break when you hand it in. Also make sure that the scenegraph directory contains two subdirectories scenes and shaders.

Provided Code and Files

The lib directory contains one new file:

The scenegraph directory contains several things:

Scene Description File Format

We'll be using an XML-based file format for our scene description files. W3Schools provides a brief introduction to XML through their XML Tutorial — start with the XML Introduction and read through the XML Attributes section.

The root element for our scene descriptions is scene. Four kinds of elements are permitted as children of scene and only one instance of each is permitted.

See the provided scene files for the attributes for these elements, and for the elements defining lights, materials, transforms, and geometry. The provided files together cover everything the core renderer needs to support.

XML DOM

A document object model (DOM) provides a standard way to access and manipulate documents. You can read more about the XML DOM in the W3Schools XML DOM tutorial — start with the DOM Nodes section and read through the DOM Get Values section.

The provided renderer.html contains code to load XML content from a text file (in loadScene) and parse that content into a structure that can be accessed via the XML DOM (in initScene). draw renders the scene, extracting the top-level elements of the scene (the camera, the projection, the list of lights, and the root of the scene graph) and traversing the scene graph, doing the WebGL stuff corresponding to various nodes (the camera, the projection, etc).

Two things in particular to notice in renderer.html:

Tips


Tasks

There are four main tasks for this project:




Demo Scenes




Core Renderer

The core renderer should be able to handle scenes with basic shapes (sphere, cube, cylinder, etc) and the lighting model discussed in class and implemented in labs 4 and 5. The provided renderer.html contains a partial implementation.

The organization of renderer.html is a little different from the WebGL programs we've been working with. In particular, the initialization functions have been split up a bit more in order to support loading shader source and scenes from external files rather than text elements within the HTML document. (This structuring is necessary because JavaScript loads files asynchronously — initialization that occurs after a file is loaded has to be set up in a callback.)

Drawing a scene means doing the usual things: set up shader parameters, draw geometry, set up shader parameters, draw more geometry, etc. In the case of the renderer, the values for setting up the shader parameters and the geometry to be drawn come from traversing the scene graph. This is draw's job.

The end result is that your renderer should be able to handle everything in the provided scene files.




User-Defined IFS Mesh Objects

There is a key omission from the scene files so far: the ability to support user-defined mesh objects. (Only certain predefined shapes — sphere, teapot, etc — are supported.) While in general one might wish to support both indexed face set (IFS) and list-of-vertices representations, you only need to support IFS representations here.

Supporting a new feature like this requires two things: designing additions/modifications to the scene description file in order to specify the thing, and updating the renderer to process the new/modified elements.

For the design: Add a new element mesh with attributes for the vertex coordinates, vertex normals, and face indices. For convenience, specifying vertex normals in the scene file should be optional — if they aren't supplied, compute them. A helper function computeNormals is provided in renderer.html for this.

Mesh objects can get very large, and having to repeat the full definition for a mesh object that appears more than once in a scene quickly gets prohibitive. A solution is the ability to name objects: a list of object definitions can be specified at the top level of the scene description and the name referenced in the scene graph. (An even better solution is support for external libraries so that mesh object definitions can go in a separate file and be reused in multiple scenes, but that's an optional extension below.)

For the design: a list of mesh object definitions can be handled like the list of lights — add an objects element to contain a list of mesh elements. Make the mesh elements into definitions by adding a name attribute to each mesh element. Within the scene graph, a mesh element with a name attribute refers to the corresponding definition.

For the renderer: a name must be defined before it is encountered during the rendering traversal of the scene graph. One option is to use querySelector to locate the DOM node with the definition when the name is encountered during the scene graph traversal. More efficient, but involving more JavaScript syntax, is to preprocess the list of definitions into a JavaScript data structure before traversing the scene graph — the idea is to build a JavaScript object indexed by the name to store a parsed version of the mesh object's data, then look that up when the name is encountered during the traversal of the scene graph.




Extensions

There is a great deal that could be added to the scene description format beyond these core features — several such features are listed below.

Most of the extensions will involve additions to the scene description format, but some only involve the renderer. When adding new elements to the scene description format, consider which attributes, if any, should be required and provide reasonable default values for the rest.

Also create new scene files to test/demonstrate each feature.

Conveniences

WebGL supports two alternatives for specifying a perspective projection: by defining the view window (gl.frustum) and by defining the field of view and aspect ratio (gl.perspective). Only one is necessary, but both are convenient in different situations.

When there are multiple lights in a scene, it is often necessary to turn down the brightness of each light to avoid things becoming too bright. However, since the light's RGB color captures both hue and brightness, this means adjusting the red, green, and blue components separately.

Named Materials

Within a scene, the same material may be applied to multiple objects. Instead of having to repeat the material properties for every object, it would be nice to be able to define a set of materials and refer to them by name in the rest of the scene. This also makes it easier to change materials — only the definition needs to be updated, rather than every instance of that material.

The key pieces of supporting this feature are similar to handling named objects: there will need to be a section at the top level of the scene description for material definitions and a way to reference those materials within the scene graph.

Use some real materials (ignore the ambient color but note that the shininess values need to be multiplied by 128) in your demo scenes.

Repeated Subgraphs

Object definitions for user-defined mesh objects allow repeated instances of specific geometry, but scenes may contain larger repeated chunks — compound objects are built from multiple objects, along with transforms to position the component objects and possibly different materials for those component objects.

Since XML is a tree-structured format, the option of simply attaching a subgraph as the child of multiple other scene graph nodes (forming a directed acyclic graph) isn't available. Instead, the key pieces of supporting this feature will be similar to handling named objects and named materials: there needs to be a way to define names for subgraphs and a way to reference those names within the scene graph to include those subgraphs.

Note that only separator elements can be the root node of a subgraph — they are the only elements in the scene graph that aren't leaf nodes. Similarly, subgraphs can only be spliced in where separator elements can occur — at the top level of the scene description or as a child of another separator.

A name must be defined before it is encountered during the rendering traversal of the scene graph. Definitions can be handled in the same way as for mesh objects and materials (up front, with a definitions section at the top level of the scene description) or inline (definitions occur within the scene graph itself by attaching a name to a separator node as it occurs as part of the scene graph). In the latter case, querySelector can be used with an appropriate selector to locate the definition when a reference is encountered, or to find all of the nodes with definitions for processing before rendering the scene graph.

Attribute Stack

Section 4.4.1 in the textbook introduces the OpenGL 1.1 attribute stack, which allows saving and restoring many aspects of the current state such as light and material properties. See the glPushAttrib API for a full list.

Only the current material is relevant for the scene descriptions, but with support for repeated subgraphs, the behavior of the current material carrying across subgraphs that are not direct descendants is potentially problematic.

As with the modelview stack, WebGL does not maintain an attribute stack — to support similar functionality, you will need to maintain a JavaScript variable for the stack and push/pop state accordingly. Note that implementing an attribute stack for the current material requires only a change to the renderer — no additions to the scene description format are required.

EC, WC, OC Lights

The shaders get lights in eye coordinates, so accommodating WC and OC lights means needing to transform the light by the viewing or modeling transform, respectively. As discussed in class, it is convenient to define EC and WC lights after the camera has been set but before any modeling transforms — at that point, modelview is the viewing transform and so it is only necessary to know if a light is EC or WC to know how to transform the light.

For OC lights, however, the entire modeling transform is needed. Section 4.4.3 in the textbook discusses a solution: make lights a node in the scene graph, similar to materials, transforms, and objects. The wrinkle is also identified: lights need to be set before geometry is drawn in order for the light to affect the object. And the solution is identified: traverse the scene graph twice, the first time updating the current modelview whenever a transform is encountered and defining a light when a light is encountered and the second time rendering everything other than light nodes.




Optional Extensions

There is a great deal that could be added to the scene description format beyond the core features and the extensions described above; some more are described below. These extensions are all optional — they are not required and can be done for extra credit.

Emission Materials [Optional]

OpenGL materials include an emissive color in addition to ambient, diffuse, and specular colors. The emissive color represents a glowing object which emits light but does not itself illuminate anything else. (Something which both glows and illuminates other objects, such as a light bulb, can be modeled by an object with an emissive material combined with a light source in the same place.)

Wireframe [Optional]

Polyhedron Objects [Optional]

Polyhedra have sharp edges between faces and should have flat shading (polygon normals) instead of smooth shading (vertex normals). While polygon normals can be achieved using a mesh object by duplicating shared vertices, it would be more convenient to be able to specify the vertices as for any other mesh (i.e. unduplicated) and have the renderer do the vertex duplication needed for flat shading.

External Libraries [Optional]

Supporting named materials within a single scene is nice, but even better would be to also support libraries of materials defined in separate files which can be imported instead of having to define common materials in every scene file.

Even better than materials libraries would be object libraries, where definitions of mesh objects can be imported into scenes instead of requiring redefinition in every scene. And why stop with single objects — whole subgraphs could be imported.

Technical note: this is a little tricky because JavaScript loads files asynchronously. See how loading scene files and shaders is done in renderer.html.

Transforms [Optional]

Global Ambient [Optional]




Writeup

Include a short writeup addressing the following: