使用计算着色器生成共享顶点的平面网格

Generating a flat mesh that shares vertices using compute shaders

我遇到了一个看起来很简单的问题,但现在却因为我沮丧的尖叫声而引起了邻居的噪音投诉。

长话短说;博士 程序网格通常使用四边形条带制作。相反,我试图将一个网格作为一个整体,重复使用边缘顶点,而不是像一个网格一样排列四边形条带。

我正在测试一些东西,所以这可能是一种奇怪的方法,但它应该有效。

着色器 1:

RWStructuredBuffer<float3> vertexBuffer;
uniform uint yColumnHeight; 

[numthreads(8,8,1)]
void calcVerts (uint3 id : SV_DispatchThreadID)
{
    //convert x and y to 1 dimensional counter
    int idx = (id.y + (yColumnHeight * id.x));

    //create a flat array of vertices
    float3 vA = float3(id.x, 1, id.y); 
    vertexBuffer[idx] = vA;
}

着色器 2:

RWStructuredBuffer<float3> vertexBuffer;
RWStructuredBuffer<float3> triangleBuffer;
uniform uint yColumnHeight; 

[numthreads(8,8,1)]
void createMeshFromVerts (uint3 id : SV_DispatchThreadID)
{

    int idx = (id.y + (yColumnHeight * id.x));
    
    if (id.x > 0 && id.y > 0){

        //convert idx to index for tri/quad vertices, skipping first row and column
        int subtractFirstYColumn = idx - yColumnHeight;
        int subtractFirstXRow = id.y - 1;
        int trID = (subtractFirstYColumn - subtractFirstXRow) * 6;

        //find the vertices of the quad using verts from first row and column
        int tri_a = idx - yColumnHeight - 1;
        int tri_b = idx - 1;
        int tri_c = idx;
        int tri_d = idx - yColumnHeight;

        triangleBuffer[trID]     = vertexBuffer[tri_a];
        triangleBuffer[trID + 1] = vertexBuffer[tri_b];
        triangleBuffer[trID + 2] = vertexBuffer[tri_c];

        triangleBuffer[trID + 3] = vertexBuffer[tri_d];
        triangleBuffer[trID + 4] = vertexBuffer[tri_a];
        triangleBuffer[trID + 5] = vertexBuffer[tri_c];
    }
}

第二个着色器最初可能看起来很迟钝,但它非常简单。我得到了一组顶点:

. . . . 
. . . .
. . . .
. . . .

在上面,这是一个 3x3 的四边形网格,由 4x4 的顶点组成。 我首先让 vert 1 穿过和 1 向下,然后用左上角的顶点制作一个四边形。 每个四边形都以 vert _ 开头并使用前面的 verts 。像这样:

. . 
. _

并在主 C# 中捆绑在一起:

        //buffers for vertices and map of vertices to make triangles
        vertexBuffer = new ComputeBuffer(triVertCount, stride, ComputeBufferType.Default);
        triangleBuffer = new ComputeBuffer(tris, stride, ComputeBufferType.Default);

        //create initial vertices grid
        calcVerts.SetBuffer(verts, "vertexBuffer", vertexBuffer);

        calcVerts.Dispatch(verts, Mathf.Max(1, (widthInVertices) / (int)threadsx), Mathf.Max(1, (heightInVertices) / (int)threadsy), (int)z);

        //use vertices grid to make mesh
        createMeshFromVerts.SetBuffer(meshFromVerts, "vertexBuffer", vertexBuffer);
        createMeshFromVerts.SetBuffer(meshFromVerts, "triangleBuffer", triangleBuffer);

        createMeshFromVerts.Dispatch(meshFromVerts, Mathf.Max(1, (widthInVertices) / (int)threadsx), Mathf.Max(1, (heightInVertices) / (int)threadsy), (int)z);

我跳过了法线的代码,并在其中传递给 material 进行渲染。当它运行时,我得到了混乱的三角形。你能看到我哪里搞砸了吗?

trId 的计算导致某些索引重叠,并跳过其他值。

具有 4x2 顶点网格(显示 idx)和 yColumnHeight 4:

0 4
 x <- (desired trID 0)
1 5
 x <- (desired trID 6)
2 6
 x <- (desired trID 12)
3 7

当前为id = 1,1 (idx 5)计算的trId结果为6,但它可能应该为0,以便[=19中的前6项=] 设置为有用的东西。事实上,使用当前计算,没有 trId 等于 0。此外,当前计算的 trId for id = 1,2 (idx 6) 也为 6! id=1,3 (idx 7) 也是如此。

遗憾的是,这种重叠发生在每一列中,因此大多数 triangleBuffer 都未设置。

答案是改变 trId 的计算方式。

一个简单的方法是重复使用从二维数组映射到一维数组的方法,只将 x 和 y 坐标减 1,同时将高度减 1:

顶点映射(当前):

int idx = (id.y + (yColumnHeight * id.x));

三角形映射(提议):

int trId = ((id.y-1) + ((yColumnHeight-1) * (id.x-1));
trId *= 6;

或更简单地说:

int trId = 6 * (id.y - 1 + (yColumnHeight-1) * (id.x-1));

或者,扩展和替换 idx。我发现这不太清楚发生了什么,但它更简洁:

//       = 6 * (id.y - 1 + yColumnHeight * id.x - yColumnHeight - id.x + 1)
//       = 6 * (id.y + yColumnHeight * id.x - yColumnHeight - id.x)
int trId = 6 * (idx - yColumnHeight - id.x);