Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by onehand · May 08, 2017 at 12:56 PM · shaderdrawcallscompute shaderprocedural-generationdirectx 11

Calling Graphics.DrawProcedural multiple times for chunked procedural terrain

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

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

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<Vert> _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?

overlapping-meshes-no-issue.jpg (212.6 kB)
overlapping-meshes-issue.jpg (260.2 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by onehand · May 14, 2017 at 07:30 PM

I managed to fix it using the aforementioned initializeMeshBuffer compute shader. I just had the thread groups set wrong in my dispatch call! Changed it to:

 initializeMeshBuffer.Dispatch(0, 1, 1, 1);

And it now clears the buffer data successfully! :)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Meffjuw · May 21, 2017 at 02:47 AM

Hi @onehand,

I've experimented a bit with procedural voxel generation, but that has always been on the CPU side so far. I am now attempting to learn how to carry out the same generation, but on GPUs, due to their parallel architecture. Would you mind sharing your source code with me? If not, can you at least point me to some tutorials/articles you have used which helped you?

Thanks :)

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image onehand · May 21, 2017 at 03:59 AM 0
Share

@$$anonymous$$effjuw I don't want to provide my source as I plan to use it in a commercial game eventually, but I can provide you a great sample project.

Unity project https://www.dropbox.com/s/8aao2q6lvxu70am/$$anonymous$$archingCubesOnTheGPU.zip?dl=0

Blog post https://www.dropbox.com/s/vpzjwaht71a679a/$$anonymous$$arching-Cubes-on-the-GPU-in-Unity-scrawkblog.zip?dl=0

This is an amazing asset that helped me learn a lot. This blog has since been taken down, so hopefully he doesn't $$anonymous$$d me posting it. But @scrawk please let me know if you want me to remove it. I personally think it's a great one to have out there for the community interested in procedural generation.

Also, you can find his new blog here: https://www.digital-dust.com/code

avatar image scrawk onehand · May 21, 2017 at 07:10 AM 1
Share

I dont $$anonymous$$d.

A improved version of this project will be on the new blog at some point.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

More than one Kernel in Compute Shader 1 Answer

Compute Shader not work on older GPU with DX11 0 Answers

Compute Shader crashes when buffer is too big 0 Answers

Use contents of RWStructuredBuffer written by shader in another shader 0 Answers

Texture sampling will move when sampled same position. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges