TL; DR:
如何引用'not on disk'sampler2D符号并将其传递给SCNTechnique
?如果我从我的包中引用一个图像,我的技术是有效的,但如果我没有,我找不到一种方法将现有的id<MTLTexture>
传递给我的技术设置的采样器符号。
long:
我有一个有效的工作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
,我得到错误日志,指示“没有纹理存储”,金属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纹理引用。
有没有人得到这样的东西工作?
谢谢。
相当肯定我有这个工作。
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
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 + fragment着色器将这些边缘绘制在场景的原始渲染之上。我使用纯黑色作为边缘,但在看了这之后,我似乎能够从MTLTexture
中提供的SCNTechnique
读取颜色并将其用于边缘。