Ejemplo n.º 1
0
        /** Fastest removal */
        public void RemoveFoliageInstance(int typeHash, System.Guid guid, Vector3 position)
        {
            FoliageCellDataRuntime cell;

            if (m_FoliageData.TryGetValue(FoliageCell.MakeHash(position), out cell))
            {
                RemoveFoliageInstanceCell(typeHash, guid, cell);
            }
        }
        public static void IterateMinMax(Vector3 min, Vector3 max, bool subdivided, FoliageIterationAction action)
        {
            FoliageCell cMin = new FoliageCell(min, subdivided);
            FoliageCell cMax = new FoliageCell(max, subdivided);

            for (int x = cMin.x; x <= cMax.x; x++)
            {
                for (int y = cMin.y; y <= cMax.y; y++)
                {
                    for (int z = cMin.z; z <= cMax.z; z++)
                    {
                        action(MakeHash(x, y, z));
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /**
         * Remove the foliage with the marked GUID. Not supported for grass since
         * we are not having that data for it.
         */
        public void RemoveInstanceGuid(int typeHash, Vector3 position, System.Guid guid)
        {
            FoliageCellData cell;

            if (m_FoliageData.TryGetValue(FoliageCell.MakeHash(position), out cell) == false)
            {
                return;
            }

            bool anyRemoved = false;

            // Look through the cell
            if (cell.m_TypeHashLocationsEditor.ContainsKey(typeHash))
            {
                var labeled = cell.m_TypeHashLocationsEditor[typeHash];

                foreach (var instances in labeled.Values)
                {
                    for (int i = 0; i < instances.Count; i++)
                    {
                        if (instances[i].m_UniqueId == guid)
                        {
                            instances.RemoveAt(i);
                            anyRemoved = true;

                            // Yea, I know. Don't use goto... However we want to break all the iterations
                            goto finished;
                        }
                    }
                } // Foreach labeled finished
                finished :;
            }

            // If we removed everything from a cell then clear it from the list completely
            RemoveEmptyTypeDataCell(cell);
            if (IsCellEmpty(cell))
            {
                m_FoliageData.Remove(cell.GetHashCode());
            }

            if (anyRemoved)
            {
                RecalculateBoundsAfterRemove();
            }
        }
Ejemplo n.º 4
0
        /** Add foliage instance. Only works for trees at runtime.  */
        public void AddFoliageInstance(int typeHash, FoliageInstance instance)
        {
            int keyHash = FoliageCell.MakeHash(instance.m_Position);

            FoliageCellDataRuntime cell;

            if (m_FoliageData.ContainsKey(keyHash) == false)
            {
                cell = new FoliageCellDataRuntime();

                FoliageCell fCell = new FoliageCell(instance.m_Position, false);

                // Set the standard data
                cell.m_Bounds   = fCell.GetBounds();
                cell.m_Position = fCell;

                // Empty subdivided data
                cell.m_FoliageDataSubdivided = new FoliageKeyValuePair <int, FoliageCellSubdividedDataRuntime> [0];

                // Empty type data
                cell.m_TypeHashLocationsRuntime = new FoliageKeyValuePair <int, FoliageTuple <FoliageInstance[]> > [0];

                // Add the data
                m_FoliageData.Add(keyHash, cell);
            }

            cell = m_FoliageData[keyHash];

            // Check if we have all the data
            int idx = System.Array.FindIndex(cell.m_TypeHashLocationsRuntime, (x) => x.Key == keyHash);

            if (idx < 0)
            {
                System.Array.Resize(ref cell.m_TypeHashLocationsRuntime, cell.m_TypeHashLocationsRuntime.Length + 1);
                idx = cell.m_TypeHashLocationsRuntime.Length - 1;

                // Add the type
                cell.m_TypeHashLocationsRuntime[idx] = new FoliageKeyValuePair <int, FoliageTuple <FoliageInstance[]> >(typeHash, new FoliageTuple <FoliageInstance[]>(new FoliageInstance[0]));
            }

            // We have the stuff
            System.Array.Resize(ref cell.m_TypeHashLocationsRuntime[idx].Value.m_EditTime, cell.m_TypeHashLocationsRuntime[idx].Value.m_EditTime.Length + 1);
            cell.m_TypeHashLocationsRuntime[idx].Value.m_EditTime[cell.m_TypeHashLocationsRuntime[idx].Value.m_EditTime.Length - 1] = instance;
        }
        public override bool Equals(object obj)
        {
            FoliageCell other = (FoliageCell)obj;

            if (other.x != x)
            {
                return(false);
            }
            if (other.y != y)
            {
                return(false);
            }
            if (other.z != z)
            {
                return(false);
            }

            return(true);
        }
        /**
         * The depth should be around 1 or maximum 2 at runtime.
         */
        public static void IterateNeighboring(FoliageCell cell, int depth, FoliageIterationAction action)
        {
            int minX = cell.x - depth;
            int maxX = cell.x + depth;

            int minY = cell.y - depth;
            int maxY = cell.y + depth;

            int minZ = cell.z - depth;
            int maxZ = cell.z + depth;

            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        action(MakeHash(x, y, z));
                    }
                }
            }
        }
        public static void GenerateBillboards(Bounds bounds, FoliageCell cell, GameObject owner, List <FoliageInstance> trees, FoliageType type, bool addLodGroup, float screenFadeSize, bool animatedCrossFade)
        {
            int[] originalTriangles = m_SystemQuadTriangles;

            GameObject meshObj = new GameObject();

            // Mark object as static
#if UNITY_EDITOR
            GameObjectUtility.SetStaticEditorFlags(meshObj, StaticEditorFlags.OccludeeStatic | StaticEditorFlags.ReflectionProbeStatic);
#endif

            string name = string.Format("MeshCell[{0}_{1}]", cell.GetHashCode(), type.m_Prefab.name);

            Transform existing = owner.transform.Find(name);
            if (existing != null)
            {
#if UNITY_EDITOR
                if (UnityEditor.EditorApplication.isPlaying == false)
                {
                    Object.DestroyImmediate(existing.gameObject);
                }
                else
                {
                    Object.Destroy(existing.gameObject);
                }
#else
                Object.Destroy(existing.gameObject);
#endif
                existing = null;
            }

            meshObj.transform.SetParent(owner.transform);
            meshObj.name = name;

            var data = type.m_RuntimeData.m_SpeedTreeData;

            Vector3 worldScale = new Vector3(data.m_Size.x, data.m_Size.y, data.m_Size.x);

            // Set material
            MeshRenderer rend = meshObj.AddComponent <MeshRenderer>();
            rend.sharedMaterial = GenerateBillboardMaterial(type.m_RuntimeData.m_SpeedTreeData);

            MeshFilter filter = meshObj.AddComponent <MeshFilter>();

            Mesh treeMesh = new Mesh();
            treeMesh.name = meshObj.name;

            List <Vector4> m_TempWorldPositions = new List <Vector4>();
            List <Vector3> m_TempWorldScales    = new List <Vector3>();
            List <Vector3> m_TempQuadVertices   = new List <Vector3>();
            List <Vector4> m_TempQuadTangents   = new List <Vector4>();
            List <Vector3> m_TempQuadNormals    = new List <Vector3>();
            List <int>     m_TempQuadIndices    = new List <int>();

            for (int treeIndex = 0; treeIndex < trees.Count; treeIndex++)
            {
                Vector3 position = trees[treeIndex].m_Position;
                Vector3 scale    = trees[treeIndex].m_Scale;
                float   rot      = trees[treeIndex].m_Rotation.eulerAngles.y * Mathf.Deg2Rad;

                // Offset world position, by the grounding factor
                Vector3 instancePos = position;

                // Don't use this, but offset in shader, so that we can have that correct hue
                // instancePos.y += data.m_Size.z;

                // Scale by the world scale too so that we don't have to do an extra multip
                Vector3 instanceScale = scale;
                instanceScale.Scale(worldScale);

                // Add the world and scale data
                for (int index = 0; index < 4; index++)
                {
                    Vector4 posAndRot = instancePos;
                    posAndRot.w = rot;

                    m_TempWorldPositions.Add(posAndRot);
                    m_TempWorldScales.Add(instanceScale);
                }

                // Add stanard quad data
                m_TempQuadVertices.AddRange(m_SystemQuadVertices);
                m_TempQuadTangents.AddRange(m_SystemQuadTangents);
                m_TempQuadNormals.AddRange(m_SystemQuadNormals);

                // Calculate triangle indixes
                m_TempQuadIndices.AddRange(originalTriangles);
                for (int triIndex = 0; triIndex < 6; triIndex++)
                {
                    // Just add to the triangles the existing triangles + the new indices
                    m_TempQuadIndices[triIndex + 6 * treeIndex] = originalTriangles[triIndex] + 4 * treeIndex;
                }
            }

            treeMesh.Clear();

            // Set standard data
            treeMesh.SetVertices(m_TempQuadVertices);
            treeMesh.SetNormals(m_TempQuadNormals);
            treeMesh.SetTangents(m_TempQuadTangents);

            // Set the custom data
            treeMesh.SetUVs(1, m_TempWorldPositions);
            treeMesh.SetUVs(2, m_TempWorldScales);

            // Set triangles and do not calculate bounds
            treeMesh.SetTriangles(m_TempQuadIndices, 0, false);

            // Set the manually calculated bounds
            treeMesh.bounds = bounds;

            treeMesh.UploadMeshData(true);

            // Set the mesh
            filter.mesh = treeMesh;

            if (addLodGroup)
            {
                // Add the mesh' lod group
                LODGroup group = meshObj.AddComponent <LODGroup>();
                group.animateCrossFading = false;

                if (animatedCrossFade)
                {
                    group.fadeMode           = LODFadeMode.CrossFade;
                    group.animateCrossFading = true;
                }
                else
                {
                    group.fadeMode           = LODFadeMode.None;
                    group.animateCrossFading = false;
                }

                group.SetLODs(new LOD[] { new LOD(screenFadeSize, new Renderer[] { rend }) });
                group.RecalculateBounds();
            }

#if UNITY_EDITOR
            UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(meshObj.scene);
#endif
        }
Ejemplo n.º 8
0
        void Update()
        {
#if UNITY_EDITOR
            FoliageLog.Assert(m_FoliageData != null);
#endif
            // Camera used for culling
            m_CurrentFrameCameraCull = m_Settings.m_UsedCameraCulling;

            // Camera used for drawing
            m_CurrentFrameCameraDraw = m_Settings.m_UsedCameraDrawing;
            m_CurrentFrameLayer      = LayerMask.NameToLayer(m_Settings.m_UsedLayer);

            // Extract the planes
            ExtractPlanes(m_CameraPlanes, m_CurrentFrameCameraCull.projectionMatrix * m_CurrentFrameCameraCull.worldToCameraMatrix);

            // Set the position
            m_CurrentFrameCameraPosition = m_CurrentFrameCameraCull.transform.position;

            // Set the bend position
            m_CurrentFrameBendPosition = m_Settings.m_BendTransform != null ? m_Settings.m_BendTransform.position : m_CurrentFrameCameraPosition;

            // Current cell position
            currentCell.Set(m_CurrentFrameCameraPosition);

            m_CurrentFrameAllowIndirect = m_Settings.m_AllowDrawInstancedIndirect;

            m_DrawStats.Reset();

            // Copy the wind for SpeedTree types
            for (int i = 0; i < m_FoliageTypesArray.Length; i++)
            {
                if (m_FoliageTypesArray[i].IsSpeedTreeType)
                {
                    m_FoliageTypesArray[i].CopyBlock();
                }
            }

            bool  applyShadowCorrection       = m_Settings.m_ApplyShadowPoppingCorrection;
            float shadowCorrectionDistanceSqr = m_Settings.m_ShadowPoppingCorrection * m_Settings.m_ShadowPoppingCorrection;

            // We iterate only as many cells as we need
            FoliageCell.IterateNeighboring(currentCell, m_CellNeighborCount, (int hash) =>
            {
                FoliageCellDataRuntime data;

                if (m_FoliageData.m_FoliageData.TryGetValue(hash, out data))
                {
                    // If it is within distance and in the frustum
                    float distanceSqr = data.m_Bounds.SqrDistance(m_CurrentFrameCameraPosition);

                    // Check for the maximum distance
                    if (distanceSqr <= m_MaxDistanceAllSqr && GeometryUtility.TestPlanesAABB(m_CameraPlanes, data.m_Bounds))
                    {
                        // Process the big cells if we are withing the tree distance
                        if (distanceSqr <= m_MaxDistanceTreeSqr)
                        {
                            ProcessCellTree(data, distanceSqr, applyShadowCorrection, shadowCorrectionDistanceSqr, false);
                        }

                        // Process subdivided cells only if we have instancing enabled and only if it is within the distance proximity for grass
                        if (distanceSqr <= m_MaxDistanceGrassSqr && m_Settings.m_DrawInstanced)
                        {
                            ProcessCellGrass(data);
                        }

                        m_DrawStats.m_ProcessedCells++;
                    }
                    else if (distanceSqr <= shadowCorrectionDistanceSqr)
                    {
                        ProcessCellTree(data, distanceSqr, applyShadowCorrection, shadowCorrectionDistanceSqr, true);
                    }
                }
            });

#if UNITY_EDITOR
            if (Time.frameCount % 300 == 0)
            {
                FoliageLog.i(string.Format("Proc cells:{0} Proc subdiv cells: {1} Proc tree instances: {2} Proc draw calls: {3}",
                                           m_DrawStats.m_ProcessedCells,
                                           m_DrawStats.m_ProcessedCellsSubdiv,
                                           m_DrawStats.m_ProcessedInstances,
                                           m_DrawStats.m_ProcessedDrawCalls));
            }
#endif
        }
Ejemplo n.º 9
0
        /**
         * Get all the instances withing the given radius of the provided location.
         *
         * @param subdivision
         *          If we should get the instance count for subdivisions (grass) or for big cells.
         */
        public int GetInstanceCountLocation(Vector3 position, float radius, bool subdivision)
        {
            int count = 0;

            Vector3 min = position - new Vector3(radius, radius, radius);
            Vector3 max = position + new Vector3(radius, radius, radius);

            float distanceDelta = radius * radius;
            float x, y, z;

            // Iterate divisions
            FoliageCell.IterateMinMax(min, max, false, (int hash) =>
            {
                FoliageCellData cell;

                if (m_FoliageData.TryGetValue(hash, out cell) == false)
                {
                    return;
                }

                if (subdivision == false)
                {
                    // Count all the tree foliage that overlaps the sphere
                    foreach (var data in cell.m_TypeHashLocationsEditor.Values)
                    {
                        foreach (var instances in data.Values)
                        {
                            for (int i = 0; i < instances.Count; i++)
                            {
                                x = instances[i].m_Position.x - position.x;
                                y = instances[i].m_Position.y - position.y;
                                z = instances[i].m_Position.z - position.z;

                                if ((x * x + y * y + z * z) < distanceDelta)
                                {
                                    count++;
                                }
                            }
                        }
                    }
                }
                else
                {
                    // Iterate subdivisions
                    Vector3 minLocal = GetLocalInCell(min, cell);
                    Vector3 maxLocal = GetLocalInCell(max, cell);

                    FoliageCell.IterateMinMax(minLocal, maxLocal, true, (int hashLocal) =>
                    {
                        FoliageCellSubdividedData cellSubdivided;

                        if (cell.m_FoliageDataSubdivided.TryGetValue(hashLocal, out cellSubdivided) == false)
                        {
                            return;
                        }

                        // Count all the grass foliage that overlaps the sphere
                        foreach (var data in cellSubdivided.m_TypeHashLocationsEditor.Values)
                        {
                            foreach (var instances in data.Values)
                            {
                                for (int i = 0; i < instances.Count; i++)
                                {
                                    x = instances[i].m_Position.x - position.x;
                                    y = instances[i].m_Position.y - position.y;
                                    z = instances[i].m_Position.z - position.z;

                                    if ((x * x + y * y + z * z) < distanceDelta)
                                    {
                                        count++;
                                    }
                                }
                            }
                        }
                    });
                }
            });

            return(count);
        }
Ejemplo n.º 10
0
        /**
         * Add a new foliage instance to the underlaying data.
         *
         * The painter should decide if our data is added to the subdivisions or if it is a tree type and must not be added to the subdivision.
         */
        public void AddInstance(int typeHash, FoliageInstance instance, bool subdivision, string label = FoliageGlobals.LABEL_PAINTED)
        {
            int hash = FoliageCell.MakeHash(instance.m_Position);

            if (m_FoliageData.ContainsKey(hash) == false)
            {
                FoliageCellData data = new FoliageCellData();
                data.m_Position = new FoliageCell();
                data.m_Position.Set(instance.m_Position);

                data.m_Bounds         = data.m_Position.GetBounds();
                data.m_BoundsExtended = data.m_Bounds;

                // Add the foliage cell
                m_FoliageData.Add(hash, data);
            }

            FoliageCellData cellData = m_FoliageData[hash];

            if (subdivision == false)
            {
                if (cellData.m_TypeHashLocationsEditor.ContainsKey(typeHash) == false)
                {
                    cellData.m_TypeHashLocationsEditor.Add(typeHash, new Dictionary <string, List <FoliageInstance> >());
                }

                var labeled = cellData.m_TypeHashLocationsEditor[typeHash];

                if (labeled.ContainsKey(label) == false)
                {
                    labeled.Add(label, new List <FoliageInstance>());
                }

                // Add the foliage data
                labeled[label].Add(instance);

                // Make the extended bounds larger. Encapsulate anything that might make the bounds larger. Only applied to trees
                m_FoliageData[hash].m_BoundsExtended.Encapsulate(instance.m_Bounds);
            }
            else
            {
                var foliageSubdividedData = cellData.m_FoliageDataSubdivided;

                Vector3 localPosition = GetLocalInCell(instance.m_Position, cellData);

                int hashSubdivided = FoliageCell.MakeHashSubdivided(localPosition);

                if (foliageSubdividedData.ContainsKey(hashSubdivided) == false)
                {
                    FoliageCellSubdividedData data = new FoliageCellSubdividedData();
                    data.m_Position = new FoliageCell();
                    data.m_Position.SetSubdivided(localPosition);

                    // Get bounds in world space
                    data.m_Bounds        = data.m_Position.GetBoundsSubdivided();
                    data.m_Bounds.center = GetWorldInCell(data.m_Bounds.center, cellData);

                    foliageSubdividedData.Add(hashSubdivided, data);
                }

                FoliageCellSubdividedData cellDataSubdivided = foliageSubdividedData[hashSubdivided];

                if (cellDataSubdivided.m_TypeHashLocationsEditor.ContainsKey(typeHash) == false)
                {
                    cellDataSubdivided.m_TypeHashLocationsEditor.Add(typeHash, new Dictionary <string, List <FoliageInstance> >());
                }

                var labeled = cellDataSubdivided.m_TypeHashLocationsEditor[typeHash];

                if (labeled.ContainsKey(label) == false)
                {
                    labeled.Add(label, new List <FoliageInstance>());
                }

                labeled[label].Add(instance);
            }
        }
Ejemplo n.º 11
0
        /**
         * Removes foliage instances.
         *
         * @return True if we removed anything
         */
        public bool RemoveInstances(int typeHash, Vector3 position, float radius = 0.3f /*30cm default position delta */)
        {
            Vector3 min = position - new Vector3(radius, radius, radius);
            Vector3 max = position + new Vector3(radius, radius, radius);

            bool anyRemoved      = false;
            bool anyGrassRemoved = false;

            float x, y, z;
            float distanceDelta = radius * radius;

            // Remove all the foliage that overlaps the sphere
            FoliageCell.IterateMinMax(min, max, false, (int hash) =>
            {
                if (m_FoliageData.ContainsKey(hash) == false)
                {
                    return;
                }

                FoliageCellData cell = m_FoliageData[hash];

                // Remove the types from the cell
                if (cell.m_TypeHashLocationsEditor.ContainsKey(typeHash))
                {
                    var labeledData = cell.m_TypeHashLocationsEditor[typeHash];

                    foreach (var instances in labeledData.Values)
                    {
                        for (int i = instances.Count - 1; i >= 0; i--)
                        {
                            x = instances[i].m_Position.x - position.x;
                            y = instances[i].m_Position.y - position.y;
                            z = instances[i].m_Position.z - position.z;

                            // If we are at a distance smaller than the threshold then remove the instance
                            if ((x * x + y * y + z * z) < distanceDelta)
                            {
                                instances.RemoveAt(i);

                                // We removed from the cell, we have to recalculate the extended bounds
                                anyRemoved = true;
                            }
                        }
                    }
                }

                // Remove the types from the subdivided cells

                // Iterate subdivisions
                Vector3 minLocal = GetLocalInCell(min, cell);
                Vector3 maxLocal = GetLocalInCell(max, cell);

                FoliageCell.IterateMinMax(minLocal, maxLocal, true, (int hashLocal) =>
                {
                    FoliageCellSubdividedData cellSubdivided;

                    if (cell.m_FoliageDataSubdivided.TryGetValue(hashLocal, out cellSubdivided) == false)
                    {
                        return;
                    }

                    // Count all the grass foliage that overlaps the sphere
                    if (cellSubdivided.m_TypeHashLocationsEditor.ContainsKey(typeHash))
                    {
                        var data = cellSubdivided.m_TypeHashLocationsEditor[typeHash];

                        foreach (var instances in data.Values)
                        {
                            for (int i = instances.Count - 1; i >= 0; i--)
                            {
                                x = instances[i].m_Position.x - position.x;
                                y = instances[i].m_Position.y - position.y;
                                z = instances[i].m_Position.z - position.z;

                                // If we are at a distance smaller than the threshold then remove the instance
                                if ((x * x + y * y + z * z) < distanceDelta)
                                {
                                    instances.RemoveAt(i);

                                    // Just for grass removal...
                                    anyGrassRemoved = true;
                                }
                            }
                        }
                    }

                    RemoveEmptyTypeDataCellSubdivided(cellSubdivided);
                    if (IsSubCellEmpty(cellSubdivided))
                    {
                        cell.m_FoliageDataSubdivided.Remove(hashLocal);
                    }
                });

                // If we removed everything from a cell then clear it from the list completely
                RemoveEmptyTypeDataCell(cell);
                if (IsCellEmpty(cell))
                {
                    m_FoliageData.Remove(hash);
                }
            });

            if (anyRemoved)
            {
                RecalculateBoundsAfterRemove();
            }

            return(anyRemoved || anyGrassRemoved);
        }
 private static void ReadFoliageCell(BinaryReader a, out FoliageCell fc)
 {
     fc.x = a.ReadInt32();
     fc.y = a.ReadInt32();
     fc.z = a.ReadInt32();
 }
 private static void WriteFoliageCell(BinaryWriter a, FoliageCell fc)
 {
     a.Write(fc.x);
     a.Write(fc.y);
     a.Write(fc.z);
 }
        private void Update()
        {
            if (!m_Settings.m_WatchedTransform)
            {
                return;
            }

            m_CameraPosTemp = m_Settings.m_WatchedTransform.position;

            float x = m_CameraPosTemp.x - m_LastPosition.x;
            float y = m_CameraPosTemp.y - m_LastPosition.y;
            float z = m_CameraPosTemp.z - m_LastPosition.z;

            float distWalked = x * x + y * y + z * z;

            // If we didn't walked enough, return
            if (distWalked > m_Settings.m_CollisionRefreshDistance * m_Settings.m_CollisionRefreshDistance)
            {
                // Update last position
                m_LastPosition = m_CameraPosTemp;

                m_Layer = LayerMask.NameToLayer(m_Settings.m_UsedLayer);

                // Reset counter
                m_DataIssuedActiveColliders = 0;

                // Reset all the cache's data
                foreach (CollisionCache cache in m_Cache.Values)
                {
                    if (cache != null)
                    {
                        cache.Reset();
                    }
                }

                // Set the current cell
                currentCell.Set(m_LastPosition);

                // Refresh eveything
                float collDistSqr = m_Settings.m_CollisionDistance * m_Settings.m_CollisionDistance;

                // Iterate cells
                FoliageCell.IterateNeighboring(currentCell, 1, (int hash) =>
                {
                    FoliageCellDataRuntime data;

                    if (m_FoliageData.m_FoliageData.TryGetValue(hash, out data))
                    {
                        // If it is within distance and in the frustum
                        float distanceSqr = data.m_Bounds.SqrDistance(m_LastPosition);

                        if (distanceSqr <= collDistSqr)
                        {
                            ProcessCell(data, collDistSqr);
                        }
                    }
                });
            }

#if UNITY_EDITOR
            if (Time.frameCount % 300 == 0)
            {
                FoliageLog.i("Issued colliders: " + m_DataIssuedActiveColliders);
            }
#endif
        }