Canvas 3d JS Library

WebGL made easy!
  • rss
  • What is C3DL?
  • Download
  • Tutorials
    • Tutorial #1: WebGL Browsers
    • Tutorial #2: A simple scene
    • Tutorial #3: Callback
    • Tutorial #4: Models
    • Tutorial #5: Light effects
    • Tutorial #6: Picking
  • Development News
  • Documentation
  • Community
  • Resources
  • Contact
  • About

Some time ago we had a demo that would give a 3D representation of routes obtained from the Google maps api, along with some points of interest the user could search for (like coffee shops). While the library keeps getting updated, this demo did not, and no longer worked on systems running recent versions of the library. This was unfortunate as the demo showed some neat applications for C3DL, so we decided to resurrect it.

Having never seen the original working, I had a difficult decision to make. Do I update the existing code to work with the newer versions of the library? Or do I write a new demo from scratch? In theory the update should have been the easier route, but it was using code that had been rendered obsolete before I joined this project. Instead of learning an outdated version of the library to update one demo, I kept only the basis of the code (mostly the interaction with the Google Maps API), and wrote most of the rest. As the demo progressed we had several ideas about things to be improved or added. For example, each of those points of interest gets a little 3D model (a tetrahedron for now) to show where it is, but we realized it would be better if the user could click on that point of interest and find out what it is, what the address is etc., so now you get a pop-up with the name, address and phone-number of the point.

Without further ado, here’s a picture of (and link to) the demo:

mapsInAction

I did have to limit the number of roads that are visible at one time, and only show points of interest that are close by, just to reduce the strain on the system (A trip from Toronto to Vancouver involves a lot of roads and an extraordinary number of coffee shops).

There are a few things that I’d like to improve on when the opportunity presents itself, or would be happy to see other people try.

  • This uses an old version of Google’s API. It would be nice to bring it up to version 3.
  • The overhead compass would look nicer if it was partially transparent (So you could see the letters indicating the directions, but not the rectangle they sit on). While this concept is supported by OpenGL and the png format, support for it isn’t in the library yet.
  • The tetrahedron’s that indicate points of interest work, but a better model would make the demo look nicer.
  • A road model that was more than just a flat rectangle could make the demo look nicer too.
  • When you click on a point of interest, it causes a pop-up with information about that location, instead it would be nice to have that information appear as floating text in the canvas, so it doesn’t interrupt the demo.
  • It would also be nice to get elevation data, but the Google Maps API doesn’t provide it, so it would have to come from somewhere else. Then we could make the roads go up and down with the elevation instead of assuming the world is perfectly flat. That would require a little extra code to accommodate the new data, but most of the hard calculations are already done.
  • The overhead compass often misses getting drawn when the page first loads, but will show up on a refresh. This is peculiar as the code is supposed to wait until all models are loaded before it actually starts.

When I first started work on porting the C3DL library from using Canvas 3D to WebGL, I ran into a problem with instanceof. In a particular line of code, I check if an object is an instance of a type. It always worked on Firefox 3.5 using Canvas 3D and everything renders properly. However, using Firefox 3.7a1pre, the conditional evaluated to false. I commented the line and I continued working eventually getting something drawn. I did this by adding ID’s to most of the C3DL classes as well as a getObjectType() function. This was simply a workaround so I could focus on more important tasks. This week I went back to the instanceof problem. I needed an isolated case to see if perhaps the library was at fault, so I wrote a short script in an HTML file. I found that on Firefox 3.5, it worked fine, but on Firefox 3.7a1pre, it didn’t. After mentioning this in #seneca on irc.mozilla.org, Chris Tyler suggested I file the bug. So I did. The next morning I continued to work on the bug. After talking with a number of people on IRC, I learned a few things. There is a JavaScript shell available when you check out the Firefox source. On my machine I found it at
mozilla-central/obj-ff-dbg/dist/bin/js
I started the shell and tried the folowing:
macbook-pro:bin andor$ ./js
js> var ns = {};
js> ns.test = function(){};
(function () {})
js> var iTest = new ns.test();
js> print(iTest instanceof ns.test);
false
Still false. I decided to update my repository and rebuild. Maybe the issue was already resolved and only existed for a few days? I went back to my console and updated.
hg pull
I then did a full build.
make -f client.mk build
The first thing I noticed is that the small icons in each tab are now cute little progress bars. progress bar Back to the issue, I ran the test again and it still fails. I’m pretty much stuck and this point in regards to the bug. I’ll either have to wait for someone else to confirm or I may try on another system. While I wait for that, I’ll be returning my attention back to porting to WebGL. As promised, I posted the updated orbiter demo which works with the 1.1 version of our library. The old version of the demo used a zoom() method which I thought should be divided into two functions: goCloser() and goFarther(). In my last post, I managed to get our library to run without crashing using WebGL. After playing with the code a bit more, I was able to render untextured models. Clearing the color buffer and now untextured models. I would say progress isn’t too bad. duck Today I sat down and started cleaning up the code and I focused on getting points to render. I figured using VBOs to render points would give me some practice before trying to apply them to more difficult situations, such as with COLLADA files. COLLADA models load, but the VBO code isn’t in the right place. With a bit of effort, I managed to render the points just like we used to with the Canvas 3D plug-in. mocap I experimented with the different types of buffer usages (static, dynamic and stream drawing). I didn’t see any performance change. Albeit, this is probably because I have to specify the data for each frame. When rendering COLLADA models, the data won’t change per frame and we may see a performance increase. C3DL currently uses the Canvas3D plug-in. If a user wants to see any of our demos run in the browser, they’ll need to install the plug-in. Canvas3D is precursor to WebGL, which was recently added to the Mozilla nightly trunk and will soon be included in a future release of Firefox. Therefore, we need to update our library so demos will run without requiring any plug-ins.
Before I started to update the library, I took another look at Vlad’s spore creature viewer. I noticed he was using VBOs. This is interesting because when I tried using them in C3DL a while ago, I didn’t experience any performance increase I should have. Maybe there was an issue and it was resolved? I’ll come back to VBOs in a later blog.
On my system I have Firefox 3.0.13, 3.5.3 and 3.7a1pre. I’ll be using the two latest versions to get this going. I use the Canvas3D plug-in with 3.5. Firefox 3.7 is endowed with the awesomeness of WebGL, so it should be enough to run some of my local C3DL demos. Theoretically, the only line which needs changing is the line which acquires the rendering context. Unfortunately, you’ll see how that’s not the case.
So I opened up the C3DL rendering file and updated how the library acquires a rendering context:
try
{
  // Does the user have the Canvas3D plugin?
  glCanvas3D = cvs.getContext('moz-glweb20');
}
catch (err)
{
  glCanvas3D = null;
}
if(!glCanvas3D)
{
  try
  {
    // Does the user have a browser that supports WebGL?
    // If so, use that instead.
    glCanvas3D = cvs.getContext('moz-webgl');
  }
  catch (err)
  {
    glCanvas3D = null;
  }
}
I started Minefield (3.7) and tried to open a demo. I immediately received a C3DL error. This is a bit odd because the conditional below returns true on 3.5 and false on 3.7.
if(effectTemplate instanceof c3dl.EffectTemplate){...}
I decided to make the conditional pass regardless, since I knew for a fact effectTemplate WAS an instaceof c3dl.EffectTemplate. At the same time I thought it would be nice to have a JavaScript debugger in case I need it. Unfortunately, I didn’t find a compatible version of Firebug for 3.7 and I didn’t know how to use Venkman after I had installed it. I was a bit impatient so I just used printf equivalents.
c3dl.debug.logInfo("I'm running");
After forcing the conditional to pass, I tried my code again and got the following error in the Firefox console:
Error: uncaught exception: [Exception... "Not enough arguments 
[nsICanvasRenderingContextWebGL.uniformMatrix4fv]"  nsresult: 
"0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)"  location: 
"JS frame :: file:///Users/andor/Documents/Canvas3D/canvas3dapi/
renderer/rendereropengles20.js :: anonymous :: line 985"  data: no]
It looked like it was blowing up on this line:
glCanvas3D.uniformMatrix4fv(varLocation, matrix);
I checked out the WebGL IDL file and it had the function defined as such:
void uniformMatrix4fv (in GLint location, in GLboolean transpose, 
in nsICanvasArray value);
It seemed some things have been changed since Canvas3D. I only needed to add another parameter, but decided to comment out the line and see what other functions changed.
I got this exception next:
Error: uncaught exception: [Exception... "Component returned failure code: 
0x80004005 (NS_ERROR_FAILURE) [nsICanvasRenderingContextWebGL.
vertexAttribPointer]" nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: 
"JS frame :: file:///Users/andor/Documents/Canvas3D/canvas3dapi/shaders/
model/standard/std_callback.js :: anonymous :: line 66"  data: no]
My code:
glCanvas3D.vertexAttribPointer(normalAttribLoc, 3, glCanvas3D.FLOAT, false, 
0, currColl.getNormals());
No data exists in currColl.getNormals()? I know it still works with 3.5, Commented. Next I got this one:
Error: uncaught exception: [Exception... "Could not convert JavaScript 
argument arg 1 [nsICanvasRenderingContextWebGL.bindTexture]"  nsresult: 
"0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)"  location: "JS frame :: 
file:///Users/andor/Documents/Canvas3D/canvas3dapi/shaders/model/
standard/std_callback.js :: anonymous :: line 110"  data: no]
It was happening on this line:
glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D,-1);
Here I bind to an invalid texture object in case an object isn’t textured. This prevents the last active texture from being used by this object. Commented.

Next one.
Error: uncaught exception: [Exception... "Component returned failure code: 
0x80004005 (NS_ERROR_FAILURE) [nsICanvasRenderingContextWebGL.
vertexAttribPointer]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: 
"JS frame :: file:///Users/andor/Documents/Canvas3D/canvas3dapi/renderer/
rendereropengles20.js :: anonymous :: line 950"  data: no]
The code:
this.setVertexAttribArray = function(shader, varName, size, array)
{
    let attribLoc = glCanvas3D.getAttribLocation(shader, varName);
    if(attribLoc != c3dl.const.SHADER_VAR_NOT_FOUND)
    {
        // This line is blowing up.
        // glCanvas3D.vertexAttribPointer(attribLoc, size, glCanvas3D.FLOAT, false, 0, array);
        glCanvas3D.enableVertexAttribArray(attribLoc);
    }
    else
    {
        c3dl.debug.logError('Attribute variable "' +  varName + '" not found in shader with ID = ' + shader);
    }
}
This is a wrapper I wrote to make the C3DL code a bit cleaner, since the third, fourth and fifth parameters always had to be the same. Commented.

The next line wasn’t really a surprise. There are enough changes to the library now that this is expected.
No VBO bound to index 0 (or it's been deleted)!
Error: uncaught exception: [Exception... "Component returned failure code: 
0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsICanvasRenderingContextWebGL.
drawArrays]"  nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)"  location:
 "JS frame :: file:///Users/andor/Documents/Canvas3D/canvas3dapi/
shaders/model/standard/std_callback.js :: anonymous :: line 120"  data: no]
My line:
glCanvas3D.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().
length/3);
Commented, next.
No VBO bound to index 0 (or it's been deleted)!
Error: uncaught exception: [Exception... "Component returned failure code: 
0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsICanvasRenderingContextWebGL.
drawArrays]"  nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)"  location: 
"JS frame :: file:///Users/andor/Documents/Canvas3D/canvas3dapi/renderer/
rendereropengles20.js :: anonymous :: line 928"  data: no]
This is because I’m running a mocap demo and I’m rendering points.
glCanvas3D.drawArrays(c3dl.const.FILL,0, 
(c3dl.const.POINT_VERTICES.length)/3);
Again, I commented the line and finally got an interesting one:
Error: glCanvas3D.swapBuffers is not a function
Source File: file:///Users/andor/Documents/Canvas3D/canvas3dapi/renderer/
rendereropengles20.js
Line: 222
I first thought the name might have changed to SwapBuffers (uppercase ‘S’). I looked up the API and saw it was no longer present. This had to be a mistake. I need to tell OpenGL when the backbuffer should be swapped with the front buffer. I commented it and that’s when the errors ceased. I saw the FPS changing on my page, but the context was white. I should have been blue. snapshot-2009-09-29-23-09-49 I was pretty excited since I was sure that now I had to be getting a graphics context, but the context should have been colored blue. Was it really working? Something was wrong. I sat thinking about it and thought no rendering was happening because I commented out the swapBuffers() call. It’s probably drawing to the backbuffer and not swapping to the front. I went back to Vlad’s spore creature viewer demo and poked around wondering how he was doing it. I saw there weren’t any call to swapBuffers. The only lines that gave a hint were:
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, numVertexPoints);
He’s clearing the color and depth buffer in one call and drawing what he needs. I couldn’t argue with the code since it was working and mine wasn’t. I was a bit stuck. I turned to my IRC client and pinged joe, mark, dave. Bas and mstange also got involved, trying to help out too. Thanks guys! So I was told that the swapping is probably happening automatically. I decided this is something I can accept since Firefox is now handling the rendering. It uses double buffering to display the content, probably does the same with the canvas. Still, I couldn’t get the canvas to change color.
I thought I would then try to set the clear color and do a clear right after I got the graphics context. No other C3DL code would execute in between. I thought it might be worth a try…
glCanvas3D = cvs.getContext('moz-webgl');
glCanvas3D.clearColor(0,1,0,1);
glCanvas3D.clear(glCanvas3D.COLOR_BUFFER_BIT);
It worked! snapshot-2009-09-29-22-49-07 I admit, my demo is not quite as impressive as Vlad’s demo, but hey, I have something!
Next, I’ll have to address all those functions which have different signatures and find out what is preventing the framebuffer from being cleared.

Videos

Demos

  • Asteroids-3D
  • Particle Systems Demo
  • Cross-Browser Orbiter
  • Mocap Demo With Spheres
  • Google Maps-3D

C3DL Development News

C3DL 2.0-WebGL and beyond

It has been a long time coming but we have now updated all the core features of C3DL to use WebGL. You can dowload our 2.0 release here. We have also updated all our demos to use WebGL. Our tutorials have all been updated (tutorial 5 and 6 needs a better example [...]

Preliminary WebGL RTS Game

Cathy asked me to make a cool demo using our library. After thinking about, I started getting many ideas, but creating a preliminary real-time strategy game made the most sense. It not only demonstrates a lot of C3DL features such as model loading, transformations, lighting, shaders, picking, cameras, textures, etc, but since animation is kept [...]

Tutorials

  • Tutorial #1: WebGL Browsers
  • Tutorial #2: A simple scene
  • Tutorial #3: Callback
  • Tutorial #4: Models
  • Tutorial #5: Light effects
  • Tutorial #6: Picking

Documentation

Archives

Archives

C3DL Development News

Recent Comments

  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • C3DL 2.0-WebGL and beyond
  • Preliminary WebGL RTS Game
  • Asteroids in 3D… and a bit of 2D
  • Another demo updated
  • Simplifying the Interface
  • Updating Demos
  • Cross-browser progress update
  • let there be vars
  • Creating tester pages
  • Problems with porting
  • keep it coming ve... - gero3
  • congrats on a great... - Paul Brunt
  • c++ not c# actually... - Cathy Leung
  • It's unbelievable ho... - Paul
  • Wow, now that's a co... - Andor Salga
  • Hi, is the project... - Sascha Hendel
  • I agree with both co... - Cathy Leung
  • Your library is real... - Sascha Hendel
  • Hi, as a more gener... - Sascha Hendel
  • Thanks. I just pull... - peter



Canvas 3d JS Library

©2007- 2009 Canvas 3d JS Library

Disclaimer: This website is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 Canada License.
The Canvas 3d JS Library and Demos found on this website are licenced under the MIT License

Creative Commons License