Tuesday, April 14th, 2009

Metatunnel: The (Future) Web Strikes Back

Category: Canvas, Fun

Last week, we posted a story on the Metatunnel demo, a concisely-written Linux and Win32 demo that Paulo Falcão ported to JS. We looked at the pitiful performance of the JS version as evidence that, high-speed JS engines notwithstanding, the web’s got a ways to go on the fx front.

We didn’t dig deep enough.

Someone posted a follow-up to our story saying that the JS code was poorly optimized and that the JS version could be made to run faster. That got me wondering how efficient the desktop version was, and how apples-to-apples the versions were in terms of total calculations performed per frame. My thinking was that if the JS version could be made faster but via optimization contortions that the desktop version didn’t require, that’s missing the point.

It turns out the desktop source is trivial: it’s an assembler bootstrap for passing OpenGL shader instructions to the system’s OpenGL driver:

  1. // we don't have a "shader" syntax highlighting;
  2. // using "Java" instead :-)
  3. vec2 v=(gl_FragCoord.xy-vec2(400,300))/vec2(400,300);
  4. float w=dot(gl_Color.xyz,vec3(1,256,65536))*.25;
  5. const float s=0.4;
  7. float obj(vec3 pos){
  8.     float final=1.0;
  9.     final*=distance(pos,vec3(cos(w)+sin(w*0.2),0.3,2.0+cos(w*0.5)*0.5));
  10.     final*=distance(pos,vec3(-cos(w*0.7),0.3,2.0+sin(w*0.5)));
  11.     final*=distance(pos,vec3(-sin(w*0.2)*0.5,sin(w),2.0));
  12.     final *=cos(pos.y)*cos(pos.x)-0.1-cos(pos.z*7.+w*7.)*cos(pos.x*3)*cos(pos.y*4.)*0.1;
  13.     return final;
  14. }
  16. void main(){vec3 o=vec3(v.x,v.y*1.25,0.0);
  17.     vec3 d=vec3(v.x+cos(w)*.3,v.y,1.0)/64.0;
  18.     vec4 color=vec4(0.0);
  19.     float t=0.0;
  20.     for(int i=0;i<75;i++) {
  21.         if(obj(o+d*t)<s){
  22.             t-=5.0;
  23.             for(int j=0;j<5;j++){
  24.                 if(obj(o+d*t)<s){
  25.                     break;
  26.                 }
  27.                 t+=1.0;
  28.             }
  29.             vec3 e=vec3(0.01,.0,.0);
  30.             vec3 n=vec3(0.0);
  31.             n.x=obj(o+d*t)-obj(vec3(o+d*t+e.xyy));
  32.             n.y=obj(o+d*t)-obj(vec3(o+d*t+e.yxy));
  33.             n.z=obj(o+d*t)-obj(vec3(o+d*t+e.yyx));
  34.             n=normalize(n);
  35.             color+=max(dot(vec3(0.0,0.0,-0.5),n),0.0)+max(dot(vec3(0.0,-0.5,0.5),n),0.0)*0.5;break;
  36.         }
  37.         t+=5.0;
  38.     }
  39.     gl_FragColor=color+vec4(0.1,0.2,0.5,1.0)*(t*0.025);
  40. }

Shoot, passing instructions to the video card? That’s not a fair fight. It turns out Firefox 3.5 has a prototype Canvas 3D plug-in, and it exposes an OpenGL API. It was quick work for one of Mozilla’s graphics gurus and the plug-in’s primary developer, Vlad Vukicevic, to port the Metatunnel demo to Canvas 3D. The result is quite impressive:

See for yourself, but you’ll need Firefox 3.5 Beta 3 or later and the Canvas 3D plug-in.

We should also mention that Paulo, Jacob Seidelin, and Hans Schmucker collaborated on optimizations in the JS software-rendering version that resulted in much higher FPS on “next-gen JS” browsers (Safari 4, Chrome, and Firefox 3.5). Note, on this demo you can use the Q and W keys to adjust quality.

Posted by Ben Galbraith at 7:00 am

2.9 rating from 30 votes


Comments feed TrackBack URI

Haha nice! JS taking names and kicking ass :D

I know that realistically we’re far away from playing canvas based UT in Chrome, but we’re getting there.

Comment by iliad — April 14, 2009

Why does everyone keep referring to Firefox 3.1 as 3.5?

Comment by vvtim — April 14, 2009

Because thats what it’s called:

Comment by TNO — April 14, 2009

This is epic – I’m getting absolutely no lag at all on both versions, and with full antialiasing on the 3D one :D

And my PC is nearly two years old and was only a cheap-ish gaming PC when built.

Comment by Darkimmortal — April 14, 2009

I suspected that the original was deeply unfair as it was probably using the GPU, and I’m glad it seems I was correct. The idea of being able to access the OpenGL API with javascript is very exciting. I look forward to seeing what people accomplish with it — all previous attempts at web-based 3D seem to have been half-baked at best.

Comment by jsutcliffe — April 14, 2009

This is starting to get good! It’d be neat to see how it can look on a JS VM w/ a more incremental GC strategy, though. A big part of why the chromexperiments stuff works so well in Chrome is that the browser isn’t hitting big GC pauses, and I’d love to see that kind of thing applied to demos like this.

Comment by slightlyoff — April 14, 2009

Wow! I was on vacations, and so many stuff happened :) I was also going to port to 3dcanvas, it turns out that vlad himself did the port! Awesome! Very nice work! :)

Comment by PauloFalcao — April 14, 2009

This is looking really promising, time for me to check out Canvas3D in detail. Sadly, I can’t get the demo to run on FF3.5b3 for OS X:

Error: uncaught exception: [Exception… “Component returned failure code: 0x80004005 (NS_ERROR_FAILURE)” nsresult: “0x80004005 (NS_ERROR_FAILURE)” location: “JS frame :: http://people.mozilla.com/~vladimir/misc/metatunnel-3d.html :: go :: line 9″ data: no]

Anyone else having any luck?

Comment by Udo — April 14, 2009

Oh no, I’m sorry: I didn’t realize I had to give explicit permission for the site in the Canvas3D preferences window. It works, beautiful! Around 20% single CPU load on a 2008 Mac Pro…

Comment by Udo — April 14, 2009

Leave a comment

You must be logged in to post a comment.