diff --git a/punyverse/camera.py b/punyverse/camera.py
index f50a3a6..6d7fd0d 100644
--- a/punyverse/camera.py
+++ b/punyverse/camera.py
@@ -1,4 +1,4 @@
-from math import sin, cos, radians, hypot
+from math import sin, cos, radians, hypot, tan
 
 from punyverse.glgeom import Matrix4f
 from punyverse.utils import cached_property
@@ -13,6 +13,11 @@ class Camera(object):
         self.yaw = yaw
         self.roll = roll
 
+        self.fov = radians(45)
+        self.aspect = 1
+        self.znear = 1
+        self.zfar = 50000000
+
         self.speed = 0
         self.roll_left = False
         self.roll_right = False
@@ -71,3 +76,12 @@ class Camera(object):
     @cached_property
     def view_matrix(self):
         return Matrix4f.from_angles((self.x, self.y, self.z), (self.pitch, self.yaw, self.roll), view=True)
+
+    def projection_matrix(self):
+        scale_y = 1 / tan(self.fov / 2)
+        scale_x = scale_y / self.aspect
+        frustrum = self.znear - self.zfar
+        return Matrix4f([scale_x, 0, 0, 0,
+                         0, scale_y, 0, 0,
+                         0, 0, (self.znear + self.zfar) / frustrum, -1,
+                         0, 0, (2 * self.znear * self.zfar) / frustrum, 0])
diff --git a/punyverse/ui.py b/punyverse/ui.py
index f699e0e..3acdcbb 100644
--- a/punyverse/ui.py
+++ b/punyverse/ui.py
@@ -208,13 +208,12 @@ class Punyverse(pyglet.window.Window):
             self.world.cam.roll_right = False
 
     def on_resize(self, width, height):
-        height = max(height, 1)  # Prevent / by 0
         self.label.y = height - 20
         glViewport(0, 0, width, height)
+
         glMatrixMode(GL_PROJECTION)
-        glLoadIdentity()
-        # A field of view of 45
-        gluPerspective(45.0, width / float(height), 1, 50000000.0)
+        self.world.resize(width, height)
+        glLoadMatrixf(self.world.projection_matrix().as_gl())
         glMatrixMode(GL_MODELVIEW)
 
     def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
diff --git a/punyverse/world.py b/punyverse/world.py
index f0c5e41..a9f76f5 100644
--- a/punyverse/world.py
+++ b/punyverse/world.py
@@ -31,6 +31,7 @@ class World(object):
         del self.callback  # So it can't be used after loading finishes
 
         self._time_accumulate = 0
+        self._projection_matrix = self.cam.projection_matrix()
 
         for entity in self.tracker:
             entity.update()
@@ -146,3 +147,10 @@ class World(object):
 
     def view_matrix(self):
         return self.cam.view_matrix
+
+    def projection_matrix(self):
+        return self._projection_matrix
+
+    def resize(self, width, height):
+        self.cam.aspect = width / max(height, 1)
+        self._projection_matrix = self.cam.projection_matrix()