public void Search <T>(Func <ISpatialObject, bool> predicate, Func <ISpatialObject, float> prioritizer, int maxResultsCount, ICollection <T> results) where T : ISpatialObject { lock (m_Lock) { var count = 0; m_PriorityHeap.Clear(); results.Clear(); m_PriorityHeap.Push(m_RootNode); while (count < maxResultsCount && !m_PriorityHeap.isEmpty) { if (!m_PriorityHeap.TryPop(out var obj)) { break; } if (obj is SpatialNode node) { foreach (var child in node.children) { if (!predicate(child)) { continue; } child.priority = prioritizer(child); m_PriorityHeap.Push(child); } continue; } results.Add((T)obj); ++count; } } }
protected override void UpdateInternal(float unscaledDeltaTime) { if (!settings.isActive) { return; } CacheCameraData(); if (spatialCollection.objectCount <= 0) { return; } if (!m_IsPendingVisibilityUpdate) { return; } m_IsPendingVisibilityUpdate = false; m_BoundingBoxIndex = 0; foreach (var obj in m_ObjectsByStreamKey.Values) { // early exit if neither the visibility nor the renderers have changed // and the object doesn't require displaying its bounding box (not visible or renderers are loaded) // make sure not to exit if we're displaying only bounding boxes // or if the bounding box display toggle has changed, to correctly refresh MeshRenderers if (!obj.TryRefreshVisibility() && !obj.HasMeshRendererChanged && (!obj.isVisible || obj.HasMeshRenderers) && !m_DisplayOnlyBoundingBoxes && m_DisplayOnlyBoundingBoxes == settings.displayOnlyBoundingBoxes) { continue; } obj.HasMeshRendererChanged = false; // if the object is visible but there is no renderer loaded, display the bounding box instead // due to async visibility changes there might be more visible objects than bounding boxes // so check to make sure we haven't reached the limit yet if ((obj.TryRefreshRenderers(settings.displayOnlyBoundingBoxes) && !settings.displayOnlyBoundingBoxes) || !obj.isVisible || !settings.displayUnloadedObjectBoundingBoxes || m_BoundingBoxIndex >= m_BoundingBoxes.Length) { continue; } var box = m_BoundingBoxes[m_BoundingBoxIndex]; box.transform.localPosition = obj.center; box.transform.localScale = obj.max - obj.min; var meshRenderer = box.meshRenderer; if (!meshRenderer.enabled) { meshRenderer.enabled = true; } ++m_BoundingBoxIndex; } m_DisplayOnlyBoundingBoxes = settings.displayOnlyBoundingBoxes; if (m_ObjectsToLoad.count > 0) { const int count = 5; // TODO improve how we determine the count for (var i = 0; i < count; ++i) { if (!m_ObjectsToLoad.TryPop(out var obj)) { break; } obj.IsLoaded = true; m_StreamOutput.SendStreamAdded(obj.StreamAsset); } // clear any remaining objects, they will re-add themselves during the next visibility update m_ObjectsToLoad.Clear(); } if (!settings.displayUnloadedObjectBoundingBoxes) { return; } // hide unused visible boxes for (var i = m_BoundingBoxIndex; i < m_PrevBoundingBoxIndex; ++i) { var meshRenderer = m_BoundingBoxes[i].meshRenderer; if (meshRenderer.enabled) { meshRenderer.enabled = false; } } m_PrevBoundingBoxIndex = m_BoundingBoxIndex; }