我正在查看SceneKit的句柄绑定方法,并按照此处所述回调SCNBufferBindingBlock:
https://developer.apple.com/documentation/scenekit/scnbufferbindingblock
有没有人举例说明这是如何运作的?
let program = SCNProgram()
program.handleBinding(ofBufferNamed: "", frequency: .perFrame) { (steam, theNode, theShadable, theRenderer) in
}
对我来说,就像我可以在SCNNode上使用* .metal着色器而不必经历SCNTechniques的麻烦....任何接受者?
答案 0 :(得分:1)
.handleBinding(ofBufferNamed:frequency:handler:)
方法为SceneKit注册一个块,以便在渲染时调用Metal缓冲区到着色器程序。此方法只能与基于Metal或OpenGL着色语言的程序一起使用。 SCNProgram
对象有助于执行此自定义呈现。程序对象包含顶点着色器和片段着色器。使用程序对象完全取代了SceneKit的渲染。着色器从SceneKit获取输入,并负责您想要生成的所有变换,光照和着色效果。使用.handleBinding()
方法将块与Metal Shader程序相关联,以处理该着色器中使用的缓冲区的设置。
这是SCNProgram类Developer Documentation的链接。
此外,您还需要一个实例方法writeBytes(_:count:)
,它将所有必要的数据字节复制到底层的Metal缓冲区中以供着色器使用。
SCNTechnique
专门用于后处理SceneKit使用自定义Metal或OpenGL着色器的附加绘图过程渲染场景。使用SCNTechnique
,您可以创建颜色分级或置换,运动模糊和渲染环境遮挡以及其他渲染过程等效果。
以下是第一段代码摘录如何正确使用.handleBinding()方法:
func useTheseAPIs(shadable: SCNShadable,
bufferStream: SCNBufferStream
voidPtr: UnsafeMutableRawPointer,
bindingBlock: @escaping SCNBindingBlock,
bufferFrequency: SCNBufferFrequency,
bufferBindingBlock: @escaping SCNBufferBindingBlock,
program: SCNProgram) {
bufferStream.writeBytes(voidPtr, count: 4)
shadable.handleBinding!(ofSymbol: "symbol", handler: bindingBlock)
shadable.handleUnbinding!(ofSymbol: "symbol", handler: bindingBlock)
program.handleBinding(ofBufferNamed: "pass",
frequency: bufferFrequency,
handler: bufferBindingBlock)
}
这是第二段代码的摘录:
let program = SCNProgram()
program.delegate = self as? SCNProgramDelegate
program.vertexShader = NextLevelGLContextYUVVertexShader
program.fragmentShader = NextLevelGLContextYUVFragmentShader
program.setSemantic(
SCNGeometrySource.Semantic.vertex.rawValue,
forSymbol: NextLevelGLContextAttributeVertex,
options: nil)
program.setSemantic(
SCNGeometrySource.Semantic.texcoord.rawValue,
forSymbol: NextLevelGLContextAttributeTextureCoord,
options: nil)
if let material = self._material {
material.program = program
material.handleBinding(ofSymbol: NextLevelGLContextUniformTextureSamplerY, handler: {
(programId: UInt32, location: UInt32, node: SCNNode?, renderer: SCNRenderer) in
glUniform1i(GLint(location), 0);
})
material.handleBinding(ofSymbol: NextLevelGLContextUniformTextureSamplerUV, handler: {
(programId: UInt32, location: UInt32, node: SCNNode?, renderer: SCNRenderer) in
glUniform1i(GLint(location), 1);
})
}
另外,请查看Simulating refraction in SceneKit SO帖子。
答案 1 :(得分:1)
只需发布此信息,以防其他人来这里寻找简洁的示例。这是SCNProgram
的{{1}}方法如何与 Metal 一起使用的方法:
首先在handleBinding()
着色器文件中定义一个数据结构:
.metal
然后将其作为参数传递给着色器函数:
struct MyShaderUniforms {
float myFloatParam;
float2 myFloat2Param;
};
接下来,在您的 Swift 文件中定义相同的数据结构:
fragment half4 myFragmentFunction(MyVertex vertexIn [[stage_in]],
constant MyShaderUniforms& shaderUniforms [[buffer(0)]]) {
...
}
现在创建此数据结构的实例,更改其值并定义struct MyShaderUniforms {
var myFloatParam: Float = 1.0
var myFloat2Param = simd_float2()
}
:
SCNBufferBindingBlock
在这里,传递给var myUniforms = MyShaderUniforms()
myUniforms.myFloatParam = 3.0
...
program.handleBinding(ofBufferNamed: "shaderUniforms", frequency: .perFrame) { (bufferStream, node, shadable, renderer) in
bufferStream.writeBytes(&myUniforms, count: MemoryLayout<MyShaderUniforms>.stride)
}
的字符串与片段函数中的参数名称相对应。然后,该块的ofBufferNamed:
属性包含用户定义的数据类型bufferStream
,然后可以使用更新后的值将其写入。