diff --git a/src/client.cpp b/src/client.cpp
index a5ed6f61bf204807399b9e342d7f330bf83aa754..df792d116e616049bb8c4fc389c839b2c5583c24 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -189,8 +189,6 @@ Client::Client(
 	),
 	m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
 	m_device(device),
-	camera_position(0,0,0),
-	camera_direction(0,0,1),
 	m_server_ser_ver(SER_FMT_VER_INVALID),
 	m_inventory_updated(false),
 	m_time_of_day(0),
@@ -1983,8 +1981,11 @@ void Client::addNode(v3s16 p, MapNode n)
 void Client::updateCamera(v3f pos, v3f dir)
 {
 	m_env.getClientMap().updateCamera(pos, dir);
-	camera_position = pos;
-	camera_direction = dir;
+}
+
+void Client::renderPostFx()
+{
+	m_env.getClientMap().renderPostFx();
 }
 
 MapNode Client::getNode(v3s16 p)
@@ -1998,6 +1999,11 @@ NodeMetadata* Client::getNodeMetadata(v3s16 p)
 	return m_env.getMap().getNodeMetadata(p);
 }
 
+LocalPlayer* Client::getLocalPlayer()
+{
+	return m_env.getLocalPlayer();
+}
+
 v3f Client::getPlayerPosition(v3f *eye_position)
 {
 	//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
diff --git a/src/client.h b/src/client.h
index 1a7ef924ac53d7b9085c4a75e59e480dd60f9761..9c942ff9ac150c1a67f0a417fe6bfac52511df4f 100644
--- a/src/client.h
+++ b/src/client.h
@@ -201,14 +201,16 @@ class Client : public con::PeerHandler, public InventoryManager
 	
 	void updateCamera(v3f pos, v3f dir);
 	
+	void renderPostFx();
+	
 	// Returns InvalidPositionException if not found
 	MapNode getNode(v3s16 p);
 	// Wrapper to Map
 	NodeMetadata* getNodeMetadata(v3s16 p);
 
-	// Get the player position, and optionally put the
-	// eye position in *eye_position
-	v3f getPlayerPosition(v3f *eye_position=NULL);
+	LocalPlayer* getLocalPlayer();
+
+	v3f getPlayerPosition(v3f *eye_position);
 
 	void setPlayerControl(PlayerControl &control);
 
@@ -302,15 +304,6 @@ class Client : public con::PeerHandler, public InventoryManager
 	{
 		return m_access_denied_reason;
 	}
-	
-	/*
-		This should only be used for calling the special drawing stuff in
-		ClientEnvironment
-	*/
-	ClientEnvironment * getEnv()
-	{
-		return &m_env;
-	}
 
 private:
 	
@@ -342,9 +335,6 @@ class Client : public con::PeerHandler, public InventoryManager
 
 	IrrlichtDevice *m_device;
 
-	v3f camera_position;
-	v3f camera_direction;
-	
 	// Server serialization version
 	u8 m_server_ser_ver;
 
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index 51f2f97368e1d8da31ce77f324e7826e24878218..89171755e33a1ec8f640c2927a42c5cf08f9cfd8 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -385,6 +385,7 @@ void content_mapnode_init()
 	f->liquid_alternative_source = CONTENT_WATERSOURCE;
 	f->liquid_viscosity = WATER_VISC;
 	f->vertex_alpha = WATER_ALPHA;
+	f->post_effect_color = video::SColor(64, 100, 100, 200);
 	if(f->special_material == NULL && g_texturesource)
 	{
 		// Flowing water material
@@ -433,6 +434,7 @@ void content_mapnode_init()
 	f->liquid_alternative_source = CONTENT_WATERSOURCE;
 	f->liquid_viscosity = WATER_VISC;
 	f->vertex_alpha = WATER_ALPHA;
+	f->post_effect_color = video::SColor(64, 100, 100, 200);
 	if(f->special_material == NULL && g_texturesource)
 	{
 		// Flowing water material
@@ -465,6 +467,7 @@ void content_mapnode_init()
 	f->liquid_alternative_source = CONTENT_LAVASOURCE;
 	f->liquid_viscosity = LAVA_VISC;
 	f->damage_per_second = 4*2;
+	f->post_effect_color = video::SColor(192, 255, 64, 0);
 	if(f->special_material == NULL && g_texturesource)
 	{
 		// Flowing lava material
@@ -514,6 +517,7 @@ void content_mapnode_init()
 	f->liquid_alternative_source = CONTENT_LAVASOURCE;
 	f->liquid_viscosity = LAVA_VISC;
 	f->damage_per_second = 4*2;
+	f->post_effect_color = video::SColor(192, 255, 64, 0);
 	if(f->special_material == NULL && g_texturesource)
 	{
 		// Flowing lava material
diff --git a/src/environment.cpp b/src/environment.cpp
index 8103b7110436ddf3c7c4c8de7eb2678b9b5e3a59..80f41f9fd44905dfc6673b00c1d82853e64f30ed 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -1940,29 +1940,6 @@ ClientEnvEvent ClientEnvironment::getClientEvent()
 	return m_client_event_queue.pop_front();
 }
 
-void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
-{
-	/*LocalPlayer *player = getLocalPlayer();
-	assert(player);
-	v3f pos_f = player->getPosition() + v3f(0,BS*1.625,0);*/
-	v3f pos_f = camera_pos;
-	v3s16 p_nodes = floatToInt(pos_f, BS);
-	MapNode n = m_map->getNodeNoEx(p_nodes);
-	if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
-	{
-		v2u32 ss = driver->getScreenSize();
-		core::rect<s32> rect(0,0, ss.X, ss.Y);
-		driver->draw2DRectangle(video::SColor(64, 100, 100, 200), rect);
-	}
-	else if(content_features(n).solidness == 2 &&
-			g_settings.getBool("free_move") == false)
-	{
-		v2u32 ss = driver->getScreenSize();
-		core::rect<s32> rect(0,0, ss.X, ss.Y);
-		driver->draw2DRectangle(video::SColor(255, 0, 0, 0), rect);
-	}
-}
-
 #endif // #ifndef SERVER
 
 
diff --git a/src/environment.h b/src/environment.h
index d9248d2adbb7d131b9edffe335be7911c60d5446..055e2b1f68c0fc5ab78e4082ffab09e779c3f5ae 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -406,9 +406,6 @@ class ClientEnvironment : public Environment
 	
 	// Get event from queue. CEE_NONE is returned if queue is empty.
 	ClientEnvEvent getClientEvent();
-
-	// Post effects
-	void drawPostFx(video::IVideoDriver* driver, v3f camera_pos);
 	
 private:
 	ClientMap *m_map;
diff --git a/src/game.cpp b/src/game.cpp
index dc3ed24569cbb56587bd5a5fe449f35fcb69ceb3..afe1ce80f7c23fc0e88a47799a0049b8c21c0707 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -2032,7 +2032,7 @@ void the_game(
 			update_skybox(driver, smgr, skybox, brightness);
 
 		/*
-			Update coulds
+			Update clouds
 		*/
 		if(clouds)
 		{
@@ -2313,6 +2313,13 @@ void the_game(
 			driver->draw3DBox(*i, video::SColor(255,0,0,0));
 		}
 
+		/*
+			Post effects
+		*/
+		{
+			client.renderPostFx();
+		}
+
 		/*
 			Frametime log
 		*/
@@ -2352,13 +2359,6 @@ void the_game(
 		// 0-1ms
 		guienv->drawAll();
 
-		/*
-			Environment post fx
-		*/
-		{
-			client.getEnv()->drawPostFx(driver, camera_position);
-		}
-		
 		/*
 			Draw hotbar
 		*/
diff --git a/src/map.cpp b/src/map.cpp
index 7de79c75d8f4a963fad21443c6e19f15e5ef5b24..6f22498fede2173af16955ab133a9bc83af94206 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -3925,6 +3925,35 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
 			<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
 }
 
+void ClientMap::renderPostFx()
+{
+	// Sadly ISceneManager has no "post effects" render pass, in that case we
+	// could just register for that and handle it in renderMap().
+
+	m_camera_mutex.Lock();
+	v3f camera_position = m_camera_position;
+	m_camera_mutex.Unlock();
+
+	MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
+
+	// - If the player is in a solid node, make everything black.
+	// - If the player is in liquid, draw a semi-transparent overlay.
+	ContentFeatures& features = content_features(n);
+	video::SColor post_effect_color = features.post_effect_color;
+	if(features.solidness == 2 && g_settings.getBool("free_move") == false)
+	{
+		post_effect_color = video::SColor(255, 0, 0, 0);
+	}
+	if (post_effect_color.getAlpha() != 0)
+	{
+		// Draw a full-screen rectangle
+		video::IVideoDriver* driver = SceneManager->getVideoDriver();
+		v2u32 ss = driver->getScreenSize();
+		core::rect<s32> rect(0,0, ss.X, ss.Y);
+		driver->draw2DRectangle(post_effect_color, rect);
+	}
+}
+
 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
 		core::map<v3s16, MapBlock*> *affected_blocks)
 {
diff --git a/src/map.h b/src/map.h
index e0b67eb6e9aa4baa4dfaac901edb0a0fd0bb09eb..5bea4a137c054dde6ef739732a048b95c1a978de 100644
--- a/src/map.h
+++ b/src/map.h
@@ -552,6 +552,8 @@ class ClientMap : public Map, public scene::ISceneNode
 
 	void renderMap(video::IVideoDriver* driver, s32 pass);
 
+	void renderPostFx();
+
 	/*
 		Methods for setting temporary modifications to nodes for
 		drawing.
diff --git a/src/mapnode.h b/src/mapnode.h
index 3ad67aaf6bebc152078d09a9959ef8bbe3ca7da3..19dfb28025c199d5e0cb23aa46fff5d6dcb6ce13 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -160,6 +160,8 @@ struct ContentFeatures
 	u8 liquid_viscosity;
 	// Used currently for flowing liquids
 	u8 vertex_alpha;
+	// Post effect color, drawn when the camera is inside the node.
+	video::SColor post_effect_color;
 	// Special irrlicht material, used sometimes
 	video::SMaterial *special_material;
 	AtlasPointer *special_atlas;
@@ -197,6 +199,7 @@ struct ContentFeatures
 		liquid_alternative_source = CONTENT_IGNORE;
 		liquid_viscosity = 0;
 		vertex_alpha = 255;
+		post_effect_color = video::SColor(0, 0, 0, 0);
 		special_material = NULL;
 		special_atlas = NULL;
 		light_source = 0;