I try to implement MarchingCubes algorithm on compute shader so I need to know actual number of generated triangles. I use Unreal Engine 4 and HLSL (Shader Model 5) How can I get back one single uint from shader?
I tried to generate RWStructuredBuffer with one variable and increment it with InterlockedAdd but it always returns 0 (the triangles buffer works fine).
Here is my code:
Initialization and reading in UE:
struct FVertex
{
FVector position;
FVector normal;
};
struct FTriangle
{
FVertex vertices[3];
};
void MeshGeneratorShaderHelper::Initialize(const float voxel_size_mm, const size_t slices, const size_t rows, const size_t columns, const size_t cube_size)
{
_constantParameters.voxel_size_mm = voxel_size_mm;
_constantParameters.slices = slices;
_constantParameters.rows = rows;
_constantParameters.columns = columns;
_constantParameters.cube_size = cube_size;
_constantParameters.threshold = 0.95;
// Setup buffers
if (shaderOutDataBuffer != NULL)
{
shaderOutDataBuffer.SafeRelease();
}
// This is not very fine numbers
size_t number_of_triangles = slices*rows;
number_of_triangles = FMath::Min(10*(size_t)DEF_SIZE_VERT, number_of_triangles);
// Now init actual output of shader
_meshData.Init(FTriangle(), number_of_triangles);
TResourceArray<FTriangle> bufferData;
bufferData.Init(FTriangle(), number_of_triangles);
bufferData.SetAllowCPUAccess(true);
FRHIResourceCreateInfo createInfo;
createInfo.ResourceArray = &bufferData;
// This is FStructuredBufferRHIRef and FUnorderedAccessViewRHIRef
shaderOutDataBuffer = RHICreateStructuredBuffer(sizeof(FTriangle), sizeof(FTriangle) * number_of_triangles, BUF_UnorderedAccess | BUF_ShaderResource, createInfo);
shaderOutDataBufferUAV = RHICreateUnorderedAccessView(shaderOutDataBuffer, true, false);
// This is one element buffer for intanced triangles number
if (sizeOutBuffer != NULL)
{
sizeOutBuffer.SafeRelease();
}
TResourceArray<uint32> bufferData2;
bufferData2.Init(0, 1);
bufferData2.SetAllowCPUAccess(true);
FRHIResourceCreateInfo sizeCreateInfo;
sizeCreateInfo.ResourceArray = &bufferData2;
sizeOutBuffer = RHICreateStructuredBuffer(sizeof(uint32), sizeof(uint32), BUF_UnorderedAccess | BUF_ShaderResource, sizeCreateInfo);
sizeOutBufferUAV = RHICreateUnorderedAccessView(sizeOutBuffer, true, false);
// This is buffer for voxel input of shader
if (voxelData != NULL)
{
voxelData.SafeRelease();
}
TResourceArray<float> bufferDataV;
bufferDataV.Init(float(), columns*rows*slices);
bufferDataV.SetAllowCPUAccess(true);
FRHIResourceCreateInfo CreateInfoVoxel;
CreateInfoVoxel.ResourceArray = &bufferDataV;
voxelData = RHICreateStructuredBuffer(sizeof(float),
columns*rows*slices *sizeof(float),
EBufferUsageFlags::BUF_UnorderedAccess | BUF_ShaderResource,
CreateInfoVoxel
);
voxelDataUAV = RHICreateUnorderedAccessView(voxelData, true, false);
}
void MeshGeneratorShaderHelper::RetrieveDataInternal()
{
check(IsInRenderingThread());
// Try to get number of triangles, always get 0
uint32 total_size;
uint8* srcPtr = (uint8*)RHILockStructuredBuffer(sizeOutBuffer, 0, sizeof(uint32), EResourceLockMode::RLM_ReadOnly);
FMemory::Memcpy((uint8*)(&total_size), srcPtr, sizeof(uint32));
RHIUnlockStructuredBuffer(sizeOutBuffer);
if (total_size == 0)
{
_meshData.Empty();
result_size = total_size;
//return;
total_size = DEF_SIZE_VERT;
}
// This works fine
_meshData.Init(FTriangle{ {FVector{-5,-5,-5}, FVector {-5,-5,-5}, FVector {-5,-5,-5}} }, total_size);
srcPtr = (uint8*)RHILockStructuredBuffer(shaderOutDataBuffer, 0, sizeof(FTriangle) * total_size, EResourceLockMode::RLM_ReadOnly);
// Reference pointer to first element for our destination ComputedColors
uint8* dstPtr = (uint8*)_meshData.GetData();
// Copy from GPU to main memory
FMemory::Memcpy(dstPtr, srcPtr, sizeof(FTriangle) * total_size);
//Unlock texture
RHIUnlockStructuredBuffer(shaderOutDataBuffer);
}
Shader code:
StructuredBuffer<float> DensityTexture; // voxel data
struct Vertex
{
float3 Position;
float3 Normal;
};
struct Triangle
{
Vertex vertices[3];
};
AppendStructuredBuffer<Triangle> MeshData; // this need to be counted
RWStructuredBuffer<uint> ResultSize; // This is one num buffer
...
[numthreads(SIMULATION_BLOCK_SIZE, 1, 1)]
void MarchingCubes(
uint3 Gid : SV_GroupID,
uint3 DTid : SV_DispatchThreadID,
uint3 GTid : SV_GroupThreadID,
uint GI : SV_GroupIndex )
{
...
for(uint i = 0; i<numVertsTable[cube_index]; i+=3)
{
Vertex vertices[3];
for (uint j = 0; j<3; ++j)
{
Vertex v;
float3 Position = vertlist[triTable[cube_index][i + j]];
v.Normal = normalize(CalculateGradient(Position));
v.Position = Position;
vertices[j] = v;
}
Triangle t;
t.vertices[0] = vertices[0];
t.vertices[1] = vertices[1];
t.vertices[2] = vertices[2];
MeshData.Append(t);
InterlockedAdd(ResultSize[0], 1); // Here I want to count data
}
}