/* Test if a scene node intersected a portal during the last time delta * (from last frame time to current frame time). This function checks * if the node "crossed over" the portal also. */ public PortalIntersectResult intersects(PCZSceneNode pczsn) { // Only check if portal is open if (this.mOpen) { if (pczsn == this.mNode) { // ignore the scene node if it is the node the portal is associated with return(PortalIntersectResult.NO_INTERSECT); } // most complicated case - if the portal is a quad: if (this.mType == PORTAL_TYPE.PORTAL_TYPE_QUAD) { // the node is modeled as a line segment (prevPostion to currentPosition) // intersection test is then between the capsule and the line segment. var nodeSegment = new Segment(); nodeSegment.Set(pczsn.PreviousPosition, pczsn.DerivedPosition); // we model the portal as a line swept sphere (mPrevDerivedCP to mDerivedCP). var portalCapsule = new Capsule(); portalCapsule.Set(this.mPrevDerivedCP, this.mDerivedCP, this.mRadius); if (portalCapsule.Intersects(nodeSegment)) { // the portal intersected the node at some time from last frame to this frame. // Now check if node "crossed" the portal // a crossing occurs if the "side" of the final position of the node compared // to the final position of the portal is negative AND the initial position // of the node compared to the initial position of the portal is non-negative if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) == PlaneSide.Negative && this.mPrevDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative) { // safety check - make sure the node has at least one dimension which is // small enough to fit through the portal! (avoid the "elephant fitting // through a mouse hole" case) Vector3 nodeHalfVector = pczsn.WorldAABB.HalfSize; var portalBox = new Vector3(this.mRadius, this.mRadius, this.mRadius); portalBox.Floor(nodeHalfVector); if (portalBox.x < this.mRadius) { // crossing occurred! return(PortalIntersectResult.INTERSECT_CROSS); } } } // there was no crossing of the portal by the node, but it might be touching // the portal. We check for this by checking the bounding box of the node vs. // the sphere of the portal if (this.mDerivedSphere.Intersects(pczsn.WorldAABB) && this.mDerivedPlane.GetSide(pczsn.WorldAABB) == PlaneSide.Both) { // intersection but no crossing // note this means that the node is CURRENTLY touching the portal. if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative) { // the node is on the positive (front) or exactly on the CP of the portal return(PortalIntersectResult.INTERSECT_NO_CROSS); } else { // the node is on the negative (back) side of the portal - it might be in the wrong zone! return(PortalIntersectResult.INTERSECT_BACK_NO_CROSS); } } // no intersection CURRENTLY. (there might have been an intersection // during the time between last frame and this frame, but it wasn't a portal // crossing, and it isn't touching anymore, so it doesn't matter. return(PortalIntersectResult.NO_INTERSECT); } else if (this.mType == PORTAL_TYPE.PORTAL_TYPE_AABB) { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. var aabb = new AxisAlignedBox(this.mDerivedCorners[0], this.mDerivedCorners[1]); //bool previousInside = aabb.contains(pczsn->getPrevPosition()); bool currentInside = aabb.Contains(pczsn.DerivedPosition); if (this.mDirection == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if (currentInside == true) { return(PortalIntersectResult.INTERSECT_CROSS); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if (currentInside == false) { return(PortalIntersectResult.INTERSECT_CROSS); } } // doesn't cross, but might be touching. This is a little tricky because we only // care if the node aab is NOT fully contained in the portal aabb because we consider // the surface of the portal aabb the actual 'portal'. First, check to see if the // aab of the node intersects the aabb portal if (aabb.Intersects(pczsn.WorldAABB)) { // now check if the intersection between the two is not the same as the // full node aabb, if so, then this means that the node is not fully "contained" // which is what we are looking for. AxisAlignedBox overlap = aabb.Intersection(pczsn.WorldAABB); if (overlap != pczsn.WorldAABB) { return(PortalIntersectResult.INTERSECT_NO_CROSS); } } return(PortalIntersectResult.NO_INTERSECT); } else { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(pczsn->getPrevPosition()); Real currentDistance2 = this.mDerivedCP.DistanceSquared(pczsn.DerivedPosition); Real mRadius2 = this.mRadius * this.mRadius; if (this.mDirection == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if (currentDistance2 < mRadius2) { return(PortalIntersectResult.INTERSECT_CROSS); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if (currentDistance2 >= mRadius2) { return(PortalIntersectResult.INTERSECT_CROSS); } } // no crossing, but might be touching - check distance if (System.Math.Sqrt(System.Math.Abs(mRadius2 - currentDistance2)) <= this.mRadius) { return(PortalIntersectResult.INTERSECT_NO_CROSS); } return(PortalIntersectResult.NO_INTERSECT); } } return(PortalIntersectResult.NO_INTERSECT); }
/* This function check if *this* portal "crossed over" the other portal. */ public bool crossedPortal( Portal otherPortal ) { // Only check if portal is open if ( otherPortal.mOpen ) { // we model both portals as line swept spheres (mPrevDerivedCP to mDerivedCP). // intersection test is then between the capsules. // BUGBUG! This routine needs to check for case where one or both objects // don't move - resulting in simple sphere tests // BUGBUG! If one (or both) portals are aabb's this is REALLY not accurate. Capsule portalCapsule, otherPortalCapsule; portalCapsule = new Capsule(); portalCapsule.Set( this.getPrevDerivedCP(), this.getDerivedCP(), this.getRadius() ); otherPortalCapsule = new Capsule(); otherPortalCapsule.Set( otherPortal.mPrevDerivedCP, otherPortal.mDerivedCP, otherPortal.mRadius ); if ( portalCapsule.Intersects( otherPortalCapsule ) ) { // the portal intersected the other portal at some time from last frame to this frame. // Now check if this portal "crossed" the other portal switch ( otherPortal.Type ) { case PORTAL_TYPE.PORTAL_TYPE_QUAD: // a crossing occurs if the "side" of the final position of this portal compared // to the final position of the other portal is negative AND the initial position // of this portal compared to the initial position of the other portal is non-negative // NOTE: This function assumes that this portal is the smaller portal potentially crossing // over the otherPortal which is larger. if ( otherPortal.getDerivedPlane().GetSide( mDerivedCP ) == PlaneSide.Negative && otherPortal.getPrevDerivedPlane().GetSide( mPrevDerivedCP ) != PlaneSide.Negative ) { // crossing occurred! return true; } break; case PORTAL_TYPE.PORTAL_TYPE_AABB: { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. AxisAlignedBox aabb = new AxisAlignedBox( otherPortal.getDerivedCorner( 0 ), otherPortal.getDerivedCorner( 1 ) ); //bool previousInside = aabb.contains(mPrevDerivedCP); bool currentInside = aabb.Contains( mDerivedCP ); if ( otherPortal.getDerivedDirection() == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if ( currentInside == true ) { return true; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if ( currentInside == false ) { return true; } } } break; case PORTAL_TYPE.PORTAL_TYPE_SPHERE: { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(otherPortal->getPrevDerivedCP()); Real currentDistance2 = mDerivedCP.DistanceSquared( otherPortal.getDerivedCP() ); Real mRadius2 = System.Math.Sqrt( otherPortal.getRadius() ); if ( otherPortal.getDerivedDirection() == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if ( currentDistance2 < mRadius2 ) { return true; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if ( currentDistance2 >= mRadius2 ) { return true; } } } break; } } } // there was no crossing of the portal by this portal. It might be touching // the other portal (but we don't care currently) return false; }
/* This function check if *this* portal "crossed over" the other portal. */ public bool crossedPortal(Portal otherPortal) { // Only check if portal is open if (otherPortal.mOpen) { // we model both portals as line swept spheres (mPrevDerivedCP to mDerivedCP). // intersection test is then between the capsules. // BUGBUG! This routine needs to check for case where one or both objects // don't move - resulting in simple sphere tests // BUGBUG! If one (or both) portals are aabb's this is REALLY not accurate. Capsule portalCapsule, otherPortalCapsule; portalCapsule = new Capsule(); portalCapsule.Set(getPrevDerivedCP(), getDerivedCP(), getRadius()); otherPortalCapsule = new Capsule(); otherPortalCapsule.Set(otherPortal.mPrevDerivedCP, otherPortal.mDerivedCP, otherPortal.mRadius); if (portalCapsule.Intersects(otherPortalCapsule)) { // the portal intersected the other portal at some time from last frame to this frame. // Now check if this portal "crossed" the other portal switch (otherPortal.Type) { case PORTAL_TYPE.PORTAL_TYPE_QUAD: // a crossing occurs if the "side" of the final position of this portal compared // to the final position of the other portal is negative AND the initial position // of this portal compared to the initial position of the other portal is non-negative // NOTE: This function assumes that this portal is the smaller portal potentially crossing // over the otherPortal which is larger. if (otherPortal.getDerivedPlane().GetSide(this.mDerivedCP) == PlaneSide.Negative && otherPortal.getPrevDerivedPlane().GetSide(this.mPrevDerivedCP) != PlaneSide.Negative) { // crossing occurred! return(true); } break; case PORTAL_TYPE.PORTAL_TYPE_AABB: { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. var aabb = new AxisAlignedBox(otherPortal.getDerivedCorner(0), otherPortal.getDerivedCorner(1)); //bool previousInside = aabb.contains(mPrevDerivedCP); bool currentInside = aabb.Contains(this.mDerivedCP); if (otherPortal.getDerivedDirection() == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if (currentInside == true) { return(true); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if (currentInside == false) { return(true); } } } break; case PORTAL_TYPE.PORTAL_TYPE_SPHERE: { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(otherPortal->getPrevDerivedCP()); Real currentDistance2 = this.mDerivedCP.DistanceSquared(otherPortal.getDerivedCP()); Real mRadius2 = System.Math.Sqrt(otherPortal.getRadius()); if (otherPortal.getDerivedDirection() == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if (currentDistance2 < mRadius2) { return(true); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if (currentDistance2 >= mRadius2) { return(true); } } } break; } } } // there was no crossing of the portal by this portal. It might be touching // the other portal (but we don't care currently) return(false); }
/* Test if a scene node intersected a portal during the last time delta * (from last frame time to current frame time). This function checks * if the node "crossed over" the portal also. */ public PortalIntersectResult intersects( PCZSceneNode pczsn ) { // Only check if portal is open if ( mOpen ) { if ( pczsn == mNode ) { // ignore the scene node if it is the node the portal is associated with return PortalIntersectResult.NO_INTERSECT; } // most complicated case - if the portal is a quad: if ( mType == PORTAL_TYPE.PORTAL_TYPE_QUAD ) { // the node is modeled as a line segment (prevPostion to currentPosition) // intersection test is then between the capsule and the line segment. Segment nodeSegment = new Segment(); nodeSegment.Set( pczsn.PreviousPosition, pczsn.DerivedPosition ); // we model the portal as a line swept sphere (mPrevDerivedCP to mDerivedCP). Capsule portalCapsule = new Capsule(); portalCapsule.Set( mPrevDerivedCP, mDerivedCP, mRadius ); if ( portalCapsule.Intersects( nodeSegment ) ) { // the portal intersected the node at some time from last frame to this frame. // Now check if node "crossed" the portal // a crossing occurs if the "side" of the final position of the node compared // to the final position of the portal is negative AND the initial position // of the node compared to the initial position of the portal is non-negative if ( mDerivedPlane.GetSide( pczsn.DerivedPosition ) == PlaneSide.Negative && mPrevDerivedPlane.GetSide( pczsn.DerivedPosition ) != PlaneSide.Negative ) { // safety check - make sure the node has at least one dimension which is // small enough to fit through the portal! (avoid the "elephant fitting // through a mouse hole" case) Vector3 nodeHalfVector = pczsn.WorldAABB.HalfSize; Vector3 portalBox = new Vector3( mRadius, mRadius, mRadius ); portalBox.Floor( nodeHalfVector ); if ( portalBox.x < mRadius ) { // crossing occurred! return PortalIntersectResult.INTERSECT_CROSS; } } } // there was no crossing of the portal by the node, but it might be touching // the portal. We check for this by checking the bounding box of the node vs. // the sphere of the portal if ( mDerivedSphere.Intersects( pczsn.WorldAABB ) && mDerivedPlane.GetSide( pczsn.WorldAABB ) == PlaneSide.Both ) { // intersection but no crossing // note this means that the node is CURRENTLY touching the portal. if ( mDerivedPlane.GetSide( pczsn.DerivedPosition ) != PlaneSide.Negative ) { // the node is on the positive (front) or exactly on the CP of the portal return PortalIntersectResult.INTERSECT_NO_CROSS; } else { // the node is on the negative (back) side of the portal - it might be in the wrong zone! return PortalIntersectResult.INTERSECT_BACK_NO_CROSS; } } // no intersection CURRENTLY. (there might have been an intersection // during the time between last frame and this frame, but it wasn't a portal // crossing, and it isn't touching anymore, so it doesn't matter. return PortalIntersectResult.NO_INTERSECT; } else if ( mType == PORTAL_TYPE.PORTAL_TYPE_AABB ) { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. AxisAlignedBox aabb = new AxisAlignedBox( mDerivedCorners[ 0 ], mDerivedCorners[ 1 ] ); //bool previousInside = aabb.contains(pczsn->getPrevPosition()); bool currentInside = aabb.Contains( pczsn.DerivedPosition ); if ( mDirection == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if ( currentInside == true ) { return PortalIntersectResult.INTERSECT_CROSS; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if ( currentInside == false ) { return PortalIntersectResult.INTERSECT_CROSS; } } // doesn't cross, but might be touching. This is a little tricky because we only // care if the node aab is NOT fully contained in the portal aabb because we consider // the surface of the portal aabb the actual 'portal'. First, check to see if the // aab of the node intersects the aabb portal if ( aabb.Intersects( pczsn.WorldAABB ) ) { // now check if the intersection between the two is not the same as the // full node aabb, if so, then this means that the node is not fully "contained" // which is what we are looking for. AxisAlignedBox overlap = aabb.Intersection( pczsn.WorldAABB ); if ( overlap != pczsn.WorldAABB ) { return PortalIntersectResult.INTERSECT_NO_CROSS; } } return PortalIntersectResult.NO_INTERSECT; } else { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(pczsn->getPrevPosition()); Real currentDistance2 = mDerivedCP.DistanceSquared( pczsn.DerivedPosition ); Real mRadius2 = mRadius * mRadius; if ( mDirection == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if ( currentDistance2 < mRadius2 ) { return PortalIntersectResult.INTERSECT_CROSS; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if ( currentDistance2 >= mRadius2 ) { return PortalIntersectResult.INTERSECT_CROSS; } } // no crossing, but might be touching - check distance if ( System.Math.Sqrt( System.Math.Abs( mRadius2 - currentDistance2 ) ) <= mRadius ) { return PortalIntersectResult.INTERSECT_NO_CROSS; } return PortalIntersectResult.NO_INTERSECT; } } return PortalIntersectResult.NO_INTERSECT; }