Example #1
0
    private void InitializeBuffers()
    {
        int computeShaderInputSize  = Marshal.SizeOf(typeof(ComputeShaderInputData));
        int computeShaderOutputSize = Marshal.SizeOf(typeof(ComputeShaderOutputData));

        m_argsBuffer                = new ComputeBuffer(m_instances.Count * NUMBER_OF_ARGS_PER_INSTANCE, 5 * sizeof(uint), ComputeBufferType.IndirectArguments);
        m_positionsBuffer           = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_lodDistancesTempBuffer    = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_culledInstanceBuffer      = new ComputeBuffer(m_numberOfInstances, computeShaderOutputSize, ComputeBufferType.Default);
        m_isVisibleBuffer           = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedInstancePredicates = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_groupSumArray             = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedGroupSumBuffer     = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);

        m_argsBuffer.SetData(m_args);
        m_positionsBuffer.SetData(instancesPositionsArray);
        m_lodDistancesTempBuffer.SetData(instancesPositionsArray);

        for (int i = 0; i < m_renderers.Count; i++)
        {
            IndirectRenderingMesh irm = m_renderers[i];
            irm.Lod00MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);
            irm.Lod01MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);
            irm.Lod02MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);
        }
    }
Example #2
0
    private void DrawVisibleInstances()
    {
        if (enableSimpleShadows)
        {
            for (int i = 0; i < m_indirectMeshes.Length; i++)
            {
                int argsIndex             = i * ARGS_BYTE_SIZE_PER_INSTANCE_TYPE;
                IndirectRenderingMesh irm = m_indirectMeshes[i];
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 0, irm.lod00MatPropBlock, ShadowCastingMode.Off);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 1, irm.lod01MatPropBlock, ShadowCastingMode.Off);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 2, irm.lod02MatPropBlock, ShadowCastingMode.Off);
                Graphics.DrawMeshInstancedIndirect(irm.shadowMesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 3, irm.shadowMatPropBlock, ShadowCastingMode.ShadowsOnly);
            }
        }
        else
        {
            for (int i = 0; i < m_indirectMeshes.Length; i++)
            {
                int argsIndex             = i * ARGS_BYTE_SIZE_PER_INSTANCE_TYPE;
                IndirectRenderingMesh irm = m_indirectMeshes[i];
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 0, irm.lod00MatPropBlock, ShadowCastingMode.On);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 1, irm.lod01MatPropBlock, ShadowCastingMode.On);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, argsIndex + ARGS_BYTE_SIZE_PER_DRAW_CALL * 2, irm.lod02MatPropBlock, ShadowCastingMode.On);
            }
        }

        if (debugDrawHiZ)
        {
            debugCamera.Render();
        }
    }
Example #3
0
    private void LateUpdate()    //OnPreCull()
    {
        if (m_renderers == null ||
            m_renderers.Count == 0 ||
            m_hiZBuffer.HiZDepthTexture == null ||
            m_showHiZTexture == true)
        {
            return;
        }

        RunCompute();

        // Draw visible objects
        if (m_debugStop == DebugStop.DontStop)
        {
            for (int i = 0; i < m_renderers.Count; i++)
            {
                IndirectRenderingMesh irm = m_renderers[i];

                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_drawBounds, m_argsBuffer, (i * 60) + 00, irm.Lod00MatPropBlock, m_shadowCastingMode, m_receiveShadows);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_drawBounds, m_argsBuffer, (i * 60) + 20, irm.Lod01MatPropBlock, m_shadowCastingMode, m_receiveShadows);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_drawBounds, m_argsBuffer, (i * 60) + 40, irm.Lod02MatPropBlock, m_shadowCastingMode, m_receiveShadows);
            }
        }
    }
    private void DrawInstances()
    {
        ShadowCastingMode objShadowCastingMode = (m_enableLOD02Shadow) ? ShadowCastingMode.Off : ShadowCastingMode.On;

        for (int i = 0; i < m_renderers.Length; i++)
        {
            IndirectRenderingMesh irm = m_renderers[i];
            if (!m_debugDisableMesh)
            {
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, (i * 80) + 00, irm.Lod00MatPropBlock, objShadowCastingMode, true);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, (i * 80) + 20, irm.Lod01MatPropBlock, objShadowCastingMode, true);
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, (i * 80) + 40, irm.Lod02MatPropBlock, objShadowCastingMode, true);
            }

            if (m_enableLOD02Shadow)
            {
                Graphics.DrawMeshInstancedIndirect(irm.mesh, 0, irm.material, m_bounds, m_argsBuffer, (i * 80) + 60, irm.ShadowMatPropBlock, ShadowCastingMode.ShadowsOnly, false);
            }
        }
    }
Example #5
0
    public void Initialize()
    {
        m_00_lodSortingCSKernelID          = m_00_lodSortingCS.FindKernel("BitonicSort");
        m_00_lodSortingTransposeCSKernelID = m_00_lodSortingCS.FindKernel("MatrixTranspose");
        m_01_occlusionKernelID             = m_01_occlusionCS.FindKernel("CSMain");
        m_02_scanInstancesKernelID         = m_02_scanInstancesCS.FindKernel("CSMain");
        m_03_scanGroupSumsKernelID         = m_03_scanGroupSumsCS.FindKernel("CSMain");
        m_04_copyInstanceDataKernelID      = m_04_copyInstanceDataCS.FindKernel("CSMain");
        m_05_calcInstanceOffsetsKernelID   = m_05_calcInstanceOffsetsCS.FindKernel("CSMain");

        int materialPropertyCounter = 0;
        int instanceCounter         = 0;

        m_args = new uint[m_instances.Count * NUMBER_OF_ARGS_PER_INSTANCE];
        for (int i = 0; i < m_instances.Count; i++)
        {
            IndirectRenderingMesh irm  = new IndirectRenderingMesh();
            IndirectInstanceData  data = m_instances[i];

            // Initialize Mesh
            irm.mesh = new Mesh();
            irm.mesh.CombineMeshes(
                new CombineInstance[] {
                new CombineInstance()
                {
                    mesh = data.lod00Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod01Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod02Mesh
                }
            },
                true,                           // Merge Submeshes
                false,                          // Use Matrices
                false                           // Has lightmap data
                );

            // Arguments
            int argsIndex = i * NUMBER_OF_ARGS_PER_INSTANCE;

            // Buffer with arguments has to have five integer numbers
            // LOD00
            m_args[argsIndex + 0] = data.lod00Mesh.GetIndexCount(0);                            // 0 - index count per instance,
            m_args[argsIndex + 1] = 0;                                                          // 1 - instance count
            m_args[argsIndex + 2] = 0;                                                          // 2 - start index location
            m_args[argsIndex + 3] = 0;                                                          // 3 - base vertex location
            m_args[argsIndex + 4] = 0;                                                          // 4 - start instance location

            // LOD01
            m_args[argsIndex + 5] = data.lod01Mesh.GetIndexCount(0);                    // 0 - index count per instance,
            m_args[argsIndex + 6] = 0;                                                  // 1 - instance count
            m_args[argsIndex + 7] = m_args[argsIndex + 0] + m_args[argsIndex + 2];      // 2 - start index location
            m_args[argsIndex + 8] = 0;                                                  // 3 - base vertex location
            m_args[argsIndex + 9] = 0;                                                  // 4 - start instance location

            // LOD02
            m_args[argsIndex + 10] = data.lod02Mesh.GetIndexCount(0);                   // 0 - index count per instance,
            m_args[argsIndex + 11] = 0;                                                 // 1 - instance count
            m_args[argsIndex + 12] = m_args[argsIndex + 5] + m_args[argsIndex + 7];     // 2 - start index location
            m_args[argsIndex + 13] = 0;                                                 // 3 - base vertex location
            m_args[argsIndex + 14] = 0;                                                 // 4 - start instance location


            // Materials
            irm.Lod00MatPropBlock = new MaterialPropertyBlock();
            irm.Lod01MatPropBlock = new MaterialPropertyBlock();
            irm.Lod02MatPropBlock = new MaterialPropertyBlock();

            // ----------------------------------------------------------
            // Silly workaround for a shadow bug.
            // If we don't set a unique value to the property block we
            // only get shadows in one of our draw calls.
            irm.Lod00MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 1);
            irm.Lod01MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 2);
            irm.Lod02MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 3);
            // End of silly workaround!
            // ----------------------------------------------------------

            irm.Lod00MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);
            irm.Lod01MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);
            irm.Lod02MatPropBlock.SetBuffer("positionBuffer", m_culledInstanceBuffer);

            irm.material = new Material(data.material);

            // Add the instance data (positions, rotations, scaling, bounds...)
            for (int j = 0; j < m_instances[i].positions.Length; j++)
            {
                instanceCounter++;
                IndirectInstanceData   _data   = m_instances[i];
                ComputeShaderInputData newData = new ComputeShaderInputData();

                Bounds b = new Bounds();
                b.Encapsulate(_data.lod00Mesh.bounds);
                b.Encapsulate(_data.lod01Mesh.bounds);
                b.Encapsulate(_data.lod02Mesh.bounds);
                // b.extents *= _data.uniformScales[j];

                newData.drawCallID       = (uint)i * NUMBER_OF_ARGS_PER_INSTANCE;
                newData.position         = _data.positions[j];
                newData.rotation         = _data.rotations[j];
                newData.uniformScale     = _data.uniformScales[j];
                newData.boundsCenter     = _data.positions[j];
                newData.boundsExtents    = b.extents * 0.5f;
                newData.distanceToCamera = Vector3.Distance(newData.position, m_camera.transform.position);

                irm.computeInstances.Add(newData);
            }

            // Add the data to the renderer list
            m_renderers.Add(irm);
        }

        // HACK! Padding the data so it becomes the power of two.
        if (!Mathf.IsPowerOfTwo(instanceCounter))
        {
            int iterations = Mathf.NextPowerOfTwo(instanceCounter) - instanceCounter;
            for (int j = 0; j < iterations; j++)
            {
                m_renderers[0].computeInstances.Add(new ComputeShaderInputData()
                {
                    drawCallID = HACK_POT_PADDING_DRAW_ID
                });
            }
        }

        List <ComputeShaderInputData> tempInstancesPositionsList = new List <ComputeShaderInputData>();

        for (int i = 0; i < m_renderers.Count; i++)
        {
            tempInstancesPositionsList.AddRange(m_renderers[i].computeInstances);
        }

        instancesPositionsArray = tempInstancesPositionsList.ToArray();
        m_numberOfInstances     = tempInstancesPositionsList.Count;

        InitializeBuffers();
    }
Example #6
0
    private void LogStats()
    {
        if (!debugLogStats)
        {
            return;
        }
        debugLogStats = false;

        if (m_sb == null)
        {
            m_sb = new StringBuilder();
        }

        uint[] argsData = new uint[m_instances.Length * NUMBER_OF_ARGS_PER_INSTANCE_TYPE];
        m_argsBuffer.GetData(argsData);
        uint totalNumOfInstances = 0;
        uint totalNumOfIndices   = 0;
        uint totalNumOfVertices  = 0;
        uint totalShadowVertices = 0;
        uint totalShadowIndices  = 0;

        m_sb.AppendLine("---------------");
        int counter = 0;

        for (int i = 0; i < argsData.Length; i = i + 20)
        {
            IndirectRenderingMesh irm = m_indirectMeshes[counter];
            if (i > 0)
            {
                m_sb.AppendLine();
            }

            uint numOfLod00Instances = argsData[i + 1];
            uint numOfLod01Instances = argsData[i + 6];
            uint numOfLod02Instances = argsData[i + 11];

            uint numOfLod00Indices = argsData[i + 0];
            uint numOfLod01Indices = argsData[i + 5];
            uint numOfLod02Indices = argsData[i + 10];

            uint numOfLod00Vertices = (uint)irm.numOfVerticesLod00;
            uint numOfLod01Vertices = (uint)irm.numOfVerticesLod01;
            uint numOfLod02Vertices = (uint)irm.numOfVerticesLod02;

            uint numOfInstances =
                numOfLod00Instances
                + numOfLod01Instances
                + numOfLod02Instances;
            uint numOfIndices =
                numOfLod00Instances * numOfLod00Indices
                + numOfLod01Instances * numOfLod01Indices
                + numOfLod02Instances * numOfLod02Indices;
            uint numOfVertices =
                numOfLod00Instances * numOfLod00Vertices
                + numOfLod01Instances * numOfLod01Vertices
                + numOfLod02Instances * numOfLod02Vertices;
            uint numOfShadowIndices  = (enableSimpleShadows) ? numOfInstances * numOfLod02Indices : numOfIndices;
            uint numOfShadowVertices = (enableSimpleShadows) ? numOfInstances * numOfLod02Vertices : numOfVertices;

            totalNumOfInstances += numOfInstances;
            totalNumOfIndices   += numOfIndices;
            totalNumOfVertices  += numOfVertices;
            totalShadowIndices  += numOfShadowIndices;
            totalShadowVertices += numOfShadowVertices;

            m_sb.AppendLine("Instances: " + numOfInstances.ToString("N0") + " ("
                            + numOfLod00Instances.ToString("N0") + ", "
                            + numOfLod01Instances.ToString("N0") + ", "
                            + numOfLod02Instances.ToString("N0") + ")"
                            );
            m_sb.AppendLine("Vertices: " + numOfVertices.ToString("N0") + " ("
                            + numOfLod00Vertices.ToString("N0") + ", "
                            + numOfLod01Vertices.ToString("N0") + ", "
                            + numOfLod02Vertices.ToString("N0") + ")"
                            );
            m_sb.AppendLine("Indices: " + numOfIndices.ToString("N0") + " ("
                            + numOfLod00Indices.ToString("N0") + ", "
                            + numOfLod01Indices.ToString("N0") + ", "
                            + numOfLod02Indices.ToString("N0") + ")"
                            );
            m_sb.AppendLine("Shadow: " + numOfShadowVertices.ToString("N0") + " Vertices "
                            + numOfShadowIndices.ToString("N0") + " indices"
                            );

            counter++;
        }

        StringBuilder total = new StringBuilder();

        total.Append("Total Instances: ");
        total.AppendLine(totalNumOfInstances.ToString("N0"));
        total.Append("Total Vertices: ");
        total.AppendLine(totalNumOfVertices.ToString("N0"));
        total.Append("Total Indices: ");
        total.AppendLine(totalNumOfIndices.ToString("N0"));
        total.Append("Shadow Vertices: ");
        total.AppendLine(totalShadowIndices.ToString("N0"));
        total.Append("Shadow Indices: ");
        total.AppendLine(totalShadowVertices.ToString("N0"));

        Debug.Log(total.ToString());
        Debug.Log(m_sb.ToString());
    }
Example #7
0
    public void Initialize(IndirectInstanceData[] _instances)
    {
        m_instances             = _instances;
        m_numberOfInstanceTypes = m_instances.Length;

        m_lodSortingCSKernelID          = lodSortingCS.FindKernel("BitonicSort");
        m_lodSortingTransposeCSKernelID = lodSortingCS.FindKernel("MatrixTranspose");
        m_occlusionKernelID             = occlusionCS.FindKernel("CSMain");
        m_scanInstancesKernelID         = scanInstancesCS.FindKernel("CSMain");
        m_scanGroupSumsKernelID         = scanGroupSumsCS.FindKernel("CSMain");
        m_copyInstanceDataKernelID      = copyInstanceDataCS.FindKernel("CSMain");

        int instanceCounter = 0;
        List <InstanceData> allInstancesPositionsList = new List <InstanceData>();

        m_indirectMeshes = new IndirectRenderingMesh[m_numberOfInstanceTypes];
        m_args           = new uint[m_numberOfInstanceTypes * NUMBER_OF_ARGS_PER_INSTANCE_TYPE];
        for (int i = 0; i < m_numberOfInstanceTypes; i++)
        {
            IndirectRenderingMesh irm  = new IndirectRenderingMesh();
            IndirectInstanceData  data = m_instances[i];

            // Initialize Mesh
            irm.numOfVerticesLod00  = (uint)data.lod00Mesh.vertexCount;
            irm.numOfVerticesLod01  = (uint)data.lod01Mesh.vertexCount;
            irm.numOfVerticesLod02  = (uint)data.lod02Mesh.vertexCount;
            irm.numOfVerticesShadow = (uint)data.shadowMesh.vertexCount;
            irm.numOfIndicesLod00   = data.lod00Mesh.GetIndexCount(0);
            irm.numOfIndicesLod01   = data.lod01Mesh.GetIndexCount(0);
            irm.numOfIndicesLod02   = data.lod02Mesh.GetIndexCount(0);
            irm.numOfIndicesShadow  = data.shadowMesh.GetIndexCount(0);

            irm.mesh = new Mesh();
            irm.mesh.CombineMeshes(
                new CombineInstance[] {
                new CombineInstance()
                {
                    mesh = data.lod00Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod01Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod02Mesh
                }
            },
                true,       // Merge Submeshes
                false,      // Use Matrices
                false       // Has lightmap data
                );

            irm.shadowMesh = data.shadowMesh;

            // Arguments
            int argsIndex = i * NUMBER_OF_ARGS_PER_INSTANCE_TYPE;

            // Buffer with arguments has to have five integer numbers
            // LOD00
            m_args[argsIndex + 0] = irm.numOfIndicesLod00;                          // 0 - index count per instance,
            m_args[argsIndex + 1] = 0;                                              // 1 - instance count
            m_args[argsIndex + 2] = 0;                                              // 2 - start index location
            m_args[argsIndex + 3] = 0;                                              // 3 - base vertex location
            m_args[argsIndex + 4] = 0;                                              // 4 - start instance location

            // LOD01
            m_args[argsIndex + 5] = irm.numOfIndicesLod01;                          // 0 - index count per instance,
            m_args[argsIndex + 6] = 0;                                              // 1 - instance count
            m_args[argsIndex + 7] = m_args[argsIndex + 0] + m_args[argsIndex + 2];  // 2 - start index location
            m_args[argsIndex + 8] = 0;                                              // 3 - base vertex location
            m_args[argsIndex + 9] = 0;                                              // 4 - start instance location

            // LOD02
            m_args[argsIndex + 10] = irm.numOfIndicesLod02;                         // 0 - index count per instance,
            m_args[argsIndex + 11] = 0;                                             // 1 - instance count
            m_args[argsIndex + 12] = m_args[argsIndex + 5] + m_args[argsIndex + 7]; // 2 - start index location
            m_args[argsIndex + 13] = 0;                                             // 3 - base vertex location
            m_args[argsIndex + 14] = 0;                                             // 4 - start instance location

            // Shadow
            m_args[argsIndex + 15] = irm.numOfIndicesShadow;                        // 0 - index count per instance,
            m_args[argsIndex + 16] = 0;                                             // 1 - instance count
            m_args[argsIndex + 17] = 0;                                             // 2 - start index location
            m_args[argsIndex + 18] = 0;                                             // 3 - base vertex location
            m_args[argsIndex + 19] = 0;                                             // 4 - start instance location

            // Materials
            irm.material = new Material(data.material);

            // Add the instance data (positions, rotations, scaling, bounds...)
            for (int j = 0; j < m_instances[i].positions.Length; j++)
            {
                IndirectInstanceData _data   = m_instances[i];
                InstanceData         newData = new InstanceData();

                // Calculate the renderer bounds
                GameObject obj = Instantiate(m_instances[i].prefab);
                obj.transform.localScale = obj.transform.localScale;
                Renderer[] rends = obj.GetComponentsInChildren <Renderer>();
                Bounds     b     = new Bounds();
                for (int r = 0; r < rends.Length; r++)
                {
                    b.Encapsulate(rends[r].bounds);
                }
                DestroyImmediate(obj);

                newData.drawDataID       = (uint)(instanceCounter);
                newData.drawCallID       = (uint)argsIndex;
                newData.position         = _data.positions[j];
                newData.rotation         = _data.rotations[j];
                newData.uniformScale     = _data.uniformScales[j];
                newData.boundsCenter     = b.center;//_data.positions[j];
                newData.boundsExtents    = b.extents * _data.uniformScales[j];
                newData.distanceToCamera = Vector3.Distance(_data.positions[j], mainCamera.transform.position);
                irm.computeInstances.Add(newData);
                allInstancesPositionsList.Add(newData);

                instanceCounter++;
            }

            // Add the data to the renderer list
            m_indirectMeshes[i] = irm;
        }

        InstanceData[] instancesPositionsArray = allInstancesPositionsList.ToArray();
        m_numberOfInstances = allInstancesPositionsList.Count;

        int computeShaderInputSize  = Marshal.SizeOf(typeof(InstanceData));
        int computeShaderOutputSize = Marshal.SizeOf(typeof(InstanceDrawData));

        m_argsBuffer                = new ComputeBuffer(m_numberOfInstanceTypes * 20, sizeof(uint), ComputeBufferType.IndirectArguments);
        m_instanceDataBuffer        = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_instanceDrawDataBuffer    = new ComputeBuffer(m_numberOfInstances, computeShaderOutputSize, ComputeBufferType.Default);
        m_lodDistancesTempBuffer    = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_culledInstanceBuffer      = new ComputeBuffer(m_numberOfInstances, computeShaderOutputSize, ComputeBufferType.Default);
        m_isVisibleBuffer           = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedInstancePredicates = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_groupSumArray             = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedGroupSumBuffer     = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);

        m_argsBuffer.SetData(m_args);
        m_instanceDataBuffer.SetData(instancesPositionsArray);
        m_lodDistancesTempBuffer.SetData(instancesPositionsArray);

        // Setup the Material Property blocks for our meshes...
        int materialPropertyCounter = 0;

        for (int i = 0; i < m_indirectMeshes.Length; i++)
        {
            IndirectRenderingMesh irm = m_indirectMeshes[i];
            int argsIndex             = i * NUMBER_OF_ARGS_PER_INSTANCE_TYPE;

            irm.lod00MatPropBlock  = new MaterialPropertyBlock();
            irm.lod01MatPropBlock  = new MaterialPropertyBlock();
            irm.lod02MatPropBlock  = new MaterialPropertyBlock();
            irm.shadowMatPropBlock = new MaterialPropertyBlock();

            // ----------------------------------------------------------
            // Silly workaround for a shadow bug in Unity.
            // If we don't set a unique value to the property block we
            // only get shadows in one of our draw calls.
            irm.lod00MatPropBlock.SetFloat("_Whatever", +materialPropertyCounter++);
            irm.lod01MatPropBlock.SetFloat("_Whatever", +materialPropertyCounter++);
            irm.lod02MatPropBlock.SetFloat("_Whatever", +materialPropertyCounter++);
            irm.shadowMatPropBlock.SetFloat("_Whatever", +materialPropertyCounter++);
            // End of silly workaround!
            // ----------------------------------------------------------

            irm.lod00MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.lod01MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.lod02MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.shadowMatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);

            irm.lod00MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
            irm.lod01MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
            irm.lod02MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
            irm.shadowMatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);

            irm.lod00MatPropBlock.SetInt("_ArgsOffset", argsIndex + 4);
            irm.lod01MatPropBlock.SetInt("_ArgsOffset", argsIndex + 9);
            irm.lod02MatPropBlock.SetInt("_ArgsOffset", argsIndex + 14);
            irm.shadowMatPropBlock.SetInt("_ArgsOffset", argsIndex + 19);
        }

        // Create the buffer containing draw data for all instances
        m_createInstanceDrawBufferCSKernelID = createInstanceDrawBufferCS.FindKernel("CSMain");
        createInstanceDrawBufferCS.SetBuffer(m_createInstanceDrawBufferCSKernelID, "_InstanceDataIn", m_instanceDataBuffer);
        createInstanceDrawBufferCS.SetBuffer(m_createInstanceDrawBufferCSKernelID, "_InstanceDataOut", m_instanceDrawDataBuffer);
        int groupX = m_numberOfInstances / (2 * SCAN_THREAD_GROUP_SIZE);

        createInstanceDrawBufferCS.Dispatch(m_createInstanceDrawBufferCSKernelID, groupX, 1, 1);

        CreateCommandBuffers();
    }
    public void Initialize(IndirectInstanceData[] _instances)
    {
        m_instances             = _instances;
        m_numberOfInstanceTypes = m_instances.Length;

        m_00_lodSortingCSKernelID          = m_00_lodSortingCS.FindKernel("BitonicSort");
        m_00_lodSortingTransposeCSKernelID = m_00_lodSortingCS.FindKernel("MatrixTranspose");
        m_01_occlusionKernelID             = m_01_occlusionCS.FindKernel("CSMain");
        m_02_scanInstancesKernelID         = m_02_scanInstancesCS.FindKernel("CSMain");
        m_03_scanGroupSumsKernelID         = m_03_scanGroupSumsCS.FindKernel("CSMain");
        m_04_copyInstanceDataKernelID      = m_04_copyInstanceDataCS.FindKernel("CSMain");
        m_05_calcInstanceOffsetsKernelID   = m_05_calcInstanceOffsetsCS.FindKernel("CSMain");

        int materialPropertyCounter = 0;
        int instanceCounter         = 0;

        List <InstanceData> allInstancesPositionsList = new List <InstanceData>();

        m_renderers = new IndirectRenderingMesh[m_numberOfInstanceTypes];
        m_args      = new uint[m_numberOfInstanceTypes * NUMBER_OF_ARGS_PER_INSTANCE];
        for (int i = 0; i < m_numberOfInstanceTypes; i++)
        {
            IndirectRenderingMesh irm  = new IndirectRenderingMesh();
            IndirectInstanceData  data = m_instances[i];

            // Initialize Mesh
            irm.mesh = new Mesh();
            irm.mesh.CombineMeshes(
                new CombineInstance[] {
                new CombineInstance()
                {
                    mesh = data.lod00Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod01Mesh
                },
                new CombineInstance()
                {
                    mesh = data.lod02Mesh
                }
            },
                true,       // Merge Submeshes
                false,      // Use Matrices
                false       // Has lightmap data
                );

            // Arguments
            int argsIndex = i * NUMBER_OF_ARGS_PER_INSTANCE;

            // Buffer with arguments has to have five integer numbers
            // LOD00
            m_args[argsIndex + 0] = data.lod00Mesh.GetIndexCount(0);                // 0 - index count per instance,
            m_args[argsIndex + 1] = 0;                                              // 1 - instance count
            m_args[argsIndex + 2] = 0;                                              // 2 - start index location
            m_args[argsIndex + 3] = 0;                                              // 3 - base vertex location
            m_args[argsIndex + 4] = 0;                                              // 4 - start instance location

            // LOD01
            m_args[argsIndex + 5] = data.lod01Mesh.GetIndexCount(0);                // 0 - index count per instance,
            m_args[argsIndex + 6] = 0;                                              // 1 - instance count
            m_args[argsIndex + 7] = m_args[argsIndex + 0] + m_args[argsIndex + 2];  // 2 - start index location
            m_args[argsIndex + 8] = 0;                                              // 3 - base vertex location
            m_args[argsIndex + 9] = 0;                                              // 4 - start instance location

            // LOD02
            m_args[argsIndex + 10] = data.lod02Mesh.GetIndexCount(0);               // 0 - index count per instance,
            m_args[argsIndex + 11] = 0;                                             // 1 - instance count
            m_args[argsIndex + 12] = m_args[argsIndex + 5] + m_args[argsIndex + 7]; // 2 - start index location
            m_args[argsIndex + 13] = 0;                                             // 3 - base vertex location
            m_args[argsIndex + 14] = 0;                                             // 4 - start instance location

            // Shadow
            m_args[argsIndex + 15] = m_args[argsIndex + 10];                        // 0 - index count per instance,
            m_args[argsIndex + 16] = 0;                                             // 1 - instance count
            m_args[argsIndex + 17] = m_args[argsIndex + 12];                        // 2 - start index location
            m_args[argsIndex + 18] = 0;                                             // 3 - base vertex location
            m_args[argsIndex + 19] = 0;                                             // 4 - start instance location

            // Materials
            irm.Lod00MatPropBlock  = new MaterialPropertyBlock();
            irm.Lod01MatPropBlock  = new MaterialPropertyBlock();
            irm.Lod02MatPropBlock  = new MaterialPropertyBlock();
            irm.ShadowMatPropBlock = new MaterialPropertyBlock();

            // ----------------------------------------------------------
            // Silly workaround for a shadow bug.
            // If we don't set a unique value to the property block we
            // only get shadows in one of our draw calls.
            irm.Lod00MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 1);
            irm.Lod01MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 2);
            irm.Lod02MatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 3);
            irm.ShadowMatPropBlock.SetFloat("_Whatever" + materialPropertyCounter++, 4);
            // End of silly workaround!
            // ----------------------------------------------------------

            irm.material = new Material(data.material);

            // Add the instance data (positions, rotations, scaling, bounds...)
            for (int j = 0; j < m_instances[i].positions.Length; j++)
            {
                instanceCounter++;
                IndirectInstanceData _data   = m_instances[i];
                InstanceData         newData = new InstanceData();

                Bounds b = new Bounds();
                b.Encapsulate(_data.lod00Mesh.bounds);
                b.Encapsulate(_data.lod01Mesh.bounds);
                b.Encapsulate(_data.lod02Mesh.bounds);
                b.extents *= _data.uniformScales[j];

                newData.drawCallID       = (uint)i * NUMBER_OF_ARGS_PER_INSTANCE;
                newData.position         = _data.positions[j];
                newData.rotation         = _data.rotations[j];
                newData.uniformScale     = _data.uniformScales[j];
                newData.boundsCenter     = _data.positions[j];
                newData.boundsExtents    = b.extents;
                newData.distanceToCamera = Vector3.Distance(newData.position, m_camera.transform.position);

                irm.computeInstances.Add(newData);
                allInstancesPositionsList.Add(newData);
            }

            // Add the data to the renderer list
            m_renderers[i] = irm;
        }

        // HACK!
        // Padding the buffer with data so the size is in power of two.
        // Reason is that the current implementation of the Bitonic Sort
        // only supports that. On the todo list to fix!
        if (!Mathf.IsPowerOfTwo(instanceCounter))
        {
            int iterations = Mathf.NextPowerOfTwo(instanceCounter) - instanceCounter;
            for (int j = 0; j < iterations; j++)
            {
                InstanceData newData = new InstanceData()
                {
                    drawCallID = HACK_POT_PADDING_DRAW_ID
                };
                m_renderers[0].computeInstances.Add(newData);
                allInstancesPositionsList.Add(newData);
            }
        }

        instancesPositionsArray = allInstancesPositionsList.ToArray();
        m_numberOfInstances     = allInstancesPositionsList.Count;

        int computeShaderInputSize  = Marshal.SizeOf(typeof(InstanceData));
        int computeShaderOutputSize = Marshal.SizeOf(typeof(InstanceDrawData));

        m_argsBuffer                = new ComputeBuffer(m_numberOfInstanceTypes, sizeof(uint) * NUMBER_OF_ARGS_PER_INSTANCE, ComputeBufferType.IndirectArguments);
        m_instanceDataBuffer        = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_lodDistancesTempBuffer    = new ComputeBuffer(m_numberOfInstances, computeShaderInputSize, ComputeBufferType.Default);
        m_culledInstanceBuffer      = new ComputeBuffer(m_numberOfInstances, computeShaderOutputSize, ComputeBufferType.Default);
        m_isVisibleBuffer           = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedInstancePredicates = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_groupSumArray             = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);
        m_scannedGroupSumBuffer     = new ComputeBuffer(m_numberOfInstances, sizeof(uint), ComputeBufferType.Default);

        m_argsBuffer.SetData(m_args);
        m_instanceDataBuffer.SetData(instancesPositionsArray);
        m_lodDistancesTempBuffer.SetData(instancesPositionsArray);

        for (int i = 0; i < m_renderers.Length; i++)
        {
            IndirectRenderingMesh irm = m_renderers[i];
            irm.Lod00MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.Lod01MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.Lod02MatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);
            irm.ShadowMatPropBlock.SetBuffer("_InstanceDrawDataBuffer", m_culledInstanceBuffer);

            int argsIndex = i * NUMBER_OF_ARGS_PER_INSTANCE;
            if (Application.platform == RuntimePlatform.WindowsEditor ||
                Application.platform == RuntimePlatform.WindowsPlayer)
            {
                irm.Lod00MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
                irm.Lod01MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
                irm.Lod02MatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);
                irm.ShadowMatPropBlock.SetBuffer("_ArgsBuffer", m_argsBuffer);

                irm.Lod00MatPropBlock.SetInt("_ArgsOffset", argsIndex + 4);
                irm.Lod01MatPropBlock.SetInt("_ArgsBuffer", argsIndex + 9);
                irm.Lod02MatPropBlock.SetInt("_ArgsBuffer", argsIndex + 14);
                irm.ShadowMatPropBlock.SetInt("_ArgsBuffer", argsIndex + 19);
            }
        }
    }