Metatunnel in javascript を試してみた

連日の HTML5::Canvas ネタ投下です。Canvasのテストデータに飢えてて、色々と試したりしてます。

Ajaxian で紹介されていた
http://ajaxian.com/archives/metatunnel-1k-demo-js-vs-os

を、所々最適化して、IEでも動くようにしてみたのがこちら、
http://pigs.sourceforge.jp/blog/20090428/Metatunnel.htm

元の js のほぼ1.5倍速で動作するようです。

IE でも一応動きますが、うちの IE6 だと2秒に1フレームしか描画されませんでした。
IEで動かす場合は、先に Silverlight をインストールすることをお勧めします。


Google Chrome だとかなりなめらかに動きます。Opera10α や Firefox3.1β3 もそれなりですね。

元々は、メガデモ(1k) 作品

本来はこのようになめらかな動きをするようです。

これが 1KByte なんてね。ステキすぎます。

ソース

<script type="text/xaml" id="xaml"><?xml version="1.0"?>
  <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas></script> 
<script type="text/javascript" src="uupaa-excanvas.js"></script> 
 
<script type="text/javascript"> 
var time=0;
var sin=Math.sin;var cos=Math.cos;var sqrt=Math.sqrt;
var hex = (function() {
    var rv = [], i, j;
    for (i = 0; i < 16; ++i) {
      for (j = 0; j < 16; ++j) {
        rv[i * 16 + j] = i.toString(16) + j.toString(16);
      }
    }
    return rv;
})();
 
 
function obj(x,y,z,t){
  var f=1.0,_x,_y,_z;
  _x = cos(t)+sin(t*0.2)-x, _y = 0.3-y, _z = 2.0+cos(t*0.5)*0.5-z;
  f*=sqrt(_x*_x+_y*_y+_z*_z)
 
  _x = -cos(t*0.7)-x, _y = 0.3-y, _z = 2.0+sin(t*0.5)-z;
  f*=sqrt(_x*_x+_y*_y+_z*_z)
 
  _x = -sin(t*0.2)*0.5-x, _y = sin(t)-y, _z = 2.0-z;
  f*=sqrt(_x*_x+_y*_y+_z*_z)
 
  f*=cos(y)*cos(x)-0.1-cos(z*7.0+t*7.0)*cos(x*3.0)*cos(y*4.0)*0.1;
  return f;
}
 
function evalColor(x,y,t){
   var vx=x*2.0-1.0; var vy=-y*2.0+1.0;
   var s=0.4;
   var ox=vx;var oy=vy*1.25;var oz=0.0;
   var dx=(vx+cos(t)*0.3)/64.0;var dy=vy/64.0;var dz=1.0/64.0;
   var tt=0.0;
   var g=1.0;
      var _f, _x, _y, _z;
      var _dx, _dy, _dz;
   while((g>s)&&(tt<375)){
      _f = 1.0;
      _x = ox+dx*tt;
      _y = oy+dy*tt;
      _z = oz+dz*tt;
 
      _dx = cos(t)+sin(t*0.2)-_x, _dy = 0.3-_y, _dz = 2.0+cos(t*0.5)*0.5 - _z;
      _f*=sqrt(_dx*_dx+_dy*_dy+_dz*_dz);
      _dx = -cos(t*0.7)-_x, _dy = 0.3-_y, _dz = 2.0+sin(t*0.5) - _z;
      _f*=sqrt(_dx*_dx+_dy*_dy+_dz*_dz);
      _dx = -sin(t*0.2)*0.5-_x, _dy = sin(t)-_y, _dz = 2.0 - _z;
      _f*=sqrt(_dx*_dx+_dy*_dy+_dz*_dz);
      _f*=cos(_y)*cos(_x)-0.1-cos(_z*7.0+t*7.0)*cos(_x*3.0)*cos(_y*4.0)*0.1;
 
      g = _f;
 
      tt+=g*4;
   };
   var color=0.0;
   var dxtt=ox+dx*tt;var dytt=oy+dy*tt;var dztt=oz+dz*tt;
   var objd=obj(dxtt,dytt,dztt,t);
   var nx=objd-obj(dxtt+0.01,dytt,dztt,t);
   var ny=objd-obj(dxtt,dytt+0.01,dztt,t);
   var nz=objd-obj(dxtt,dytt,dztt+0.01,t);
   var d=sqrt(nx*nx+ny*ny+nz*nz);ny=ny/d;nz=nz/d;
     var max1 = -0.5*nz, max2 = -0.5*ny+0.5*nz;
     color+=(max1>0?max1:0)+(max2>0?max2:0)*0.5;
   var r=(color+0.1*tt*0.025);
   var g=(color+0.2*tt*0.025);
   var b=(color+0.5*tt*0.025);
 
  if (r<0) r=0; else if (r>1) r=1;
  if (g<0) g=0; else if (g>1) g=1;
  if (b<0) b=0; else if (b>1) b=1;
//  return ((r*255)&255)+","+((g*255)&255)+","+((b*255)&255);
  return "#"+hex[(r*255)&0xff]+hex[(g*255)&0xff]+hex[(b*255)&0xff];
}
 
var canvas;
var ctx;
function draw(){
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var px, py, maxr=64;
 
        for(x=0;x<maxr;++x){
                px=x/maxr;
                for(y=0;y<maxr;++y){
                        py=y/maxr;
//                      ctx.fillStyle="rgb("+eval(px,py,time)+")";
                        ctx.fillStyle=evalColor(px,py,time);
                        ctx.fillRect(x*2,y*2,2,2);
                }
        }
        time+=0.1;
        setTimeout(draw,1);
};
 
window.onload = function() {
  uuCanvas.ready(function() {
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    draw();
  });
}
</script> 
<canvas id="canvas" width="128" height="128"></canvas>