伪造在画布的3d球形

时间:2012-06-25 13:19:32

标签: javascript image canvas

我有一个关于在HTML5 / Canvas / Javascript中伪造3D的问题......

基本上,我使用<canvas>drawImage()上绘制了一张二维图像。
我想做的是绘制图像,然后将球体上的纹理移动到...... 球状 ...

为清晰起见,请参见下图:

Spherise in Javascript

有什么想法吗?

我已经用谷歌搜索了自己近乎死亡的事情,不能成为WebGL,因为它必须在手机上工作......有没有办法做到这一点?

2 个答案:

答案 0 :(得分:5)

您可以在此处查看工作原型:http://jsbin.com/ipaliq/edit

我敢打赌,优化和更好/更快算法的空间很大,但我希望这个概念证明可以指出你正确的方向。

基本算法遍历原始图像的每个像素,并在其受到球面变形时计算其新位置。

结果如下:

Sphere

代码:

var w = 150, h = 150;
var canvas=document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");
    ctx.fillStyle="red";
    ctx.fillRect(0,0,w,h);

//-- Init Canvas
var initCanvas = function()
{
  var imgData=ctx.getImageData(0,0,w,h);
  for (i=0; i<imgData.width*imgData.height*4;i+=4)
  {
    imgData.data[i]=i%150*1.5;
    imgData.data[i+1]=i%150*1.5;
    imgData.data[i+2]=(i/imgData.width)%150*1.5;
    imgData.data[i+3]=255;
  }
  ctx.putImageData(imgData,0,0);
};
initCanvas();

var doSpherize = function()
{
    var refractionIndex = 0.5; // [0..1]
        //refraction index of the sphere
    var radius = 75;
    var radius2 = radius * radius;
    var centerX = 75; 
    var centerY = 75; 
        //center of the sphere
    var origX = 0;
    var origY = 0;


    for (x=0; x<w;x+=1)
    for (y=0; y<h;y+=1)
    {
        var distX = x - centerX;
        var distY = y - centerY;

        var r2 = distX * distX + distY * distY;

        origX = x;
        origY = y;

        if ( r2 > 0.0 && r2 < radius2 )
        {
            // distance
            var z2 = radius2 - r2;
            var z = Math.sqrt(z2);

            // refraction
            var xa = Math.asin( distX / Math.sqrt( distX * distX + z2 ) );
            var xb = xa - xa * refractionIndex;
            var ya = Math.asin( distY / Math.sqrt( distY * distY + z2 ) );
            var yb = ya - ya * refractionIndex;

            // displacement
            origX = origX - z * Math.tan( xb );
            origY = origY - z * Math.tan( yb );
        }

      // read
      var imgData=ctx.getImageData(origX,origY,1,1);
      // write
      ctx.putImageData(imgData,x+w,y+h);
    }
};
doSpherize();

注意

我会再次建议在没有webGL像素着色器的情况下由前端传递如此强烈的操作。这些都是非常优化的,并且能够利用GPU加速。

答案 1 :(得分:0)

你绝对可以做这样的事情。我不确定质量和速度是否足够好,特别是在移动设备上。

你想要getImageData像素,对它们进行一些我暂时无法想到的数学变换,然后putImageData它们回来。

它可能看起来有点模糊或像素化(你可以尝试插值,但这只会让你到目前为止)。并且您可能必须大大优化您的JavaScript,以便在合理的时间内在移动设备上完成。

转换可能类似于反方位投影。