// remove culling planes created from the given portal void PCZFrustum::removePortalCullingPlanes(PortalBase* portal) { PCPlaneList::iterator pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; if (plane->getPortal() == portal) { // put the plane back in the reservoir mCullingPlaneReservoir.push_front(plane); // erase the entry from the active culling plane list pit = mActiveCullingPlanes.erase(pit); } else { pit++; } } }
/* special function that returns true only when portal fully fits inside the frustum. */ bool PCZFrustum::isFullyVisible(const PortalBase* portal) const { // if portal isn't enabled, it's not visible if (!portal->getEnabled()) return false; // if the frustum has no planes, just return true if (mActiveCullingPlanes.empty()) { return true; } // check if this portal is already in the list of active culling planes (avoid // infinite recursion case) PCPlaneList::const_iterator pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; if (plane->getPortal() == portal) { return false; } pit++; } // if portal is of type AABB or Sphere, then use simple bound check against planes if (portal->getType() == PortalBase::PORTAL_TYPE_AABB) { AxisAlignedBox aabb; aabb.setExtents(portal->getDerivedCorner(0), portal->getDerivedCorner(1)); return isFullyVisible(aabb); } else if (portal->getType() == PortalBase::PORTAL_TYPE_SPHERE) { return isFullyVisible(portal->getDerivedSphere()); } // only do this check if it's a portal. (anti portal doesn't care about facing) if (portal->getTypeFlags() == PortalFactory::FACTORY_TYPE_FLAG) { // check if the portal norm is facing the frustum Vector3 frustumToPortal = portal->getDerivedCP() - mOrigin; Vector3 portalDirection = portal->getDerivedDirection(); Real dotProduct = frustumToPortal.dotProduct(portalDirection); if ( dotProduct > 0 ) { // portal is faced away from Frustum return false; } } // Check originPlane if told to if (mUseOriginPlane) { // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { Plane::Side side = mOriginPlane.getSide(portal->getDerivedCorner(corner)); if (side == Plane::NEGATIVE_SIDE) return false; } } // For each active culling plane, see if any portal points are on the negative // side. If so, the portal is not fully visible pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; // we have to check each corner of the portal for (int corner = 0; corner < 4; corner++) { Plane::Side side =plane->getSide(portal->getDerivedCorner(corner)); if (side == Plane::NEGATIVE_SIDE) return false; } pit++; } // no plane culled all the portal points and the norm // was facing the frustum, so this portal is fully visible return true; }
// NOTE: Everything needs to be updated spatially before this function is // called including portal corners, frustum planes, etc. bool PCZFrustum::isVisible(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.size() == 0) { return true; } // check if this portal is already in the list of active culling planes (avoid // infinite recursion case) PCPlaneList::const_iterator pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; if (plane->getPortal() == portal) { return false; } pit++; } // if portal is of type AABB or Sphere, then use simple bound check against planes if (portal->getType() == Portal::PORTAL_TYPE_AABB) { AxisAlignedBox aabb; aabb.setExtents(portal->getDerivedCorner(0), portal->getDerivedCorner(1)); return isVisible(aabb); } else if (portal->getType() == Portal::PORTAL_TYPE_SPHERE) { return isVisible(portal->getDerivedSphere()); } // check if the portal norm is facing the frustum Vector3 frustumToPortal = portal->getDerivedCP() - mOrigin; Vector3 portalDirection = portal->getDerivedDirection(); Real dotProduct = frustumToPortal.dotProduct(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++) { Plane::Side side = mOriginPlane.getSide(portal->getDerivedCorner(corner)); if (side != Plane::NEGATIVE_SIDE) { 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 pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; // 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++) { Plane::Side side =plane->getSide(portal->getDerivedCorner(corner)); if (side != Plane::NEGATIVE_SIDE) { 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; } pit++; } // no plane culled all the portal points and the norm // was facing the frustum, so this portal is visible return true; }