如何在 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)
我正在尝试访问 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)