/// <summary> /// This is static to make this a non-virtual call /// </summary> /// <param name="nodeData"></param> /// <param name="value"></param> private static void setVisibility(CompactQuadTree <bool> .Node nodeData, ref CullingInfo info, bool value) { // Check if visiblity has changed. This shouldnt be relevant, since only non-leaf nodes, without cullables // can have this status called if (nodeData.Get(info.Tree) == value) { return; } nodeData.Set(info.Tree, value); int modifier; if (value) { modifier = 1; } else { modifier = -1; } var cullables = info.Culler.GetCullNode(nodeData.Index).Cullables; for (int i = 0; i < cullables.Count; i++) { info.CullablesReferenceCounts[cullables[i].Index] += modifier; } }
private static void setInvisibleRecursive(ref CullingInfo info, ref BoundingBox bb, CompactQuadTree <bool> .Node nodeData, bool isLeaf) { if (nodeData.Get(info.Tree) == false) { return; } setVisibility(nodeData, ref info, false); if (isLeaf) { return; } //Note that, these calls are not strictly necessary. EDIT: are prohibited, this is exactly the speedup of using a quadtree struct // When traversing the tree from top to bottom, a invisible node will be reached, // lower nodes need not be updated. updateVisibility(nodeData, CompactQuadTreeChild.LowerLeft, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.LowerRight, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.UpperLeft, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.UpperRight, ref info, ref bb, true); }
/// <summary> /// This is static to make this a non-virtual call /// </summary> /// <param name="nodeData"></param> /// <param name="info"></param> /// <param name="bb"></param> /// <param name="skipFrustumCheck"></param> private static void updateVisibility(CompactQuadTree <bool> .Node nodeData, ref CullingInfo info, ref BoundingBox bb, bool skipFrustumCheck) { var isLeaf = nodeData.IsLeaf(info.Tree); //if (info.Culler.GetCullNode(nodeData.Index).Tag != null) System.Diagnostics.Debugger.Break(); if (skipFrustumCheck) { if (nodeData.Get(info.Tree) == nodeData.Parent.Get(info.Tree)) { return; } setVisibility(nodeData, ref info, nodeData.Parent.Get(info.Tree)); if (isLeaf) { return; } updateVisibility(nodeData, CompactQuadTreeChild.LowerLeft, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.LowerRight, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.UpperLeft, ref info, ref bb, true); updateVisibility(nodeData, CompactQuadTreeChild.UpperRight, ref info, ref bb, true); return; } // This optimization is mainly for the pointlight shadow frustum, but probably also good for large trees var firstResult = info.FrustumBoundingBox.xna().Intersects(bb.xna()); // NOTE: possible slowdown due to xna() conversion if (!firstResult) { // The node is not in the viewing frustum, so it is surely invisible setInvisibleRecursive(ref info, ref bb, nodeData, isLeaf); return; } var result = info.Frustum.Contains(bb); if (result == ContainmentType.Disjoint) { setInvisibleRecursive(ref info, ref bb, nodeData, isLeaf); return; } if (result == ContainmentType.Contains) { if (nodeData.Get(info.Tree)) { return; } skipFrustumCheck = true; } setVisibility(nodeData, ref info, true); if (isLeaf) { return; } updateVisibility(nodeData, CompactQuadTreeChild.LowerLeft, ref info, ref bb, skipFrustumCheck); updateVisibility(nodeData, CompactQuadTreeChild.LowerRight, ref info, ref bb, skipFrustumCheck); updateVisibility(nodeData, CompactQuadTreeChild.UpperLeft, ref info, ref bb, skipFrustumCheck); updateVisibility(nodeData, CompactQuadTreeChild.UpperRight, ref info, ref bb, skipFrustumCheck); }