/// <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; } }
public FrustumCullerView(FrustumCuller culler) { this.culler = culler; visibleCullables = new List <ICullable>(); tree = new CompactQuadTree <bool>(culler.NumberLevels); cullablesReferenceCounts = new int[16]; }
public void TestCompactQuadTree() { var tree = new CompactQuadTree <bool>(6); if (tree.GetRoot().UpperLeft.UpperLeft.UpperLeft.Index != 1 + 4 + 16) { throw new Exception("Test failed"); // This is a lame test but anyways } }
private void buildCullNodeArray(CullNode node, CompactQuadTree <bool> .Node cNode) { cullNodes[cNode.Index] = node; node.Index = cNode.Index; if (QuadTree.IsLeafNode(node)) { return; } buildCullNodeArray(node.NodeData.LowerLeft, cNode.LowerLeft); buildCullNodeArray(node.NodeData.LowerRight, cNode.LowerRight); buildCullNodeArray(node.NodeData.UpperLeft, cNode.UpperLeft); buildCullNodeArray(node.NodeData.UpperRight, cNode.UpperRight); }
public FrustumCuller(BoundingBox quadtreeBounding, int numberLevels) { TreeBounding = quadtreeBounding; NumberLevels = numberLevels; RootNode = new CullNode(); QuadTreeNodeData <CullNode> data = new QuadTreeNodeData <CullNode>(); data.BoundingBox = quadtreeBounding; RootNode.NodeData = data; QuadTree.Split(RootNode, numberLevels - 1); cullNodes = new CullNode[CompactQuadTree <bool> .CalculateNbNodes(numberLevels)]; buildCullNodeArray(RootNode, new CompactQuadTree <bool> .Node(0)); expandCullablesBuffer(); }
/// <summary> /// /// This is static to make this a non-virtual call /// </summary> /// <param name="parent"></param> /// <param name="child"></param> /// <param name="frustum"></param> /// <param name="parentBB"></param> /// <param name="skipFrustumCheck"></param> private static void updateVisibility(CompactQuadTree <bool> .Node parent, CompactQuadTreeChild child, ref CullingInfo frustum, ref BoundingBox parentBB, bool skipFrustumCheck) { BoundingBox bb; switch (child) { case CompactQuadTreeChild.UpperLeft: bb = new BoundingBox( new Vector3( parentBB.Minimum.X, parentBB.Minimum.Y, parentBB.Minimum.Z), new Vector3( (parentBB.Maximum.X + parentBB.Minimum.X) * 0.5f, parentBB.Maximum.Y, (parentBB.Maximum.Z + parentBB.Minimum.Z) * 0.5f)); break; case CompactQuadTreeChild.UpperRight: bb = new BoundingBox( new Vector3((parentBB.Minimum.X + parentBB.Maximum.X) * 0.5f, parentBB.Minimum.Y, parentBB.Minimum.Z), new Vector3(parentBB.Maximum.X, parentBB.Maximum.Y, (parentBB.Maximum.Z + parentBB.Minimum.Z) * 0.5f)); break; case CompactQuadTreeChild.LowerLeft: bb = new BoundingBox( new Vector3(parentBB.Minimum.X, parentBB.Minimum.Y, (parentBB.Maximum.Z + parentBB.Minimum.Z) * 0.5f), new Vector3((parentBB.Maximum.X + parentBB.Minimum.X) * 0.5f, parentBB.Maximum.Y, parentBB.Maximum.Z)); break; case CompactQuadTreeChild.LowerRight: bb = new BoundingBox( new Vector3((parentBB.Maximum.X + parentBB.Minimum.X) * 0.5f, parentBB.Minimum.Y, (parentBB.Maximum.Z + parentBB.Minimum.Z) * 0.5f), new Vector3(parentBB.Maximum.X, parentBB.Maximum.Y, parentBB.Maximum.Z)); break; default: throw new ArgumentOutOfRangeException("child"); } updateVisibility(parent.GetChild(child), ref frustum, ref bb, skipFrustumCheck); }
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); }