Quantcast
Channel: Questions in topic: "compute shader"
Viewing all articles
Browse latest Browse all 287

Calling Graphics.DrawProcedural multiple times for chunked procedural terrain

$
0
0
In my project, I'm creating chunks of 3D procedural terrain (voxels) using a series of compute shaders and then passing the vertex data of each chunk from a ComputeBuffer to the Graphics.DrawProcedural method to be rendered in a surface shader. void OnPostRender() { foreach(GPUMeshData gMeshData in gpuMeshData) { m_drawBuffer.SetBuffer("_Buffer", gMeshData._Vert); m_drawBuffer.SetBuffer("_ColorBuffer", gMeshData._Color); m_drawBuffer.SetPass(0); Graphics.DrawProcedural(MeshTopology.Triangles, SIZE); } } ... ... public struct GPUMeshData { public int meshNum; public ComputeBuffer _Vert; public ComputeBuffer _Color; public GPUMeshData(int meshNumber, ComputeBuffer vert, ComputeBuffer color) { meshNum = meshNumber; _Vert = vert; _Color = color; } } It works OK, but the problem is that it appears the buffer data seems to get jumbled up intermittently. Newer buffer vertex data is somehow getting merged with older vertex data that was in previous frames but should no longer be present in my GPUMeshData list. As a result, old meshes at different LODs are overlapping my newly rendered chunks. It starts to get ugly quick. ![alt text][1] Through debugging, I know for certain that I'm not making calls to re-render the "bad" chunks/buffers after I remove them, yet somehow the old data gets mixed into one of my new buffers. When I remove objects from the GPUMeshData list, I am doing a Release() on the ComputeBuffers as well: public void removeChunkGPU(int meshNum) { if(gpuMeshData.Exists(x => x.meshNum == meshNum)) { GPUMeshData gMeshData = gpuMeshData.Find(x => x.meshNum == meshNum); if(gMeshData._Vert != null) gMeshData._Vert.Release(); if(gMeshData._Color != null) gMeshData._Color.Release(); gpuMeshData.RemoveAll(x => x.meshNum == meshNum); } } I'm just trying to find out... am I doing a big "no-no" here by making multiple DrawProcedural calls for different buffers per frame? I can't understand how the older data is getting "stuck" in the Graphics pipeline. I also found a very similar question asked here: https://forum.unity3d.com/threads/compute-shaders-and-drawprocedural-drawproceduralindirect.413196/ In my case though, I only need to render a maximum of ~350 chunks in the worst case. But as that poster mentioned, merging all chunks into a single buffer just seems counter-intuitive to me. Any thoughts are appreciated! **EDIT: ** So I discovered something that seems to fix the issue, but I'm not sure why exactly. Essentially if I pre-initialize all the values in my mesh ComputeBuffers using a **SetData()** call before generating data in them, the problem no longer occurs. public void generateChunkGPU(OctreeNode node) { ... ... gpuMeshData.Add(new GPUMeshData(meshNum, new ComputeBuffer(SIZE, sizeof(float)*7), new ComputeBuffer(SIZE, sizeof(float)*4))); GPUMeshData gMeshData = gpuMeshData[gpuMeshData.Count-1]; // Initialize all verts to -1 float[] val = new float[SIZE*7]; for(int k = 0; k < SIZE*7; k++) val[k] = -1.0f; gMeshData._Vert.SetData(val); ... perlinNoise.SetFloat("_ChunkWidth", chunkWidth); ... perlinNoise.SetBuffer(0, "_Result", noiseBuffer); perlinNoise.Dispatch(0, 4, 4, 4); marchingCubes.SetFloat("_ChunkWidth", chunkWidth); ... marchingCubes.SetBuffer(0, "_Voxels", noiseBuffer); marchingCubes.SetBuffer(0, "_Buffer", gMeshData._Vert); marchingCubes.Dispatch(0, 4, 4, 4); } ![alt text][2] Obviously though **SetData()** is very expensive and stalls on the CPU, so I'd like to avoid using it. But this seems to suggest that whenever I create a new ComputeBuffer, there is some "left over" data sitting in memory where it's allocating to create the new buffer. I also tried writing another ComputeShader to just "clear" the buffer in my remove function: public void removeChunkGPU(int meshNum) { if(gpuMeshData.Exists(x => x.meshNum == meshNum)) { GPUMeshData gMeshData = gpuMeshData.Find(x => x.meshNum == meshNum); // Clear buffer before releasing initializeMeshBuffer.SetInt("SIZE", SIZE); initializeMeshBuffer.SetBuffer(0, "_Buffer", gMeshData._Vert); initializeMeshBuffer.Dispatch(0, 0, 0, 1); if(gMeshData._Vert != null) gMeshData._Vert.Release(); if(gMeshData._Color != null) gMeshData._Color.Release(); gpuMeshData.RemoveAll(x => x.meshNum == meshNum); } } But that didn't seem to help at all.. Here's the shader code for it anyway: #pragma kernel CSMain struct Vert { float4 position; float3 normal; }; int SIZE; RWStructuredBuffer _Buffer; [numthreads(1,1,1)] void CSMain (uint3 id : SV_DispatchThreadID) { Vert vert; vert.position = float4(-1.0, -1.0, -1.0, -1.0); vert.normal = float3(-1.0, -1.0, -1.0); for(int i = 0; i < SIZE; i++) _Buffer[i] = vert; } Anybody have any thoughts on how I can avoid using **SetData()** and truly get a clear ComputeBuffer each time I create a new one? [1]: /storage/temp/93386-overlapping-meshes-issue.jpg [2]: /storage/temp/93958-overlapping-meshes-no-issue.jpg

Viewing all articles
Browse latest Browse all 287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>