/** * Subdivides or unsubdivides this quad based on the current * viewer distance to this quad, relatively to its size. This * method uses the current viewer position provided by the * TerrainNode to which this quadtree belongs. */ public void Update() { Frustum.VISIBILTY v = (m_parent == null) ? Frustum.VISIBILTY.PARTIALLY : m_parent.GetVisible(); if (v == Frustum.VISIBILTY.PARTIALLY) { m_visible = m_owner.GetVisibility(m_localBox); } else { m_visible = v; } // here we reuse the occlusion test from the previous frame: // if the quad was found unoccluded in the previous frame, we suppose it is // still unoccluded at this frame. If it was found occluded, we perform // an occlusion test to check if it is still occluded. if (m_visible != Frustum.VISIBILTY.INVISIBLE && m_occluded) { m_occluded = m_owner.IsOccluded(m_localBox); if(m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } double ground = m_owner.GetView().GetGroundHeight(); double dist = m_owner.GetCameraDist(new Box3d(m_ox, m_ox + m_length, m_oy, m_oy + m_length, Math.Min(0.0, ground), Math.Max(0.0, ground))); if ((m_owner.GetSplitInvisibleQuads() || m_visible != Frustum.VISIBILTY.INVISIBLE) && dist < m_length * m_owner.GetSplitDist() && m_level < m_owner.GetMaxLevel()) { if (IsLeaf()) { Subdivide(); } int[] order = new int[4]; double ox = m_owner.GetLocalCameraPos().x; double oy = m_owner.GetLocalCameraPos().y; double cx = m_ox + m_length / 2.0; double cy = m_oy + m_length / 2.0; if (oy < cy) { if (ox < cx) { order[0] = 0; order[1] = 1; order[2] = 2; order[3] = 3; } else { order[0] = 1; order[1] = 0; order[2] = 3; order[3] = 2; } } else { if (ox < cx) { order[0] = 2; order[1] = 0; order[2] = 3; order[3] = 1; } else { order[0] = 3; order[1] = 1; order[2] = 2; order[3] = 0; } } m_children[order[0]].Update(); m_children[order[1]].Update(); m_children[order[2]].Update(); m_children[order[3]].Update(); // we compute a more precise occlusion for the next frame (see above), // by combining the occlusion status of the child nodes m_occluded = (m_children[0].GetOccluded() && m_children[1].GetOccluded() && m_children[2].GetOccluded() && m_children[3].GetOccluded()); } else { if (m_visible != Frustum.VISIBILTY.INVISIBLE) { // we add the bounding box of this quad to the occluders list m_occluded = m_owner.AddOccluder(m_localBox); if (m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } if (!IsLeaf()) { Release(); } } }
public override Frustum.VISIBILTY GetVisibility(TerrainNode t, Box3d localBox) { Vector3d2[] deformedBox = new Vector3d2[4]; deformedBox[0] = LocalToDeformed(new Vector3d2(localBox.xmin, localBox.ymin, localBox.zmin)); deformedBox[1] = LocalToDeformed(new Vector3d2(localBox.xmax, localBox.ymin, localBox.zmin)); deformedBox[2] = LocalToDeformed(new Vector3d2(localBox.xmax, localBox.ymax, localBox.zmin)); deformedBox[3] = LocalToDeformed(new Vector3d2(localBox.xmin, localBox.ymax, localBox.zmin)); double a = (localBox.zmax + R) / (localBox.zmin + R); double dx = (localBox.xmax - localBox.xmin) / 2 * a; double dy = (localBox.ymax - localBox.ymin) / 2 * a; double dz = localBox.zmax + R; double f = Math.Sqrt(dx * dx + dy * dy + dz * dz) / (localBox.zmin + R); Vector4d[] deformedFrustumPlanes = t.GetDeformedFrustumPlanes(); Frustum.VISIBILTY v0 = GetVisibility(deformedFrustumPlanes[0], deformedBox, f); if (v0 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } Frustum.VISIBILTY v1 = GetVisibility(deformedFrustumPlanes[1], deformedBox, f); if (v1 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } Frustum.VISIBILTY v2 = GetVisibility(deformedFrustumPlanes[2], deformedBox, f); if (v2 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } Frustum.VISIBILTY v3 = GetVisibility(deformedFrustumPlanes[3], deformedBox, f); if (v3 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } Frustum.VISIBILTY v4 = GetVisibility(deformedFrustumPlanes[4], deformedBox, f); if (v4 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } Vector3d2 c = t.GetDeformedCameraPos(); double lSq = c.SqrMagnitude(); double rm = R + Math.Min(0.0, localBox.zmin); double rM = R + localBox.zmax; double rmSq = rm * rm; double rMSq = rM * rM; Vector4d farPlane = new Vector4d(c.x, c.y, c.z, Math.Sqrt((lSq - rmSq) * (rMSq - rmSq)) - rmSq); Frustum.VISIBILTY v5 = GetVisibility(farPlane, deformedBox, f); if (v5 == Frustum.VISIBILTY.INVISIBLE) { return(Frustum.VISIBILTY.INVISIBLE); } if (v0 == Frustum.VISIBILTY.FULLY && v1 == Frustum.VISIBILTY.FULLY && v2 == Frustum.VISIBILTY.FULLY && v3 == Frustum.VISIBILTY.FULLY && v4 == Frustum.VISIBILTY.FULLY && v5 == Frustum.VISIBILTY.FULLY) { return(Frustum.VISIBILTY.FULLY); } return(Frustum.VISIBILTY.PARTIALLY); }
/* * Subdivides or unsubdivides this quad based on the current * viewer distance to this quad, relatively to its size. This * method uses the current viewer position provided by the * TerrainNode to which this quadtree belongs. */ public void Update() { Frustum.VISIBILTY v = (m_parent == null) ? Frustum.VISIBILTY.PARTIALLY : m_parent.GetVisible(); if (v == Frustum.VISIBILTY.PARTIALLY) { m_visible = m_owner.GetVisibility(m_localBox); } else { m_visible = v; } // here we reuse the occlusion test from the previous frame: // if the quad was found unoccluded in the previous frame, we suppose it is // still unoccluded at this frame. If it was found occluded, we perform // an occlusion test to check if it is still occluded. if (m_visible != Frustum.VISIBILTY.INVISIBLE && m_occluded) { m_occluded = m_owner.IsOccluded(m_localBox); if (m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } double ground = m_owner.GetView().GetGroundHeight(); double dist = m_owner.GetCameraDist(new Box3d(m_ox, m_ox + m_length, m_oy, m_oy + m_length, Math.Min(0.0, ground), Math.Max(0.0, ground))); if ((m_owner.GetSplitInvisibleQuads() || m_visible != Frustum.VISIBILTY.INVISIBLE) && dist < m_length * m_owner.GetSplitDist() && m_level < m_owner.GetMaxLevel()) { if (IsLeaf()) { Subdivide(); } int[] order = new int[4]; double ox = m_owner.GetLocalCameraPos().x; double oy = m_owner.GetLocalCameraPos().y; double cx = m_ox + m_length / 2.0; double cy = m_oy + m_length / 2.0; if (oy < cy) { if (ox < cx) { order[0] = 0; order[1] = 1; order[2] = 2; order[3] = 3; } else { order[0] = 1; order[1] = 0; order[2] = 3; order[3] = 2; } } else { if (ox < cx) { order[0] = 2; order[1] = 0; order[2] = 3; order[3] = 1; } else { order[0] = 3; order[1] = 1; order[2] = 2; order[3] = 0; } } m_children[order[0]].Update(); m_children[order[1]].Update(); m_children[order[2]].Update(); m_children[order[3]].Update(); // we compute a more precise occlusion for the next frame (see above), // by combining the occlusion status of the child nodes m_occluded = (m_children[0].GetOccluded() && m_children[1].GetOccluded() && m_children[2].GetOccluded() && m_children[3].GetOccluded()); } else { if (m_visible != Frustum.VISIBILTY.INVISIBLE) { // we add the bounding box of this quad to the occluders list m_occluded = m_owner.AddOccluder(m_localBox); if (m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } if (!IsLeaf()) { Release(); } } }