【问题标题】:How to pass non-texture data to SCNTechnique Metal shaders如何将非纹理数据传递给 SCNTechnique 金属着色器
【发布时间】:2018-12-02 01:37:17
【问题描述】:

我可以将sampler2D 类型的自定义参数传递给SCNTechniqueMetal fragment function,并且我有一个有效的第二次传递:

PList:

<key>inputs</key>
<dict>
    <key>imageFromPass1</key>
    <string>COLOR</string>
    <key>myCustomImage</key>
    <string>myCustomImage_sym</string>
</dict>

...

<key>symbols</key>
<dict>
    <key>myCustomImage_sym</key>
    <dict>
        <key>type</key>
        <string>sampler2D</string>
    </dict>
</dict>

相关Obj-C代码:

[technique setValue: UIImagePNGRepresentation(myCustomTexture) forKey:@"myCustomImage_sym"];

金属功能参数:

fragment half4 myFS(out_vertex_t vert [[stage_in]],
    texture2d<float, access::sample> imageFromPass1 [[texture(0)]],
    texture2d<float, access::sample> myCustomImage [[texture(1)]],
    constant SCNSceneBuffer& scn_frame [[buffer(0)]]) { ...

我在着色器函数中访问和使用所有这些输入。它有效!

到目前为止一切顺利!

但是,当我添加另一个 float 类型的自定义参数时...

<key>blob_pos</key>
<string>blob_pos_sym</string>

...

<key>blob_pos_sym</key>
<dict>
    <key>type</key>
    <string>float</string>
</dict>

[_sceneView.technique setValue:[NSNumber numberWithFloat:0.5f] forKey:@"blob_pos_sym"];

 constant float& blob_pos [[buffer(2)]]

...传递的值永远不会到达着色器函数。

我试过了

  • 使用最多 6 个不同的缓冲区 (N) 值
  • 在顶点函数中有自定义参数
  • 输入 vec3 和 float3 而不是 float
  • 将我的浮点数编码为 NSData 的不同方法
  • 将我的浮点数包装在一个结构中

    [technique setValue:[NSValue valueWithSCNVector3: SCNVector3Make(0.5, 0.5, 0.5)] forKey:@"blob_pos_"];
    
    SCNVector3 xx = SCNVector3Make(0.5, 0.5, 0.5);
    [technique setValue:[NSData dataWithBytes:&xx length:sizeof(xx)] forKey:@"blob_pos_"];
    [technique setValue:[NSData dataWithBytesNoCopy:&xx length:sizeof(xx)] forKey:@"blob_pos_"];
    
    simd_float3 x = simd_make_float3(0.5, 0.5, 0.5);
    [technique setValue:[NSData dataWithBytes:&x length:sizeof(x)] forKey:@"blob_pos_"];
    
    float y = 0.5;
    [technique setValue:[NSData dataWithBytes:&y length:sizeof(y)] forKey:@"blob_pos_"];
    
    struct MyStruct {
        float x;
    };
    struct MyStruct myStruct = {
        0.5
    };
    
    [technique setValue:[NSValue valueWithBytes:&myStruct objCType:@encode(struct MyStruct)] forKey:@"blob_pos_"];
    [technique setObject:[NSValue valueWithBytes:&myStruct objCType:@encode(struct MyStruct)] forKeyedSubscript:@"blob_pos_"];
    

...一切都失败了。

然后我查看了handleBindingOfSymbol:usingBlock: ...但它只是 GLSL。

我发现它是 Metal 对应物,handleBindingOfBufferNamed:frequency:usingBlock: ... 在 SCNTechnique 中不可用。

我在 Google 上搜索了 SCNTechnique Metal ... 并发现所有项目只使用了 sampler2D 参数。

最后我知道这不是新的,而是bugs developers for years

在我将这个浮点数编码到纹理中之前,让我知道丢失的位以使其按预期方式工作。

【问题讨论】:

标签: shader scenekit metal scntranscaction


【解决方案1】:

您必须使用结构来包装您的输入符号,并确保使用[SCNTechnique setObject:forKeyedSubscript:] 将您的符号值传递给您的技术。 setObject:forKeyedSubscript: 的文档提到了 Metal,但它没有解释如何在 Metal 函数中接收值,这是不幸的。

使用您的示例:

技术定义:

"inputs": [
    "imageFromPass1": "COLOR",
    "myCustomImage": "myCustomImage_sym",
    "blob_pos": "blob_pos_sym",
],
...

"symbols": [
    "myCustomImage_sym": ["type": "sampler2D"],
    "blob_pos_sym": ["type": "float"]
 ]

对象-C:

[_sceneView.technique setObject:[NSNumber numberWithFloat:0.5f] forKeyedSubscript:@"blob_pos_sym"];

金属:

typedef struct {
    float blob_pos; // Must be spelled exactly the same as in inputs dictionary.
} Inputs;

fragment half4 myFS(out_vertex_t vert [[stage_in]],
    texture2d<float, access::sample> imageFromPass1 [[texture(0)]],
    texture2d<float, access::sample> myCustomImage [[texture(1)]],
    constant Inputs& myInputs [[buffer(0)]]) { 

    float blob_pos = myInputs.blob_pos;

    ...

【讨论】:

  • 是的,这很有效,而且比我找到的解决方法要快得多。我很高兴你发现了。谢谢!你是怎么发现的?
  • 我无法让它工作 - 一直在尝试一切。有源代码可以分享吗?
猜你喜欢
  • 1970-01-01
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
  • 2016-12-20
  • 1970-01-01
  • 2023-03-15
  • 2017-01-24
  • 2014-04-20
相关资源
最近更新 更多