diff --git a/src/d_main.c b/src/d_main.c
index 29eaec1807f3ef914f326e0889c90415ede9bf67..fe10f6a38909ed946c3e50957e7c8af661432fc5 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -478,7 +478,7 @@ static void D_Display(void)
 
 			if (!automapactive && !dedicated && cv_renderview.value)
 			{
-				R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
+				R_ApplyLevelInterpolators(players[displayplayer].world, R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
 				PS_START_TIMING(ps_rendercalltime);
 				if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
 				{
diff --git a/src/p_world.h b/src/p_world.h
index f2d426aec0f43a1a550ef7e89cec9fc2485fc59e..919cf915aaf3ce43ce384d18c96f432334f0b963 100644
--- a/src/p_world.h
+++ b/src/p_world.h
@@ -118,6 +118,14 @@ typedef struct
 	taggroup_t* tags_sectors[MAXTAGS + 1];
 	taggroup_t* tags_lines[MAXTAGS + 1];
 	taggroup_t* tags_mapthings[MAXTAGS + 1];
+
+	void **interpolators;
+	size_t interpolators_len;
+	size_t interpolators_size;
+
+	void **interpolated_mobjs;
+	size_t interpolated_mobjs_len;
+	size_t interpolated_mobjs_capacity;
 } world_t;
 
 extern world_t *world;
diff --git a/src/r_fps.c b/src/r_fps.c
index 2d30c9f01920959c783da056d1db2f0858969209..b5fee18764acfae907a42d39229378f973bc1bc9 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -89,10 +89,6 @@ viewvars_t *newview = &p1view_new;
 
 enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1;
 
-static levelinterpolator_t **levelinterpolators;
-static size_t levelinterpolators_len;
-static size_t levelinterpolators_size;
-
 
 static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac)
 {
@@ -358,28 +354,28 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
 
 static void AddInterpolator(levelinterpolator_t* interpolator)
 {
-	if (levelinterpolators_len >= levelinterpolators_size)
+	if (world->interpolators_len >= world->interpolators_size)
 	{
-		if (levelinterpolators_size == 0)
+		if (world->interpolators_size == 0)
 		{
-			levelinterpolators_size = 128;
+			world->interpolators_size = 128;
 		}
 		else
 		{
-			levelinterpolators_size *= 2;
+			world->interpolators_size *= 2;
 		}
 
-		levelinterpolators = Z_ReallocAlign(
-			(void*) levelinterpolators,
-			sizeof(levelinterpolator_t*) * levelinterpolators_size,
+		world->interpolators = Z_ReallocAlign(
+			(void*) world->interpolators,
+			sizeof(levelinterpolator_t*) * world->interpolators_size,
 			PU_LEVEL,
 			NULL,
 			sizeof(levelinterpolator_t*) * 8
 		);
 	}
 
-	levelinterpolators[levelinterpolators_len] = interpolator;
-	levelinterpolators_len += 1;
+	world->interpolators[world->interpolators_len] = interpolator;
+	world->interpolators_len += 1;
 }
 
 static levelinterpolator_t *CreateInterpolator(levelinterpolator_type_e type, thinker_t *thinker)
@@ -473,9 +469,9 @@ void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope)
 
 void R_InitializeLevelInterpolators(void)
 {
-	levelinterpolators_len = 0;
-	levelinterpolators_size = 0;
-	levelinterpolators = NULL;
+	world->interpolators_len = 0;
+	world->interpolators_size = 0;
+	world->interpolators = NULL;
 }
 
 static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
@@ -527,13 +523,16 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
 
 void R_UpdateLevelInterpolators(void)
 {
-	size_t i;
-
-	for (i = 0; i < levelinterpolators_len; i++)
+	for (INT32 i = 0; i < numworlds; i++)
 	{
-		levelinterpolator_t *interp = levelinterpolators[i];
+		world_t *w = worldlist[i];
+
+		for (size_t j = 0; j < w->interpolators_len; j++)
+		{
+			levelinterpolator_t *interp = w->interpolators[j];
 
-		UpdateLevelInterpolatorState(interp);
+			UpdateLevelInterpolatorState(interp);
+		}
 	}
 }
 
@@ -541,9 +540,9 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker)
 {
 	size_t i;
 
-	for (i = 0; i < levelinterpolators_len; i++)
+	for (i = 0; i < world->interpolators_len; i++)
 	{
-		levelinterpolator_t *interp = levelinterpolators[i];
+		levelinterpolator_t *interp = world->interpolators[i];
 
 		if (interp->thinker == thinker)
 		{
@@ -554,13 +553,15 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker)
 	}
 }
 
-void R_ApplyLevelInterpolators(fixed_t frac)
+void R_ApplyLevelInterpolators(void *wptr, fixed_t frac)
 {
+	world_t *w = (world_t *)wptr;
+
 	size_t i, ii;
 
-	for (i = 0; i < levelinterpolators_len; i++)
+	for (i = 0; i < w->interpolators_len; i++)
 	{
-		levelinterpolator_t *interp = levelinterpolators[i];
+		levelinterpolator_t *interp = (levelinterpolator_t*)w->interpolators[i];
 
 		switch (interp->type)
 		{
@@ -609,13 +610,13 @@ void R_ApplyLevelInterpolators(fixed_t frac)
 	}
 }
 
-void R_RestoreLevelInterpolators(void)
+static void R_RestoreLevelInterpolatorsForWorld(world_t *w)
 {
 	size_t i, ii;
 
-	for (i = 0; i < levelinterpolators_len; i++)
+	for (i = 0; i < w->interpolators_len; i++)
 	{
-		levelinterpolator_t *interp = levelinterpolators[i];
+		levelinterpolator_t *interp = w->interpolators[i];
 
 		switch (interp->type)
 		{
@@ -664,19 +665,28 @@ void R_RestoreLevelInterpolators(void)
 	}
 }
 
+void R_RestoreLevelInterpolators(void)
+{
+	for (INT32 wi = 0; wi < numworlds; wi++)
+	{
+		world_t *w = worldlist[wi];
+		R_RestoreLevelInterpolatorsForWorld(w);
+	}
+}
+
 void R_DestroyLevelInterpolators(thinker_t *thinker)
 {
 	size_t i;
 
-	for (i = 0; i < levelinterpolators_len; i++)
+	for (i = 0; i < world->interpolators_len; i++)
 	{
-		levelinterpolator_t *interp = levelinterpolators[i];
+		levelinterpolator_t *interp = world->interpolators[i];
 
 		if (interp->thinker == thinker)
 		{
 			// Swap the tail of the level interpolators to this spot
-			levelinterpolators[i] = levelinterpolators[levelinterpolators_len - 1];
-			levelinterpolators_len -= 1;
+			world->interpolators[i] = world->interpolators[world->interpolators_len - 1];
+			world->interpolators_len -= 1;
 
 			Z_Free(interp);
 			i -= 1;
@@ -684,36 +694,32 @@ void R_DestroyLevelInterpolators(thinker_t *thinker)
 	}
 }
 
-static mobj_t **interpolated_mobjs = NULL;
-static size_t interpolated_mobjs_len = 0;
-static size_t interpolated_mobjs_capacity = 0;
-
 // NOTE: This will NOT check that the mobj has already been added, for perf
 // reasons.
 void R_AddMobjInterpolator(mobj_t *mobj)
 {
-	if (interpolated_mobjs_len >= interpolated_mobjs_capacity)
+	if (world->interpolated_mobjs_len >= world->interpolated_mobjs_capacity)
 	{
-		if (interpolated_mobjs_capacity == 0)
+		if (world->interpolated_mobjs_capacity == 0)
 		{
-			interpolated_mobjs_capacity = 256;
+			world->interpolated_mobjs_capacity = 256;
 		}
 		else
 		{
-			interpolated_mobjs_capacity *= 2;
+			world->interpolated_mobjs_capacity *= 2;
 		}
 
-		interpolated_mobjs = Z_ReallocAlign(
-			interpolated_mobjs,
-			sizeof(mobj_t *) * interpolated_mobjs_capacity,
+		world->interpolated_mobjs = Z_ReallocAlign(
+			world->interpolated_mobjs,
+			sizeof(mobj_t *) * world->interpolated_mobjs_capacity,
 			PU_LEVEL,
 			NULL,
 			64
 		);
 	}
 
-	interpolated_mobjs[interpolated_mobjs_len] = mobj;
-	interpolated_mobjs_len += 1;
+	world->interpolated_mobjs[world->interpolated_mobjs_len] = mobj;
+	world->interpolated_mobjs_len++;
 
 	R_ResetMobjInterpolationState(mobj);
 	mobj->resetinterp = true;
@@ -723,16 +729,16 @@ void R_RemoveMobjInterpolator(mobj_t *mobj)
 {
 	size_t i;
 
-	if (interpolated_mobjs_len == 0) return;
+	if (world->interpolated_mobjs_len == 0) return;
 
-	for (i = 0; i < interpolated_mobjs_len; i++)
+	for (i = 0; i < world->interpolated_mobjs_len; i++)
 	{
-		if (interpolated_mobjs[i] == mobj)
+		if (world->interpolated_mobjs[i] == mobj)
 		{
-			interpolated_mobjs[i] = interpolated_mobjs[
-				interpolated_mobjs_len - 1
+			world->interpolated_mobjs[i] = world->interpolated_mobjs[
+				world->interpolated_mobjs_len - 1
 			];
-			interpolated_mobjs_len -= 1;
+			world->interpolated_mobjs_len--;
 			return;
 		}
 	}
@@ -741,20 +747,23 @@ void R_RemoveMobjInterpolator(mobj_t *mobj)
 void R_InitMobjInterpolators(void)
 {
 	// apparently it's not acceptable to free something already unallocated
-	// Z_Free(interpolated_mobjs);
-	interpolated_mobjs = NULL;
-	interpolated_mobjs_len = 0;
-	interpolated_mobjs_capacity = 0;
+	// Z_Free(world->interpolated_mobjs);
+	world->interpolated_mobjs = NULL;
+	world->interpolated_mobjs_len = 0;
+	world->interpolated_mobjs_capacity = 0;
 }
 
 void R_UpdateMobjInterpolators(void)
 {
-	size_t i;
-	for (i = 0; i < interpolated_mobjs_len; i++)
+	for (INT32 wi = 0; wi < numworlds; wi++)
 	{
-		mobj_t *mobj = interpolated_mobjs[i];
-		if (!P_MobjWasRemoved(mobj))
-			R_ResetMobjInterpolationState(mobj);
+		world_t *w = worldlist[wi];
+		for (size_t i = 0; i < w->interpolated_mobjs_len; i++)
+		{
+			mobj_t *mobj = w->interpolated_mobjs[i];
+			if (!P_MobjWasRemoved(mobj))
+				R_ResetMobjInterpolationState(mobj);
+		}
 	}
 }
 
diff --git a/src/r_fps.h b/src/r_fps.h
index 85c87a2f49ff1c3177f7fb8b8e9136e88316ebc9..1c8af5cb6f94d95e46c9a88e26e15c942e12ea83 100644
--- a/src/r_fps.h
+++ b/src/r_fps.h
@@ -143,7 +143,7 @@ void R_UpdateLevelInterpolators(void);
 // Clear states for all level interpolators for the thinker
 void R_ClearLevelInterpolatorState(thinker_t *thinker);
 // Apply level interpolators to the actual game state
-void R_ApplyLevelInterpolators(fixed_t frac);
+void R_ApplyLevelInterpolators(void *wptr, fixed_t frac);
 // Restore level interpolators to the real game state
 void R_RestoreLevelInterpolators(void);
 // Destroy interpolators associated with a thinker