我已将SCNProgram附加到SceneKit的几何体上,并且我试图将制服传递给片段着色器。在我的简单代码片段中,我只是将输出颜色作为一个统一体传递给片段着色器,它将其作为输出值返回。
我已经测试了着色器并且它们可以工作,因为我可以在顶点着色器中成功旋转对象,或者在片段着色器中以不同颜色绘制对象等等...但是问题是我通过制服。这是我的片段着色器:
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:错误,缺少缓冲区[-1/0]
修改 我试图按照@lock的建议,但我仍然得到同样的错误。这是完整的项目存储库:https://github.com/ramy89/Shaded-Cube.git
答案 0 :(得分:3)
你的着色器代码看起来很好,你穿制服的方式接近于工作。
着色器制服的名称必须与setValue
中使用的名称相匹配。在这种情况下,您的Metal变量名称为uniforms
,您在setValue
中使用的值为uniforms.color
。这些不匹配,因此您看到的错误。建议更改快速代码,只需在uniforms
调用中使用setValue
。
接下来,您需要确保传入的数据,因为setValue
的值在Metal和Swift中都是相同的。 SCNVector4
是四个64位双精度(CGFloats)的结构,而Metal的float4
是四个32位浮点数的结构。该文档似乎表明您可以将SCNVector作为NSValue传递,但我从来没有让它工作。
在你的swift代码中,我创建了一个包含你想要传入的制服的结构。vector_float4
结构上没有很多文档,但它与金属float4
结构相匹配它是四个32位浮点数。
struct Uniforms {
var color:vector_float4
}
将其作为setValue
传递到NSData
函数。
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")
}