- Home /
 
Graphics.DrawProceduralIndirect isnt rendering anything
Hi, I am running marching cubes on compute shaders and then was constructing meshes on the CPU which works fine.
I have now tried to use
 Graphics.DrawProceduralIndirect
 
               to draw the meshes straight from the GPU however nothing is rendering with this new approach. I was wondering if anyone could figure out what is wrong?
The compute shader:
 // Each #kernel tells which function to compile; you can have many kernels
 #pragma kernel March
 #include "MarchTables.compute"
  
 float isoLevel = 0;
 int width = 16;
 float resolution = 1;
  
  
 struct Triangle
 {
     float3 v[3];
 };
  
 float3 interpolateVertices(float3 v1, float3 v2, float value1, float value2)
 {
     float mu = (isoLevel - value1) / (value2 - value1);
  
     return float3(v1.xyz + mu * (v2.xyz - v1.xyz));
 }
  
 int flattenedIndex(int x, int y, int z)
 {
     return (x * (width + 1) * (width + 1)) + (y * (width + 1)) + z;
 }
  
  
 AppendStructuredBuffer<Triangle> triangleBuffer;
 RWStructuredBuffer<float> densityBuffer;
  
 //int height;
 //int width;
 //float isoLevel;
  
 [numthreads(8, 8, 8)]
 void March(int3 id : SV_DispatchThreadID)
 {
     if (id.x >= (width) || id.y >= (width) || id.z >= (width))
     {
         return;
     }
  
  
     float cubeCorners[8] =
     {
         densityBuffer[flattenedIndex(id.x, id.y, id.z + 1)],
         densityBuffer[flattenedIndex(id.x + 1, id.y, id.z + 1)],
         densityBuffer[flattenedIndex(id.x + 1, id.y, id.z)],
         densityBuffer[flattenedIndex(id.x, id.y, id.z)],
         densityBuffer[flattenedIndex(id.x, id.y + 1, id.z + 1)],
         densityBuffer[flattenedIndex(id.x + 1, id.y + 1, id.z + 1)],
         densityBuffer[flattenedIndex(id.x + 1, id.y + 1, id.z)],
         densityBuffer[flattenedIndex(id.x, id.y + 1, id.z)],
     };
  
     int cubeIndex = 0;
     if (cubeCorners[0] > isoLevel)
         cubeIndex |= 1;
     if (cubeCorners[1] > isoLevel)
         cubeIndex |= 2;
     if (cubeCorners[2] > isoLevel)
         cubeIndex |= 4;
     if (cubeCorners[3] > isoLevel)
         cubeIndex |= 8;
     if (cubeCorners[4] > isoLevel)
         cubeIndex |= 16;
     if (cubeCorners[5] > isoLevel)
         cubeIndex |= 32;
     if (cubeCorners[6] > isoLevel)
         cubeIndex |= 64;
     if (cubeCorners[7] > isoLevel)
         cubeIndex |= 128;
  
     if (cubeIndex == 0 || cubeIndex == 255)
     {
         return;
     }
  
     // Create triangles for current cube configuration
     for (int i = 0; triangulation[cubeIndex][i] != -1; i += 3)
     {
         // Get indices of corner points A and B for each of the three edges
         // of the cube that need to be joined to form the triangle.
         int a0 = cornerIndexAFromEdge[triangulation[cubeIndex][i]];
         int b0 = cornerIndexBFromEdge[triangulation[cubeIndex][i]];
  
         int a1 = cornerIndexAFromEdge[triangulation[cubeIndex][i + 1]];
         int b1 = cornerIndexBFromEdge[triangulation[cubeIndex][i + 1]];
  
         int a2 = cornerIndexAFromEdge[triangulation[cubeIndex][i + 2]];
         int b2 = cornerIndexBFromEdge[triangulation[cubeIndex][i + 2]];
  
         Triangle tri;
         tri.v[0] = interpolateVertices(float3(((id * resolution) + (vertexPositions[a0] * resolution))), float3(((id * resolution) + (vertexPositions[b0] * resolution))), cubeCorners[a0], cubeCorners[b0]);
         tri.v[1] = interpolateVertices(float3(((id * resolution) + (vertexPositions[a1] * resolution))), float3(((id * resolution) + (vertexPositions[b1] * resolution))), cubeCorners[a1], cubeCorners[b1]);
         tri.v[2] = interpolateVertices(float3(((id * resolution) + (vertexPositions[a2] * resolution))), float3(((id * resolution) + (vertexPositions[b2] * resolution))), cubeCorners[a2], cubeCorners[b2]);
         triangleBuffer.Append(tri);
     }
 }
 
               The shader:
 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  
 Shader "Unlit/TerrainShader"
 {
     Properties
     {
     }
         SubShader
     {
         Tags { "RenderType" = "Opaque" }
         LOD 100
  
         Pass
         {
             CGPROGRAM
             #pragma enable_d3d11_debug_symbols
             #pragma target 5.0
             #pragma vertex vert
             #pragma fragment frag
             // make fog work
             #pragma multi_compile_fog
  
             #include "UnityCG.cginc"
  
  
             struct Triangle {
                 float3 v[3];
  
             };
  
             uniform StructuredBuffer<Triangle> triangles;
             uniform float4x4 model;
  
             struct appdata
             {
                 float4 vertex : POSITION;
                 float2 uv : TEXCOORD0;
             };
  
             struct v2f
             {
                 float4 pos: SV_POSITION;
             };
  
             v2f vert (uint id : SV_VertexID)
             {
                 uint pid = id / 3;
                 uint vid = id % 3;
              
                 float3 pos = triangles[pid].v[vid];
  
                 v2f o;
                 o.pos = mul(UNITY_MATRIX_VP,mul(model,pos));
                 return o;
             }
  
             float4 frag(v2f i) : SV_Target
             {
                 return float4(1,0.5,0,1);
             }
             ENDCG
         }
     }
 }
 
               The C# code:
 public void GeneratePlanetOnGPU()
     {
         argBuffer = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments);
         int[] args = new int[] { 0, 1, 0, 0 };
         argBuffer.SetData(args);
  
         int threadGroups = (width / 8);
         int kernelHandle = shader.FindKernel("March");
         if (!useComputeDensity)
         {
             densityMap = new float[(width + 1) * (width + 1) * (width + 1)];
             densityBuffer = new ComputeBuffer((width + 1) * (width + 1) * (width + 1), sizeof(float));
             densityBuffer.SetData(densityMap);
             shader.SetBuffer(kernelHandle, "densityBuffer", densityBuffer);
         }
         else
         {
             ComputeBuffer db = dg.Generate(radius, width, resolution, new float[] { planetCentre.x, planetCentre.y, planetCentre.z }, new float[] { worldPos.x, worldPos.y, worldPos.z }, octaves, minHeight, strength);
             shader.SetBuffer(kernelHandle, "densityBuffer", db);
         }
         triangleCountBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
         triangleBuffer = new ComputeBuffer((width) * (width) * (width) * 5, sizeof(float) * 3 * 3, ComputeBufferType.Append);
         triangleBuffer.SetCounterValue(0);
         shader.SetBuffer(kernelHandle, "triangleBuffer", triangleBuffer);
         shader.SetInt("width", width);
         shader.SetFloat("resolution", resolution);
  
         shader.Dispatch(kernelHandle, threadGroups, threadGroups, threadGroups);
  
         ComputeBuffer.CopyCount(triangleBuffer, argBuffer, 0);
         argBuffer.GetData(args);
         int tris = args[0];
         args[0] *= 3;
         argBuffer.SetData(args);
  
         float size = 16 * resolution;
         Vector3 centre = worldPos + (Vector3.one * (size / 2));
  
         b = new Bounds(centre, new Vector3(size, size, size));
         setup = true;
  
     }
  
  
     private void OnRenderObject()
     {
         if (setup)
         {
             mat.SetPass(0);
             mat.SetBuffer("triangles", triangleBuffer);
             mat.SetMatrix("model", transform.localToWorldMatrix);
             Graphics.DrawProceduralIndirect(mat,b,MeshTopology.Triangles,argBuffer);
         }
  
     }
 
               The only difference between this and the CPU method is how the meshes are constructed. The gameobject the script is running on has a mesh filter and mesh renderer but I am unclear if it needs this. I assign the material in the inspector. Also, the gameobject is a prefab that is instantiated at runtime.
There are lots of these prefabs each running this C# script.
I have successfully used Graphics.DrawProcedural in the past and, while I'm not 100% sure, I think you also need to call Graphics.ClearRandomWriteTargets(); prior to setting the buffer on the material and calling DrawProceduralIndirect
Your answer
 
             Follow this Question
Related Questions
Procedural Shader Cost/Draw Calls 1 Answer
How to access another sprite's texture from a 2D shader 0 Answers
(Shader Graph) Output resolution/ setting resolution of the main preview window 0 Answers
How to see both sides of transparrent mesh? 1 Answer
Merging, Transitioning, or Blending from one texture to the other based upon Height Maps 0 Answers