diff --git a/src/p_setup.c b/src/p_setup.c
index a1c96bed3f52d39ae4f82eb0bb3168de5c0e78cf..4c3e08be10c88af6e1bc6df969798e2e510ccf14 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -33,6 +33,7 @@
 #include "r_picformats.h"
 #include "r_sky.h"
 #include "r_draw.h"
+#include "r_fps.h" // R_ResetViewInterpolation in level load
 
 #include "s_sound.h"
 #include "st_stuff.h"
@@ -4466,6 +4467,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
 
 	P_MapEnd(); // tmthing is no longer needed from this point onwards
 
+	if (rendermode != render_none)
+	{
+		R_ResetViewInterpolation();
+	}
+
 	// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
 	if (!titlemapinaction)
 	{
diff --git a/src/r_fps.c b/src/r_fps.c
index ce30fd48e55003a81991ce7b76596ebdedfb122f..f9f1d60c0ba97e4ffd33355ea79160e0dbda4d56 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -34,6 +34,7 @@ static viewvars_t sky2view_old;
 static viewvars_t sky2view_new;
 
 static viewvars_t *oldview = &p1view_old;
+static BOOL oldview_valid = FALSE;
 viewvars_t *newview = &p1view_new;
 
 
@@ -87,18 +88,25 @@ static void R_SetupFreelook(player_t *player, boolean skybox)
 
 void R_InterpolateView(fixed_t frac)
 {
+	viewvars_t* prevview = oldview;
 	boolean skybox = 0;
 	if (FIXED_TO_FLOAT(frac) < 0)
 		frac = 0;
 	if (frac > FRACUNIT)
 		frac = FRACUNIT;
 
-	viewx = oldview->x + R_LerpFixed(oldview->x, newview->x, frac);
-	viewy = oldview->y + R_LerpFixed(oldview->y, newview->y, frac);
-	viewz = oldview->z + R_LerpFixed(oldview->z, newview->z, frac);
+	if (oldview_valid == FALSE)
+	{
+		// interpolate from newview to newview
+		prevview = newview;
+	}
+
+	viewx = prevview->x + R_LerpFixed(prevview->x, newview->x, frac);
+	viewy = prevview->y + R_LerpFixed(prevview->y, newview->y, frac);
+	viewz = prevview->z + R_LerpFixed(prevview->z, newview->z, frac);
 
-	viewangle = oldview->angle + R_LerpAngle(oldview->angle, newview->angle, frac);
-	aimingangle = oldview->aim + R_LerpAngle(oldview->aim, newview->aim, frac);
+	viewangle = prevview->angle + R_LerpAngle(prevview->angle, newview->angle, frac);
+	aimingangle = prevview->aim + R_LerpAngle(prevview->aim, newview->aim, frac);
 
 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
@@ -123,6 +131,12 @@ void R_UpdateViewInterpolation(void)
 	p2view_old = p2view_new;
 	sky1view_old = sky1view_new;
 	sky2view_old = sky2view_new;
+	oldview_valid = TRUE;
+}
+
+void R_ResetViewInterpolation(void)
+{
+	oldview_valid = FALSE;
 }
 
 void R_SetViewContext(enum viewcontext_e _viewcontext)
diff --git a/src/r_fps.h b/src/r_fps.h
index 6e3ff3adba77a2e7f0cfda4c63af6e3fe4cc5de3..831ffbdc89e5fce501f3a9229f98d999e59d984a 100644
--- a/src/r_fps.h
+++ b/src/r_fps.h
@@ -48,6 +48,8 @@ extern viewvars_t *newview;
 void R_InterpolateView(fixed_t frac);
 // Buffer the current new views into the old views. Call once after each real tic.
 void R_UpdateViewInterpolation(void);
+// Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data
+void R_ResetViewInterpolation(void);
 // Set the current view context (the viewvars pointed to by newview)
 void R_SetViewContext(enum viewcontext_e _viewcontext);