art with code

2009-04-22

Google's O3D

Executive summary


Google's O3D is a 3D scene graph plugin for Windows and Mac. See Ben Garney's Technical Notes on O3D. Also see the O3D API blog.

I like it.

It doesn't build here though. So I can't test it.

The people behind it are GPU & games industry veterans. Which is good.

It doesn't have anything for playing sounds. Which is par the course but still a bit of a letdown.

I think that the 3D canvas and O3D should use the same shading language, the same viewport origin (D3D uses y-grows-down, OGL y-grows-up) and the same content semantics (loading HTML elements as textures, buffer types.)

Longer ramble


If you want to download the O3D repo, be warned that it has copies of textures as TGAs and PSDs. And 3DS Max files and mp3s... The repo is 1.6 GB in size. And it doesn't build. So I can't test it. All the following is gleaned from the documentation and guessed from the source code.

Anyhow, I like it. It does shaders, imports data from 3D programs and clearly has a clue. The downsides are that it's quite complex and weighs in at around 60 thousand lines of source code (compared to nine thousand for the OpenGL canvas.) But it's a scene graph, so it's no wonder it's a lot bigger.

O3D has a solution to The Shader Problem, namely they use Nvidia's Cg for compiling the shaders and have an ANTLR parser to validate the shaders. The shading language is HLSL SM 2.0 / Cg though, but it probably works the same across hardware / OS / driver combos? I hope so at least.

O3D is a scene graph renderer. Their scene graph consists of transform trees, which contain transform nodes that contain drawable objects, and render trees, which draw transform trees.

Transform nodes are basically utility-wrapped transformation matrices.

Drawables are Shapes, which consist of primitives, each of which has a material to determine the render pass and a bunch of coordinate arrays that interact with the shaders somehow. It's too complicated for me to understand at this time of the day so I'll just paste some "Hello, Cube" example code:

var viewInfo = o3djs.rendergraph.createBasicView(
g_pack,
g_client.root,
g_client.renderGraphRoot);

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.
viewInfo.drawContext.view = g_math.matrix4.lookAt([0, 1, 5], // eye
[0, 0, 0], // target
[0, 1, 0]); // up

var redEffect = g_pack.createObject('Effect');
var shaderString = document.getElementById('effect').value;
redEffect.loadFromFXString(shaderString);

var redMaterial = g_pack.createObject('Material');
redMaterial.drawList = viewInfo.performanceDrawList;
redMaterial.effect = redEffect;

var cubeShape = g_pack.createObject('Shape');
var cubePrimitive = g_pack.createObject('Primitive');
var streamBank = g_pack.createObject('StreamBank');

cubePrimitive.material = redMaterial;
cubePrimitive.owner = cubeShape;
cubePrimitive.streamBank = streamBank;

cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
cubePrimitive.numberPrimitives = 12; // 12 triangles
cubePrimitive.numberVertices = 8; // 8 vertices in total

var positionsBuffer = g_pack.createObject('VertexBuffer');
var positionsField = positionsBuffer.createField('FloatField', 3);
positionsBuffer.set(g_positionArray); // vertex buffer with cube coords

var indexBuffer = g_pack.createObject('IndexBuffer');
indexBuffer.set(g_indicesArray); // indices to vertex buffer
streamBank.setVertexStream(
g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
0, // semantic index: First (and only) position stream
positionsField, // field: the field this stream uses.
0); // start_index: How many elements to skip in the
// field.
cubePrimitive.indexBuffer = indexBuffer;

g_cubeTransform = g_pack.createObject('Transform');
g_cubeTransform.addShape(cubeShape);

g_cubeTransform.parent = g_client.root;

cubeShape.createDrawElements(g_pack, null);

No comments:

Blog Archive