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-ordered
DrawPass
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.
- Import 3D models and worlds created in external applications.
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.