【问题标题】:"SceneKit: error, missing buffer [-1/2]" when trying to pass uniforms to a metal shader尝试将制服传递给金属着色器时出现“SceneKit:错误,缺少缓冲区 [-1/2]”
【发布时间】:2016-07-20 14:36:12
【问题描述】:

我已将 SCNProgram 附加到 SceneKit 的几何体,并且我正在尝试将制服传递给片段着色器。在我的简单代码 sn-p 中,我只是将输出颜色作为统一传递给片段着色器,后者将其作为输出值返回。

我已经测试了着色器并且它们可以工作,因为我可以成功地在顶点着色器中旋转一个对象,或者在片段着色器中以不同的颜色绘制一个对象,等等......但问题是当我通过制服时。这是我的片段着色器:

struct Uniforms
{
    float4 color;
};


fragment float4 myFragment(MyVertexOutput in [[ stage_in ]],
                           constant Uniforms& uniforms [[buffer(2)]])
{
    return uniforms.color;
}

这就是我尝试在我的 SceneKit+Swift 代码中传递制服的方式:

SCNTransaction.begin()
cube.geometry?.setValue(NSValue(SCNVector4:SCNVector4(0.0,1.0,0.0,1.0)), forKey: "uniforms.color")
SCNTransaction.commit()

但是我的对象(它是一个立方体)甚至没有被绘制(它是黑色的),我得到了这个错误:

2016-04-01 01:00:34.485 阴影立方体[30266:12687154] SceneKit:错误,缺少缓冲区 [-1/0]

编辑 我试图遵循@lock 的建议,但我仍然遇到同样的错误。这是完整的项目存储库:https://github.com/ramy89/Shaded-Cube.git

【问题讨论】:

  • 嗨,Ramy,我可以通过电子邮件向您介绍一个潜在的项目吗?在 GitHub 页面上找不到您的电子邮件地址。谢谢!

标签: ios swift shader scenekit metal


【解决方案1】:

您的着色器代码看起来不错,并且您传递制服的方式接近工作。

着色器统一的名称必须与setValue 中使用的名称相匹配。在这种情况下,您的 Metal 变量名称是 uniforms,而您在 setValue 中使用的值是 uniforms.color。这些不匹配,因此您会看到错误。建议将 swift 代码更改为在 setValue 调用中简单地使用 uniforms

接下来,您需要确保作为 setValue 的值传入的数据在 Metal 和 Swift 中是相同的。 SCNVector4 是四个 64 位双精度 (CGFloats) 的结构,而 Metal 的 float4 是四个 32 位浮点的结构。文档似乎表明您可以将 SCNVector 作为 NSValue 传递,但我从来没有让它工作。

在您的 swift 代码中,我将创建一个结构来包含您要传入的制服。关于 vector_float4 结构的文档并不多,但它与 Metal float4 结构相匹配,因为它是四个32位浮点数。

struct Uniforms {
    var color:vector_float4
}

将此作为NSData 传递给setValue 函数。

let myColor = vector_float4(0,1,0,1)
var myUniforms = Uniforms(color:myColor)
var myData = NSData(bytes:&myUniforms, length:sizeof(Uniforms))
cube.geometry?.setValue(myData, forKey: "uniforms")

我不确定您是否需要 SCNTransaction 调用,我过去不需要它们,而且它们的性能成本可能很高。

更新

查看 Ramy 的代码后,似乎 setValue 和 SCNPrograms 在应用于几何时存在问题。我不能告诉你为什么,但是将自定义着色器设置为材质似乎可以解决这个问题,例如;

func makeShaders()
{
    let program = SCNProgram()
    program.vertexFunctionName = "myVertex"
    program.fragmentFunctionName = "myFragment"
    //cube.geometry?.program = program
    cube.geometry?.firstMaterial?.program = program

    var uniforms = Uniforms(color: vector_float4(0.0,1.0,0.0,1.0))
    let uniformsData = NSData(bytes: &uniforms, length: sizeof(Uniforms))
    //cube.geometry?.setValue(uniformsData, forKey: "uniforms")
    cube.geometry?.firstMaterial?.setValue(uniformsData, forKey: "uniforms")
}

【讨论】:

  • 我仍然得到同样的错误,我不知道我的代码有什么问题。我创建了一个 github 存储库并将链接添加到我的问题。
  • 我认为您的代码@RamyAlZuhouri 没有任何问题,请参阅上面的更新。对我来说看起来像一个 SceneKit 错误,可能值得填写一个雷达。
猜你喜欢
  • 2016-02-06
  • 2017-06-02
  • 2017-03-21
  • 1970-01-01
  • 2018-10-15
  • 2014-12-05
  • 2021-09-08
  • 1970-01-01
  • 2017-01-24
相关资源
最近更新 更多