我有一个每实例统一缓冲区,其中缓冲区中的每个元素都是64字节,但我只使用顶点着色器中每个元素的前16个字节(float3) . 我把步伐向上描述了这一点 . 问题是它没有超过其他48个字节 unless 我在着色器中向结构添加填充,以便它也是64个字节 .
// Particle Instance Position
vertexDescriptor.attributes[2].format = .Float3 // 16 bytes with padding.
vertexDescriptor.attributes[2].offset = 0
vertexDescriptor.attributes[2].bufferIndex = 2
vertexDescriptor.layouts[2].stride = strideof(Particle)
vertexDescriptor.layouts[2].stepFunction = .PerInstance
...
commandEncoder.setVertexBuffer(instanceUniformBuffer, offset:0, atIndex:2)
App侧粒子结构:
struct Particle {
var position = float3()
var prevPos = float3()
var attractPoint = float3()
var ref: DataRef!
var state = State.Free
enum State: Int {
case Free = 0
case Active
}
}
这里是相应的Metal结构,即 Particle.position
对应于着色器中的 InstanceUniforms.instanceTranslate
. 我希望上面的步幅设置意味着每个实例都会加载 Particle.position
,并且跳过缓冲区中每个 Particle
的其他48个字节 .
struct InstanceUniforms
{
float3 instanceTranslate [[ attribute(2) ]];
};
一些健全性检查,一切都有道理:
sizeof(float3) 16
alignof(float3) 16
sizeof(Particle) 57
alignof(Particle) 16
strideof(Particle) 64
但它不起作用,除非我将着色器结构填充到64字节:
struct InstanceUniforms
{
float3 instanceTranslate [[ attribute(2) ]];
float4 pad[3];
};
否则对于第二个实例,着色器实际上将 instanceTranslate
设置为缓冲区中 first 元素的 Particle.prevPos
,就像它只跨越 InstanceUniforms
结构的大小一样,无论在顶点描述符中设置了什么步幅 .
我确定我必须在这里做错事,看起来你不应该填充你的着色器结构 .
1 回答
所以看起来这就是Just The Way It Is™with Metal缓冲区:你必须填充着色器结构以匹配app结构的步幅 . 我不认为Metal Shader运行时从缓冲区加载
stride
字节并转换它们的第一个sizeof(MyShaderStruct)
会很困难 . 或者在附加管道状态时自动加载结构 . 但这些便利可能具有效率影响 .这是我的Swift / Shader结构现在的样子供参考:
Metal:
Swift: