带有 Scene Kit 相机的鱼眼广角镜头:可能吗?

Fish Eye Wide-angle with a Scene Kit Camera: Possible?

如何使用 Scene Kit 中的 SCNCamera 获得像鱼眼镜头对视图所做的那样的失真?

像这样的 "bowing" 图像:

// 正如 Rickster 指出的那样,这种失真被称为 "Barrel Distortion"。

从文档中,这是让我对使用相机进行这种失真的可能性感兴趣的部分:

If you compute your own projection transform matrix, you can use this method to set it directly, overriding the transformation synthesized from the camera’s geometric properties.

不幸的是,我对计算自己的投影变换矩阵的能力和可能性一无所知。我希望可以通过它进行这种失真……但不知道,因此才有了这个问题。

通过相机的任何其他方式都是理想的。也。希望避免 post 处理技巧,并在相机旋转和移动通过场景时获得更多 "organic" 这种失真的外观。

查看任何滑板视频,了解这在现实生活中的样子。

您要找的是 Barrel Distrortion。

有几种方法可以做到这一点,所有方法都使用 GLSL 着色器。

您可以使用经典的 OpenGL 代码,例如用于 Occulus Rift 的 this example(您需要稍微更改着色器),或者我个人最喜欢的代码:SCNTechnique.

创建一个包含桶形片段着色器 (.fsh) 的技术,并将其 draw 参数设置为 DRAW_QUAD。然后,只需将此技术应用到您的相机即可。

您可以在此处找到桶形失真着色器的示例:http://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/2/


编辑:这是一个示例代码:

barrel.json(这应该放在你的 scnassets 包中)

{
  "passes" : {
    "barrel" : {
      "outputs" : {
        "color" : "COLOR"
      },
      "inputs" : {
        "colorSampler" : "COLOR",
        "noiseSampler" : "noiseSymbol",
        "a_position" : "a_position-symbol"
      },
      "program" : "art.scnassets/barrel",
      "draw" : "DRAW_QUAD"
    }
  },
  "sequence" : [
    "barrel"
  ],
  "symbols" : {
    "a_position-symbol" : {
      "semantic" : "vertex"
    },
    "noiseSymbol" : {
      "image" : "noise.png",
      "type" : "sampler2D"
    },
    "barrelPower" : {
      "type" : "float"
    }
  }
}

barrel.vsh

attribute vec4 a_position;
varying vec2 uv;

void main() {
    gl_Position = a_position;
    uv = a_position.xy;
}

barrel.fsh

// Adapted from :
// http://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/2/

uniform sampler2D colorSampler;
const float PI = 3.1415926535;
uniform float barrelPower;

varying vec2 uv;


vec2 Distort(vec2 p)
{
    float theta  = atan(p.y, p.x);
    float radius = length(p);
    radius = pow(radius, barrelPower);
    p.x = radius * cos(theta);
    p.y = radius * sin(theta);
    return 0.5 * (p + 1.0);
}


void main() {

    vec2 rg = 2.0 * uv.xy - 1.0;
    vec2 uv2;
    float d = length(xy);
    if (d < 1.0){
        uv2 = Distort(xy);
    }else{
        uv2 = uv.xy;
    }

    gl_FragColor = texture2D(colorSampler, uv2);
}

something.m

NSURL *url = [[NSBundle mainBundle] URLForResource:@"art.scnassets/barrel" withExtension:@"json"];
NSDictionary *tecDic = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL: url] options:nil error:nil];

SCNTechnique* technique = [SCNTechnique techniqueWithDictionary:tecDic];

[technique setValue: [NSNumber numberWithFloat:0.5]  forKey:@"barrelPower"];


cameraNode.technique = technique;