我正在尝试为一个项目创建一个ios 9应用程序,它将使用这些特殊的理论镜头glenses来显示3D场景。
一个名为TIM的射线追踪程序已经从头开始编写,用于模拟这些格林威尔等等,但简单地将其移植到ios是不可行的。
我从搜索网站(即this答案和其他许多着色器)的理解是它应该是可能的,但我很难获得预期的效果。
我决定在开始进行更复杂的峡谷型折射之前,首先实施一种更简单的折射形式:
我能够使用SCNTechnique
在相机上使用桶形失真(鱼眼镜头)效果,但是看起来你只能在相机或整个场景上使用技术,而不是单个几何体。
之后,我试图通过使用SCNMaterial
的{{1}}属性注入opengl代码来获取应用于几何体的桶形失真效果:
shaderModifiers
我使用了here:
稍加修改的着色器 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);
指令应该使它透明。
为了说清楚,我想在这里实现的是在一个场景中有一个3D镜头,你可以通过它看到另一边的任何东西的折射图像。
非常感谢任何帮助!
答案 0 :(得分:2)
如果您想使用自己的顶点和片段着色器而不是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