// check if portal is close to another portal. // Note, both portals are assumed to be stationary // and DerivedCP is the current position. // this function is INTENTIONALLY NOT EXACT because // it is used by PCZSM::connectPortalsToTargetZonesByLocation // which is a utility function to link up nearby portals // public bool closeTo(Portal otherPortal) { // only portals of the same type can be "close to" each other. if (this.mType != otherPortal.Type) { return(false); } bool close = false; switch (this.mType) { default: case PORTAL_TYPE.PORTAL_TYPE_QUAD: { // quad portals must be within 1/4 sphere of each other Sphere quarterSphere1 = this.mDerivedSphere; quarterSphere1.Radius = quarterSphere1.Radius * 0.25f; Sphere quarterSphere2 = otherPortal.getDerivedSphere(); quarterSphere2.Radius = quarterSphere2.Radius * 0.25f; close = quarterSphere1.Intersects(quarterSphere2); } break; case PORTAL_TYPE.PORTAL_TYPE_AABB: // NOTE: AABB's must match perfectly if (this.mDerivedCP == otherPortal.getDerivedCP() && this.mCorners[0] == otherPortal.getCorner(0) && this.mCorners[1] == otherPortal.getCorner(1)) { close = true; } break; case PORTAL_TYPE.PORTAL_TYPE_SPHERE: // NOTE: Spheres must match perfectly if (this.mDerivedCP == otherPortal.getDerivedCP() && this.mRadius == otherPortal.getRadius()) { close = true; } break; } return(close); }
/// <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; }
/// <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> /// <returns> /// true if the Portal is visible. /// </returns> public bool IsObjectVisible( Portal portal ) { // if portal isn't open, it's not visible if ( !portal.IsOpen ) { return false; } // if the frustum has no planes, just return true if ( mActiveCullingPlanes.Count == 0 ) { return true; } // check if this portal is already in the list of active culling planes (avoid // infinite recursion case) foreach ( PCPlane plane in mActiveCullingPlanes ) { if ( plane.Portal == 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 ) { AxisAlignedBox aabb = new AxisAlignedBox(); aabb.SetExtents( portal.getDerivedCorner( 0 ), portal.getDerivedCorner( 1 ) ); return IsObjectVisible( aabb ); } else if ( portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE ) { return IsObjectVisible( portal.getDerivedSphere() ); } // check if the portal norm is facing the frustum Vector3 frustumToPortal = portal.getDerivedCP() - mOrigin; Vector3 portalDirection = portal.getDerivedDirection(); Real dotProduct = frustumToPortal.Dot( portalDirection ); if ( dotProduct > 0 ) { // portal is faced away from Frustum return false; } // check against frustum culling planes bool visible_flag; // Check originPlane if told to if ( mUseOriginPlane ) { // set the visible flag to false visible_flag = false; // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = mOriginPlane.GetSide( portal.getDerivedCorner( corner ) ); if ( side != PlaneSide.Negative ) { visible_flag = true; } } // if the visible_flag is still false, then the origin plane // culled all the portal points if ( visible_flag == false ) { // ALL corners on negative side therefore out of view return false; } } // For each active culling plane, see if all portal points are on the negative // side. If so, the portal is not visible foreach ( PCPlane plane in mActiveCullingPlanes ) { visible_flag = false; // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = 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 return false; } } // no plane culled all the portal points and the norm // was facing the frustum, so this portal is visible return true; }
/// <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> /// <returns> /// true if the Portal is visible. /// </returns> public bool IsObjectVisible(Portal portal) { // if portal isn't open, it's not visible if (!portal.IsOpen) { return(false); } // if the frustum has no planes, just return true if (this.mActiveCullingPlanes.Count == 0) { return(true); } // check if this portal is already in the list of active culling planes (avoid // infinite recursion case) foreach (PCPlane plane in this.mActiveCullingPlanes) { if (plane.Portal == 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(); aabb.SetExtents(portal.getDerivedCorner(0), portal.getDerivedCorner(1)); return(IsObjectVisible(aabb)); } else if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE) { return(IsObjectVisible(portal.getDerivedSphere())); } // check if the portal norm is facing the frustum Vector3 frustumToPortal = portal.getDerivedCP() - this.mOrigin; Vector3 portalDirection = portal.getDerivedDirection(); Real dotProduct = frustumToPortal.Dot(portalDirection); if (dotProduct > 0) { // portal is faced away from Frustum return(false); } // check against frustum culling planes bool visible_flag; // Check originPlane if told to if (this.mUseOriginPlane) { // set the visible flag to false visible_flag = false; // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { PlaneSide side = this.mOriginPlane.GetSide(portal.getDerivedCorner(corner)); if (side != PlaneSide.Negative) { visible_flag = true; } } // if the visible_flag is still false, then the origin plane // culled all the portal points if (visible_flag == false) { // ALL corners on negative side therefore out of view return(false); } } // For each active culling plane, see if all portal points are on the negative // side. If so, the portal is not visible foreach (PCPlane plane in this.mActiveCullingPlanes) { visible_flag = false; // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { PlaneSide side = 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 return(false); } } // no plane culled all the portal points and the norm // was facing the frustum, so this portal is visible return(true); }
// check if portal is close to another portal. // Note, both portals are assumed to be stationary // and DerivedCP is the current position. // this function is INTENTIONALLY NOT EXACT because // it is used by PCZSM::connectPortalsToTargetZonesByLocation // which is a utility function to link up nearby portals // public bool closeTo( Portal otherPortal ) { // only portals of the same type can be "close to" each other. if ( mType != otherPortal.Type ) { return false; } bool close = false; switch ( mType ) { default: case PORTAL_TYPE.PORTAL_TYPE_QUAD: { // quad portals must be within 1/4 sphere of each other Sphere quarterSphere1 = mDerivedSphere; quarterSphere1.Radius = quarterSphere1.Radius * 0.25f; Sphere quarterSphere2 = otherPortal.getDerivedSphere(); quarterSphere2.Radius = quarterSphere2.Radius * 0.25f; close = quarterSphere1.Intersects( quarterSphere2 ); } break; case PORTAL_TYPE.PORTAL_TYPE_AABB: // NOTE: AABB's must match perfectly if ( mDerivedCP == otherPortal.getDerivedCP() && mCorners[ 0 ] == otherPortal.getCorner( 0 ) && mCorners[ 1 ] == otherPortal.getCorner( 1 ) ) { close = true; } break; case PORTAL_TYPE.PORTAL_TYPE_SPHERE: // NOTE: Spheres must match perfectly if ( mDerivedCP == otherPortal.getDerivedCP() && mRadius == otherPortal.getRadius() ) { close = true; } break; } return close; }
/// <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); }