歪曲収差

歪曲収差は、ザイデル収差の一種であり、要約してしまえば、像を陣笠に歪ませる効果と言える。今回は、写像に対し、この歪曲収差を反映させる実装、およびその結果を示す。

中心座標を \(cx\) と \(cy\)、対象座標を \(px\) と \(py\) とした場合、中心からの距離 \(d\) は

$$ d = \sqrt{ (px - cx)^2 + (py - cy)^2 } $$

で求まる。

また、単位半径の半球面で考えると、対象座標の奥行 \(pz\) は

$$ pz = \sqrt{ 1.0 - d^2 } $$

になることがわかる。

奥行に対する角度 \(\theta\) は

$$ \theta = \arctan \frac{d}{dz} $$

になるため、\(xy\) 平面における半径 \(r\) を

$$ r = \frac{\theta}{\pi} $$

と仮定する。

距離 \(d\) の \(x\) 成分 \(dx\) と \(y\) 成分 \(dy\) から、\(xy\) 平面における角度 \(\phi\) は

$$ \phi = \arctan \frac{dy}{dx} $$

になる。

この時点で、\(xy\) 平面における半径と角度が判明しているため、極座標系で示すことができる。

最終的には、極座標系ではなく、直交座標系で考えればよいので

$$ px' = r \cos \phi $$ $$ py' = r \sin \phi $$

により、歪曲収差後の座標 \(px'\) と \(py'\) が求まる。

以上の計算から

のように歪ませることが期待できる。

実装

通常のカメラ映像をバッファにレンダリングしておき、そのバッファに対して画像処理を施す、いわゆるポストエフェクトとして実装する。今回の歪曲収差効果において、頂点パイプラインでは、通常の MVP 変換行列をかけているだけであり、画素パイプラインで前述のアルゴリズムに従い計算を行う。下記は、WebGL (GLSL) の実装例になる。

頂点処理

varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

画素処理

varying vec2 vUv;
uniform sampler2D inputBuffer;
void main() {
    vec2 coord = vUv * 2.0 - 1.0;
    float d = length(coord);
    if (d > 1.0) {
        gl_FragColor = vec4(texture2D(inputBuffer, vUv).rgb * 0.25, 1.0);
        return;
    }
    float r = atan(d, 1.0 - dot(coord, coord) * 0.5) / 3.1415926;
    float phi = atan(coord.y, coord.x);
    coord = vec2(cos(phi), sin(phi)) * r;
    gl_FragColor = texture2D(inputBuffer, coord + 0.5);
}

結果

下記のボタンで WebGL (GLSL) の実装例の結果が確認できる。