Skip to content

Camera

Camera

A camera class designed to handle the position and orientation of a virtual camers within a 3D game world. It manages the camera's perspective projection and its transformation based on player input or other in-game events.

Parameters:

Name Type Description Default
window_resolution Tuple[float, float]

The resolution of the window.

required
camera_parameters CameraParameters

The parameters of the camera.

required
Source code in pynecraft/camera.py
class Camera:
    """A camera class designed to handle the position and orientation of a
    virtual camers within a 3D game world. It manages the camera's perspective
    projection and its transformation based on player input or other in-game
    events.

    Args:
        window_resolution (Tuple[float, float]): The resolution of the window.
        camera_parameters (CameraParameters): The parameters of the camera.
    """

    def __init__(
        self,
        window_resolution: Tuple[float, float],
        camera_parameters: CameraParameters,
    ) -> None:
        self.window_resolution = glm.vec2(window_resolution)
        self.position = glm.vec3(camera_parameters.position)
        self.yaw = glm.radians(camera_parameters.yaw)
        self.pitch = glm.radians(camera_parameters.pitch)
        self.field_of_view = camera_parameters.field_of_view
        self.near_plane_of_view_frustum = camera_parameters.near_plane_of_view_frustum
        self.far_plane_of_view_frustum = camera_parameters.far_plane_of_view_frustum
        self.pitch_max = camera_parameters.pitch_max

        self.aspect_ratio = self.window_resolution.x / self.window_resolution.y

        # The angle between the top and bottom of the view frustum. It determines how
        # much of the scene is visible vertically from the camera's perspective.
        # A larger vertical field of view makes more of the scene visible vertically,
        # which can make the game feel more immersive.
        self.vertical_field_of_view = glm.radians(self.field_of_view)

        # The horizontal field of view is derived from the vertical field of view using
        # the aspect ratio of the game window. This ensures that the field of view remains
        # consistent and proportionate across different screen sizes and aspect ratios. By
        # adjusting the vertical field of view and the aspect ratio, the horizontal field
        # of view is automatically adjusted to provide a correct and visually pleasing
        # perspective.
        self.horizontal_field_of_view = 2 * math.atan(
            math.tan(self.vertical_field_of_view / 2) * self.aspect_ratio
        )

        self.up = glm.vec3(0.0, 1.0, 0.0)
        self.right = glm.vec3(1.0, 0.0, 0.0)
        self.forward = glm.vec3(0.0, 0.0, -1.0)

        self.projection_matrix = glm.perspective(
            self.vertical_field_of_view,
            self.aspect_ratio,
            self.near_plane_of_view_frustum,
            self.far_plane_of_view_frustum,
        )
        self.view_matrix = glm.mat4()

    def update_vectors(self):
        """Update the camera vectors."""
        self.forward.x = glm.cos(self.yaw) * glm.cos(self.pitch)
        self.forward.y = glm.sin(self.pitch)
        self.forward.z = glm.sin(self.yaw) * glm.cos(self.pitch)

        self.forward = glm.normalize(self.forward)
        self.right = glm.normalize(glm.cross(self.forward, glm.vec3(0.0, 1.0, 0.0)))
        self.up = glm.normalize(glm.cross(self.right, self.forward))

    def update_view_matrix(self):
        """Update the view matrix."""
        self.view_matrix = glm.lookAt(
            self.position, self.position + self.forward, self.up
        )

    def update(self):
        """Update the camera vectors and view matrix based on the controls."""
        self.update_vectors()
        self.update_view_matrix()

    def rotate_pitch(self, vertical_offset):
        """Rotate the camera pitch."""
        self.pitch -= vertical_offset
        self.pitch = glm.clamp(self.pitch, -self.pitch_max, self.pitch_max)

    def rotate_yaw(self, horizontal_offset):
        """Rotate the camera yaw."""
        self.yaw += horizontal_offset

    def move_left(self, velocity):
        """Move the camera left."""
        self.position -= self.right * velocity

    def move_right(self, velocity):
        """Move the camera right."""
        self.position += self.right * velocity

    def move_up(self, velocity):
        """Move the camera up."""
        self.position += self.up * velocity

    def move_down(self, velocity):
        """Move the camera down."""
        self.position -= self.up * velocity

    def move_forward(self, velocity):
        """Move the camera forward."""
        self.position += self.forward * velocity

    def move_backward(self, velocity):
        """Move the camera backward."""
        self.position -= self.forward * velocity

move_backward(velocity)

Move the camera backward.

Source code in pynecraft/camera.py
def move_backward(self, velocity):
    """Move the camera backward."""
    self.position -= self.forward * velocity

move_down(velocity)

Move the camera down.

Source code in pynecraft/camera.py
def move_down(self, velocity):
    """Move the camera down."""
    self.position -= self.up * velocity

move_forward(velocity)

Move the camera forward.

Source code in pynecraft/camera.py
def move_forward(self, velocity):
    """Move the camera forward."""
    self.position += self.forward * velocity

move_left(velocity)

Move the camera left.

Source code in pynecraft/camera.py
def move_left(self, velocity):
    """Move the camera left."""
    self.position -= self.right * velocity

move_right(velocity)

Move the camera right.

Source code in pynecraft/camera.py
def move_right(self, velocity):
    """Move the camera right."""
    self.position += self.right * velocity

move_up(velocity)

Move the camera up.

Source code in pynecraft/camera.py
def move_up(self, velocity):
    """Move the camera up."""
    self.position += self.up * velocity

rotate_pitch(vertical_offset)

Rotate the camera pitch.

Source code in pynecraft/camera.py
def rotate_pitch(self, vertical_offset):
    """Rotate the camera pitch."""
    self.pitch -= vertical_offset
    self.pitch = glm.clamp(self.pitch, -self.pitch_max, self.pitch_max)

rotate_yaw(horizontal_offset)

Rotate the camera yaw.

Source code in pynecraft/camera.py
def rotate_yaw(self, horizontal_offset):
    """Rotate the camera yaw."""
    self.yaw += horizontal_offset

update()

Update the camera vectors and view matrix based on the controls.

Source code in pynecraft/camera.py
def update(self):
    """Update the camera vectors and view matrix based on the controls."""
    self.update_vectors()
    self.update_view_matrix()

update_vectors()

Update the camera vectors.

Source code in pynecraft/camera.py
def update_vectors(self):
    """Update the camera vectors."""
    self.forward.x = glm.cos(self.yaw) * glm.cos(self.pitch)
    self.forward.y = glm.sin(self.pitch)
    self.forward.z = glm.sin(self.yaw) * glm.cos(self.pitch)

    self.forward = glm.normalize(self.forward)
    self.right = glm.normalize(glm.cross(self.forward, glm.vec3(0.0, 1.0, 0.0)))
    self.up = glm.normalize(glm.cross(self.right, self.forward))

update_view_matrix()

Update the view matrix.

Source code in pynecraft/camera.py
def update_view_matrix(self):
    """Update the view matrix."""
    self.view_matrix = glm.lookAt(
        self.position, self.position + self.forward, self.up
    )