我正在尝试访问hsl中的ByteAddressBuffer。缓冲区包含顶点。我想写一个函数,给定一个索引,将返回该索引处的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个字节)访问值。
然而,当我使用这个函数并返回值时,只有在索引0处返回的float3是正确的。所有其他float3值都是错误的。
为了防止我做了一些非常愚蠢的事情,下面是我如何返回值的:
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)
中指出了这一点。