"SceneKit: error, missing buffer [-1/2]" 尝试将制服传递给金属着色器时
"SceneKit: error, missing buffer [-1/2]" when trying to pass uniforms to a metal shader
我已将 SCNProgram 附加到 SceneKit 的几何体,并且正在尝试将制服传递给片段着色器。在我的简单代码片段中,我只是将输出颜色作为统一传递给片段着色器,returns 它作为输出值。
我已经测试了着色器并且它们可以工作,因为我可以在顶点着色器中成功地旋转一个对象,或者在片段着色器中以不同的颜色绘制一个对象,等等......但是问题是当我通过制服时。这是我的片段着色器:
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 Shaded Cube[30266:12687154] SceneKit: error, missing buffer [-1/0]
编辑
我尝试遵循@lock 的建议,但我仍然遇到同样的错误。这是完整的项目存储库:https://github.com/ramy89/Shaded-Cube.git
您的着色器代码看起来不错,并且您传递制服的方式接近于正常工作。
着色器制服的名称必须与 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 应用于几何体时存在问题。我不能告诉你为什么,但是将自定义着色器设置为 material 似乎可以解决这个问题,例如;
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")
}
我已将 SCNProgram 附加到 SceneKit 的几何体,并且正在尝试将制服传递给片段着色器。在我的简单代码片段中,我只是将输出颜色作为统一传递给片段着色器,returns 它作为输出值。
我已经测试了着色器并且它们可以工作,因为我可以在顶点着色器中成功地旋转一个对象,或者在片段着色器中以不同的颜色绘制一个对象,等等......但是问题是当我通过制服时。这是我的片段着色器:
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 Shaded Cube[30266:12687154] SceneKit: error, missing buffer [-1/0]
编辑 我尝试遵循@lock 的建议,但我仍然遇到同样的错误。这是完整的项目存储库:https://github.com/ramy89/Shaded-Cube.git
您的着色器代码看起来不错,并且您传递制服的方式接近于正常工作。
着色器制服的名称必须与 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 应用于几何体时存在问题。我不能告诉你为什么,但是将自定义着色器设置为 material 似乎可以解决这个问题,例如;
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")
}