Example #1
0
 private void Update()
 {
     if (splitors != null)
     {
         bool completed = true;
         foreach (var splitor in splitors)
         {
             splitor.OnUpdate();
             if (!splitor.IsComplete)
             {
                 completed = false;
             }
         }
         if (completed)
         {
             int totalCullCnt = 0;
             int batchCount   = 0;
             foreach (var splitor in splitors)
             {
                 totalCullCnt += splitor.TotalCount;
                 foreach (var batch in splitor.SplitedBatches)
                 {
                     if (batch.InstanceCount > 0)
                     {
                         ++batchCount;
                     }
                 }
             }
             batchRendererGroup = new BatchRendererGroup(this.OnPerformCulling);
             cullData           = new NativeArray <CullData>(totalCullCnt, Allocator.Persistent);
             cullDataOffset     = new NativeArray <int>(batchCount, Allocator.Persistent);
             int cullOffset = 0;
             int batchIdx   = 0;
             for (int i = 0; i < splitors.Length; ++i)
             {
                 var splitor = splitors[i];
                 if (splitor.TotalCount <= 0)
                 {
                     continue;
                 }
                 var proto = layers[i];
                 foreach (var batch in splitor.SplitedBatches)
                 {
                     if (batch.InstanceCount > 0)
                     {
                         cullDataOffset[batchIdx] = cullOffset;
                         ++batchIdx;
                         AddBatch(proto.mesh, proto.mat, batch, ref cullOffset);
                     }
                 }
             }
             //clear
             foreach (var splitor in splitors)
             {
                 splitor.Clear();
             }
             splitors = null;
         }
     }
 }
Example #2
0
    private void Awake()
    {
        Camera camera = null;
        var    data   = camera.GetUniversalAdditionalCameraData();

        // data.antialiasing = AntialiasingMode.None;
        // camera.clearFlags = CameraClearFlags.Depth;
        // camera.RenderWithShader();
        // data.clearDepth = false;
        batchRendererGroup = new BatchRendererGroup(this.OnPerformCulling);
        cullData           = new NativeArray <CullData>(25000, Allocator.Persistent);

        for (int j = 0; j < 50; j++)
        {
            var pos   = new float3[50];
            var rot   = new quaternion[50];
            var scale = new float3[50];
            for (int i = 0; i < 50; i++)
            {
                pos[i]   = new float3(i * 2, 0, j * 2);
                rot[i]   = quaternion.identity;
                scale[i] = new float3(1.0f, 1.0f, 1.0f);
            }
            this.AddBatch(100 * j, 50, pos, rot, scale);
        }
    }
Example #3
0
 private void OnDestroy()
 {
     if (this._batchRendererGroup != null)
     {
         this._batchRendererGroup.Dispose();
         this._batchRendererGroup = null;
         _cullDatas.Dispose();
     }
 }
Example #4
0
    private void OnEnable()
    {
        batchRendererGroup = new BatchRendererGroup(CullingCallback);
        batchIndexes       = new List <int>(10);

        foreach (var prefab in prefabs)
        {
            SetupBatch(prefab);
        }
    }
Example #5
0
        // private void Start()
        // {
        //  // instance 的buffer 需要关闭 batcher
        //  // ((UniversalRenderPipelineAsset) GraphicsSettings.currentRenderPipeline).useSRPBatcher = false;
        // }

        private void OnDestroy()
        {
            if (batchRendererGroup != null)
            {
                cullingDependency.Complete();
                batchRendererGroup.Dispose();
                batchRendererGroup = null;
                cullData.Dispose();
            }
        }
    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);
    }
    private void Start()
    {
        _batchRendererGroup = new BatchRendererGroup(OnPerformCulling);
        //    _cullDatas = new NativeArray<CullData>(50000,Allocator.Persistent);

        _cullDic = new NativeMultiHashMap <int, CullData>(100, Allocator.Persistent);

        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Restart();
        aDD();
        Debug.Log("batch render group :" + stopwatch.ElapsedMilliseconds);
    }
Example #8
0
 private JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext)
 {
     // no culling at all! this just sets up everything as visible.
     for (int batch = 0; batch < cullingContext.batchVisibility.Length; batch++)
     {
         var bv = cullingContext.batchVisibility[batch];
         bv.visibleCount = bv.instancesCount;
         cullingContext.batchVisibility[batch] = bv;
         for (int instance = 0; instance < bv.instancesCount; instance++)
         {
             cullingContext.visibleIndices[bv.offset + instance] = instance;
         }
     }
     return(new JobHandle());
 }
    // You can safely ignore this. It is just a pass-throught that performs no culling
    JobHandle CullingCallback(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext)
    {
        // dummy culling
        for (var batchIndex = 0; batchIndex < cullingContext.batchVisibility.Length; ++batchIndex)
        {
            var batchVisibility = cullingContext.batchVisibility[batchIndex];

            for (var i = 0; i < batchVisibility.instancesCount; ++i)
            {
                cullingContext.visibleIndices[batchVisibility.offset + i] = i;
            }

            batchVisibility.visibleCount = batchVisibility.instancesCount;
            cullingContext.batchVisibility[batchIndex] = batchVisibility;
        }
        return(default);
Example #10
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);
 }
Example #11
0
 protected override void OnCreate()
 {
     _renderGroup    = new BatchRendererGroup(OnPerformCulling);
     _spriteEntities = Entities.WithAllReadOnly <SpriteComponent, LocalToWorld, SharedSpriteMaterialComponent>().ToEntityQuery();
     _spriteWithMesh = GetEntityQuery(new EntityQueryDesc
     {
         All = new[] {
             ComponentType.ReadOnly <SharedSpriteMaterialComponent>(),
             ComponentType.ChunkComponentReadOnly <ChunkSpriteMeshComponent>()
         },
     });
     _spriteMissingMesh = GetEntityQuery(new EntityQueryDesc
     {
         All  = new[] { ComponentType.ReadOnly <SharedSpriteMaterialComponent>() },
         None = new[] { ComponentType.ChunkComponent <ChunkSpriteMeshComponent>() }
     });
 }
    private JobHandle OnPerformCulling(BatchRendererGroup batchRendererGroup, BatchCullingContext cullingContext)
    {
        var planes   = Unity.Rendering.FrustumPlanes.BuildSOAPlanePackets(cullingContext.cullingPlanes, Allocator.TempJob);
        var lodParms = LODGroupExtensions.CalculateLODParams(cullingContext.lodParameters);

        var cull = new MyCullJob()
        {
            Planes    = planes,
            LODParams = lodParms,
            IndexList = cullingContext.visibleIndices,
            Batches   = cullingContext.batchVisibility,
            CullDatas = _cullDic,
        };
        // Debug.Log(_cullDic.GetKeyArray(Allocator.Temp).Length); ;
        var handle = cull.Schedule(batchIndex + 1, 1);

        return(handle);
    }
Example #13
0
    private JobHandle CullingCallback(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext)
    {
        var inputDependency = _jobDependency;

        for (var i = 0; i < cullingContext.batchVisibility.Length; ++i)
        {
            var job = new CullingJob
            {
                CullingContext = cullingContext,
                Matrices       = rendererGroup.GetBatchMatrices(i),
                BatchIndex     = i
            }.Schedule(inputDependency);

            // Jobの依存関係を更新
            _jobDependency = JobHandle.CombineDependencies(job, _jobDependency);
        }

        return(_jobDependency);
    }
Example #14
0
    private JobHandle OnPerformCulling(
        BatchRendererGroup rendererGroup,
        BatchCullingContext cullingContext)
    {
        var planes    = FrustumPlanes.BuildSOAPlanePackets(cullingContext.cullingPlanes, Allocator.TempJob);
        var lodParams = LODGroupExtensions.CalculateLODParams(cullingContext.lodParameters);
        var cull      = new MyCullJob()
        {
            Planes    = planes,
            LODParams = lodParams,
            IndexList = cullingContext.visibleIndices,
            Batches   = cullingContext.batchVisibility,
            CullDatas = cullData,
        };
        var handle = cull.Schedule(100, 32, cullingDependency);

        cullingDependency = JobHandle.CombineDependencies(handle, cullingDependency);
        return(handle);
    }
Example #15
0
        private void Awake()
        {
            batchRendererGroup = new BatchRendererGroup(MyOnPerformCulling);
            cullData           = new NativeArray <CullData>(25000, Allocator.Persistent);

            for (int i = 0; i < 50; i++)
            {
                var pos   = new float3[50];
                var rot   = new quaternion[50];
                var scale = new float3[50];
                for (int j = 0; j < 50; j++)
                {
                    pos[j]   = new float3(j * 2, 0, i * 2);
                    rot[j]   = quaternion.identity;   //Random.rotation;
                    scale[j] = 1;                     //Random.value;
                }

                AddBatch(100 * i, 50, pos, rot, scale);
            }
        }
Example #16
0
        private JobHandle MyOnPerformCulling(BatchRendererGroup renderergroup, BatchCullingContext cullingContext)
        {
            var planes    = OtherUtils.BuildSOAPlanePackets(cullingContext.cullingPlanes, Allocator.TempJob);
            var lodParams = OtherUtils.CalculateLODParams(cullingContext.lodParameters);
            //传入visibleIndices和batchVisibility 在job里面修改
            var cull = new MyCullJob()
            {
                planes    = planes,
                lodParams = lodParams,
                indexList = cullingContext.visibleIndices,
                batches   = cullingContext.batchVisibility,
                cullDatas = cullData,
            };
            //50组lod0 + 50组lod1 = 100
            // cullingDependency 形成队列关系
            var handle = cull.Schedule(100, 32, cullingDependency);

            cullingDependency = JobHandle.CombineDependencies(handle, cullingDependency);
            return(handle);
        }
Example #17
0
    private void Start()
    {
        _batchRendererGroup = new BatchRendererGroup(OnPerformCulling);
        _cullDatas          = new NativeArray <CullData>(50000, Allocator.Persistent);
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Restart();
        for (int j = 0; j < arrayLength; j++)
        {
            var pos   = new float3[3];
            var rot   = new quaternion[3];
            var scale = new float3[3];

            for (int i = 0; i < 3; i++)
            {
                pos[i]   = new float3(i * 5, j * 2, j * 2);
                rot[i]   = quaternion.identity;
                scale[i] = new float3(1, 1, 1);
            }
            AddBatch(3 * j, 3, pos, rot, scale);
        }
        Debug.Log("batch render group :" + stopwatch.ElapsedMilliseconds);
    }
Example #18
0
    private JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext)
    {
        var planes = new NativeArray <float4>(cullingContext.cullingPlanes.Length, Allocator.TempJob);

        for (int i = 0; i < cullingContext.cullingPlanes.Length; ++i)
        {
            var p = cullingContext.cullingPlanes[i];
            planes[i] = new float4(p.normal, p.distance);
        }
        var cull = new MTDetailCullJob()
        {
            Planes         = planes,
            CamerPos       = cullingContext.lodParameters.cameraPosition,
            IndexList      = cullingContext.visibleIndices,
            Batches        = cullingContext.batchVisibility,
            CullDataOffset = cullDataOffset,
            CullDatas      = cullData,
        };
        var handle = cull.Schedule(cullingContext.batchVisibility.Length, 16, cullingDependency);

        cullingDependency = JobHandle.CombineDependencies(handle, cullingDependency);
        return(handle);
    }
Example #19
0
 /// <summary>
 /// This is the culling callback. The batch renderer calls this once and you need schedule your culling jobs here.
 /// The culling context contains an array of visible indices of the total size of all batches. Each batch has an
 /// offset into that array in the batch visibility struct. To perform the culling, write the number of visible
 /// objects per batch back into that batch's batch visibility struct and write the indices of all visible objects
 /// into the array of visible indices. The indices must be the indices of the objects in the batch.
 /// </summary>
 JobHandle PerformCulling(BatchRendererGroup renderergroup, BatchCullingContext cullingcontext)
 {
     if (m_UseSimdCulling)
     {
         // kick-off your SIMD jobs here!
         return(default);
Example #20
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 #21
0
    public JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext, BatchCullingOutput cullingOutput, IntPtr userContext)
    {
        if (!m_initialized)
        {
            return(new JobHandle());
        }

#if ENABLE_PICKING
        bool isPickingCulling = cullingContext.viewType == BatchCullingViewType.Picking;
#endif

        var splitCounts = new NativeArray <int>(cullingContext.cullingSplits.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
        for (int i = 0; i < splitCounts.Length; ++i)
        {
            var split = cullingContext.cullingSplits[i];
            splitCounts[i] = split.cullingPlaneCount;
        }

        var planes = FrustumPlanes.BuildSOAPlanePacketsMulti(cullingContext.cullingPlanes, splitCounts, Allocator.TempJob);

        BatchCullingOutputDrawCommands drawCommands = new BatchCullingOutputDrawCommands();
        drawCommands.drawRanges   = Malloc <BatchDrawRange>(m_drawRanges.Length);
        drawCommands.drawCommands = Malloc <BatchDrawCommand>(m_drawBatches.Length *
                                                              splitCounts.Length * 10); // TODO: Multiplying the DrawCommand count by splitCount*10 is NOT an conservative upper bound. But in practice is enough. Sorting would give us a real conservative bound...

        drawCommands.visibleInstances = Malloc <int>(m_instanceIndices.Length);
#if ENABLE_PICKING
        drawCommands.drawCommandPickingInstanceIDs = isPickingCulling ? Malloc <int>(m_drawBatches.Length) : null;
#endif

        // Zero init: Culling job sets the values!
        drawCommands.drawRangeCount       = 0;
        drawCommands.drawCommandCount     = 0;
        drawCommands.visibleInstanceCount = 0;

        drawCommands.instanceSortingPositions          = null;
        drawCommands.instanceSortingPositionFloatCount = 0;

        cullingOutput.drawCommands[0] = drawCommands;

        var visibilityLength   = (m_renderers.Length + 7) / 8;
        var rendererVisibility = new NativeArray <ulong>(visibilityLength, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

        var cullingJob = new CullingJob
        {
            planes             = planes,
            splitCounts        = splitCounts,
            renderers          = m_renderers,
            rendererVisibility = rendererVisibility
        };

        var drawOutputJob = new DrawCommandOutputJob
        {
            batchID            = m_batchID,
            rendererVisibility = rendererVisibility,
            instanceIndices    = m_instanceIndices,
            drawBatches        = m_drawBatches,
            drawRanges         = m_drawRanges,
            drawIndices        = m_drawIndices,
            drawCommands       = cullingOutput.drawCommands
        };

        var jobHandleCulling = cullingJob.Schedule(visibilityLength, 8);
        var jobHandleOutput  = drawOutputJob.Schedule(jobHandleCulling);

        return(jobHandleOutput);
    }
Example #22
0
    // The callback method called by Unity whenever it visibility culls to determine which
    // objects to draw. This method will output draw commands that describe to Unity what
    // should be drawn for this BatchRendererGroup.
    public unsafe JobHandle OnPerformCulling(
        BatchRendererGroup rendererGroup,
        BatchCullingContext cullingContext,
        BatchCullingOutput cullingOutput,
        IntPtr userContext)
    {
        // UnsafeUtility.Malloc() requires an alignment, so use the largest integer type's alignment
        // which is a reasonable default.
        int alignment = UnsafeUtility.AlignOf <long>();

        // Acquire a pointer to the BatchCullingOutputDrawCommands struct so we can easily
        // modify it directly.
        var drawCommands = (BatchCullingOutputDrawCommands *)cullingOutput.drawCommands.GetUnsafePtr();

        // Allocate memory for the output arrays. In a more complicated implementation the amount of memory
        // allocated could be dynamically calculated based on what we determined to be visible.
        // In this example, we will just assume that all of our instances are visible and allocate
        // memory for each of them. We need the following allocations:
        // - a single draw command (which draws kNumInstances instances)
        // - a single draw range (which covers our single draw command)
        // - kNumInstances visible instance indices.
        // The arrays must always be allocated using Allocator.TempJob.
        drawCommands->drawCommands     = (BatchDrawCommand *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <BatchDrawCommand>(), alignment, Allocator.TempJob);
        drawCommands->drawRanges       = (BatchDrawRange *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <BatchDrawRange>(), alignment, Allocator.TempJob);
        drawCommands->visibleInstances = (int *)UnsafeUtility.Malloc(kNumInstances * sizeof(int), alignment, Allocator.TempJob);

        drawCommands->drawCommandCount     = 1;
        drawCommands->drawRangeCount       = 1;
        drawCommands->visibleInstanceCount = kNumInstances;

        // Our example does not use depth sorting, so we can leave the instanceSortingPositions as null.
        drawCommands->instanceSortingPositions          = null;
        drawCommands->instanceSortingPositionFloatCount = 0;

        // Configure our single draw command to draw kNumInstances instances
        // starting from offset 0 in the array, using the batch, material and mesh
        // IDs that we registered in the Start() method. No special flags are set.
        drawCommands->drawCommands[0].visibleOffset   = 0;
        drawCommands->drawCommands[0].visibleCount    = kNumInstances;
        drawCommands->drawCommands[0].batchID         = m_BatchID;
        drawCommands->drawCommands[0].materialID      = m_MaterialID;
        drawCommands->drawCommands[0].meshID          = m_MeshID;
        drawCommands->drawCommands[0].submeshIndex    = 0;
        drawCommands->drawCommands[0].flags           = 0;
        drawCommands->drawCommands[0].sortingPosition = 0;

        // Configure our single draw range to cover our single draw command which
        // is at offset 0.
        drawCommands->drawRanges[0].drawCommandsBegin = 0;
        drawCommands->drawRanges[0].drawCommandsCount = 1;
        // In this example we don't care about shadows or motion vectors, so we leave everything
        // to the default zero values, except the renderingLayerMask which we have to set to all ones
        // so the instances will be drawn regardless of mask settings when rendering.
        drawCommands->drawRanges[0].filterSettings = new BatchFilterSettings {
            renderingLayerMask = 0xffffffff,
        };

        // Finally, write the actual visible instance indices to their array. In a more complicated
        // implementation, this output would depend on what we determined to be visible, but in this example
        // we will just assume that everything is visible.
        for (int i = 0; i < kNumInstances; ++i)
        {
            drawCommands->visibleInstances[i] = i;
        }

        // This simple example does not use jobs, so we can just return an empty JobHandle.
        // Performance sensitive applications are encouraged to use Burst jobs to implement
        // culling and draw command output, in which case we would return a handle here that
        // completes when those jobs have finished.
        return(new JobHandle());
    }
Example #23
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);
    }
Example #24
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;
    }
Example #25
0
    public JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext, BatchCullingOutput cullingOutput, IntPtr userContext)
    {
        if (!m_initialized)
        {
            return(new JobHandle());
        }

        BatchCullingOutputDrawCommands drawCommands = new BatchCullingOutputDrawCommands();

        drawCommands.drawRangeCount = 1;
        drawCommands.drawRanges     = Malloc <BatchDrawRange>(1);
        drawCommands.drawRanges[0]  = new BatchDrawRange
        {
            drawCommandsBegin = 0,
            drawCommandsCount = 1,
            filterSettings    = new BatchFilterSettings
            {
                renderingLayerMask = 1,
                layer              = 0,
                motionMode         = m_motionVectorTest ? MotionVectorGenerationMode.Object : MotionVectorGenerationMode.Camera,
                shadowCastingMode  = ShadowCastingMode.On,
                receiveShadows     = true,
                staticShadowCaster = false,
                allDepthSorted     = false
            }
        };

        drawCommands.visibleInstances = Malloc <int>(m_itemCount);
        int n       = 0;
        int radius  = (itemGridSize / 2) * (itemGridSize / 2);      // (grid/2)^2
        int radiusO = (radius * 90) / 100;
        int radiusI = (radiusO * 85) / 100;

        for (int r = 0; r < itemGridSize; r++)
        {
            for (int i = 0; i < itemGridSize; i++)
            {
                bool visible = true;
                if (m_cullTest)
                {
                    int dist = (r - itemGridSize / 2) * (r - itemGridSize / 2) + (i - itemGridSize / 2) * (i - itemGridSize / 2);
                    if ((dist >= radiusI) && (dist <= radiusO))
                    {
                        visible = false;
                    }
                }
                if (visible)
                {
                    drawCommands.visibleInstances[n++] = r * itemGridSize + i;
                }
            }
        }
        drawCommands.visibleInstanceCount = n;

        drawCommands.drawCommandCount = 1;
        drawCommands.drawCommands     = Malloc <BatchDrawCommand>(1);
        drawCommands.drawCommands[0]  = new BatchDrawCommand
        {
            visibleOffset       = 0,
            visibleCount        = (uint)n,
            batchID             = m_batchID,
            materialID          = m_materialID,
            meshID              = m_meshID,
            submeshIndex        = 0,
            splitVisibilityMask = 0xff,
            flags           = m_motionVectorTest ? BatchDrawCommandFlags.HasMotion : BatchDrawCommandFlags.None,
            sortingPosition = 0
        };


        drawCommands.instanceSortingPositions          = null;
        drawCommands.instanceSortingPositionFloatCount = 0;

        cullingOutput.drawCommands[0] = drawCommands;
        return(new JobHandle());
    }