O3D Technical Overview
O3D is an open-source JavaScript API for creating interactive 3D graphics applications that run in a browser window—games, ads, 3D model viewers, product demos, virtual worlds. O3D extends the client-side software of a web application by providing features at the following levels:
- System : O3D provides a browser plug-in that adds graphics capabilities inside standard web browsers on Windows, Macintosh, and Linux (TBP) platforms.
- Content : Content for today's web is in the form of HTML, image files, and video files. The Developer's Guide provides information on how to create a file converter and loader for any 3D content. O3D provides a sample COLLADA Converter, which can be used to import files in the COLLADA format, an open standard for 3D assets that is supported by popular content creation applications such as SketchUp, 3ds Max, and Maya. Use this sample converter directly, or write your own converter and loader for other formats.
- Code : O3D extends application JavaScript code with an API for 3D graphics . It uses standard JavaScript event processing and callback methods.
Contents
- Audience
- Other Sources of Information
- Architecture
- Imported Content
- What Is the Scene Graph API?
- Creating the Transform Graph
- Packs for Memory Management
- Creating the Render Graph
Audience
The O3D API is intended for web developers who are familiar with JavaScript and have some background in 3D graphics. It is also intended for game developers eager to share their work with users of popular browsers such as Firefox, Safari, Google Chrome, and Internet Explorer. Because the O3D application runs as a browser plug-in, users do not have to overcome the hurdles of downloading and running standalone application code on their systems. The O3D API maximizes performance by programming to the GPU's shader language directly, an advantage over pure software rendering.
If you're new to graphics programming, you'll probably also want to consult some additional resources for background on basic 3D graphics programming concepts. This guide is intended to help you get started, and to explain the features unique to O3D in detail.
Other Sources of Information
For additional information on basic 3D graphics programming, the following sources provide useful information:
- 3D Computer Graphics by Alan Watt (Addison-Wesley, 1989)
- Introduction to 3D Game Programming with DirectX 10 by Frank D. Luna (Wordware Publishing, 2008)
- The Cg Tutorial by Randima Fernando and Mark J. Kilgard (Addison-Wesley, 2003)
Architecture
The following figure shows a simplified view of the O3D software stack:
The major components of the this software stack are the following:
- Your O3D JavaScript application.
- JavaScript Utilities provided as sample code to help you with common programming tasks.
- O3D Javascript API, which contains the classes and functions used in your application. This source code, written in C++, is open source and can be viewed in the Downloads area of the O3D Project .
The O3D JavaScript application code is completely contained in an HTML document that is loaded into a web browser. To develop a O3D application, all you need is the O3D plug-in and a text editor for writing JavaScript code.
As the architecture diagram shows, the O3D software communicates with your system's graphics hardware (its GPU —graphics processing unit) through either the OpenGL or Direct3D library.
Imported Content
The O3D library provides drawing primitives for creating shapes directly within your application (point list, line list, triangle list, triangle strip, triangle fan). As an example, O3D provides sample code to show how you could import content from a COLLADA file. This sample COLLADA Converter imports content from content creation applications such as Autodesk 3ds Max, Maya, and Google SketchUp, as shown in this figure:
As shown in this diagram, "raw" COLLADA files exported from 3ds Max, Maya, and SketchUp are converted by the sample COLLADA Converter (blue box) for use by the O3D JavaScript API. See Importing Scene Files in the Developer's Guide for more information on writing converters and loaders.
What Is the Scene Graph API?
The O3D scene graph API is used to create a transform graph and a render graph. The transform graph stores information about the position, size, shapes, materials, and shaders that comprise the basic data about the application's 3D "world." The render graph stores information about how these 3D objects are converted into the actual pixels that are displayed on the user's screen. The render graph is responsible for the following:
- It contains information about which 3D shapes are hidden from view.
- It traverses the transform graph to assemble primitives to be drawn.
- It handles the computation involved for special rendering effects
such as transparency, multiple views of the same world, and heads-up
displays.
- Import 3D models and worlds created in external applications. Content creation applications such as SketchUp, 3ds Max, and Maya export data using the COLLADA format, and O3D includes a sample converter that can be used with COLLADA files. The models in Google 3D Warehouse also use this format. (Using this sample converter as a model, you can also write your own importer and reader for files in any other format.) Examples that import externally created scene files are the Hello, World and Procedural Texture examples in this website as well as the O3D demos. See the section on Imported Content earlier in this page and Importing Scene Files for more information.
- Construct the transform graph from scratch, providing vertex data on position, normals, color, and effects, and then explicitly specifying how to position the objects in 3D space. This approach is used in most of the other examples in this website.
- The
Viewport
object sets up the rectangular area on the screen where the subsequent rendering will occur (the render graph can have multiple viewport objects).The settings of theViewport
object are inherited by its children in the render graph. - The
ClearBuffer
object clears the current buffer—in this case, the screen. - The
TreeTraversal
object traverses the transform graph and adds each draw element to one or more draw lists, as shown in the diagram below. The standard render graph has two draw lists: one for the performance rendering pass used for opaque materials and one for the z-ordered rendering pass, which is used for transparent materials. TheTreeTraversal
object performs a number of checks as it walks the transform graph, efficiently skipping objects that will not be rendered. For example, if a transform'svisible
parameter is FALSE, it is skipped, and no draw element is created for its associated shape objects. If theculling
parameter for the transform is set to TRUE, theTreeTraversal
uses bounding box calculations to determine whether the transform's children are contained in the viewing area of theDrawContext
for the associatedDrawList
. - The
StateSet
objects set various render states that are inherited by their children. For example, theStateSet
that is the parent of the z-orderedDrawPass
object turns on alpha blending (for transparency). - Each
DrawPass
object renders itsDrawList
, which in turn contains all the draw elements gathered by theTreeTraversal
for that pass.
Your application first constructs the transform graph for the 3D world and the basic render graph for the drawing details. Then O3D traverses the render graph which gathers information from the transform graph to display (render ) the 3D content. This approach contrasts with "immediate-mode graphics," where individual draw commands are issued and immediately executed.
Transform Graph
A transform contains a matrix that specifies how associated shapes are positioned and sized in 3D space. A transform graph is an ordered collection of transforms that are arranged in a parent/child hierarchy. The application's transform graph has one root transform at the top of the tree and any number of child transforms arranged in branches below the root transform.
Transforms have a cumulative effect, with transforms defined higher in the tree applying to the child transforms on lower branches of the transform graph.
Shapes
A transform can have one or more shapes associated with it. A shape defines a piece of geometry that is positioned and sized as a unit. A shape, in turn, is composed of primitives , each of which can have a different material assigned to it. Shapes are defined independently and then associated with a transform that positions the shape in its own local coordinate space. For example, if you were creating a table with four identical legs, you would model the shape for the leg and then reference it four times in four transforms that specify the positions for the four table legs. Then you would create the table top and reference it in a transform that places it on top of its four legs. Finally, you would create a parent transform for the table unit to move the entire grouping to its desired location. The basic transform graph for the transforms and shapes that make up this table would look like this:
Materials
Every primitive contains a material parameter. A material can be shared among multiple primitives. If you import models from an external 3D modeling application, primitives are created automatically as needed for different materials.
A primitive contains a material parameter
Effects
A material contains a parameter for an effect and a parameter for an optional state . The effect, in turn, contains a vertex shader and a fragment (pixel) shader , which together specify how to color the pixels that make up the shape. The parameters of the material, such as its diffuse color, specular color, ambient color, and so on, are used by the effect it refers to.
A material contains a parameter for an effect
Creating the Transform Graph
With O3D, you can create the transform graph in one of two ways:
You can also use a combined approach, importing some models and creating others from scratch. In most common cases, O3D renders the scene for you, using the view and projection matrix data provided by your application. In addition, O3D provides support for advanced rendering control, including shadows, transparency, glows, depth-of-field calculations, and multiple simultaneous views of the same scene.
Packs for Memory Management
When you create an object in O3D, it is automatically added to a pack
,
which ensures that objects are not accidentally deleted. Each time an
object is referenced by another object, its reference count is
incremented by 1. The pack itself also holds one reference to each
object. The pack.removeObject
function releases an
individual reference to an object, and pack.destroy
releases all references in that pack. If that call removes the last
reference to a particular asset, the asset will be removed from memory.
Creating the Render Graph
O3D provides a DrawContext
object that is used to define
the view matrix and projection matrix. The view matrix
represents a transformation that converts vertices from world
coordinates to view coordinates. The projection matrix
is a
transformation that converts view coordinates to clipspace coordinates.
Any 3D content that falls outside of the viewing frustum is discarded,
or clipped
. This matrix is usually an orthographic
or perspective
transformation. The DrawContext
is shared by the DrawPass
objects and the TreeTraversal
object. The TreeTraversal
object uses it for culling, and the DrawPass
object uses
it during rendering. You can specify these matrices explicitly, or if
you're importing models from other sources, O3D can obtain the camera
information contained in the imported content.
The createDrawElements()
function walks the transform
graph and generates a draw element for each primitive in the transform
graph. A draw element is basically an instruction to "Draw this
primitive." Without draw elements, nothing is drawn. Draw elements allow
O3D to efficiently draw the same primitive multiple times (for example,
once as the actual shape and once as the shadow for that shape). In
some cases, the draw element uses the material assigned to the
primitive. In other cases, the draw element may have its own material
assigned to it (for example, for shadows). In cases where both the
primitive and the draw element have materials assigned to them, the
material assigned to the draw element overrides the material assigned
earlier to the primitive.
A draw element is an instruction to "Draw this primitive" with the specified material and effect
A typical render graph, created using the JavaScript utility function
renderGraph.createBasicView
, contains the following
objects:
The objects in the render graph are traversed (that is, read and executed) from the top down, and from left to right (by priority). Here's a brief explanation of the tasks performed by the objects in this typical render graph:
The TreeTraversal object puts draw elements into draw lists, which are used by the draw pass objects
At the end of each render graph traversal, the scene is displayed.