c# – Unity Compute着色器顶点索引错误
作者:互联网
我有一个计算着色器和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
关于封闭的体积:我不确定,因为有了立方体{8顶点}一切似乎都相应地移动,但是具有奇数个顶点的形状,第一个(或者最后没有检查过)似乎不被处理
我尝试了许多不同的形状,但细分的飞机是最明显的,一个角落总是不动.
编辑:
进一步研究后,我发现它只是计算着色器,它不计算网格的最后一个(不是第一个我检查过的)顶点,它似乎与缓冲区类型有关,我仍然不明白为什么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的大小)
所以Doc需要请
与此同时,我将尝试提供一个足够灵活(通用?)的版本,以使其更强大,并开始在我的着色器中添加一些不错的数组处理函数…
解决方法:
我熟悉计算着色器,但从未接触过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)个wave / wavefronts数量(即Dispatch(60,1) ,1)使用numThreads(1,1,1)).
为了获得最佳/更好的性能,线程组/ wave中的线程数应至少为64的倍数,以便在AMD硬件上实现最佳效率.然后,您只需要调度ceil(numVertices / 64)波前,然后只需在着色器中插入一些逻辑,以确保id.x不会超出任何给定线程的范围.
编辑:
ComputeBuffer构造函数的文档在这里:Unity ComputeBuffer Documentation
虽然它没有明确地说“步幅”以字节为单位,但它是唯一合理的假设.
标签:c,unity3d,hlsl,stride,compute-shader 来源: https://codeday.me/bug/20190703/1366688.html