vad*_*ade 5 3d shader scenekit metal
TL; DR:
如何引用“不在磁盘上” sampler2D符号并将其传递给SCNTechnique?如果我从捆绑中引用图像,则我的技术有效,但如果不引用,则无法找到将现有id<MTLTexture>技术传递给我的技术已设置的采样器符号的方法。
长:
我有一个有效的工作SCNTechnique,它使用自定义的sampler2D符号作为金属碎片通道的输入。我试图传入id<MTLTexture>从硬件传感器获得的外部(不是来自Scenekit)作为后期处理过程中的输入。
跟随SCNShadable状态为docs的文档id<MTLTexture>可以通过SCNMaterialProperty具有正确内容集的an作为着色器输入传递。此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)
Run Code Online (Sandbox Code Playgroud)
对于a SCNTechnique,我得到了错误日志,指示“纹理没有存储”,Metal GPU帧捕获指示为采样器设置了默认的4x4像素白色纹理(大概是从SCNTecnique?开始)。但是,我已经能够验证我的自定义设置id<MTLTexture>是否有效并且调试器中是否包含内容-其格式,宽度,高度和内容均符合预期,我只是似乎无法在场景工具包技术中引用任意纹理正确通过。
如果我在SCNTechniqueplist文件中声明我的符号以引用如下图像:
<dict>
<key>type</key>
<string>sampler2D</string>
<key>image</key>
<string>star.png</string>
</dict>
Run Code Online (Sandbox Code Playgroud)
我的通行证输入如下:
<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>
Run Code Online (Sandbox Code Playgroud)
然后,我的通行证开始工作,并且引用了star.png纹理。
有没有人得到像这样的东西上班?
谢谢。
相当肯定我能做到这一点。
Swift 代码来设置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
Run Code Online (Sandbox Code Playgroud)
gradient.png是一个 256 x 1px 颜色渐变(蓝色 -> 绿色 -> 红色)图像,我用它来将单个值映射到伪颜色。(例如;
)
这是我的 plist 中的 pass 字典中的完整技术 pass 定义。
<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>
Run Code Online (Sandbox Code Playgroud)
myTexture还需要在技术 plist 的符号部分中定义。
<key>symbols</key>
<dict>
<key>myTexture</key>
<dict>
<key>type</key>
<string>sampler2D</string>
</dict>
</dict>
Run Code Online (Sandbox Code Playgroud)
当不包含此符号块时,我也看到了“pass has no storage for input 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);
}
Run Code Online (Sandbox Code Playgroud)
该技术还涉及其他一些通道,但我没有包括在内;只是为了提供一些上下文,它在一个通道中渲染场景,并在另一通道中使用输出深度缓冲区和 Sobel 运算符在纹理中生成边缘depthSampler。上面的通道 + 片段着色器在场景的原始渲染之上绘制这些边缘。我使用纯黑色作为边缘,但经过研究后,我似乎能够从MTLTexture我提供的颜色中读取颜色SCNTechnique并将其用于边缘。