在SceneKit中使用金属着色器

4

我想使用Metal着色器在场景中应用卡通/背景渲染材料。我正在尝试实现的着色器是苹果自己的AAPLCelShader,可以在MetalShaderShowcase中找到。由于我对在SceneKit中实现着色器还不太熟悉,所以我可能做错了一切。

根据文档,自iOS 9和Xcode 7起,可以使用Metal或GL着色器修改SceneKit渲染。文档建议这样做的方式与GL着色器相同。

我的方法是尝试获取.metal文件的路径,然后将其加载到字符串中以形成[String: String]字典的形式,以便在SCNMaterial shaderModifiers属性中使用,就像使用GL着色器一样(虽然我还没有完全搞清楚如何正确地实现它)。

我的代码如下:

var shaders = [String: String]()
let path = NSBundle.mainBundle().pathForResource("AAPLCelShader", ofType: "metal")!

do{
  let celShader = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
  shaders[SCNShaderModifierEntryPointLightingModel] = celShader
}catch let error as NSError{
  error.description
}
scene.rootNode.enumerateChildNodesUsingBlock({ (node, stop) -> Void in
  node.geometry?.firstMaterial?.shaderModifiers = shaders
})

这是在一个测试场景上运行的,它包含一个单一的盒子几何体,该几何体从一个.scn文件中加载。文件加载正常工作,所以这不是问题。
错误来自第二行,我试图找到路径时,它给了我"found nil while unwrapping optional value",这是可以预料的强制解包错误,除了它正在尝试加载的文件肯定在程序包中,并且相同的代码对其他文件类型也能很好地工作,只有.metal文件不能加载。
我完全错了吗?我不明白为什么它无法访问该文件,除非是我误用了metal文件。
是否有更简单或更好的方法来实现单元格着色和最终边缘的粗略轮廓?
1个回答

5
AAPLCelShader.metal 是一个完整的顶点/rastex/片段实现,这不是 shaderModifiers 的作用:它们是将注入到已经完整的着色器中的源代码。

相反,您可以创建一个 SCNProgram,使用AAPLCelShader.metal中的顶点和片段函数。与GLSL相比,Metal的好处在于您可以使用Metal函数的名称,而不是源代码字符串,这更容易处理,并且在运行时之前编译函数,而GLSL不支持此功能。(这仍然不如它应该是的那样好,Swift将识别Metal函数为正确类型、可重构的命名空间闭包。)当然,虽然GLSL SCNPrograms将转换为Metal,用于兼容硬件的Metal SCNPrograms将不会翻译为过时设备。

至于从SceneKit到rastex(错误命名为ColorInOut)成员的映射:

float4 position [[position]];
float shine;
float3 normal_cameraspace;
float3 eye_direction_cameraspace;
float3 light_direction_cameraspace;

很抱歉,我目前还没有答案。


这是一些很棒的信息,谢谢。对于我来说,这是一个全新的领域,这真的让我有了更多的了解。 - Andy Heard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接