TL; DR:
如何引用“不在磁盘上” sampler2D符号并将其传递给SCNTechnique
?如果我从捆绑中引用图像,则我的技术有效,但如果不引用,我将找不到将现有id<MTLTexture>
传递到我的技术已设置的采样器符号的方法。
长
:我有一个有效的工作SCNTechnique
,它使用自定义的sampler2D符号作为金属碎片通道的输入。我正在尝试传入从硬件传感器获得的外部(不是来自Scenekit)id<MTLTexture>
作为后期处理过程中的输入。
遵循SCNShadable
文档,声明一个id<MTLTexture>
可以通过设置了适当内容的SCNMaterialProperty
作为着色器输入传递。此100%可以在着色器修改器遍历中使用-但对SCNTecnique
无效!
let texture = CVMetalTextureGetTexture(textureRef!)
if self.material == nil
{
self.material = SCNMaterialProperty(contents:texture)
}
else
{
self.material?.contents = texture
}
self.currentTechnique?.setObject(self.material, forKeyedSubscript: "myTextureSamplerSymbol" as NSCopying)
对于SCNTechnique
,我收到错误日志,指出“没有存储纹理”,并且Metal GPU帧捕获指示为采样器设置了默认的4x4像素白色纹理(大概来自SCNTecnique
?)。但是,我已经能够验证我的自定义id<MTLTexture>
是否有效并且调试器中是否包含内容-其格式,宽度,高度和内容均符合预期,我似乎无法引用任意纹理进入场景工具箱技术可以正确通过。
如果我在SCNTechnique
plist文件中声明我的符号以引用如下图像:
<dict>
<key>type</key>
<string>sampler2D</string>
<key>image</key>
<string>star.png</string>
</dict>
我的通行证输入如下:
<dict>
<key>colorSampler</key>
<string>COLOR</string>
<key>depthSampler</key>
<string>DEPTH</string>
<key> myTextureSampler</key>
<dict>
<key>target</key>
<string> myTextureSamplerSymbol </string>
</dict>
</dict>
然后我的通行证开始工作,并引用star.png纹理。
有人能像这样工作吗?
谢谢。
答案 0 :(得分:1)
可以肯定的是我能做到这一点。
快速代码以设置MTLTexture
并将其设置为SCNTechnique
。
let tech:SCNTechnique = getTechnique()
let textureLoader = MTKTextureLoader(device: MTLCreateSystemDefaultDevice()!)
let filePath = Bundle.main.url(forResource: "gradient", withExtension: "png")!
do {
let gradTexture: MTLTexture = try textureLoader.newTexture(URL: filePath, options: nil)
let matPropTexture = SCNMaterialProperty(contents: gradTexture)
tech.setObject(matPropTexture, forKeyedSubscript: "myTexture" as NSCopying)
} catch {
print("Unexpected error: \(error).")
}
scnView.technique = tech
gradient.png
是256 x 1px的颜色渐变(蓝色->绿色->红色)图像,用于将单个值映射为伪色。
(例如)
这是我的plist中的传球字典的完整技术传球定义。
<key>mix_outline</key>
<dict>
<key>draw</key>
<string>DRAW_QUAD</string>
<key>metalVertexShader</key>
<string>pass_through_vertex</string>
<key>metalFragmentShader</key>
<string>mix_outline_fragment</string>
<key>inputs</key>
<dict>
<key>colorSampler</key>
<string>color_scene</string>
<key>depthSampler</key>
<string>depth_outline</string>
<key>myTextureSampler</key>
<string>myTexture</string>
</dict>
<key>outputs</key>
<dict>
<key>color</key>
<string>COLOR</string>
</dict>
</dict>
myTexture
也需要在技术plist的符号部分中定义。
<key>symbols</key>
<dict>
<key>myTexture</key>
<dict>
<key>type</key>
<string>sampler2D</string>
</dict>
</dict>
当不包含此符号块时,我也看到“通行证没有存储输入myTextureSampler的错误”消息。 这可能是您的问题吗?
最后是片段着色器定义。
fragment half4 mix_outline_fragment(out_vertex_t vert [[stage_in]],
texture2d<float, access::sample> colorSampler [[texture(0)]],
texture2d<float, access::sample> depthSampler [[texture(1)]],
texture2d<float, access::sample> myTextureSampler [[texture(2)]])
{
float4 myTextureColor = myTextureSampler.read(uint2(55, 0));
float4 outline = depthSampler.sample( s, vert.uv);
float4 scene_color = colorSampler.sample( s, vert.uv);
// float4 fragment_color = mix(scene_color, float4(0.0, 0.0, 0.0, 0.0), outline.r);
float4 fragment_color = mix(scene_color, myTextureColor, outline.r);
return half4(fragment_color);
}
我还没有包括此技术中涉及的其他几个步骤;只是为了提供一些上下文,它在一个过程中渲染了场景,并在另一个过程中与Sobel运算符一起使用了输出深度缓冲区,以将边缘生成到depthSampler
纹理中。上面的pass +片段着色器在场景的原始渲染之上绘制这些边缘。我在边缘上使用了纯黑色,但是仔细研究之后,似乎可以从MTLTexture
提供的SCNTechnique
中读取颜色并将其用于边缘。>