iOS Metal 缓冲区不尊重步幅值

标签 ios metal

我有一个每个实例的统一缓冲区,其中缓冲区中的每个元素都是 64 字节,但我只使用顶点着色器中每个元素的前 16 字节 (float3)。我大步向前来描述这一点。问题是它不会跨过其他 48 个字节除非我在着色器中向结构添加填充,以便它也是 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)

应用端粒子结构:

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对应shader中的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 结构的大小,无论在顶点描述符中设置的步幅如何。

我敢肯定我一定是在这里做错了什么,看起来你不应该需要填充你的着色器结构。

最佳答案

所以看起来这就是使用 Metal 缓冲区的 Just The Way It Is™:您必须填充着色器结构以匹配应用程序结构的步幅。我认为 Metal 着色器运行时从缓冲区加载 stride 字节并转换第一个 sizeof(MyShaderStruct) 并不困难 个。或者在附加管道状态时自动填充结构。但这些便利可能会影响效率。

这是我的 Swift/Shader 结构现在的样子以供引用:

Metal :

struct Particle
{
   float3 position;
   float3 prevPos;
   float4 color;
   float4 lineColor;
   float  scale;
   char   pad[60];
};

swift :

struct Particle {
    var position = float3()
    var prevPos = float3()
    var color = float4()
    var lineColor = float4()
    var scale:Float = 0
    var gravity = float3()

    var data: DataRef!
    weak var physics: Physics? = nil
    var state = State.Free

    enum State: Int {
        case Free = 0
        case Active
    }
}

sizeof(Particle) 113
alignof(Particle) 16
strideof(Particle) 128

关于iOS Metal 缓冲区不尊重步幅值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33290986/

相关文章:

iphone - iPhone应用程序上的iPad风格导航栏

swift - 如何在 SceneKit 中使用 SCNBufferBindingBlock?

metal - Metal 中使用的坐标系是什么?

ios - Swift SpriteKit iOS - 碰撞 : didBeginContact for one sprite, 而不是其他人

ios - 打开应用程序商店页面来评价我的应用程序

ios - 简单但不可能 - 从 view swift 调用基于点击事件的函数

ios - Metal 顶点着色器扩展单个三角形

ios - Metal Shader 调试 - 捕获 GPU 帧

graphics - 什么是 Metal 中的 colorAttachment[n]?

objective-c - UINavigationController 内存问题