簡體   English   中英

在 computeShader 代碼運行后將數據存儲在 GraphicsBuffer 中總是 (0,0,0)

[英]Storing data inside GraphicsBuffer after computeShader code runs always are (0,0,0)

工作環境:Unity3D 2021.2.7.f1 Direct3D11

我嘗試讓 Laplacian Smoothing 在 GPU 上工作 對於這種情況,我在其他 VertexBuffer(輸入圖形緩沖區)和 outVertexBuffer(output Grpahics 緩沖區)中設置了 Compute Shader,不幸的是,我在將數據存儲到 GraphicsBuffer(存儲頂點 Vector3)時遇到了一個奇怪的問題我用作計算着色器的“輸出”。

ComputeShader 組件的分配:

public void RunSmoothingShader(int kernel,int verticesNo)
{
    ComputeBuffer connectionsBuffer = new 
ComputeBuffer(_builder._triangleBudget*6,sizeof(int));

    ComputeBuffer offsetsBuffer = new ComputeBuffer(_builder._triangleBudget, sizeof(int));
    ComputeBuffer _counterBuffer = new ComputeBuffer(1, 4, ComputeBufferType.Counter);
    connectionsBuffer.SetData(VertexConnection.connectionsTable);
    offsetsBuffer.SetData(VertexConnection.offsetsTable);
    smoothingShader.SetBuffer(0,"ConnectionsBuffer",connectionsBuffer);
    smoothingShader.SetBuffer(0,"OffsetsBuffer",offsetsBuffer);
    smoothingShader.SetBuffer(0, "Counter", _counterBuffer);
    smoothingShader.SetBuffer(0,"OutVertexBuffer",outVertexBuffer);
    smoothingShader.SetInt("MaxVerticesNumber", verticesNo);
    smoothingShader.SetBuffer(0,"VertexBuffer", _builder._vertexBuffer);
    
 
    smoothingShader.Dispatch(kernel,64,64,64);
}

outVertexBuffer 的初始化:(步長等於 12,因為類型為 float3)

 outVertexBuffer =
            new GraphicsBuffer(GraphicsBuffer.Target.Vertex, 5000000, 12);

在 LaplacianSmoothing ComputeShader 中,我想重新計算頂點的位置並使用 Store3 function 將它們存儲到outVertexBuffer中。下面是 ComputeShader 中 LaplacianSmoothing 的代碼(HLSL 樣式):

#pragma kernel LaplacianSmooth

RWTexture2D<float4> Result;
RWByteAddressBuffer VertexBuffer;
RWStructuredBuffer<uint> Counter; // used only for counting
RWByteAddressBuffer ConnectionsBuffer;
RWByteAddressBuffer OffsetsBuffer;
RWByteAddressBuffer OutVertexBuffer;
int MaxVerticesNumber;

#define SIZEOF_UINT 4
#define SIZEOF_FLOAT3 12

[numthreads(8,8,8)]
void LaplacianSmooth (uint3 id : SV_DispatchThreadID)
{
    uint currentIndex = 512*512*id.z + 512*id.y+id.x;
    if (currentIndex < MaxVerticesNumber)
    {
        float3 currentVertex = asfloat(VertexBuffer.Load3(2*currentIndex*SIZEOF_FLOAT3));
        float3 sumNeighVertex = 0;
        uint neighborAdrr=0;
        int currentOffset = OffsetsBuffer.Load(currentIndex*SIZEOF_UINT);
        int nextOffset = OffsetsBuffer.Load((currentIndex+1)*SIZEOF_UINT);
        int connectionCount = nextOffset-currentOffset;
        for (int i=0; i<connectionCount;i++)
        
        {
            neighborAdrr = ConnectionsBuffer.Load((currentOffset+i)*SIZEOF_UINT);// Adress of neighbor;
        
            sumNeighVertex += asfloat(VertexBuffer.Load3(neighborAdrr*2*SIZEOF_FLOAT3));
        }

        sumNeighVertex = sumNeighVertex / connectionCount;

        float3 newVert = sumNeighVertex+currentVertex;
        OutVertexBuffer.Store3(currentIndex*SIZEOF_FLOAT3,asuint(currentVertex));
    }
}

在下一步中,我想從 outVertexBuffer 獲取數據並將它們分配到 vertexArray GraphicsBuffer.GetData(Vector3[] array) function。

public void OnSmoothMeshLaplacian()
{

PrepareSmoothing();
var mesh = GetComponent<MeshFilter>().mesh;
Mesh testMesh = Instantiate(mesh);
GameObject.Find("Laplacian").GetComponent<MeshFilter>().sharedMesh = testMesh;
//testMesh = LaplacianFilter(testMesh, 5,1f);

Vector3[] vertexArray;
vertexArray = new Vector3[2*testMesh.vertices.Length];
var network = VertexConnection.BuildNetwork(testMesh.triangles);
RunSmoothingShader(smoothingShader.FindKernel("LaplacianSmooth"), testMesh.vertexCount);
outVertexBuffer.GetData(vertexArray);
testMesh.SetVertexBufferData(vertexArray, 0, 0, vertAndPosList.Length);
testMesh.RecalculateBounds();
Debug.Log("Mesh:" + mesh.bounds.size);
Debug.Log("Test Mesh:" + testMesh.bounds.size);
Debug.Log($"Shrinkage: {(mesh.bounds.size - testMesh.bounds.size).magnitude / mesh.bounds.size.magnitude * 100f}%");
    }

我在getData function之后設置斷點,查看數據,都是(0,0,0)。 我使用 RenderDoc 檢查緩沖區的工作方式,用谷歌搜索了着色器和主程序中使用的所有 function 的文檔,但沒有任何解釋缺少分配數據。 我想補充一點,當我將 inputBuffer 也用作 output 時,我會得到數據(邏輯上不正確,但仍然不是 (0,0,0)。

嘗試這個:

outVertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 5000000, 12);

請注意更改后的目標。 圖形緩沖區需要至少一個計算目標標志才能綁定到計算 kernel。Target.Vertex 不是這樣的標志。 您仍然可以添加它,但在您的情況下不需要。

事實上outVertexBuffer可能只是一個ComputeBuffer 無需使用GraphicsBuffer ,因為您只需將其復制到 CPU 端的網格。

編輯 - -

另一件事: SetVertexBufferData()要求您首先配置所有頂點屬性,並且您傳遞的數據基本上應該是原始頂點數據:位置、法線、uvs(如果有)等。

如果您只想設置頂點,也許使用Mesh.SetVertices()會更容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM