O3D Update: New features and expanded compatibility

Monday, June 29, 2009 | 6:22 PM

Labels:

We're happy to announce that today we shipped a substantial update to O3D, an API for creating rich 3D applications in a web browser. With today's release, we focused on addressing a theme we heard in the requests and feedback from the community: that O3D should run as well as possible on many different types of hardware. Toward that end, we're releasing two new additions: software rendering and feature requirements. If you've already installed the O3D plugin, you should receive these additions automatically.

Software rendering allows O3D to use the main processor to render 3D images if the machine running the app doesn't have supported graphics hardware. While the hardware O3D requires to run in hardware-accelerated mode is fairly modest by today's standards (a DirectX 9, Pixel Shader 2.0 capable graphics card), there are nonetheless PCs that don't meet these requirements, and we think it's important for web apps to run on all machines, regardless of hardware.

Because software rendering is significantly slower than hardware-accelerated rendering, we're also introducing a concept called "feature requirements" that will help minimize how often O3D will have to fall back to software rendering. Feature requirements allow developers to state upfront that their app will require certain hardware capabilities to render properly. If the machine running the app supports those features, O3D will run it fully hardware accelerated; if however, it is lacking any of the required capabilities, O3D will drop into a software rendered mode. Anecdotally, we found that this tiering allows 45 of our 48 samples to now run in hardware-accelerated mode with less capable graphics cards.

Finally, while it has nothing to do with extending hardware support, we're also adding a couple other goodies: a full-screen mode to make O3D apps more absorbing and a community gallery to feature cool demos that use O3D (like Infinite Journey, the first game developed outside Google using O3D). If you've developed an application or sample that would be useful to the O3D community, please be sure to submit it for our team to review for inclusion in the gallery using this form.



Dealing with Asynchronous JavaScript

Wednesday, June 24, 2009 | 4:24 PM

Labels:

I'm sure many of you reading this are JavaScript experts but I'm sure some of you, like me, might have lots of graphics experience with C or C++ but not so much with JavaScript. This post is about one of the things that is different about JavaScript that I needed to learn as an experienced programmer in other languages.

First, I highly recommend you get the book, "JavaScript: The Good Parts" by Douglas Crockford. It's a book that really changed my mind about JavaScript and has showed me how to use it much more effectively.

As O3D is a JavaScript based API for the browser, there are many times when one needs to do asynchronous calls to some function. A good example is when you load a 3d scene. You call loadScene, and when the scene has finished loading some moments later, it calls a callback you specify. In C++, these types of functions usually have a parameter for you to pass in some kind of user data that will then be passed to your callback. That way you can associate something with each call. JavaScript APIs don't generally have that user data concept. The reason is, they don't need it. Here's why:

First off, unlike C or C++, JavaScript does not define scope with braces. To see what I mean check out the following code.

function someFunc() {
{
var foo = 123;
}
{
console.log("foo = " + foo);
}
};

To a C++ programmer that looks like it has 3 scopes. The scope of the function, "someFunc", the scope surrounding the declaration of "foo", and the scope printing the result. (*) As such, in C++ that code would fail to compile because foo does not exist when it gets to the line to print it. In JavaScript though this is perfectly valid code because, as I mentioned, JavaScript does not use braces to define scope.

Instead, JavaScript uses functions to define scope so foo is visible inside someFunc but it is not visible outside of someFunc.

Functions can see the scopes above them so for example look at the code below:
function someFunc() {

var foo = 123;

function innerFunc() {
console.log("foo = " + foo);
}

innerFunc();
};

In this code, someFunc has an inner function called "innerFunc" and innerFunc can see the variable foo. Pretty straight forward.

Here is where the magic comes in and points out a big difference between JavaScript and C++.
function someFunc() {
var foo = 123;

function innerFunc() {
console.log("foo = " + foo);
}

return innerFunc;
}

This version of someFunc does not print anything. Instead it returns a function that prints something. To see it print, you have to call the function it returns. If you look at the code you'll see innerFunc prints the value of "foo" but foo is declared outside of its scope. If you tried this in C++, assuming you could make it compile, your function would crash because foo would get destroyed when someFunc returned. JavaScript on the other hand doesn't work like that. This code will work just fine. You would use it like this:
var functionReturnedBySomeFunc = someFunc();

// call the function returned by someFunc
functionReturnedBySomeFunc();

someFunc returned a function which is stored in a variable and then that function is called.

What is this good for? Well, it's great for asynchronous callbacks like o3djs.scene.loadScene because the callback you pass in will retain knowledge of the things that were in its scope when it was defined. For example:
// A constructor for a MyObject
function MyObject(client, viewInfo) {
this.client = client;
this.viewInfo = viewInfo;
this.pack = client.createPack();
this.transform = this.pack.createObject('Transform');
};

MyObject.prototype.loadScene = function(url) {
// declare a local variable so inner functions can see it.
var that = this;

// An inner function that loadScene will call on completion.
function loadCallback(pack, parent, exception) {
if (!exception) {
// you can reference the particular MyObject through
// the "that" variable implicitly.
that.initScene();
}
}

// load the scene.
o3djs.scene.loadScene(
this.client,
this.pack,
this.transform,
url,
loadCallback);
};

MyObject.prototype.initScene = function() {
o3djs.pack.preparePack(this.pack, this.viewInfo);
};

You can use MyObject like this:
var obj = new MyObject(client, viewInfo);
obj.loadScene('http://someplace.com/somemodel.o3dtgz');

As you can hopefully see, unlike C++, we didn't need a special user data parameter to make loadScene useful. JavaScript makes it easy for us to allow the callback to have as much or as little access to other data as it needs.

If you're new to JavaScript I hope that's a useful example. It can take a little while to get used to a new language but every language has its strengths.

(*) console.log is something that only works on Safari, Firefox and Chrome when the debugger is running. It is non-standard JavaScript but helped to make these examples clearer.

We are live

Thursday, June 11, 2009 | 2:36 PM

Labels:

If you've been looking at our code repository history at all, you might be forgiven for assuming that Antoine and I are the only ones who work on O3D code, and that we're really sporadic about when we submit code (but look at how much we get done!).

Since our launch, we've been syncing our internal repository intermittently with the public Google Code repository while we made the transition to some new tools and did some rearranging. Now that transition is complete.

The plan for O3D in the near future is to become more closely integrated into Chromium (while continuing to support plugins for other browsers). To make this integration easier, our code now has a new home in the Chromium.org Subversion repository. From now on, we're going to stop doing merely intermittent pushes and just do our daily work directly on the public repository, so you'll get to see all the changes as they happen, and you can follow along (and maybe now you'll see some other developers do some work! Or maybe you'll be one of those developers! ).

If you want to download the O3D source, or have downloaded it in the past, you'll want to use the Chromium server by following our updated build instructions. Don't worry, you don't need to download all of Chromium to build O3D.

We will continue to use our current issue tracker on the code.google.com site to track and log bugs and feature requests so you can see if they are being worked on, or pick one out to work on yourself.

If you've been itching to fix one of those bugs, you can now submit patches to our source using the same process that Chromium developers use. Look at the Chromium guidelines for patch submission if you're interested in contributing. Some things, like the buildbots, aren't set up for O3D yet, but will be available in the future. The reviewer mailing list for o3d is o3d-review@googlegroups.com, if you are looking for a reviewer.

The code on the Google Code site will be available for some time to come, but will not be updated, and eventually we'll just redirect visitors directly to the Chromium repository. It currently contains the latest code as of Friday May 29th.

The API documentation will remain where it is.

Enjoy!

Posted by Greg Spencer, Senior Software Engineer

O3D at Google I/O 2009 Part 2

| 1:44 AM

Labels:

After we introduced O3D to the world in April this year, we were eager to present rich 3D web applications created with O3D. Two weeks ago, at Google I/O, we presented and demoed O3D based apps by Disney/ABC, Large Animal and Crazy Pixel Productions. We could not be more proud of what they created and showed off at Google I/O.

At Google I/O, we also had a chance to interview representatives from these companies and learn more about them and their experiences with O3D. In the interviews, they talked more about their 3D projects with O3D and where the projects are heading, shared feedback they got from I/O attendees at the Developer Sandbox pods, and also shared their thoughts about Google I/O.

1) Crazy Pixel Productions


Crazy Pixel Productions, a full service 3D animation and game development studio, built the O3D beach demo (demo here or video here), and is developing a 3D Tower Defense game.

2) Disney / ABC Television Group


Disney / ABC Television Group Digital Media introduced Visual Search Interface (app here or video here), an engaging 3D based application to both visually search and navigate through ABC's online catalog of video content.

3) Large Animal Games


Large Animal Games, a developer/publisher of social games for casual gamers developed and presented Infinite Journey (demo here or video here), a 3D online platformer game that will ultimately be integrated with social networks.

We are looking forward to seeing more exciting 3D web applications and services based on O3D in the future. To learn more about O3D's presence at Google I/O, please read our previous blog post, O3D at Google I/O 2009. Thank you.

Posted by Mickey Kim, New Business Developer Manager

O3D at Google I/O 2009

Tuesday, June 2, 2009 | 8:17 PM

Labels: , , ,

Thank you to everyone who came to our O3D sessions at Google I/O last week! It was exhilarating to get to meet so many people that are passionate about both graphics and the web. We were really happy about both the turnout at our talks as well as the quality of the questions from the audience.

For those of you who where unable to join us, here's a quick recap of the O3D activity at I/O:

  1. Our very own Matt Papakipos showed off the Beach Demo during the first day's keynote, described the technology behind O3D, and talked about how 3D fits into the future open web platform.
  2. We had a deep dive session on using O3D "Adding Interactive 3D Content to Your Site". Vangelis Kokkevis gave a architectural overview of O3D and how it compares to other 3D APIs. Gregg Tavares took us through the steps necessary to build a simple game in 20 minutes, from getting an object on the screen to getting an animated robot walking and jumping through an environment. You can download those steps here.



  3. Three of our partners showed off their wares at the developer sandbox and talked about their experiences building apps at our panel session, "Developing on O3D: A View from the Trenches". ABC/Disney showed off an awesome 3D search visualization (app here or video here); Crazy Pixel Productions talked about their experience building the O3D Beach Demo and an upcoming Tower Defense game; and Large Animal Games demoed a beautiful and addictive platformer game that they're working on called "Infinite Journey". It's exciting to see real apps that use O3D emerge and we're really looking forward to see how they develop!




A gallery for your samples and applications

Tuesday, May 26, 2009 | 10:55 AM

Labels:

All of us at the O3D team are very excited to see developers from around the world getting involved in our project. We appreciate the great feedback we have received in the O3D discussion group, the translations of our documentation into other languages and some of the videos that have been created and posted on YouTube.

We are also excited by some of the samples that the community has created. From medieval castles, to medical imagery and dancing teapots, developers have shown a strong interest to experiment with O3D's technology and showcase its potential. To highlight some of this work we are planning to create a small gallery that will feature screenshots and links to the samples and applications that have been created with O3D.

To have your apps and samples considered for this new gallery, all you need to do is fill in this form. Our engineering team will then select out of all the submissions, those that we think could be of interest to the wider O3D development community.

We look forward to seeing your submissions and stay tuned for the gallery coming soon.

How to find a Model

Tuesday, May 12, 2009 | 5:46 PM

Labels:

No, we're not talking about live models to use in your work, human or otherwise. This is about how to look up a 3D model from a file loaded in O3D.

The first thing that should be made clear is that O3D does not directly support loading models. Instead, it provides a framework for you to build your own model loading and we've provided a sample art path to do that. The sample art path is split into 2 parts. The first part, the o3dConverter takes a collada file and converts it into a gzipped tar file with a JSON file inside describing the scene and other files storing vertices, skinning, animation and textures. The second part is a sample loader in samples/o3djs/serialization.js which loads the JSON file and uses the data inside to recreate the scene in O3D.

The important points about that are:

  1. They are samples. If you don't like them or your application has different needs then change them.

  2. They are not directly part of O3D. There is no fixed file format for O3D. If you want to make better exporters that export to a format that matches your application better, you're free to do that. If you have a solution that solves a problem better than collada and our sample format does and you want to load that format, you have the power to do it. In fact, we are really hoping you will, and if we're lucky, you'll make your solutions available to the community.

  3. There are 4 parts to that entire path: The modeler you use, the exporter you use, the converter you use, the loader you use. You can replace or change any of those 4 parts if they don't meet your needs. It's also important to notice that what you get through our sample art path is dependent on the first 2 parts, the modeler and the exporter. If you have an exporter doing something you'd like done differently you might need to find a new one or write your own. For example, maybe you'd like your exporter to combine hierarchies of models into a single model. Or, maybe you'd like your art path to export things like "shape: {type: 'sphere', radius: '50'}" instead of saving out the mesh for a sphere and you'd like your loader to create spheres at load time when it sees that. More importantly, maybe you'd like to your exporter to export materials as they are in your art tool and then have your loader create materials that match instead of our sample art path which can't do that because it's limited by collada.

With that out of the way, let's talk about the sample art path we have provided and how to find a model. If you are not familar with the O3D API it might be good to review the technical overview doc, especially the part about the scene graph.

Assuming you loaded a scene like this:
 var path = "http://somedomain.com/assets/somescene.o3dtgz";

function loadCallback(pack, parent, exception) {
if (exception) {
alert("Could not load: " + path + "\n" + exception);
} else {
// Scene has been loaded.
}
}

scenePack = client.createPack();
sceneRoot = pack.createObject('Transform');
o3djs.scene.loadScene(client, scenePack, sceneRoot, path, loadCallback);

At this point, you can search for models in several ways. Most modeling packages show the name of the transform above a model instead of the name of the model itself. So, if you want to search by transform name there are 2 easy ways:
 var transforms = scenePack.getObjects("myModel", "o3d.Transform");

This searches the entire pack for transforms with the name "myModel".

another way is with:
 var transforms = sceneRoot.getTransformsFromTreeByName("myModel");

This searches a sub tree of transforms for transforms with the name "myModel". Both functions return an array of results.

Once you have the transforms, you may be able to use them as transforms, or if you want to find the shapes then you can try something like:
 // assuming you found multiple transforms
for (var ii = 0; ii < transforms.length; ++ii) {
var shapes = transforms[ii].shapes;
// now iterate through the shapes.
for (var jj = 0; jj < shapes.length; ++jj) {
var shape = shapes[jj];
}
}

Often, if you are making your own assets, you'll know the exact structure of your scene. For example, if you know there is only 1 transform named "house" and you know there is only one shape under it, you could just do the following:
 // get the 1 transform we expect.
var houseTransform = scenePack.getObjects("house", "o3d.Transform")[0];
// get the single shape we expect.
var houseShape = houseTransform.shapes[0];

On the other hand, if you know the name of the shape itself, you can look for shapes directly. I'm personally more familar with Maya and its default behavior is to automatically name shapes with the suffix "Shape". If you rename a transform to "house", the shape will be renamed "houseShape". In this case, if you know there is only 1 shape named "houseShape" in your scene you can do this:
 // get the 1 shape we expect.
var houseShape = scenePack.getObjects("houseShape", "o3d.Shape")[0];

The next thing to be aware of is that Shapes are made from Primitives. The point of having both Shapes and Primitives is that most modeling packages let you put more than one material on a particular model. For example you could make a house and texture the walls with one material and the roof with a different material. If that was one shape in the modeler, it would load as one shape in O3D with 2 primitives. The sample o3dCoverter takes the names of the materials and appends them to the name of the shape to make the names of the primitives. Assuming the name of the house shape was "houseShape", the primitives will be named "houseShape|roof_material" and "houseShape|wall_material".

Primitives can be found similarly to how we found previous objects.
 // get the 1 primitive we expect.
var housePrimitives =
scenePack.getObjects("houseShape|roof_material", "o3d.Shape")[0];

Or probably more useful, assuming we have already found the shape for the house following the methods above we can use:
 var housePrimitives = houseShape.elements;
for (var ii = 0; ii < housePrimitives.length; ++ii) {
var primitive = housePrimitives[ii];
...
}

I hope this makes things a little clearer. It would be really awesome if some of you will take up the challenge and go off and make some improved exporters, better converters and better loaders that provide even more solutions. We've heard from the community that a custom Blender exporter is being worked on. We'd love to see exporters for other modeling packages that take advantage of the specific strengths and features of those packages.

If there is anything you'd like to us to post about or other questions you have please join us in the o3d discuss group. We really appreciate your ideas and feedback.