【问题标题】:Unity Compute Shaders Vertex Index errorUnity Compute Shaders 顶点索引错误
【发布时间】:2013-12-17 09:47:51
【问题描述】:

我有一个计算着色器和附带的 C# 脚本,用于修改 y 轴上的顶点数组,简单到足以清晰。

但尽管它运行良好,但着色器似乎忘记了我的形状的第一个顶点(除非该形状是封闭体积?)

这是 C# 类:

Mesh m;
//public bool stopProcess = false; //Useless in this version of exemple
MeshCollider coll;
public ComputeShader csFile; //the compute shader file added the Unity way
Vector3[] arrayToProcess; //An array of vectors i'll use to store data
ComputeBuffer cbf; //the buffer CPU->GPU (An early version with exactly 
                   //the same result had only this one)
ComputeBuffer cbfOut; //the Buffer GPU->CPU
int vertexLength;

void Awake() { //Assigning my stuff
  coll = gameObject.GetComponent<MeshCollider>();
  m = GetComponent<MeshFilter>().sharedMesh;
  vertexLength = m.vertices.Length;
  arrayToProcess = m.vertices; //setting the first version of the vertex array (copy of mesh)
}

void Start () {

   cbf = new ComputeBuffer(vertexLength,32); //Buffer in
   cbfOut = new ComputeBuffer(vertexLength,32); //Buffer out
   csFile.SetBuffer(0,"Board",cbf); 
   csFile.SetBuffer(0,"BoardOut",cbfOut);

}

void Update () {
   csFile.SetFloat("time",Time.time);
   cbf.SetData(m.vertices);
   csFile.Dispatch(0,vertexLength,vertexLength,1); //Dispatching (i think there is my mistake)
   cbfOut.GetData(arrayToProcess); //getting back my processed vertices
   m.vertices = arrayToProcess; //assigning them to the mesh
   //coll.sharedMesh = m; //collider stuff useless in this demo
}

还有我的计算着色器脚本:

#pragma kernel CSMain

RWStructuredBuffer<float3> Board : register(s[0]);
RWStructuredBuffer<float3> BoardOut : register(s[1]);

float time;

[numthreads(1,1,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    float valx = (sin((time*4)+Board[id.x].x));
    float valz = (cos((time*2)+Board[id.x].z));
    Board[id.x].y = (valx + valz)/5;
    BoardOut[id.x] = Board[id.x];
}

一开始我是从同一个缓冲区读取和写入,但由于遇到问题,我尝试使用单独的缓冲区,但没有成功。我还是有同样的问题。

也许我误解了应该使用计算着色器的方式(我知道我可以使用顶点着色器,但我只是想尝试计算着色器以进一步改进。)

为了完成我所说的,我想它与顶点在 Mesh.vertices 数组中的索引方式有关。

我尝试了很多不同的块/线程配置,但似乎没有解决问题组合尝试:

Block            Thread   
60,60,1         1,1,1
1,1,1           60,60,3
10,10,3         3,1,1

还有一些我不记得了。我认为最好的配置应该是平衡良好的配置,例如:

Block : VertexCount,1,1 Thread : 3,1,1

关于封闭体积:我不确定,因为对于 Cube {8 Vertices},一切似乎都相应地移动,但是对于具有奇数个顶点的形状,第一个(或最后一个尚未检查) ) 似乎没有被处理

我试过很多不同的形状,但细分平面最明显,一个角总是不动。

编辑:

经过进一步研究,我发现它只是计算着色器不计算网格的最后(不是我检查的第一个)顶点,它似乎与缓冲区类型有关,我仍然不明白为什么 RWStructuredBuffer 应该是一个问题或我使用它有多糟糕,它是否保留给流?我无法理解关于这个的 MSDN 文档。

编辑:解决后

C# 脚本:

using UnityEngine;
using System.Collections;


public class TreeObject : MonoBehaviour {
    Mesh m;
    public bool stopProcess = false;
    MeshCollider coll;
    public ComputeShader csFile;
    Vector3[] arrayToProcess;
    ComputeBuffer cbf;
    ComputeBuffer cbfOut;
    int vertexLength;
    // Use this for initialization
    void Awake() {
        coll = gameObject.GetComponent<MeshCollider>();
        m = GetComponent<MeshFilter>().mesh;
        vertexLength = m.vertices.Length+3; //I add 3 because apparently  
                                                        //vertexnumber is odd
        //arrayToProcess = new Vector3[vertexLength];
        arrayToProcess = m.vertices;
    }

    void Start () {

        cbf = new ComputeBuffer(vertexLength,12);
        cbfOut = new ComputeBuffer(vertexLength,12);
        csFile.SetBuffer(0,"Board",cbf);
        csFile.SetBuffer(0,"BoardOut",cbfOut);

    }

    // Update is called once per frame
    void Update () {
        csFile.SetFloat("time",Time.time);
        cbf.SetData(m.vertices);
        csFile.Dispatch(0,vertexLength,1,1);
        cbfOut.GetData(arrayToProcess);
        m.vertices = arrayToProcess;
        coll.sharedMesh = m;
    }

}

我已经回滚到 块 VCount,1,1 在你回答之前,因为这是我使用 VCount*VCount 的逻辑,所以处理顶点的次数比需要的多。

要完成,您是绝对正确的,Stride 显然给出了问题,您能否通过有关 stride 参数的文档链接来完成您的答案? (从任何地方,因为 Unity 文档是 VOID 并且 MSDN 没有帮助我理解为什么它应该是 12 而不是 32(因为我认为 32 是 float3 的大小)

所以请提供文档

与此同时,我将尝试提供足够灵活(通用?)的版本以使其更强大,并开始在我的着色器中添加一些不错的数组处理功能...

【问题讨论】:

    标签: c# unity3d hlsl compute-shader stride


    【解决方案1】:

    我熟悉 Compute Shaders,但从未接触过 Unity,但在查看 Unity 中的 Compute Shaders 文档后,我发现了几件事。

    创建 cbf 和 cbfOut ComputeBuffers 时的步长为 32(字节?)。您的两个 StructuredBuffers 都包含 float3s,其步长为 12 个字节,而不是 32 个。32 来自哪里?

    当您分派计算着色器时,您请求的是二维分派 (vertexLength,vertexLength, 1),但您正在对 float3s 的一维数组进行操作。您最终会遇到一个竞争条件,其中许多不同的线程认为他们负责更新数组的每个元素。虽然性能很糟糕,但如果您想要 [numthreads(1,1,1)] 的线程组大小,那么您应该在调用 Dispatch 时调度 (vertexLength, 1, 1) 个波/波前(即 Dispatch (60,1 ,1) 与 numThreads(1,1,1))。

    为获得最佳/更好的性能,线程组/波中的线程数应至少为 64 的倍数,以在 AMD 硬件上实现最佳效率。然后,您只需要调度 ceil(numVertices/64) 波前,然后只需将一些逻辑插入着色器以确保 id.x 不会超出任何给定线程的范围。

    编辑:

    ComputeBuffer 构造函数的文档在这里:Unity ComputeBuffer Documentation 虽然它没有明确说“步幅”是以字节为单位的,但这是唯一合理的假设。

    【讨论】:

    • 好吧,我试试看(实际上 32 位步幅来自一顶魔法帽,因为我不知道它代表什么)让我试试,我会尽快回到这里
    猜你喜欢
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-23
    • 2013-08-23
    相关资源
    最近更新 更多