Пример #1
0
    private void SetupBatch(GameObject prefab)
    {
        var materials = new List <Material>(10);
        var renderers = prefab.GetComponentsInChildren <Renderer>();

        foreach (var renderer in renderers)
        {
            renderer.GetSharedMaterials(materials);

            var mesh = GetMesh(renderer);
            foreach (var material in materials)
            {
                batchIndexes.Add(batchRendererGroup.AddBatch(
                                     mesh,
                                     0,
                                     material,
                                     0,
                                     ShadowCastingMode.Off,
                                     false,
                                     false,
                                     new Bounds(Vector3.zero, Vector3.one * float.MaxValue),
                                     split * split * split,
                                     null,
                                     gameObject));
            }
        }
    }
Пример #2
0
    void OnEnable()
    {
        _brg = new BatchRendererGroup(CullingCallback);

        var mesh = ObjectWeGetTheMeshFrom.GetComponent <MeshFilter>().sharedMesh;

        _batch = _brg.AddBatch(mesh, 0, _material, 0, castShadows: ShadowCastingMode.On,
                               receiveShadows: true, invertCulling: false,
                               bounds: new Bounds(Vector3.one * 10, Vector3.one * 20),
                               instanceCount: 1, customProps: null,
                               associatedSceneObject: null);
    }
Пример #3
0
 private void OnEnable()
 {
     _batchRendererGroup = new BatchRendererGroup(CullingCallback);
     _batchIndex         = _batchRendererGroup.AddBatch(
         mesh,
         0,
         material,
         0,
         ShadowCastingMode.Off,
         false,
         false,
         new Bounds(Vector3.zero, Vector3.one * float.MaxValue), // ここではすごく大きいBoundsを渡しておく
         InstanceCount,
         null,
         gameObject);
 }
Пример #4
0
        private void RenderMeshes()
        {
            using (var chunks = _spriteWithMesh.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                var sharedSpriteMaterialType = GetArchetypeChunkSharedComponentType <SharedSpriteMaterialComponent>();
                var chunkSpriteMeshType      = GetArchetypeChunkComponentType <ChunkSpriteMeshComponent>(true);
                for (int chunkIdx = 0; chunkIdx < chunks.Length; chunkIdx++)
                {
                    var chunk           = chunks[chunkIdx];
                    var chunkSpriteMesh = chunk.GetChunkComponentData(chunkSpriteMeshType);
                    int chunkMeshId     = chunkSpriteMesh.ChunkMeshId;
                    var meshData        = _meshById[chunkMeshId];

                    if (meshData.MaterialVersion != LastSystemVersion)
                    {
                        continue;
                    }

                    int renderIndex = _meshIds.IndexOf(chunkMeshId);
                    if (renderIndex >= 0)
                    {
                        _renderGroup.RemoveBatch(renderIndex);
                        _meshIds.RemoveAtSwapBack(renderIndex);
                    }

                    var sharedSprite = chunk.GetSharedComponentData(sharedSpriteMaterialType, EntityManager);
                    renderIndex = _renderGroup.AddBatch(
                        meshData.Mesh,
                        subMeshIndex: 0,
                        sharedSprite.Material,
                        sharedSprite.Layer,
                        ShadowCastingMode.Off,
                        receiveShadows: false,
                        invertCulling: false,
                        meshData.Mesh.bounds,
                        instanceCount: 1,
                        customProps: null,
                        associatedSceneObject: null
                        );
                    Debug.Assert(renderIndex == _meshIds.Count);
                    _meshIds.Add(chunkMeshId);
                    var mvp = _renderGroup.GetBatchMatrices(renderIndex);
                    mvp[0] = float4x4.identity;
                }
            }
        }
Пример #5
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;
    }
Пример #6
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;
    }
Пример #7
0
    // During initialization, we will allocate all required objects, and set up our custom instance data.
    void Start()
    {
        // Create the BatchRendererGroup and register assets
        m_BRG        = new BatchRendererGroup(this.OnPerformCulling, IntPtr.Zero);
        m_MeshID     = m_BRG.RegisterMesh(mesh);
        m_MaterialID = m_BRG.RegisterMaterial(material);

        // Create the buffer that holds our instance data
        m_InstanceData = new GraphicsBuffer(GraphicsBuffer.Target.Raw,
                                            (kExtraBytes + kBytesPerInstance * kNumInstances) / sizeof(int),
                                            sizeof(int));

        // Place one zero matrix at the start of the instance data buffer, so loads from address 0 will return zero
        var zero = new Matrix4x4[1] {
            Matrix4x4.zero
        };

        // Create transform matrices for our three example instances
        var matrices = new Matrix4x4[kNumInstances]
        {
            Matrix4x4.Translate(new Vector3(-2, 0, 0)),
            Matrix4x4.Translate(new Vector3(0, 0, 0)),
            Matrix4x4.Translate(new Vector3(2, 0, 0)),
        };

        // Convert the transform matrices into the packed format expected by the shader
        var objectToWorld = new PackedMatrix[kNumInstances]
        {
            new PackedMatrix(matrices[0]),
            new PackedMatrix(matrices[1]),
            new PackedMatrix(matrices[2]),
        };

        // Also create packed inverse matrices
        var worldToObject = new PackedMatrix[kNumInstances]
        {
            new PackedMatrix(matrices[0].inverse),
            new PackedMatrix(matrices[1].inverse),
            new PackedMatrix(matrices[2].inverse),
        };

        // Make all instances have unique colors
        var colors = new Vector4[kNumInstances]
        {
            new Vector4(1, 0, 0, 1),
            new Vector4(0, 1, 0, 1),
            new Vector4(0, 0, 1, 1),
        };

        // In this simple example, the instance data is placed into the buffer like this:
        // Offset | Description
        //      0 | 64 bytes of zeroes, so loads from address 0 return zeroes
        //     64 | 32 uninitialized bytes to make working with SetData easier, otherwise unnecessary
        //     96 | unity_ObjectToWorld, three packed float3x4 matrices
        //    240 | unity_WorldToObject, three packed float3x4 matrices
        //    384 | _BaseColor, three float4s

        // Compute start addresses for the different instanced properties. unity_ObjectToWorld starts
        // at address 96 instead of 64, because the computeBufferStartIndex parameter of SetData
        // is expressed as source array elements, so it is easier to work in multiples of sizeof(PackedMatrix).
        uint byteAddressObjectToWorld = kSizeOfPackedMatrix * 2;
        uint byteAddressWorldToObject = byteAddressObjectToWorld + kSizeOfPackedMatrix * kNumInstances;
        uint byteAddressColor         = byteAddressWorldToObject + kSizeOfPackedMatrix * kNumInstances;

        // Upload our instance data to the GraphicsBuffer, from where the shader can load them.
        m_InstanceData.SetData(zero, 0, 0, 1);
        m_InstanceData.SetData(objectToWorld, 0, (int)(byteAddressObjectToWorld / kSizeOfPackedMatrix), objectToWorld.Length);
        m_InstanceData.SetData(worldToObject, 0, (int)(byteAddressWorldToObject / kSizeOfPackedMatrix), worldToObject.Length);
        m_InstanceData.SetData(colors, 0, (int)(byteAddressColor / kSizeOfFloat4), colors.Length);

        // Set up metadata values to point to the instance data. Set the most significant bit 0x80000000 in each,
        // which instructs the shader that the data is an array with one value per instance, indexed by the instance index.
        // Any metadata values used by the shader and not set here will be zero. When such a value is used with
        // UNITY_ACCESS_DOTS_INSTANCED_PROP (i.e. without a default), the shader will interpret the
        // 0x00000000 metadata value so that the value will be loaded from the start of the buffer, which is
        // where we uploaded the matrix "zero" to, so such loads are guaranteed to return zero, which is a reasonable
        // default value.
        var metadata = new NativeArray <MetadataValue>(3, Allocator.Temp);

        metadata[0] = new MetadataValue {
            NameID = Shader.PropertyToID("unity_ObjectToWorld"), Value = 0x80000000 | byteAddressObjectToWorld,
        };
        metadata[1] = new MetadataValue {
            NameID = Shader.PropertyToID("unity_WorldToObject"), Value = 0x80000000 | byteAddressWorldToObject,
        };
        metadata[2] = new MetadataValue {
            NameID = Shader.PropertyToID("_BaseColor"), Value = 0x80000000 | byteAddressColor,
        };

        // Finally, create a batch for our instances, and make the batch use the GraphicsBuffer with our
        // instance data, and the metadata values that specify where the properties are. Note that
        // we do not need to pass any batch size here.
        m_BatchID = m_BRG.AddBatch(metadata, m_InstanceData.bufferHandle);
    }