我正在尝试为一个项目创建ios 9应用程序,该应用程序将使用称为glenses的特殊理论镜头将3d场景可视化。

已经从头开始编写了一个名为TIM的光线跟踪程序来模拟这些杂讯,甚至更多,但是将其简单地移植到ios是不可行的。

通过搜索该网站(即this答案以及着色器上的许多其他内容),我的理解是应该有可能,但我很难获得理想的效果。

我决定先开始实现更简单的折射形式,然后再转向更复杂的glens类型的折射:

我可以使用SCNTechnique在相机上获得桶形失真(鱼眼镜头)效果,但是似乎只能在相机或整个场景上使用技巧,而不能在单个几何体上使用。

之后,我尝试通过使用SCNMaterialshaderModifiers属性注入(inject)opengl代码来获得应用于几何体的桶形失真效果:

    var shaders = [SCNShaderModifierEntryPoint: String]()

    try! shaders[SCNShaderModifierEntryPoint.fragment] = String(contentsOfFile: Bundle.main.path(forResource: "FishEye", ofType: "fsh")!, encoding: String.Encoding.utf8)

    try! shaders[SCNShaderModifierEntryPoint.geometry] = String(contentsOfFile: Bundle.main.path(forResource: "FishEye", ofType: "vsh")!, encoding: String.Encoding.utf8)

    let material = SCNMaterial()
    material.shaderModifiers = shaders
    object.geometry?.materials = [material]

我使用发现了here的稍微修改的着色器:
fisheye.vsh
varying vec2 uv;

#pragma body

gl_Position = a_position;
uv = a_position.xy;
fisheye.fsh
uniform sampler2D colorSampler;
const float PI = 3.1415926535;
const float barrelPower = 0.5;
uniform vec2 rg;
uniform vec2 uv2;
varying vec2 uv;
uniform float d;
uniform vec2 xy;
uniform vec2 Vertex_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);
}

#pragma body
#pragma transparent

vec2 xy = 2.0 * Vertex_UV.xy - 1.0;
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);

这些着色器可以编译并加载到场景中的我的对象上,但不执行任何操作。当对象没有注入(inject)的着色器时几乎是透明的时,该对象是不透明的并且是白色的,并且#pragma transparent指令无论如何都应该使其透明。

为了清楚起见,我要在此处实现的目标是在场景中安装3d镜头,您可以透过它查看并看到另一侧的折射图像。

任何帮助将不胜感激!

最佳答案

如果要使用自己的顶点和片段着色器而不是SceneKit默认着色器程序,则也可以使用SCNProgram而不是SCNShaderModifierEntryPoint。

SCNShaderModifierEntryPoints仅允许修改Swift的默认着色器程序。

let material = SCNMaterial()
            let program:SCNProgram = SCNProgram()
            do {
                program.vertexShader = try String(contentsOfFile: Bundle.main.path(forResource: "fisheye", ofType: "vsh")!, encoding: String.Encoding.utf8)
            } catch let error {
                print("shaderReadingError:\(error)")
            }
            do {
                program.fragmentShader = try String(contentsOfFile: Bundle.main.path(forResource: "fisheye", ofType: "fsh")!, encoding: String.Encoding.utf8)
            } catch let error {
                print("shaderReadingError:\(error)")
            }

    // and also your vertex shader has lack.
    // You have to add some geometry source and transformation matrix to the vertex shader first with setSemantic method.

            program.setSemantic(SCNGeometrySource.Semantic.vertex.rawValue, forSymbol: "vPosition", options: nil)
            program.setSemantic(SCNGeometrySource.Semantic.texcoord.rawValue, forSymbol: "uv", options: nil)
            program.setSemantic(SCNModelViewProjectionTransform, forSymbol: "uMVPMatrix", options: nil)





    // and also your fragment shader expect some realtime data like
    // colorSampler, rg, uv2, d, xy, Vertex_UV
    // you have to use handleBinding block to update this values before rendering the object.
            material.handleBinding(ofSymbol: "resolution", handler: { (programId:UInt32, location:UInt32, node:SCNNode?, renderer:SCNRenderer) in


            })


            material.program = program
            yourNode.geometry.firstMaterial = material

关于ios - 在SceneKit中模拟折射,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40381638/

10-14 08:44