Example #1
0
    // Start is called before the first frame update
    void Start()
    {
        m_BatchRendererGroup = new BatchRendererGroup(this.OnPerformCulling, IntPtr.Zero);

#if ENABLE_PICKING
        m_PickingMaterial = LoadMaterialWithHideAndDontSave("Hidden/HDRP/BRGPicking");
        m_BatchRendererGroup.SetPickingMaterial(m_PickingMaterial);
#endif

#if ENABLE_ERROR_LOADING_MATERIALS
        if (SetFallbackMaterialsOnStart)
        {
            m_ErrorMaterial = LoadMaterialWithHideAndDontSave("Hidden/HDRP/MaterialError");
            m_BatchRendererGroup.SetErrorMaterial(m_ErrorMaterial);

            m_LoadingMaterial = LoadMaterialWithHideAndDontSave("Hidden/HDRP/MaterialLoading");
            m_BatchRendererGroup.SetLoadingMaterial(m_LoadingMaterial);
        }
#endif

        // Create a batch...
        var renderers = FindObjectsOfType <MeshRenderer>();
        Debug.Log("Converting " + renderers.Length + " renderers...");

        m_renderers   = new NativeArray <DrawRenderer>(renderers.Length, Allocator.Persistent);
        m_batchHash   = new NativeHashMap <DrawKey, int>(1024, Allocator.Persistent);
        m_rangeHash   = new NativeHashMap <RangeKey, int>(1024, Allocator.Persistent);
        m_drawBatches = new NativeList <DrawBatch>(Allocator.Persistent);
        m_drawRanges  = new NativeList <DrawRange>(Allocator.Persistent);

        // Fill the GPU-persistent scene data ComputeBuffer
        int bigDataBufferVector4Count = 4 /*zero*/ + 1 /*probes*/ + 1 /*speccube*/ + 7 /*SH*/ + m_renderers.Length * 3 * 2 /*per renderer 4x3 matrix+inverse*/;
        var vectorBuffer = new NativeArray <Vector4>(bigDataBufferVector4Count, Allocator.Temp);

        // First 4xfloat4 of ComputeBuffer needed to be zero filled for default property fall back!
        vectorBuffer[0] = new Vector4(0, 0, 0, 0);
        vectorBuffer[1] = new Vector4(0, 0, 0, 0);
        vectorBuffer[2] = new Vector4(0, 0, 0, 0);
        vectorBuffer[3] = new Vector4(0, 0, 0, 0);
        var startOffset = 4;

        // Fill global data (shared between all batches)
        var probesOcclusionOffset = startOffset;
        vectorBuffer[probesOcclusionOffset] = new Vector4(1, 1, 1, 1);
        startOffset++;

        var specCubeOffset = startOffset;
        vectorBuffer[specCubeOffset] = ReflectionProbe.defaultTextureHDRDecodeValues;
        startOffset++;

        var SHOffset = startOffset;
        var SH       = new SHProperties(RenderSettings.ambientProbe);
        vectorBuffer[SHOffset + 0] = SH.SHAr;
        vectorBuffer[SHOffset + 1] = SH.SHAg;
        vectorBuffer[SHOffset + 2] = SH.SHAb;
        vectorBuffer[SHOffset + 3] = SH.SHBr;
        vectorBuffer[SHOffset + 4] = SH.SHBg;
        vectorBuffer[SHOffset + 5] = SH.SHBb;
        vectorBuffer[SHOffset + 6] = SH.SHC;
        startOffset += 7;

        var localToWorldOffset = startOffset;
        var worldToLocalOffset = localToWorldOffset + m_renderers.Length * 3;

        m_instances = new NativeList <DrawInstance>(1024, Allocator.Persistent);

        for (int i = 0; i < renderers.Length; i++)
        {
            var renderer = renderers[i];

            m_renderers[i] = new DrawRenderer {
                bounds = new AABB {
                    Center = new float3(0, 0, 0), Extents = new float3(0, 0, 0)
                }
            };

            var meshFilter = renderer.gameObject.GetComponent <MeshFilter>();
            if (!renderer || !meshFilter || !meshFilter.sharedMesh || renderer.enabled == false)
            {
                continue;
            }

            // Disable the existing Unity MeshRenderer to avoid double rendering!
            renderer.enabled = false;

            /*  mat4x3 packed like this:
             *    p1.x, p1.w, p2.z, p3.y,
             *    p1.y, p2.x, p2.w, p3.z,
             *    p1.z, p2.y, p3.x, p3.w,
             *    0.0,  0.0,  0.0,  1.0
             */

            var m = renderer.transform.localToWorldMatrix;
            vectorBuffer[i * 3 + 0 + localToWorldOffset] = new Vector4(m.m00, m.m10, m.m20, m.m01);
            vectorBuffer[i * 3 + 1 + localToWorldOffset] = new Vector4(m.m11, m.m21, m.m02, m.m12);
            vectorBuffer[i * 3 + 2 + localToWorldOffset] = new Vector4(m.m22, m.m03, m.m13, m.m23);

            var mi = renderer.transform.worldToLocalMatrix;
            vectorBuffer[i * 3 + 0 + worldToLocalOffset] = new Vector4(mi.m00, mi.m10, mi.m20, mi.m01);
            vectorBuffer[i * 3 + 1 + worldToLocalOffset] = new Vector4(mi.m11, mi.m21, mi.m02, mi.m12);
            vectorBuffer[i * 3 + 2 + worldToLocalOffset] = new Vector4(mi.m22, mi.m03, mi.m13, mi.m23);

            // Renderer bounds
            var transformedBounds = AABB.Transform(m, meshFilter.sharedMesh.bounds.ToAABB());
            m_renderers[i] = new DrawRenderer {
                bounds = transformedBounds
            };

            var mesh = m_BatchRendererGroup.RegisterMesh(meshFilter.sharedMesh);

            var sharedMaterials = new List <Material>();
            renderer.GetSharedMaterials(sharedMaterials);

            var shadows = renderer.shadowCastingMode;

            for (int matIndex = 0; matIndex < sharedMaterials.Count; matIndex++)
            {
                var material = m_BatchRendererGroup.RegisterMaterial(sharedMaterials[matIndex]);

                var key = new DrawKey {
                    material = material, meshID = mesh, submeshIndex = (uint)matIndex, shadows = shadows
                };

#if ENABLE_PICKING
                key.pickableObjectInstanceID = renderer.gameObject.GetInstanceID();
#endif

                var drawBatch = new DrawBatch
                {
                    key            = key,
                    instanceCount  = 0,
                    instanceOffset = 0
                };

                m_instances.Add(new DrawInstance {
                    key = key, instanceIndex = i
                });

                int drawBatchIndex;
                if (m_batchHash.TryGetValue(key, out drawBatchIndex))
                {
                    drawBatch = m_drawBatches[drawBatchIndex];
                }
                else
                {
                    drawBatchIndex = m_drawBatches.Length;
                    m_drawBatches.Add(drawBatch);
                    m_batchHash[key] = drawBatchIndex;

                    // Different renderer settings? -> new range
                    var rangeKey = new RangeKey {
                        shadows = shadows
                    };
                    var drawRange = new DrawRange
                    {
                        key        = rangeKey,
                        drawCount  = 0,
                        drawOffset = 0,
                    };

                    int drawRangeIndex;
                    if (m_rangeHash.TryGetValue(rangeKey, out drawRangeIndex))
                    {
                        drawRange = m_drawRanges[drawRangeIndex];
                    }
                    else
                    {
                        drawRangeIndex = m_drawRanges.Length;
                        m_drawRanges.Add(drawRange);
                        m_rangeHash[rangeKey] = drawRangeIndex;
                    }

                    drawRange.drawCount++;
                    m_drawRanges[drawRangeIndex] = drawRange;
                }

                drawBatch.instanceCount++;
                m_drawBatches[drawBatchIndex] = drawBatch;
            }
        }

        m_GPUPersistentInstanceData = new GraphicsBuffer(GraphicsBuffer.Target.Raw, (int)bigDataBufferVector4Count * 16 / 4, 4);
        m_GPUPersistentInstanceData.SetData(vectorBuffer);

        Debug.Log("DrawRanges: " + m_drawRanges.Length + ", DrawBatches: " + m_drawBatches.Length + ", Instances: " + m_instances.Length);

        // Prefix sum to calculate draw offsets for each DrawRange
        int prefixSum = 0;
        for (int i = 0; i < m_drawRanges.Length; i++)
        {
            var drawRange = m_drawRanges[i];
            drawRange.drawOffset = prefixSum;
            m_drawRanges[i]      = drawRange;
            prefixSum           += drawRange.drawCount;
        }

        // Generate draw index ranges for each DrawRange
        m_drawIndices = new NativeArray <int>(m_drawBatches.Length, Allocator.Persistent);
        var m_internalRangeIndex = new NativeArray <int>(m_drawRanges.Length, Allocator.Temp);
        for (int i = 0; i < m_drawBatches.Length; i++)
        {
            var draw = m_drawBatches[i];
            if (m_rangeHash.TryGetValue(new RangeKey {
                shadows = draw.key.shadows
            }, out int drawRangeIndex))
            {
                var drawRange = m_drawRanges[drawRangeIndex];
                m_drawIndices[drawRange.drawOffset + m_internalRangeIndex[drawRangeIndex]] = i;
                m_internalRangeIndex[drawRangeIndex]++;
            }
        }
        m_internalRangeIndex.Dispose();

        // Prefix sum to calculate instance offsets for each DrawCommand
        prefixSum = 0;
        for (int i = 0; i < m_drawBatches.Length; i++)
        {
            // DrawIndices remap to get DrawCommands ordered by DrawRange
            var remappedIndex = m_drawIndices[i];
            var drawBatch     = m_drawBatches[remappedIndex];
            drawBatch.instanceOffset     = prefixSum;
            m_drawBatches[remappedIndex] = drawBatch;
            prefixSum += drawBatch.instanceCount;
        }

        // Generate instance index ranges for each DrawCommand
        m_instanceIndices = new NativeArray <int>(m_instances.Length, Allocator.Persistent);
        var m_internalDrawIndex = new NativeArray <int>(m_drawBatches.Length, Allocator.Temp);
        for (int i = 0; i < m_instances.Length; i++)
        {
            var instance = m_instances[i];
            if (m_batchHash.TryGetValue(instance.key, out int drawBatchIndex))
            {
                var drawBatch = m_drawBatches[drawBatchIndex];
                m_instanceIndices[drawBatch.instanceOffset + m_internalDrawIndex[drawBatchIndex]] = instance.instanceIndex;
                m_internalDrawIndex[drawBatchIndex]++;
            }
        }
        m_internalDrawIndex.Dispose();

        // Bounds ("infinite")
        UnityEngine.Bounds bounds = new Bounds(new Vector3(0, 0, 0), new Vector3(1048576.0f, 1048576.0f, 1048576.0f));
        m_BatchRendererGroup.SetGlobalBounds(bounds);

        // Batch metadata buffer...

        // Per instance data
        int objectToWorldID = Shader.PropertyToID("unity_ObjectToWorld");
        int worldToObjectID = Shader.PropertyToID("unity_WorldToObject");
        int colorID         = Shader.PropertyToID("_BaseColor");

        // Global data (should be moved to C++ side)
        int probesOcclusionID = Shader.PropertyToID("unity_ProbesOcclusion");
        int specCubeID        = Shader.PropertyToID("unity_SpecCube0_HDR");
        int SHArID            = Shader.PropertyToID("unity_SHAr");
        int SHAgID            = Shader.PropertyToID("unity_SHAg");
        int SHAbID            = Shader.PropertyToID("unity_SHAb");
        int SHBrID            = Shader.PropertyToID("unity_SHBr");
        int SHBgID            = Shader.PropertyToID("unity_SHBg");
        int SHBbID            = Shader.PropertyToID("unity_SHBb");
        int SHCID             = Shader.PropertyToID("unity_SHC");

        var batchMetadata = new NativeArray <MetadataValue>(11, Allocator.Temp);
        batchMetadata[0]  = CreateMetadataValue(objectToWorldID, localToWorldOffset * UnsafeUtility.SizeOf <Vector4>(), true);
        batchMetadata[1]  = CreateMetadataValue(worldToObjectID, worldToLocalOffset * UnsafeUtility.SizeOf <Vector4>(), true);
        batchMetadata[2]  = CreateMetadataValue(probesOcclusionID, probesOcclusionOffset * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[3]  = CreateMetadataValue(specCubeID, specCubeOffset * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[4]  = CreateMetadataValue(SHArID, (SHOffset + 0) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[5]  = CreateMetadataValue(SHAgID, (SHOffset + 1) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[6]  = CreateMetadataValue(SHAbID, (SHOffset + 2) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[7]  = CreateMetadataValue(SHBrID, (SHOffset + 3) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[8]  = CreateMetadataValue(SHBgID, (SHOffset + 4) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[9]  = CreateMetadataValue(SHBbID, (SHOffset + 5) * UnsafeUtility.SizeOf <Vector4>(), false);
        batchMetadata[10] = CreateMetadataValue(SHCID, (SHOffset + 6) * UnsafeUtility.SizeOf <Vector4>(), false);

        // Register batch
        m_batchID = m_BatchRendererGroup.AddBatch(batchMetadata, m_GPUPersistentInstanceData.bufferHandle);

        m_initialized = true;
    }
Example #2
0
    // Start is called before the first frame update
    void Start()
    {
        m_BatchRendererGroup = new BatchRendererGroup(this.OnPerformCulling, IntPtr.Zero);

        int itemCount = itemGridSize * itemGridSize;

        m_itemCount = itemCount;

        // Bounds
        UnityEngine.Bounds bounds = new Bounds(new Vector3(0, 0, 0), new Vector3(1048576.0f, 1048576.0f, 1048576.0f));
        m_BatchRendererGroup.SetGlobalBounds(bounds);

        // Register mesh and material
        if (m_mesh)
        {
            m_meshID = m_BatchRendererGroup.RegisterMesh(m_mesh);
        }
        if (m_material)
        {
            m_materialID = m_BatchRendererGroup.RegisterMaterial(m_material);
        }

        // Batch metadata buffer
        int objectToWorldID   = Shader.PropertyToID("unity_ObjectToWorld");
        int matrixPreviousMID = Shader.PropertyToID("unity_MatrixPreviousM");
        int worldToObjectID   = Shader.PropertyToID("unity_WorldToObject");
        int colorID           = Shader.PropertyToID("_BaseColor");

        // Generate a grid of objects...
        int bigDataBufferVector4Count = 4 + itemCount * (3 * 3 + 1);      // 4xfloat4 zero + per instance = { 3x mat4x3, 1x float4 color }

        m_sysmemBuffer = new NativeArray <Vector4>(bigDataBufferVector4Count, Allocator.Persistent, NativeArrayOptions.ClearMemory);
        m_GPUPersistentInstanceData = new GraphicsBuffer(GraphicsBuffer.Target.Raw, (int)bigDataBufferVector4Count * 16 / 4, 4);

        // 64 bytes of zeroes, so loads from address 0 return zeroes. This is a BatchRendererGroup convention.
        int positionOffset = 4;

        m_sysmemBuffer[0] = new Vector4(0, 0, 0, 0);
        m_sysmemBuffer[1] = new Vector4(0, 0, 0, 0);
        m_sysmemBuffer[2] = new Vector4(0, 0, 0, 0);
        m_sysmemBuffer[3] = new Vector4(0, 0, 0, 0);

        // Matrices
        UpdatePositions(m_center);

        // Colors
        int colorOffset = positionOffset + itemCount * 3 * 3;

        for (int i = 0; i < itemCount; i++)
        {
            Color col = Color.HSVToRGB(((float)(i) / (float)itemCount) % 1.0f, 1.0f, 1.0f);

            // write colors right after the 4x3 matrices
            m_sysmemBuffer[colorOffset + i] = new Vector4(col.r, col.g, col.b, 1.0f);
        }
        m_GPUPersistentInstanceData.SetData(m_sysmemBuffer);

        var batchMetadata = new NativeArray <MetadataValue>(4, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

        batchMetadata[0] = CreateMetadataValue(objectToWorldID, 64, true);                                                        // matrices
        batchMetadata[1] = CreateMetadataValue(matrixPreviousMID, 64 + itemCount * UnsafeUtility.SizeOf <Vector4>() * 3, true);   // previous matrices
        batchMetadata[2] = CreateMetadataValue(worldToObjectID, 64 + itemCount * UnsafeUtility.SizeOf <Vector4>() * 3 * 2, true); // inverse matrices
        batchMetadata[3] = CreateMetadataValue(colorID, 64 + itemCount * UnsafeUtility.SizeOf <Vector4>() * 3 * 3, true);         // colors

        // Register batch
        m_batchID = m_BatchRendererGroup.AddBatch(batchMetadata, m_GPUPersistentInstanceData.bufferHandle);

        m_initialized = true;
    }