public override bool IsObjectVisible(Sphere bound, out FrustumPlane culledBy) { if (cullingFrustum != null) { return(cullingFrustum.IsObjectVisible(bound, out culledBy)); } else { return(base.IsObjectVisible(bound, out culledBy)); } }
public override bool IsObjectVisible(Vector3 vert, out FrustumPlane culledBy) { if (cullingFrustum != null) { return(cullingFrustum.IsObjectVisible(vert, out culledBy)); } else { return(base.IsObjectVisible(vert, out culledBy)); } }
public override Plane GetFrustumPlane(FrustumPlane plane) { if (cullingFrustum != null) { return(cullingFrustum.GetFrustumPlane(plane)); } else { return(base.GetFrustumPlane(plane)); } }
public override void FindVisibleNodes(PCZCamera camera, ref List <PCZSceneNode> visibleNodeList, RenderQueue queue, VisibleObjectsBoundsInfo visibleBounds, bool onlyShadowCasters, bool displayNodes, bool showBoundingBoxes) { //return immediately if nothing is in the zone. if (mHomeNodeList.Count == 0 && mVisitorNodeList.Count == 0 && mPortals.Count == 0) { return; } // Else, the zone is automatically assumed to be visible since either // it is the camera the zone is in, or it was reached because // a connecting portal was deemed visible to the camera. // enable sky if called to do so for this zone if (mHasSky) { // enable sky mPCZSM.EnableSky(true); } // Recursively find visible nodes in the zone WalkOctree(camera, ref visibleNodeList, queue, this.rootOctree, visibleBounds, false, onlyShadowCasters, displayNodes, showBoundingBoxes); // find visible portals in the zone and recurse into them bool vis; foreach (Portal portal in mPortals) { // for portal, check visibility using world bounding sphere & direction FrustumPlane pl = FrustumPlane.None; vis = camera.IsObjectVisible(portal, out pl); if (vis) { // portal is visible. Add the portal as extra culling planes to camera int planes_added = camera.AddPortalCullingPlanes(portal); // tell target zone it's visible this frame portal.getTargetZone().LastVisibleFrame = mLastVisibleFrame; portal.getTargetZone().LastVisibleFromCamera = camera; // recurse into the connected zone portal.getTargetZone().FindVisibleNodes(camera, ref visibleNodeList, queue, visibleBounds, onlyShadowCasters, displayNodes, showBoundingBoxes); if (planes_added > 0) { // Then remove the extra culling planes added before going to the next portal in this zone. camera.RemovePortalCullingPlanes(portal); } } } }
// /// <summary> // /// // /// </summary> // /// <param name="op"></param> // public override void GetRenderOperation(RenderOperation op) { // Vector3[] r = new Vector3[8]; // // r = this.Corners; // // r[0] = GetCorner(FrustumPlane.Far,FrustumPlane.Left,FrustumPlane.Bottom); // r[1] = GetCorner(FrustumPlane.Far,FrustumPlane.Left,FrustumPlane.Top); // r[2] = GetCorner(FrustumPlane.Far,FrustumPlane.Right,FrustumPlane.Top); // r[3] = GetCorner(FrustumPlane.Far,FrustumPlane.Right,FrustumPlane.Bottom); // // r[4] = GetCorner(FrustumPlane.Near,FrustumPlane.Right,FrustumPlane.Top); // r[5] = GetCorner(FrustumPlane.Near,FrustumPlane.Left,FrustumPlane.Top); // r[6] = GetCorner(FrustumPlane.Near,FrustumPlane.Left,FrustumPlane.Bottom); // r[7] = GetCorner(FrustumPlane.Near,FrustumPlane.Right,FrustumPlane.Bottom); // // this.Corners = r; // // UpdateView(); // // //TODO: VERTEX BUFFER STUFF // } /// <summary> /// /// </summary> /// <param name="pp1"></param> /// <param name="pp2"></param> /// <param name="pp3"></param> /// <returns></returns> private Vector3 GetCorner(FrustumPlane pp1, FrustumPlane pp2, FrustumPlane pp3) { Plane p1 = _planes[(int)pp1]; Plane p2 = _planes[(int)pp1]; Plane p3 = _planes[(int)pp1]; Matrix3 mdet; mdet.m00 = p1.Normal.x; mdet.m01 = p1.Normal.y; mdet.m02 = p1.Normal.z; mdet.m10 = p2.Normal.x; mdet.m11 = p2.Normal.y; mdet.m12 = p2.Normal.z; mdet.m20 = p3.Normal.x; mdet.m21 = p3.Normal.y; mdet.m22 = p3.Normal.z; float det = mdet.Determinant; if (det == 0) { //TODO: Unsure. The C++ just returned return(Vector3.Zero); //some planes are parallel. } var mx = new Matrix3(-p1.D, p1.Normal.y, p1.Normal.z, -p2.D, p2.Normal.y, p2.Normal.z, -p3.D, p3.Normal.y, p3.Normal.z); float xdet = mx.Determinant; var my = new Matrix3(p1.Normal.x, -p1.D, p1.Normal.z, p2.Normal.x, -p2.D, p2.Normal.z, p3.Normal.x, -p3.D, p3.Normal.z); float ydet = my.Determinant; var mz = new Matrix3(p1.Normal.x, p1.Normal.y, -p1.D, p2.Normal.x, p2.Normal.y, -p2.D, p3.Normal.x, p3.Normal.y, -p3.D); float zdet = mz.Determinant; var r = new Vector3(); r.x = xdet / det; r.y = ydet / det; r.z = zdet / det; return(r); }
public int IndexOfPlane(FrustumPlane plane) { switch (plane) { case FrustumPlane.Front: return(3); case FrustumPlane.Back: return(2); case FrustumPlane.Left: return(1); case FrustumPlane.Right: return(0); case FrustumPlane.Top: return(4); case FrustumPlane.Bottom: return(5); } return(-1); }
void recalcFrustum() { // TODO< transform view frustom mesh by rotation of the camera > // we transform a mesh which describes the view frustum in global space // and then we calculate the normal and distance of the normal of the planes MeshWithExplicitFaces frustumMesh = new MeshWithExplicitFaces(); { // create a VerticesWithAttributes with just positions MutableMeshAttribute positionMeshAttribute = MutableMeshAttribute.makeDouble4ByLength(5); var positionAccessor = positionMeshAttribute.getDouble4Accessor(); positionAccessor[0] = new double[] { -1, -1, 1, 1 }; positionAccessor[1] = new double[] { 1, -1, 1, 1 }; positionAccessor[2] = new double[] { 1, 1, 1, 1 }; positionAccessor[3] = new double[] { -1, 1, 1, 1 }; positionAccessor[4] = new double[] { 0, 0, 0, 1 }; VerticesWithAttributes verticesWithAttributes = new VerticesWithAttributes(new AbstractMeshAttribute[] { positionMeshAttribute }, 0); frustumMesh.verticesWithAttributes = verticesWithAttributes; } frustumMesh.faces = new MeshWithExplicitFaces.Face[] { new MeshWithExplicitFaces.Face(new uint[] { 4, 0, 1 }), // top side new MeshWithExplicitFaces.Face(new uint[] { 4, 1, 2 }), // right side new MeshWithExplicitFaces.Face(new uint[] { 4, 2, 3 }), // bottom side new MeshWithExplicitFaces.Face(new uint[] { 4, 3, 0 }), // left side }; // TODO< use globally transformed vertices > // result is 4 component SpatialVectorDouble[] planesWith4Component = MeshUtilities.calcAllPlanes(frustumMesh.faces, frustumMesh.getVertexPositionsAsVector3Array()); // we only have 4 planes because we dont limit the maximal z frustum.planes = new FrustumPlane[4]; frustum.planes[0] = FrustumPlane.makeFrom4Component(planesWith4Component[0]); frustum.planes[1] = FrustumPlane.makeFrom4Component(planesWith4Component[1]); frustum.planes[2] = FrustumPlane.makeFrom4Component(planesWith4Component[2]); frustum.planes[3] = FrustumPlane.makeFrom4Component(planesWith4Component[3]); }
// this version checks against extra culling planes public new bool IsObjectVisible(AxisAlignedBox bound, out FrustumPlane culledBy) { culledBy = FrustumPlane.None; // Null boxes always invisible if (bound.IsNull) { return(false); } // infinite boxes always visible if (bound.IsInfinite) { return(true); } // Make any pending updates to the calculated frustum planes UpdateFrustumPlanes(); // check extra culling planes bool extraResults; extraResults = this.extraCullingFrustum.IsObjectVisible(bound); if (!extraResults) { return(false); } // check "regular" camera frustum bool regcamresults = base.IsObjectVisible(bound, out culledBy); if (!regcamresults) { // culled by regular culling planes return(regcamresults); } return(true); }
// this version checks against extra culling planes public new bool IsObjectVisible( AxisAlignedBox bound, out FrustumPlane culledBy ) { culledBy = FrustumPlane.None; // Null boxes always invisible if ( bound.IsNull ) { return false; } // infinite boxes always visible if ( bound.IsInfinite ) { return true; } // Make any pending updates to the calculated frustum planes UpdateFrustumPlanes(); // check extra culling planes bool extraResults; extraResults = this.extraCullingFrustum.IsObjectVisible( bound ); if ( !extraResults ) { return false; } // check "regular" camera frustum bool regcamresults = base.IsObjectVisible( bound, out culledBy ); if ( !regcamresults ) { // culled by regular culling planes return regcamresults; } return true; }
/// <summary> /// Tests whether the given sphere is in the viewing frustum. /// </summary> /// <param name="sphere">Bounding sphere to be checked.</param> /// <param name="culledBy"> /// Optional FrustrumPlane params which will be filled by the plane which culled /// the box if the result was false. /// </param> /// <returns>True if the box is visible, otherwise false.</returns> public bool IsObjectVisible( Sphere sphere, out FrustumPlane culledBy ) { // Make any pending updates to the calculated frustum UpdateFrustumPlanes(); // For each plane, see if sphere is on negative side // If so, object is not visible for ( var plane = 0; plane < 6; plane++ ) { if ( this._farDistance == 0 && plane == (int)FrustumPlane.Far ) { continue; } // If the distance from sphere center to plane is negative, and 'more negative' // than the radius of the sphere, sphere is outside frustum if ( this._planes[ plane ].GetDistance( sphere.Center ) < -sphere.Radius ) { // ALL corners on negative side therefore out of view culledBy = (FrustumPlane)plane; return false; } } // sphere is not culled culledBy = FrustumPlane.None; return true; }
public Plane this[FrustumPlane plane] { get { return(planes[IndexOfPlane(plane)]); } }
public new virtual bool IsVisible( Vector3 vert, FrustumPlane culledBy ) { return true; }
public Plane GetFrustumPlane( FrustumPlane plane ) { return this.frustumPlanes[ plane ]; }
/// <summary> /// IsObjectVisible() function for portals. /// </summary> /// <remarks> /// Everything needs to be updated spatially before this function is /// called including portal corners, frustum planes, etc. /// </remarks> /// <param name="portal"> /// The <see cref="Portal"/> to check visibility against. /// </param> /// <param name="culledBy"> /// The <see cref="FrustumPlane"/> that the Portal is in. /// </param> /// <returns> /// true if the Portal is visible. /// </returns> public bool IsObjectVisible(Portal portal, out FrustumPlane culledBy) { culledBy = FrustumPlane.None; // if portal isn't open, it's not visible if (!portal.IsOpen) { return(false); } // check the extra frustum first if (!this.extraCullingFrustum.IsObjectVisible(portal)) { return(false); } // if portal is of type AABB or Sphere, then use simple bound check against planes if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB) { var aabb = new AxisAlignedBox(portal.getDerivedCorner(0), portal.getDerivedCorner(1)); return(base.IsObjectVisible(aabb, out culledBy)); } else if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE) { return(base.IsObjectVisible(portal.getDerivedSphere(), out culledBy)); } // check if the portal norm is facing the camera Vector3 cameraToPortal = portal.getDerivedCP() - DerivedPosition; Vector3 portalDirection = portal.getDerivedDirection(); Real dotProduct = cameraToPortal.Dot(portalDirection); if (dotProduct > 0) { // portal is faced away from camera return(false); } // check against regular frustum planes bool visible_flag; if (null != CullFrustum) { // For each frustum plane, see if all points are on the negative side // If so, object is not visible // NOTE: We skip the NEAR plane (plane #0) because Portals need to // be visible no matter how close you get to them. for (int plane = 1; plane < 6; ++plane) { // set the visible flag to false visible_flag = false; // Skip far plane if infinite view frustum if ((FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0) { continue; } // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { PlaneSide side = CullFrustum.FrustumPlanes[plane].GetSide(portal.getDerivedCorner(corner)); if (side != PlaneSide.Negative) { visible_flag = true; } } // if the visible_flag is still false, then this plane // culled all the portal points if (visible_flag == false) { // ALL corners on negative side therefore out of view if (culledBy != FrustumPlane.None) { culledBy = (FrustumPlane)plane; } return(false); } } } else { // Make any pending updates to the calculated frustum planes UpdateFrustumPlanes(); // For each frustum plane, see if all points are on the negative side // If so, object is not visible // NOTE: We skip the NEAR plane (plane #0) because Portals need to // be visible no matter how close you get to them. // BUGBUG: This can cause a false positive situation when a portal is // behind the camera but close. This could be fixed by having another // culling plane at the camera location with normal same as camera direction. for (int plane = 1; plane < 6; ++plane) { // set the visible flag to false visible_flag = false; // Skip far plane if infinite view frustum if ((FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0) { continue; } // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { PlaneSide side = _planes[plane].GetSide(portal.getDerivedCorner(corner)); if (side != PlaneSide.Negative) { visible_flag = true; } } // if the visible_flag is still false, then this plane // culled all the portal points if (visible_flag == false) { // ALL corners on negative side therefore out of view if (culledBy != FrustumPlane.None) { culledBy = (FrustumPlane)plane; } return(false); } } } // no plane culled all the portal points and the norm // was facing the camera, so this portal is visible return(true); }
public override bool IsObjectVisible(Vector3 vert, out FrustumPlane culledBy) { if (cullingFrustum != null) return cullingFrustum.IsObjectVisible(vert, out culledBy); else return base.IsObjectVisible(vert, out culledBy); }
public new virtual bool IsVisible( Sphere bound, FrustumPlane culledBy ) { return true; }
public new bool IsObjectVisible( Sphere sphere, out FrustumPlane culledBy ) { if ( null != CullFrustum ) { return CullFrustum.IsObjectVisible( sphere, out culledBy ); } else { return base.IsObjectVisible( sphere, out culledBy ); } }
// /// <summary> // /// // /// </summary> // /// <param name="op"></param> // public override void GetRenderOperation(RenderOperation op) { // Vector3[] r = new Vector3[8]; // // r = this.Corners; // // r[0] = GetCorner(FrustumPlane.Far,FrustumPlane.Left,FrustumPlane.Bottom); // r[1] = GetCorner(FrustumPlane.Far,FrustumPlane.Left,FrustumPlane.Top); // r[2] = GetCorner(FrustumPlane.Far,FrustumPlane.Right,FrustumPlane.Top); // r[3] = GetCorner(FrustumPlane.Far,FrustumPlane.Right,FrustumPlane.Bottom); // // r[4] = GetCorner(FrustumPlane.Near,FrustumPlane.Right,FrustumPlane.Top); // r[5] = GetCorner(FrustumPlane.Near,FrustumPlane.Left,FrustumPlane.Top); // r[6] = GetCorner(FrustumPlane.Near,FrustumPlane.Left,FrustumPlane.Bottom); // r[7] = GetCorner(FrustumPlane.Near,FrustumPlane.Right,FrustumPlane.Bottom); // // this.Corners = r; // // UpdateView(); // // //TODO: VERTEX BUFFER STUFF // } /// <summary> /// /// </summary> /// <param name="pp1"></param> /// <param name="pp2"></param> /// <param name="pp3"></param> /// <returns></returns> private Vector3 GetCorner( FrustumPlane pp1, FrustumPlane pp2, FrustumPlane pp3 ) { Plane p1 = _planes[ (int)pp1 ]; Plane p2 = _planes[ (int)pp1 ]; Plane p3 = _planes[ (int)pp1 ]; Matrix3 mdet; mdet.m00 = p1.Normal.x; mdet.m01 = p1.Normal.y; mdet.m02 = p1.Normal.z; mdet.m10 = p2.Normal.x; mdet.m11 = p2.Normal.y; mdet.m12 = p2.Normal.z; mdet.m20 = p3.Normal.x; mdet.m21 = p3.Normal.y; mdet.m22 = p3.Normal.z; float det = mdet.Determinant; if ( det == 0 ) { //TODO: Unsure. The C++ just returned return Vector3.Zero; //some planes are parallel. } var mx = new Matrix3( -p1.D, p1.Normal.y, p1.Normal.z, -p2.D, p2.Normal.y, p2.Normal.z, -p3.D, p3.Normal.y, p3.Normal.z ); float xdet = mx.Determinant; var my = new Matrix3( p1.Normal.x, -p1.D, p1.Normal.z, p2.Normal.x, -p2.D, p2.Normal.z, p3.Normal.x, -p3.D, p3.Normal.z ); float ydet = my.Determinant; var mz = new Matrix3( p1.Normal.x, p1.Normal.y, -p1.D, p2.Normal.x, p2.Normal.y, -p2.D, p3.Normal.x, p3.Normal.y, -p3.D ); float zdet = mz.Determinant; var r = new Vector3(); r.x = xdet/det; r.y = ydet/det; r.z = zdet/det; return r; }
/// <summary> /// Tests whether the given box is visible in the Frustum. /// </summary> /// <param name="box"> Bounding box to be checked.</param> /// <param name="culledBy"> /// Optional FrustrumPlane params which will be filled by the plane which culled /// the box if the result was false. /// </param> /// <returns>True if the box is visible, otherwise false.</returns> public bool IsObjectVisible( AxisAlignedBox box, out FrustumPlane culledBy ) { culledBy = FrustumPlane.None; // Null boxes are always invisible if ( box.IsNull ) { return false; } // Infinite Boxes are always visible if ( box.IsInfinite ) { return true; } // Make any pending updates to the calculated frustum UpdateFrustumPlanes(); // Get corners of the box var corners = box.Corners; // For each plane, see if all points are on the negative side // If so, object is not visible for ( var plane = 0; plane < 6; plane++ ) { // skip far plane if infinite view frustum if ( this._farDistance == 0 && plane == (int)FrustumPlane.Far ) { continue; } if ( this._planes[ plane ].GetSide( corners[ 0 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 1 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 2 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 3 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 4 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 5 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 6 ] ) == PlaneSide.Negative && this._planes[ plane ].GetSide( corners[ 7 ] ) == PlaneSide.Negative ) { // ALL corners on negative side therefore out of view culledBy = (FrustumPlane)plane; return false; } } // box is not culled return true; }
/// <summary> /// Internal method for calculating the clip volumes outside of the /// frustum which can be used to determine which objects are casting /// shadow on the frustum as a whole. /// </summary> /// <remarks> /// Each of the volumes is a pyramid for a point/spot light and /// a cuboid for a directional light. /// </remarks> /// <param name="camera"></param> /// <returns></returns> internal List <PlaneBoundedVolume> GetFrustumClipVolumes(Camera camera) { // Homogenous light position Vector4 lightPos = GetAs4DVector(); // 3D version (not the same as DerivedPosition, is -direction for // directional lights) Vector3 lightPos3 = new Vector3(lightPos.x, lightPos.y, lightPos.z); Vector3 lightDir; Vector3[] clockwiseVerts = new Vector3[4]; Matrix4 eyeToWorld = camera.ViewMatrix.Inverse(); // Get worldspace frustum corners Vector3[] corners = camera.WorldSpaceCorners; bool infiniteViewDistance = (camera.Far == 0); frustumClipVolumes.Clear(); for (int n = 0; n < 6; n++) { FrustumPlane frustumPlane = (FrustumPlane)n; // skip far plane if infinite view frustum if (infiniteViewDistance && (frustumPlane == FrustumPlane.Far)) { continue; } Plane plane = camera[frustumPlane]; Vector4 planeVec = new Vector4(plane.Normal.x, plane.Normal.y, plane.Normal.z, plane.D); // planes face inwards, we need to know if light is on negative side float d = planeVec.Dot(lightPos); if (d < -1e-06f) { // Ok, this is a valid one // clockwise verts mean we can cross-product and always get normals // facing into the volume we create frustumClipVolumes.Add(new PlaneBoundedVolume()); PlaneBoundedVolume vol = (PlaneBoundedVolume)frustumClipVolumes[frustumClipVolumes.Count - 1]; switch (frustumPlane) { case (FrustumPlane.Near): clockwiseVerts[0] = corners[3]; clockwiseVerts[1] = corners[2]; clockwiseVerts[2] = corners[1]; clockwiseVerts[3] = corners[0]; break; case (FrustumPlane.Far): clockwiseVerts[0] = corners[7]; clockwiseVerts[1] = corners[6]; clockwiseVerts[2] = corners[5]; clockwiseVerts[3] = corners[4]; break; case (FrustumPlane.Left): clockwiseVerts[0] = corners[2]; clockwiseVerts[1] = corners[6]; clockwiseVerts[2] = corners[5]; clockwiseVerts[3] = corners[1]; break; case (FrustumPlane.Right): clockwiseVerts[0] = corners[7]; clockwiseVerts[1] = corners[3]; clockwiseVerts[2] = corners[0]; clockwiseVerts[3] = corners[4]; break; case (FrustumPlane.Top): clockwiseVerts[0] = corners[0]; clockwiseVerts[1] = corners[1]; clockwiseVerts[2] = corners[5]; clockwiseVerts[3] = corners[4]; break; case (FrustumPlane.Bottom): clockwiseVerts[0] = corners[7]; clockwiseVerts[1] = corners[6]; clockwiseVerts[2] = corners[2]; clockwiseVerts[3] = corners[3]; break; } // Build a volume // Iterate over world points and form side planes Vector3 normal; for (int i = 0; i < 4; i++) { // Figure out light dir lightDir = lightPos3 - (clockwiseVerts[i] * lightPos.w); // Cross with anticlockwise corner, therefore normal points in // Note: C++ mod returns 3 for the first case where C# returns -1 int test = i > 0 ? ((i - 1) % 4) : 3; // Cross with anticlockwise corner, therefore normal points in normal = (clockwiseVerts[i] - clockwiseVerts[test]).Cross(lightDir); normal.Normalize(); // NB last param to Plane constructor is negated because it's -d vol.planes.Add(new Plane(normal, normal.Dot(clockwiseVerts[i]))); } // Now do the near plane (this is the plane of the side we're // talking about, with the normal inverted (d is already interpreted as -ve) vol.planes.Add(new Plane(-plane.Normal, plane.D)); // Finally, for a point/spot light we can add a sixth plane // This prevents false positives from behind the light if (type != LightType.Directional) { // re-use our own plane normal // remember the -d negation in plane constructor vol.planes.Add(new Plane(plane.Normal, plane.Normal.Dot(lightPos3))); } } } return(frustumClipVolumes); }
/// <summary> /// 获得视见体的裁减平面 /// </summary> /// <param name="fp"></param> /// <param name="pl"></param> public void GetPlane(FrustumPlane fp, out Plane pl) { pl = this.planes[(int)fp]; }
/// <summary> /// Tests whether the given 3D point is in the viewing frustum. /// </summary> /// <param name="vertex">3D point to check for frustum visibility.</param> /// <param name="culledBy"> /// Optional FrustrumPlane params which will be filled by the plane which culled /// the box if the result was false. /// </param> /// <returns>True if the box is visible, otherwise false.</returns> public bool IsObjectVisible( Vector3 vertex, out FrustumPlane culledBy ) { // Make any pending updates to the calculated frustum UpdateFrustumPlanes(); // For each plane, see if all points are on the negative side // If so, object is not visible for ( var plane = 0; plane < 6; plane++ ) { if ( this._farDistance == 0 && plane == (int)FrustumPlane.Far ) { continue; } if ( this._planes[ plane ].GetSide( vertex ) == PlaneSide.Negative ) { // ALL corners on negative side therefore out of view culledBy = (FrustumPlane)plane; return false; } } // vertex is not culled culledBy = FrustumPlane.None; return true; }
/// <summary> /// An indexer that accepts a FrustumPlane enum value and return the appropriate plane side of the Frustum. /// </summary> public Plane this[ FrustumPlane plane ] { get { // make any pending updates to the calculated frustum UpdateFrustumPlanes(); // convert the incoming plan enum type to a int var index = (int)plane; // access the planes array by index return this._planes[ index ]; } }
/// <summary> /// IsObjectVisible() function for portals. /// </summary> /// <remarks> /// Everything needs to be updated spatially before this function is /// called including portal corners, frustum planes, etc. /// </remarks> /// <param name="portal"> /// The <see cref="Portal"/> to check visibility against. /// </param> /// <param name="culledBy"> /// The <see cref="FrustumPlane"/> that the Portal is in. /// </param> /// <returns> /// true if the Portal is visible. /// </returns> public bool IsObjectVisible( Portal portal, out FrustumPlane culledBy ) { culledBy = FrustumPlane.None; // if portal isn't open, it's not visible if ( !portal.IsOpen ) { return false; } // check the extra frustum first if ( !this.extraCullingFrustum.IsObjectVisible( portal ) ) { return false; } // if portal is of type AABB or Sphere, then use simple bound check against planes if ( portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB ) { var aabb = new AxisAlignedBox( portal.getDerivedCorner( 0 ), portal.getDerivedCorner( 1 ) ); return base.IsObjectVisible( aabb, out culledBy ); } else if ( portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE ) { return base.IsObjectVisible( portal.getDerivedSphere(), out culledBy ); } // check if the portal norm is facing the camera Vector3 cameraToPortal = portal.getDerivedCP() - DerivedPosition; Vector3 portalDirection = portal.getDerivedDirection(); Real dotProduct = cameraToPortal.Dot( portalDirection ); if ( dotProduct > 0 ) { // portal is faced away from camera return false; } // check against regular frustum planes bool visible_flag; if ( null != CullFrustum ) { // For each frustum plane, see if all points are on the negative side // If so, object is not visible // NOTE: We skip the NEAR plane (plane #0) because Portals need to // be visible no matter how close you get to them. for ( int plane = 1; plane < 6; ++plane ) { // set the visible flag to false visible_flag = false; // Skip far plane if infinite view frustum if ( (FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0 ) { continue; } // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = CullFrustum.FrustumPlanes[ plane ].GetSide( portal.getDerivedCorner( corner ) ); if ( side != PlaneSide.Negative ) { visible_flag = true; } } // if the visible_flag is still false, then this plane // culled all the portal points if ( visible_flag == false ) { // ALL corners on negative side therefore out of view if ( culledBy != FrustumPlane.None ) { culledBy = (FrustumPlane)plane; } return false; } } } else { // Make any pending updates to the calculated frustum planes UpdateFrustumPlanes(); // For each frustum plane, see if all points are on the negative side // If so, object is not visible // NOTE: We skip the NEAR plane (plane #0) because Portals need to // be visible no matter how close you get to them. // BUGBUG: This can cause a false positive situation when a portal is // behind the camera but close. This could be fixed by having another // culling plane at the camera location with normal same as camera direction. for ( int plane = 1; plane < 6; ++plane ) { // set the visible flag to false visible_flag = false; // Skip far plane if infinite view frustum if ( (FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0 ) { continue; } // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = _planes[ plane ].GetSide( portal.getDerivedCorner( corner ) ); if ( side != PlaneSide.Negative ) { visible_flag = true; } } // if the visible_flag is still false, then this plane // culled all the portal points if ( visible_flag == false ) { // ALL corners on negative side therefore out of view if ( culledBy != FrustumPlane.None ) { culledBy = (FrustumPlane)plane; } return false; } } } // no plane culled all the portal points and the norm // was facing the camera, so this portal is visible return true; }
public override Plane GetFrustumPlane(FrustumPlane plane) { if (cullingFrustum != null) return cullingFrustum.GetFrustumPlane(plane); else return base.GetFrustumPlane(plane); }
public new bool IsObjectVisible( AxisAlignedBox box, out FrustumPlane culledBy ) { if ( null != CullFrustum ) { return CullFrustum.IsObjectVisible( box, out culledBy ); } else { return base.IsObjectVisible( box, out culledBy ); } }
public override bool IsObjectVisible(Sphere bound, out FrustumPlane culledBy) { if (cullingFrustum != null) return cullingFrustum.IsObjectVisible(bound, out culledBy); else return base.IsObjectVisible(bound, out culledBy); }
public new bool IsObjectVisible( Vector3 vertex, out FrustumPlane culledBy ) { if ( null != CullFrustum ) { return CullFrustum.IsObjectVisible( vertex, out culledBy ); } else { return base.IsObjectVisible( vertex, out culledBy ); } }
/// <summary> /// /// </summary> /// <param name="bound"></param> /// <param name="culledBy">Default is Near</param> /// <returns></returns> public new virtual bool IsVisible( AxisAlignedBox bound, FrustumPlane culledBy ) { return true; }