如何在 HLSL 中索引 ByteAddressBuffer

How to index a ByteAddressBuffer in HLSL

我正在尝试访问 HLSL 中的 ByteAddressBuffer。缓冲区包含顶点。我想写一个函数,给定一个索引,将 return 该索引处的 float3。

我目前的理解是缓冲区存储了一系列字节,可以以 4 字节为单位访问这些字节(并且根据测试,我相信访问非对齐地址会将索引向下舍入为 4 的倍数)。

这是我的函数:

float3 load_vertex(int i) {
    int i_location = i * 12;
    float3 ret = float3(0.0f, 0.0f, 0.0f);
    ret.x = asfloat(vertices.Load(i_location    ));
    ret.y = asfloat(vertices.Load(i_location + 4));
    ret.z = asfloat(vertices.Load(i_location + 8));
    return ret;
}

我认为这应该可行:首先 i_location 将索引移动索引的 12 倍(3 个浮点数 = 12 字节),然后以 4 步(1 个浮点数 = 4 字节)访问值).

但是,当我使用此函数和 return 值时,只有索引 0 处的 float3 returned 是正确的。所有其他 float3 值都是错误的。

以防万一我做了一些非常愚蠢的事情,下面是我如何return设置值:

ByteAddressBuffer vertices;
ByteAddressBuffer indices;
RWStructuredBuffer<float3> result;
int index;

float3 load_vertex(int i) {...}

[numthreads(256,1,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    if (id.x == 0) {
        result[0] = load_vertex(index);
    }
}

如果相关,我正在使用 Unity 并且正在设置缓冲区并像这样调度着色器:

mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
mesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
         
GraphicsBuffer vertexBuffer = mesh.GetVertexBuffer(0);
GraphicsBuffer indexBuffer = mesh.GetIndexBuffer();

closestPointShader.SetBuffer(0, "vertices", vertexBuffer);
closestPointShader.SetBuffer(0, "indices", indexBuffer);
closestPointShader.SetBuffer(0, "result", outBuffer);
closestPointShader.SetInt("index", indexValue);

closestPointShader.Dispatch(0, 1, 1, 1);

Vector3[] k = new Vector3[1];
outBuffer.GetData(k);
Debug.Log("On GPU: " + k[0]);
Debug.Log("On CPU: " + mesh.vertices[indexValue]);

谢谢!

事实证明,unity 提供的顶点缓冲区的步幅为 56 字节,而不是 12 字节。将函数更改为:

float3 load_vertex(int i) {
    int i_location = i * 56;
    float3 ret = float3(0.0f, 0.0f, 0.0f);
    ret.x = asfloat(vertices.Load(i_location    ));
    ret.y = asfloat(vertices.Load(i_location + 4));
    ret.z = asfloat(vertices.Load(i_location + 8));
    return ret;
}

使功能正常工作。很高兴在文档中指出了这一点 (/s)