我需要将长图像扭曲成2d圆圈(webGL)。预计会出现失真

时间:2014-09-15 19:17:51

标签: javascript three.js

我需要拍摄长(最大分辨率)图像并将其包装成圆圈。因此,想象一下弯曲钢筋,使其现在呈圆形,每端接触。

quick and dirty illustration

在过去的8个小时里,我一直在对着三个人进行撞击,并且到目前为止已经设法将图像作为纹理应用于圆形几何体,但是无法弄清楚如何将纹理应用于长网格然后适当地扭曲网格。翘曲不需要(也不应该)动画。我们基本上拥有360度全景图像,我们需要“平坦化”#34;进入一个自上而下的视图。

代替共享我的代码(因为它没有显着不同),我到目前为止一直在玩这个教程:

http://www.johannes-raida.de/tutorials/three.js/tutorial06/tutorial06.htm

我(我认为)在这一点上理解了广泛的笔触。

我尝试过的其他事情就是只使用画布将图像切成条状并扭曲每个条带......这非常慢,我也无法正常工作!

任何帮助/建议?

2 个答案:

答案 0 :(得分:2)

这里还有一个着色器版本:Shadertoy - Circle Distortion

这是实际代码:

#define dPI 6.28318530718   // 2*PI
#define sR 0.3              // small radius
#define bR 1.0              // big radius

void main(void)
{
// calc coordinates on the canvas
    vec2 uv = gl_FragCoord.xy / iResolution.xy*2.-vec2(1.);
    uv.x *= iResolution.x/iResolution.y;

// calc if it's in the ring area
    float k = 0.0;
    float d = length(uv);
    if(d>sR && d<bR)
        k = 1.0;

// calc the texture UV
    // y coord is easy, but x is tricky, and certain calcs produce artifacts
    vec2 tUV = vec2(0.0,0.0);

    // 1st version (with artifact)
    //tUV.x = atan(uv.y,uv.x)/dPI;

    // 2nd version (more readable version of the 3rd version)
    //float disp = 0.0;
    //if(uv.x<0.0) disp = 0.5;
    //tUV.x = atan(uv.y/uv.x)/dPI+disp;

    // 3rd version (no branching, ugly)
    tUV.x = atan(uv.y/uv.x)/dPI+0.5*(1.-clamp(uv.x,0.0,1.0)/uv.x);

    tUV.y = (d-sR)/(bR-sR);

// output pixel
    vec3 col = texture2D(iChannel0, tUV).rgb;
    gl_FragColor = vec4(col*k,1.);
}

因此,您可以在画布上绘制矩形并添加此着色器代码。

我希望这会有所帮助。

答案 1 :(得分:1)

所以这是一个使用canvas的context2d来完成这项工作的功能。

这个想法是通过一个小的角度步骤绕过所有的圆圈,并绘制一小片纹理&#39;沿圆半径。

为了让它变得更快,我所看到的只是手动计算变换来做一个单一的setTransform而不是所有这些东西。
步数是最佳的,步长= atan(1,半径)
(如果你做的计划很明显:当你偏离中心时半径向上,然后tan = 1 / radius =&gt; step angle = atan(1,radius)。)< / p> 小提琴在这里: http://jsfiddle.net/gamealchemist/hto1s6fy/

阴天景观的一个小例子:

enter image description here

// draw the part of img defined by the rect (startX, startY, endX, endY) inside 
//   the circle of center (cx,cy) between radius (innerRadius -> outerRadius) 
// - no check performed -
function drawRectInCircle(img, cx, cy, innerRadius, outerRadius, startX, startY, endX, endY) {
    var angle = 0;

    var step = 1 * Math.atan2(1, outerRadius);
    var limit = 2 * Math.PI;

    ctx.save();
    ctx.translate(cx, cy);
    while (angle < limit) {
        ctx.save();
        ctx.rotate(angle);
        ctx.translate(innerRadius, 0);
        ctx.rotate(-Math.PI / 2);
        var ratio = angle / limit;
        var x = startX + ratio * (endX - startX);
        ctx.drawImage(img, x, startY, 1, (endY - startY), 0, 0, 1, (outerRadius - innerRadius));
        ctx.restore();
        angle += step;
    }
    ctx.restore();
}