在SceneKit中模拟折射 [英] Simulating refraction in SceneKit

查看:92
本文介绍了在SceneKit中模拟折射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为一个项目创建ios 9应用程序,该应用程序将使用称为

I am trying to create an ios 9 app for a project which will visualise 3d scenes with these special kind of theoretical lenses called glenses.

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

A ray tracing program called TIM has already been written from the ground up for simulating these glenses and more, but it's infeasable to simply port this to ios.

根据我对网站的搜索(例如,答案以及其他有关着色器的理解) )是应该的,但我很难获得理想的效果.

My understanding from searching the site (i.e. this answer and many others on shaders) is that it should be possible but I'm having a hard time getting the desired effect.

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

I decided that I would start by implementing a simpler form of refraction first before moving onto the more complex glens type refraction:

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

I was able to get a barrel distortion (fish eye lens) effect working on the camera using SCNTechnique, however it seems you can only use techniques on the camera or the whole scene, not individual pieces of geometry.

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

After that I tried to get the barrel distortion effect applied to the geometry by injecting opengl code using the SCNMaterial's shaderModifiers property:

    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]

我使用了在这里找到的着色器:

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);

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

These shaders compile and are loaded onto my object in the scene but do nothing; the object is opaque and white when it is nearly transparent without the injected shaders, and the #pragma transparent directive should make it transparent anyway.

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

To make it clear, what I'm trying to achieve here is having a 3d lens in a scene which you can look through and see the refracted image of whatever is on the other side.

任何帮助将不胜感激!

推荐答案

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

If you want to use your own vertex and fragment shader instead of SceneKit default shader program, you have too use SCNProgram instead of SCNShaderModifierEntryPoint.

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

SCNShaderModifierEntryPoints are only allow to modify default shader program of 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

这篇关于在SceneKit中模拟折射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆