Basic Tasks
The basic tasks performed in an O3D program are the following:
1:Create the O3D object.
2:Assign values to global variables and initialize utility libraries.
3:Create the pack to manage O3D objects.
4:Create the render graph.
5:Set up the draw context (perspective and viewing transformations).
6:Create an effect and load the shader information into it.
7:Create the material and shape, set the material's draw list, and set up other material parameters.
8:Add the transforms and shapes to the transform graph.
9:Create the draw elements for the primitives.
10:Set the optional render callback function, if desired, to perform special tasks each time the 3D scene is rendered.
The following sections discuss how the Hello, Cube sample implements these tasks.
//-------------------------------------------------------------------------------------------------------------
HTML Document
An O3D application is contained in an HTML document. The main code for the O3D JavaScript application is contained in a <script> element inside the <head> element of the HTML document. In this example, when the HTML page is finished loading, the O3D init() function is called. The HTML page also sets up an onunload event, which calls the application's uninit() function to perform necessary cleanup, such as removing callback functions when the HTML page is unloaded..
<script type="text/javascript" src="o3djs/base.js"></script>
<script type="text/javascript">
o3djs.require('o3djs.util');
o3djs.require('o3djs.math');
o3djs.require('o3djs.rendergraph');
window.onload = init;
window.onunload = uninit;
.
.
.
//---------------------------------------------------------------------------
Utility Libraries
O3D includes a number of utility libraries that simplify the coding of common tasks. If you use functions from one of these libraries, you also need to include that code in <script> tags at the beginning of your program as shown below. (The first <script> element defines the require
function, which is used thereafter to initialize the other utility libraries.):
<script type="text/javascript" src="o3djs/base.js"></script>
<script type="text/javascript">
o3djs.require('o3djs.util');
o3djs.require('o3djs.math');
o3djs.require('o3djs.rendergraph');
//--------------------------------------------------------------------------------
Creating the O3D Plug-in Object
In the code sample, the init() function calls the utility function o3djs.util.makeClients() to make the O3D objects. When this function returns, it invokes the callback function initStep2(). The user's browser must have scripting enabled in order for O3D HTML elements to be created.
function init() {
o3djs.util.makeClients(initStep2)
}
//-------------------------------------------------------------------------------
Setting the Size of the Client Area on the Page
Use the o3djs.util.makeClients() function to create O3D objects in HTML that can be used across platforms. This function finds all <div> elements with an id that starts with the word "o3d" (for example o3d, o3d-element, and so on) and inserts a client area inside. The size of the client area is always set to 100 percent, which means the <div> must have its size set or managed by the browser. For example:
<!-- A div of a specific size -->
<div id="o3d" style="width:800px; height:600px" />
<!-- A div that fills its containing element -->
<div id="o3d" style="width:100%; height:100%" />
The makeClients() utility takes a callback function as one of its parameters. This callback is triggered once the O3D objects have been created.
//------------------------------------------------------------
Basic Setup for O3D
This code assigns values to global variables:
var o3dElement = clientElements[0];
g_client = o3dElement.client;
g_o3d = o3dElement.o3d;
g_math = o3djs.math;
//---------------------------------------------------------------------------
These variables have the following meaning:
o3dElement is the HTML O3D element, which is part of the DOM
g_client is the entry point of the O3D application
g_o3d is the namespace for O3D
g_math is the namespace for the math library
//------------------------------------------------
Creating the Pack
The pack contains all O3D objects and manages their lifetime.
g_pack = g_client.createPack();
//---------------------------------------------------------
Creating the Render Graph
This example uses the utility function rendergraph.createBasicView() to create a standard render graph, as described in the Technical Overview. This render graph has two draw lists, one for draw elements with opaque materials (the performance draw list) and one for draw elements with transparent materials (the transparency draw list). A separate draw pass is performed for each draw list.
var viewInfo = o3djs.rendergraph.createBasicView(
g_pack,
g_client.root,
g_client.renderGraphRoot);
//------------------------------------------------------------
Setting Up the Draw Context
The draw context specifies the view projection and the position of a virtual camera that is viewing the scene (the view transformation). The drawContext object is created by the utility function renderGraph.createBasicView(). Here is an example of setting its values:
// Set up a simple perspective view.
viewInfo.drawContext.projection = g_math.matrix4.perspective(
g_math.degToRad(30), // 30 degree fov.
g_client.width / g_client.height,
1, // Near plane.
5000); // Far plane.
// Set up our view transformation to look towards the world origin where the
// cube is located.
viewInfo.drawContext.view = g_math.matrix4.lookAt([0, 1, 5], // eye
[0, 0, 0], // target
[0, 1, 0]); // up
//-----------------------------------------------------------------------------
Creating an Effect and Loading the Shaders
The vertex and pixel shaders are defined in the <textarea> element of the HTML document. The shaders control the calculations for the color of each pixel in each draw element. This code creates the effect (redEffect) and reads in the contents of the shaders:
var redEffect = g_pack.createObject('Effect');
// looks in the HTML document for an element named "effect"
var shaderString = document.getElementById('effect').value;
// loads the entire contents of the <textarea id="effect"> element into the redEffect object
redEffect.loadFromFXString(shaderString);
Creating the Material and Shape
The red material for the cube is created in the initStep2() function and assigned to the performance draw list, which handles opaque materials. The following code also sets the material's effect to redEffect so that the graphics hardware can apply the proper shading to the cube. In this example, no shading calculations are performed. The simple color red is returned for all pixels. The createCube() function constructs the cube geometry, as described in Shapes, and uses the red material. An alternative to setting up the geometry within O3D, as shown in the Hello, Cube examples, is to import geometry constructed using an application such as SketchUp, 3ds Max, or Maya.
var redMaterial = g_pack.createObject('Material');
redMaterial.drawList = viewInfo.performanceDrawList;
redMaterial.effect = redEffect;
var cubeShape = createCube(redMaterial);
Setting Up the Transform Graph
The Hello, Cube example has a very simple transform graph. The following code creates one transform for the cube shape, adds the shape to the transform, and then adds the transform to the O3D root.
g_cubeTransform = g_pack.createObject('Transform');
g_cubeTransform.addShape(cubeShape);
g_cubeTransform.parent = g_client.root;
Creating Draw Elements
Every primitive has a draw element constructed for it that describes what material and effect to use when the primitive is rendered. The createDrawElements() function creates draw elements for all primitives in the specified shape and adds the draw elements to the draw list associated with the primitive's material. At render time, one draw pass is performed for each draw list, and all draw elements in the lists are rendered.
cubeShape.createDrawElements(g_pack, null);
Setting the Render Callback Function
The scene is automatically rendered each time the hardware refreshes the screen. In this example, setRenderCallback() sets a callback that updates the cube's transform values each time the scene is rendered. This update makes the cube spin.
g_client.setRenderCallback(renderCallback);