diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index bc66955fca4aab762076b4e322afe47ba548b2b2..2340b9e8b8096e1fbf68c038f360d47597e745b9 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1117,8 +1117,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 		INT32 gl_toptexture = 0, gl_bottomtexture = 0;
 		fixed_t texturevpeg;
 
-		boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
-		boolean bothfloorssky = false; // likewise, but for floors
+		bothceilingssky = bothfloorssky = false;
 
 		SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight)
 		SLOPEPARAMS(gl_backsector->f_slope, worldlow,  worldlowslope,  gl_backsector->floorheight)
@@ -1854,12 +1853,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks
 {
 	fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
 	fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
-	boolean bothceilingssky = false, bothfloorssky = false;
-
-	if (abacksector->ceilingpic == skyflatnum && afrontsector->ceilingpic == skyflatnum)
-		bothceilingssky = true;
-	if (abacksector->floorpic == skyflatnum && afrontsector->floorpic == skyflatnum)
-		bothfloorssky = true;
 
 	// GZDoom method of sloped line clipping
 
@@ -2354,13 +2347,16 @@ static void HWR_AddLine(seg_t * line)
     }
     else
     {
-		boolean bothceilingssky = false, bothfloorssky = false;
+		bothceilingssky = bothfloorssky = false;
 
 		gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
 
-		if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum)
+		if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum
+		&& !(gl_backsector->portal_ceiling.exists || gl_frontsector->portal_ceiling.exists))
 			bothceilingssky = true;
-		if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum)
+
+		if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum
+		&& !(gl_backsector->portal_floor.exists || gl_frontsector->portal_floor.exists))
 			bothfloorssky = true;
 
 		if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
diff --git a/src/p_setup.c b/src/p_setup.c
index c590bba4f3808c71a1e991fcc4cc4831f9af4ee1..b9c2b5939332eda3ecc317ff19d6e67da0e58af8 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -980,9 +980,9 @@ static void P_LoadVertices(UINT8 *data)
 
 static void InitializeSectorPortal(sectorportal_t *secportal)
 {
-	secportal->target = NULL;
-	secportal->viewpoint.x = secportal->viewpoint.y = secportal->viewpoint.z = 0;
-	secportal->viewpoint.angle = 0;
+	secportal->exists = false;
+	secportal->target.x = secportal->target.y = secportal->target.z = 0;
+	secportal->target.angle = 0;
 }
 
 static void P_InitializeSector(sector_t *ss)
@@ -998,8 +998,8 @@ static void P_InitializeSector(sector_t *ss)
 	ss->lightingdata = NULL;
 	ss->fadecolormapdata = NULL;
 
-	InitializeSectorPortal(&ss->portal_plane_floor);
-	InitializeSectorPortal(&ss->portal_plane_ceiling);
+	InitializeSectorPortal(&ss->portal_floor);
+	InitializeSectorPortal(&ss->portal_ceiling);
 
 	ss->heightsec = -1;
 	ss->camsec = -1;
diff --git a/src/p_spec.c b/src/p_spec.c
index 5dc99ee5b0d5e8dfb6c789d85573a8193b75843b..57653416a9210d444e95fe10638ff29346d7c575 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -6186,13 +6186,18 @@ fixed_t P_GetSectorGravityFactor(sector_t *sec)
 		return sec->gravity;
 }
 
+boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b)
+{
+	return !memcmp(a, b, sizeof(sectorportal_t));
+}
+
 static void SetSectorPortal(sectorportal_t *secportal, sector_t *target_sector, fixed_t default_z, INT32 viewpoint_tag)
 {
-	secportal->target = target_sector;
-	secportal->viewpoint.x = target_sector->soundorg.x;
-	secportal->viewpoint.y = target_sector->soundorg.y;
-	secportal->viewpoint.z = default_z;
-	secportal->viewpoint.angle = 0;
+	secportal->exists = target_sector;
+	secportal->target.x = target_sector->soundorg.x;
+	secportal->target.y = target_sector->soundorg.y;
+	secportal->target.z = default_z;
+	secportal->target.angle = 0;
 
 	if (viewpoint_tag <= 0)
 		return;
@@ -6210,10 +6215,10 @@ static void SetSectorPortal(sectorportal_t *secportal, sector_t *target_sector,
 		if (!Tag_Find(&mo->spawnpoint->tags, viewpoint_tag))
 			continue;
 
-		secportal->viewpoint.x = mo->x;
-		secportal->viewpoint.y = mo->y;
-		secportal->viewpoint.z = mo->z;
-		secportal->viewpoint.angle = mo->angle;
+		secportal->target.x = mo->x;
+		secportal->target.y = mo->y;
+		secportal->target.z = mo->z;
+		secportal->target.angle = mo->angle;
 		return;
 	}
 }
@@ -6402,9 +6407,9 @@ void P_SpawnSpecials(boolean fromnetsave)
 						}
 
 						if (floor)
-							SetSectorPortal(&sectors[s1].portal_plane_floor, target_sector, target_sector->ceilingheight, lines[i].args[3]);
+							SetSectorPortal(&sectors[s1].portal_floor, target_sector, target_sector->ceilingheight, lines[i].args[3]);
 						if (ceiling)
-							SetSectorPortal(&sectors[s1].portal_plane_ceiling, target_sector, target_sector->floorheight, lines[i].args[3]);
+							SetSectorPortal(&sectors[s1].portal_ceiling, target_sector, target_sector->floorheight, lines[i].args[3]);
 					}
 				}
 				break;
diff --git a/src/p_spec.h b/src/p_spec.h
index 50ab6410f145b0d2ad180b492525cec51d786365..71c9dcf3ac7747720642bbfa11c241d098c9b646 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -521,6 +521,8 @@ INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max);
 void P_SetupSignExit(player_t *player);
 boolean P_IsFlagAtBase(mobjtype_t flag);
 
+boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b);
+
 boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec);
 boolean P_IsMobjTouching3DFloor(mobj_t *mo, ffloor_t *ffloor, sector_t *sec);
 boolean P_IsMobjTouchingPolyobj(mobj_t *mo, polyobj_t *po, sector_t *polysec);
diff --git a/src/r_bsp.c b/src/r_bsp.c
index 5c9aa3ff98a0da4e92f621150c3b95f36e1bab79..70f08e127166aa79168c7fe49f085faa947690d9 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -36,6 +36,9 @@ drawseg_t *curdrawsegs = NULL; /**< This is used to handle multiple lists for ma
 drawseg_t *drawsegs = NULL;
 drawseg_t *ds_p = NULL;
 
+boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
+boolean bothfloorssky = false; // likewise, but for floors
+
 // indicates doors closed wrt automap bugfix:
 INT32 doorclosed;
 
@@ -391,7 +394,6 @@ static void R_AddLine(seg_t *line)
 	INT32 x1, x2;
 	angle_t angle1, angle2, span, tspan;
 	static sector_t tempsec;
-	boolean bothceilingssky = false, bothfloorssky = false;
 
 	portalline = false;
 
@@ -481,10 +483,17 @@ static void R_AddLine(seg_t *line)
 	backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true);
 
 	doorclosed = 0;
+	bothceilingssky = bothfloorssky = false;
 
-	if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum)
+	// hack to allow height changes in outdoor areas
+	// This is what gets rid of the upper textures if there should be sky
+	if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum
+	&& !(backsector->portal_ceiling.exists || frontsector->portal_ceiling.exists))
 		bothceilingssky = true;
-	if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum)
+
+	// likewise, but for floors and upper textures
+	if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum
+	&& !(backsector->portal_floor.exists || frontsector->portal_floor.exists))
 		bothfloorssky = true;
 
 	if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
@@ -909,7 +918,7 @@ static void R_Subsector(size_t num)
 		|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum))
 	{
 		floorplane = R_FindPlane(frontsector, frontsector->floorheight, frontsector->floorpic, floorlightlevel,
-			frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorangle, floorcolormap, NULL, NULL, frontsector->f_slope, frontsector->portal_plane_floor.target != NULL ? &frontsector->portal_plane_floor : NULL);
+			frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorangle, floorcolormap, NULL, NULL, frontsector->f_slope, frontsector->portal_floor.exists ? &frontsector->portal_floor : NULL);
 	}
 	else
 		floorplane = NULL;
@@ -920,7 +929,7 @@ static void R_Subsector(size_t num)
 	{
 		ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic,
 			ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingangle,
-			ceilingcolormap, NULL, NULL, frontsector->c_slope, frontsector->portal_plane_ceiling.target != NULL ? &frontsector->portal_plane_ceiling : NULL);
+			ceilingcolormap, NULL, NULL, frontsector->c_slope, frontsector->portal_ceiling.exists ? &frontsector->portal_ceiling : NULL);
 	}
 	else
 		ceilingplane = NULL;
diff --git a/src/r_bsp.h b/src/r_bsp.h
index 55199405ae0d59deba6e540df5e04650e1a67042..f36f7e64df8d32a2dc3e37d017fd79551190c1e2 100644
--- a/src/r_bsp.h
+++ b/src/r_bsp.h
@@ -25,13 +25,15 @@ extern sector_t *frontsector;
 extern sector_t *backsector;
 extern boolean portalline; // is curline a portal seg?
 
-// drawsegs are allocated on the fly... see r_segs.c
-
 extern INT32 checkcoord[12][4];
 
 extern drawseg_t *curdrawsegs;
 extern drawseg_t *drawsegs;
 extern drawseg_t *ds_p;
+
+extern boolean bothceilingssky;
+extern boolean bothfloorssky;
+
 extern INT32 doorclosed;
 
 // BSP?
diff --git a/src/r_defs.h b/src/r_defs.h
index d9fe6193d2589ce12db64b0af39975344d2eeb8c..d435f69ab15e42294a0aae15b4a5074b4272fb7f 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -210,11 +210,11 @@ typedef enum
 
 typedef struct sectorportal_s
 {
-	struct sector_s *target;
+	boolean exists;
 	struct {
 		fixed_t x, y, z;
 		angle_t angle;
-	} viewpoint;
+	} target;
 } sectorportal_t;
 
 typedef struct ffloor_s
@@ -505,8 +505,8 @@ typedef struct sector_s
 	extracolormap_t *spawn_extra_colormap;
 
 	// portals
-	sectorportal_t portal_plane_floor;
-	sectorportal_t portal_plane_ceiling;
+	sectorportal_t portal_floor;
+	sectorportal_t portal_ceiling;
 } sector_t;
 
 //
diff --git a/src/r_plane.c b/src/r_plane.c
index 5cd791023824bb640e07660c0917db409fa54570..d9051ae05e06bf1d1284713ea77607f27c58a91b 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -441,8 +441,6 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
 		hash = visplane_hash(picnum, lightlevel, height);
 		for (check = visplanes[hash]; check; check = check->next)
 		{
-			if (polyobj != check->polyobj)
-				continue;
 			if (height == check->height && picnum == check->picnum
 				&& lightlevel == check->lightlevel
 				&& xoff == check->xoffs && yoff == check->yoffs
@@ -452,6 +450,7 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
 				&& check->viewangle == viewangle
 				&& check->plangle == plangle
 				&& check->slope == slope
+				&& check->polyobj == polyobj
 				&& check->portalsector == portalsector)
 			{
 				return check;
diff --git a/src/r_portal.c b/src/r_portal.c
index b4328a56e9c34014871fe9c08ca59e268d395d17..136eb4facb5e5562aaa8c45dbd3c08fd59ccbe8f 100644
--- a/src/r_portal.c
+++ b/src/r_portal.c
@@ -22,7 +22,6 @@
 #include "r_sky.h"
 
 UINT8 portalrender;			/**< When rendering a portal, it establishes the depth of the current BSP traversal. */
-UINT8 floorportalrender;	/**< Same deal, but for floorportals. */
 
 // Linked list for portals.
 portal_t *portal_base, *portal_cap;
@@ -36,7 +35,6 @@ boolean portalline; // is curline a portal seg?
 void Portal_InitList (void)
 {
 	portalrender = 0;
-	floorportalrender = 0;
 	portal_base = portal_cap = NULL;
 }
 
@@ -317,7 +315,7 @@ void Portal_AddSectorPortal (const visplane_t* plane)
 {
 	INT16 start, end;
 	sector_t *source = plane->sector;
-	sectorportal_t *target = plane->portalsector;
+	sectorportal_t *secportal = plane->portalsector;
 
 	if (TrimVisplaneBounds(plane, &start, &end))
 		return;
@@ -329,18 +327,19 @@ void Portal_AddSectorPortal (const visplane_t* plane)
 	fixed_t refx = source->soundorg.x - viewx;
 	fixed_t refy = source->soundorg.y - viewy;
 
-	if (target->viewpoint.angle)
+	// Rotate the X/Y to match the target angle
+	if (secportal->target.angle)
 	{
 		fixed_t x = refx, y = refy;
-		angle_t ang = target->viewpoint.angle >> ANGLETOFINESHIFT;
+		angle_t ang = secportal->target.angle >> ANGLETOFINESHIFT;
 		refx = FixedMul(x, FINECOSINE(ang)) - FixedMul(y, FINESINE(ang));
 		refy = FixedMul(x, FINESINE(ang)) + FixedMul(y, FINECOSINE(ang));
 	}
 
-	portal->viewx = target->viewpoint.x - refx;
-	portal->viewy = target->viewpoint.y - refy;
-	portal->viewz = target->viewpoint.z + viewz;
-	portal->viewangle = target->viewpoint.angle + viewangle;
+	portal->viewx = secportal->target.x - refx;
+	portal->viewy = secportal->target.y - refy;
+	portal->viewz = secportal->target.z + viewz;
+	portal->viewangle = secportal->target.angle + viewangle;
 
 	portal->clipline = -1;
 }
@@ -358,21 +357,17 @@ void Portal_AddSkyboxPortals (void)
 		{
 			boolean added_portal = false;
 
-			// skybox portal
-			if (pl->picnum == skyflatnum)
+			// Render sector portal if recursiveness limit hasn't been reached
+			if (pl->portalsector && portalrender < cv_maxportals.value)
 			{
-				if (cv_skybox.value && skyboxmo[0])
-				{
-					Portal_AddSkybox(pl);
-					added_portal = true;
-				}
+				Portal_AddSectorPortal(pl);
+				added_portal = true;
 			}
 
-			// floor portal
-			if (pl->portalsector && pl->portalsector->target && floorportalrender < cv_maxportals.value)
+			// Render skybox portal
+			if (!added_portal && pl->picnum == skyflatnum && cv_skybox.value && skyboxmo[0])
 			{
-				Portal_AddSectorPortal(pl);
-				floorportalrender++;
+				Portal_AddSkybox(pl);
 				added_portal = true;
 			}
 
diff --git a/src/r_portal.h b/src/r_portal.h
index 6e2a6dedbe235c2861c008e18782dde33a0d797a..1e4bbfb1215a3635c3cb342438f775c58bb7707e 100644
--- a/src/r_portal.h
+++ b/src/r_portal.h
@@ -44,7 +44,6 @@ typedef struct portal_s
 extern portal_t* portal_base;
 extern portal_t* portal_cap;
 extern UINT8 portalrender;
-extern UINT8 floorportalrender;
 
 extern line_t *portalclipline;
 extern sector_t *portalcullsector;
diff --git a/src/r_segs.c b/src/r_segs.c
index 9af83f0c7ff8af10057f253a5419dca41c86638c..a8fb635d18097764e63ffca6f5e263cecfa29830 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1787,8 +1787,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	else
 	{
 		// two sided line
-		boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
-		boolean bothfloorssky = false; // likewise, but for floors
+		bothceilingssky = bothfloorssky = false;
 
 		SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight)
 		SLOPEPARAMS(backsector->f_slope, worldlow,  worldlowslope,  backsector->floorheight)
@@ -1797,21 +1796,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		worldlow -= viewz;
 		worldlowslope -= viewz;
 
-		// hack to allow height changes in outdoor areas
-		// This is what gets rid of the upper textures if there should be sky
-		if (frontsector->ceilingpic == skyflatnum
-			&& backsector->ceilingpic == skyflatnum)
-		{
-			bothceilingssky = true;
-		}
-
-		// likewise, but for floors and upper textures
-		if (frontsector->floorpic == skyflatnum
-			&& backsector->floorpic == skyflatnum)
-		{
-			bothfloorssky = true;
-		}
-
 		ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
 		ds_p->silhouette = 0;
 
@@ -1909,6 +1893,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			|| backsector->floorlightsec != frontsector->floorlightsec
 			//SoM: 4/3/2000: Check for colormaps
 			|| frontsector->extra_colormap != backsector->extra_colormap
+			|| !P_CompareSectorPortals(&frontsector->portal_floor, &backsector->portal_floor)
 			|| (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags)))
 		{
 			markfloor = true;
@@ -1942,6 +1927,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			|| backsector->ceilinglightsec != frontsector->ceilinglightsec
 			//SoM: 4/3/2000: Check for colormaps
 			|| frontsector->extra_colormap != backsector->extra_colormap
+			|| !P_CompareSectorPortals(&frontsector->portal_ceiling, &backsector->portal_ceiling)
 			|| (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags)))
 		{
 				markceiling = true;