diff --git a/.circleci/config.yml b/.circleci/config.yml
index 00a72d8ce46a3b2d828ab6653c1a480452955608..4cbbfa9a07dfa1f816e14624d05276f494a5e211 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -176,4 +176,4 @@ workflows:
   install_and_test:
     jobs:
       - python_lint
-      - install_and_test_ubuntu
\ No newline at end of file
+      - install_and_test_ubuntu
diff --git a/examples/shortest_path_follower_example.py b/examples/shortest_path_follower_example.py
index db781de5ddfb482dc15911752b968b2c5c5fb36b..b70c69db98eb2d66d88b9993c3a78d2721ea4deb 100644
--- a/examples/shortest_path_follower_example.py
+++ b/examples/shortest_path_follower_example.py
@@ -35,7 +35,9 @@ class SimpleRLEnv(habitat.RLEnv):
 
 
 def draw_top_down_map(info, heading, output_size):
-    top_down_map = maps.colorize_topdown_map(info["top_down_map"]["map"])
+    top_down_map = maps.colorize_topdown_map(
+        info["top_down_map"]["map"], info["top_down_map"]["fog_of_war_mask"]
+    )
     original_map_size = top_down_map.shape[:2]
     map_scale = np.array(
         (1, original_map_size[1] * 1.0 / original_map_size[0])
@@ -59,8 +61,10 @@ def draw_top_down_map(info, heading, output_size):
 
 def shortest_path_example(mode):
     config = habitat.get_config(config_paths="configs/tasks/pointnav.yaml")
+    config.defrost()
     config.TASK.MEASUREMENTS.append("TOP_DOWN_MAP")
     config.TASK.SENSORS.append("HEADING_SENSOR")
+    config.freeze()
     env = SimpleRLEnv(config=config)
     goal_radius = env.episodes[0].goals[0].radius
     if goal_radius is None:
diff --git a/habitat/config/default.py b/habitat/config/default.py
index 68634e3e44196792d580ea3a1b03b3bf0a9b2c91..8fd60e74baaa3f7ce6b2bbabfa2ec5c120d812f6 100644
--- a/habitat/config/default.py
+++ b/habitat/config/default.py
@@ -72,6 +72,10 @@ _C.TASK.TOP_DOWN_MAP.MAP_RESOLUTION = 1250
 _C.TASK.TOP_DOWN_MAP.DRAW_SOURCE_AND_TARGET = True
 _C.TASK.TOP_DOWN_MAP.DRAW_BORDER = True
 _C.TASK.TOP_DOWN_MAP.DRAW_SHORTEST_PATH = True
+_C.TASK.TOP_DOWN_MAP.FOG_OF_WAR = CN()
+_C.TASK.TOP_DOWN_MAP.FOG_OF_WAR.DRAW = True
+_C.TASK.TOP_DOWN_MAP.FOG_OF_WAR.VISIBILITY_DIST = 5.0
+_C.TASK.TOP_DOWN_MAP.FOG_OF_WAR.FOV = 90
 # -----------------------------------------------------------------------------
 # # COLLISIONS MEASUREMENT
 # -----------------------------------------------------------------------------
diff --git a/habitat/tasks/nav/nav_task.py b/habitat/tasks/nav/nav_task.py
index bc9f9aeef45449a5157761bb8444df6477588aeb..27b1451522f2c009e3161250725c33f9a505278e 100644
--- a/habitat/tasks/nav/nav_task.py
+++ b/habitat/tasks/nav/nav_task.py
@@ -24,7 +24,7 @@ from habitat.core.simulator import (
 )
 from habitat.core.utils import not_none_validator
 from habitat.tasks.utils import cartesian_to_polar, quaternion_rotate_vector
-from habitat.utils.visualizations import maps
+from habitat.utils.visualizations import fog_of_war, maps
 
 MAP_THICKNESS_SCALAR: int = 1250
 
@@ -450,6 +450,10 @@ class TopDownMap(Measure):
         self._ind_x_max = range_x[-1]
         self._ind_y_min = range_y[0]
         self._ind_y_max = range_y[-1]
+
+        if self._config.FOG_OF_WAR.DRAW:
+            self._fog_of_war_mask = np.zeros_like(top_down_map)
+
         return top_down_map
 
     def draw_source_and_target(self, episode):
@@ -516,10 +520,23 @@ class TopDownMap(Measure):
                 maps.MAP_SHORTEST_PATH_COLOR,
                 self.line_thickness,
             )
+
+        self.update_fog_of_war_mask(np.array([a_x, a_y]))
+
         # draw source and target points last to avoid overlap
         if self._config.DRAW_SOURCE_AND_TARGET:
             self.draw_source_and_target(episode)
 
+    def _clip_map(self, _map):
+        return _map[
+            self._ind_x_min
+            - self._grid_delta : self._ind_x_max
+            + self._grid_delta,
+            self._ind_y_min
+            - self._grid_delta : self._ind_y_max
+            + self._grid_delta,
+        ]
+
     def update_metric(self, episode, action):
         self._step_count += 1
         house_map, map_agent_x, map_agent_y = self.update_map(
@@ -528,17 +545,15 @@ class TopDownMap(Measure):
 
         # Rather than return the whole map which may have large empty regions,
         # only return the occupied part (plus some padding).
-        house_map = house_map[
-            self._ind_x_min
-            - self._grid_delta : self._ind_x_max
-            + self._grid_delta,
-            self._ind_y_min
-            - self._grid_delta : self._ind_y_max
-            + self._grid_delta,
-        ]
+        clipped_house_map = self._clip_map(house_map)
+
+        clipped_fog_of_war_map = None
+        if self._config.FOG_OF_WAR.DRAW:
+            clipped_fog_of_war_map = self._clip_map(self._fog_of_war_mask)
 
         self._metric = {
-            "map": house_map,
+            "map": clipped_house_map,
+            "fog_of_war_mask": clipped_fog_of_war_map,
             "agent_map_coord": (
                 map_agent_x - (self._ind_x_min - self._grid_delta),
                 map_agent_y - (self._ind_y_min - self._grid_delta),
@@ -584,9 +599,24 @@ class TopDownMap(Measure):
                 thickness=thickness,
             )
 
+        self.update_fog_of_war_mask(np.array([a_x, a_y]))
+
         self._previous_xy_location = (a_y, a_x)
         return self._top_down_map, a_x, a_y
 
+    def update_fog_of_war_mask(self, agent_position):
+        if self._config.FOG_OF_WAR.DRAW:
+            self._fog_of_war_mask = fog_of_war.reveal_fog_of_war(
+                self._top_down_map,
+                self._fog_of_war_mask,
+                agent_position,
+                self.get_polar_angle(),
+                fov=self._config.FOG_OF_WAR.FOV,
+                max_line_len=self._config.FOG_OF_WAR.VISIBILITY_DIST
+                * max(self._map_resolution)
+                / (self._coordinate_max - self._coordinate_min),
+            )
+
 
 @registry.register_task(name="Nav-v0")
 class NavigationTask(EmbodiedTask):
diff --git a/habitat/utils/visualizations/fog_of_war.py b/habitat/utils/visualizations/fog_of_war.py
new file mode 100644
index 0000000000000000000000000000000000000000..388acb0e387210e20e5acec583c80147adf08c52
--- /dev/null
+++ b/habitat/utils/visualizations/fog_of_war.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+
+# Copyright (c) Facebook, Inc. and its affiliates.
+# This source code is licensed under the MIT license found in the
+# LICENSE file in the root directory of this source tree.
+
+import numba
+import numpy as np
+
+from habitat.utils.visualizations import maps
+
+
+@numba.jit(nopython=True)
+def bresenham_supercover_line(pt1, pt2):
+    r"""Line drawing algo based 
+    on http://eugen.dedu.free.fr/projects/bresenham/
+    """
+
+    ystep, xstep = 1, 1
+
+    x, y = pt1
+    dx, dy = pt2 - pt1
+
+    if dy < 0:
+        ystep *= -1
+        dy *= -1
+
+    if dx < 0:
+        xstep *= -1
+        dx *= -1
+
+    line_pts = [[x, y]]
+
+    ddx, ddy = 2 * dx, 2 * dy
+    if ddx > ddy:
+        errorprev = dx
+        error = dx
+        for i in range(int(dx)):
+            x += xstep
+            error += ddy
+
+            if error > ddx:
+                y += ystep
+                error -= ddx
+                if error + errorprev < ddx:
+                    line_pts.append([x, y - ystep])
+                elif error + errorprev > ddx:
+                    line_pts.append([x - xstep, y])
+                else:
+                    line_pts.append([x - xstep, y])
+                    line_pts.append([x, y - ystep])
+
+            line_pts.append([x, y])
+
+            errorprev = error
+    else:
+        errorprev = dx
+        error = dx
+        for i in range(int(dy)):
+            y += ystep
+            error += ddx
+
+            if error > ddy:
+                x += xstep
+                error -= ddy
+                if error + errorprev < ddy:
+                    line_pts.append([x - xstep, y])
+                elif error + errorprev > ddy:
+                    line_pts.append([x, y - ystep])
+                else:
+                    line_pts.append([x - xstep, y])
+                    line_pts.append([x, y - ystep])
+
+            line_pts.append([x, y])
+
+            errorprev = error
+
+    return line_pts
+
+
+@numba.jit(nopython=True)
+def draw_fog_of_war_line(top_down_map, fog_of_war_mask, pt1, pt2):
+    r"""Draws a line on the fog_of_war_mask mask between pt1 and pt2
+    """
+
+    for pt in bresenham_supercover_line(pt1, pt2):
+        x, y = pt
+
+        if x < 0 or x >= fog_of_war_mask.shape[0]:
+            break
+
+        if y < 0 or y >= fog_of_war_mask.shape[1]:
+            break
+
+        if top_down_map[x, y] == maps.MAP_INVALID_POINT:
+            break
+
+        fog_of_war_mask[x, y] = 1
+
+
+@numba.jit(nopython=True)
+def _draw_loop(
+    top_down_map,
+    fog_of_war_mask,
+    current_point,
+    current_angle,
+    max_line_len,
+    angles,
+):
+    for angle in angles:
+        draw_fog_of_war_line(
+            top_down_map,
+            fog_of_war_mask,
+            current_point,
+            current_point
+            + max_line_len
+            * np.array(
+                [np.cos(current_angle + angle), np.sin(current_angle + angle)]
+            ),
+        )
+
+
+def reveal_fog_of_war(
+    top_down_map: np.ndarray,
+    current_fog_of_war_mask: np.ndarray,
+    current_point: np.ndarray,
+    current_angle: float,
+    fov: float = 90,
+    max_line_len: float = 100,
+) -> np.ndarray:
+    r"""Reveals the fog-of-war at the current location
+
+    This works by simply drawing lines from the agents current location
+    and stopping once a wall is hit
+
+    Args:
+        top_down_map: The current top down map.  Used for respecting walls when revealing
+        current_fog_of_war_mask: The current fog-of-war mask to reveal the fog-of-war on
+        current_point: The current location of the agent on the fog_of_war_mask
+        current_angle: The current look direction of the agent on the fog_of_war_mask
+        fov: The feild of view of the agent
+        max_line_len: The maximum length of the lines used to reveal the fog-of-war
+
+    Returns:
+        The updated fog_of_war_mask
+    """
+    fov = np.deg2rad(fov)
+
+    # Set the angle step to a value such that delta_angle * max_line_len = 1
+    angles = np.arange(
+        -fov / 2, fov / 2, step=1.0 / max_line_len, dtype=np.float32
+    )
+
+    fog_of_war_mask = current_fog_of_war_mask.copy()
+    _draw_loop(
+        top_down_map,
+        fog_of_war_mask,
+        current_point,
+        current_angle,
+        max_line_len,
+        angles,
+    )
+
+    return fog_of_war_mask
diff --git a/habitat/utils/visualizations/maps.py b/habitat/utils/visualizations/maps.py
index 9f34c22b20f14db3463c17d8fb5e54a6d5f4a11c..714fd4e6355340ef24ade6476ebced6a0eeba851 100644
--- a/habitat/utils/visualizations/maps.py
+++ b/habitat/utils/visualizations/maps.py
@@ -327,14 +327,32 @@ def get_topdown_map(
     return top_down_map
 
 
-def colorize_topdown_map(top_down_map: np.ndarray) -> np.ndarray:
+FOG_OF_WAR_COLOR_DESAT = np.array([[0.7], [1.0]])
+
+
+def colorize_topdown_map(
+    top_down_map: np.ndarray, fog_of_war_mask: Optional[np.ndarray] = None
+) -> np.ndarray:
     r"""Convert the top down map to RGB based on the indicator values.
         Args:
             top_down_map: A non-colored version of the map.
+            fog_of_war_mask: A mask used to determine which parts of the 
+                top_down_map are visible
+                Non-visible parts will be desaturated
         Returns:
             A colored version of the top-down map.
     """
-    return TOP_DOWN_MAP_COLORS[top_down_map]
+    _map = TOP_DOWN_MAP_COLORS[top_down_map]
+
+    if fog_of_war_mask is not None:
+        # Only desaturate things that are valid points as only valid points get revealed
+        desat_mask = top_down_map != MAP_INVALID_POINT
+
+        _map[desat_mask] = (
+            _map * FOG_OF_WAR_COLOR_DESAT[fog_of_war_mask]
+        ).astype(np.uint8)[desat_mask]
+
+    return _map
 
 
 def draw_path(
diff --git a/requirements.txt b/requirements.txt
index d4aedf5cbe3934572e3919889be8648b663f266e..a95a0d5abb9247bbd20cede63e0175029f83d2aa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,3 +9,4 @@ imageio>=2.2.0
 imageio-ffmpeg>=0.2.0
 scipy>=1.0.0
 tqdm>=4.0.0
+numba>=0.44.0