Camera

Auto-generated API reference. For the view/projection maths behind cameras see the Cameras and Projection tutorial.

FirstPersonCamera

A class representing a first-person camera.

This class provides functionality for a first-person camera, including movement, rotation, and projection matrix calculation.

Attributes:
  • eye (Vec3) –

    The position of the camera.

  • look (Vec3) –

    The point the camera is looking at.

  • world_up (Vec3) –

    The world's up vector.

  • front (Vec3) –

    The front direction vector of the camera.

  • up (Vec3) –

    The up direction vector of the camera.

  • right (Vec3) –

    The right direction vector of the camera.

  • yaw (float) –

    The yaw angle of the camera.

  • pitch (float) –

    The pitch angle of the camera.

  • speed (float) –

    The movement speed of the camera.

  • sensitivity (float) –

    The mouse sensitivity.

  • zoom (float) –

    The zoom level of the camera.

  • near (float) –

    The near clipping plane.

  • far (float) –

    The far clipping plane.

  • aspect (float) –

    The aspect ratio.

  • fov (float) –

    The field of view.

  • persp_mode (PerspMode) –

    The target graphics API clip-space convention.

  • projection (Mat4) –

    The projection matrix.

  • view (Mat4) –

    The view matrix.

Source code in ncca/ngl/first_person_camera.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
class FirstPersonCamera:
    """A class representing a first-person camera.

    This class provides functionality for a first-person camera, including movement,
    rotation, and projection matrix calculation.

    Attributes:
        eye (Vec3): The position of the camera.
        look (Vec3): The point the camera is looking at.
        world_up (Vec3): The world's up vector.
        front (Vec3): The front direction vector of the camera.
        up (Vec3): The up direction vector of the camera.
        right (Vec3): The right direction vector of the camera.
        yaw (float): The yaw angle of the camera.
        pitch (float): The pitch angle of the camera.
        speed (float): The movement speed of the camera.
        sensitivity (float): The mouse sensitivity.
        zoom (float): The zoom level of the camera.
        near (float): The near clipping plane.
        far (float): The far clipping plane.
        aspect (float): The aspect ratio.
        fov (float): The field of view.
        persp_mode (PerspMode): The target graphics API clip-space convention.
        projection (Mat4): The projection matrix.
        view (Mat4): The view matrix.
    """

    def __init__(
        self,
        eye: Vec3,
        look: Vec3,
        up: Vec3,
        fov: float,
        persp_mode: PerspMode = PerspMode.OpenGL,
    ) -> None:
        """Initialize the FirstPersonCamera.

        Args:
            eye (Vec3): The position of the camera.
            look (Vec3): The point the camera is looking at.
            up (Vec3): The world's up vector.
            fov (float): The field of view.
            persp_mode (PerspMode): The target graphics API clip-space convention.
        """
        self.eye: Vec3 = eye
        self.look: Vec3 = look
        self.world_up: Vec3 = up
        self.front: Vec3 = Vec3()
        self.up: Vec3 = Vec3()
        self.right: Vec3 = Vec3()
        self.yaw: float = -90.0
        self.pitch: float = 0.0
        self.speed: float = 2.5
        self.sensitivity: float = 0.1
        self.zoom: float = 45.0
        self.near: float = 0.1
        self.far: float = 100.0
        self.aspect: float = 1.2
        self.fov: float = fov
        self.persp_mode: PerspMode = persp_mode
        self._update_camera_vectors()
        self._projection: Mat4 = self.set_projection(
            self.fov, self.aspect, self.near, self.far, persp_mode
        )

        self._view: Mat4 = look_at(self.eye, self.eye + self.front, self.up)

    def __str__(self) -> str:
        """Pretty representation showing eye, look, up, and fov."""
        return f"Camera {self.eye} {self.look} {self.world_up} {self.fov}"

    def __repr__(self) -> str:
        """Representation showing eye, look, up, and fov."""
        return f"Camera {self.eye} {self.look} {self.world_up} {self.fov}"

    @property
    def projection(self) -> Mat4:
        """The camera's projection matrix."""
        return self._projection

    @property
    def view(self) -> Mat4:
        """The camera's view matrix."""
        return self._view

    def process_mouse_movement(
        self, diffx: float, diffy: float, _constrain_pitch: bool = True
    ) -> None:
        """Process mouse movement to update the camera's direction vectors.

        Args:
            diffx (float): The difference in the x-coordinate of the mouse movement.
            diffy (float): The difference in the y-coordinate of the mouse movement.
            _constrain_pitch (bool, optional): Whether to constrain the pitch angle. Defaults to True.
        """
        diffx *= self.sensitivity
        diffy *= self.sensitivity

        self.yaw += diffx
        self.pitch += diffy

        # Make sure that when pitch is out of bounds, screen doesn't get flipped
        if _constrain_pitch:
            if self.pitch > 89.0:
                self.pitch = 89.0
            if self.pitch < -89.0:
                self.pitch = -89.0

        self._update_camera_vectors()

    def _update_camera_vectors(self) -> None:
        """Update the camera's direction vectors based on the current yaw and pitch angles."""
        pitch = math.radians(self.pitch)
        yaw = math.radians(self.yaw)
        self.front.x = math.cos(yaw) * math.cos(pitch)
        self.front.y = math.sin(pitch)
        self.front.z = math.sin(yaw) * math.cos(pitch)
        self.front = self.front.normalized()
        # Also re-calculate the Right and Up vector
        self.right = self.front.cross(self.world_up)
        self.up = self.right.cross(self.front)
        # normalize as fast movement can cause issues
        self.right = self.right.normalized()
        self.front = self.front.normalized()

        self._view = look_at(self.eye, self.eye + self.front, self.up)

    def set_projection(
        self,
        fov: float,
        aspect: float,
        near: float,
        far: float,
        persp_mode: PerspMode = PerspMode.OpenGL,
    ) -> Mat4:
        """Set the projection matrix for the camera.

        Args:
            fov (float): The field of view.
            aspect (float): The aspect ratio.
            near (float): The near clipping plane.
            far (float): The far clipping plane.
            persp_mode (PerspMode): The target graphics API clip-space convention.

        Returns:
            Mat4: The projection matrix.
        """
        return perspective(fov, aspect, near, far, persp_mode)

    def move(self, x: float, y: float, delta: float) -> None:
        """Move the camera based on input directions.

        Args:
            x (float): The movement in the x-direction.
            y (float): The movement in the y-direction.
            delta (float): The amount to move the camera.
        """
        velocity = self.speed * delta
        self.eye += self.front * velocity * x
        self.eye += self.right * velocity * y
        self._update_camera_vectors()

    def get_vp(self) -> Mat4:
        """Get the view-projection matrix.

        Returns:
            Mat4: The view-projection matrix.
        """
        return self._projection @ self._view

    def process_mouse_scroll(self, y_offset: float) -> None:
        """Process mouse scroll events.

        Args:
            y_offset (float): The scroll offset.
        """
        if self.zoom >= 1.0 and self.zoom <= 45.0:
            self.zoom -= y_offset
        if self.zoom <= 1.0:
            self.zoom = 1.0
        if self.zoom >= 45.0:
            self.zoom = 45.0
        self._projection = perspective(
            self.zoom, self.aspect, self.near, self.far, self.persp_mode
        )

projection property

The camera's projection matrix.

view property

The camera's view matrix.

__init__(eye, look, up, fov, persp_mode=PerspMode.OpenGL)

Initialize the FirstPersonCamera.

Parameters:
  • eye (Vec3) –

    The position of the camera.

  • look (Vec3) –

    The point the camera is looking at.

  • up (Vec3) –

    The world's up vector.

  • fov (float) –

    The field of view.

  • persp_mode (PerspMode, default: OpenGL ) –

    The target graphics API clip-space convention.

Source code in ncca/ngl/first_person_camera.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def __init__(
    self,
    eye: Vec3,
    look: Vec3,
    up: Vec3,
    fov: float,
    persp_mode: PerspMode = PerspMode.OpenGL,
) -> None:
    """Initialize the FirstPersonCamera.

    Args:
        eye (Vec3): The position of the camera.
        look (Vec3): The point the camera is looking at.
        up (Vec3): The world's up vector.
        fov (float): The field of view.
        persp_mode (PerspMode): The target graphics API clip-space convention.
    """
    self.eye: Vec3 = eye
    self.look: Vec3 = look
    self.world_up: Vec3 = up
    self.front: Vec3 = Vec3()
    self.up: Vec3 = Vec3()
    self.right: Vec3 = Vec3()
    self.yaw: float = -90.0
    self.pitch: float = 0.0
    self.speed: float = 2.5
    self.sensitivity: float = 0.1
    self.zoom: float = 45.0
    self.near: float = 0.1
    self.far: float = 100.0
    self.aspect: float = 1.2
    self.fov: float = fov
    self.persp_mode: PerspMode = persp_mode
    self._update_camera_vectors()
    self._projection: Mat4 = self.set_projection(
        self.fov, self.aspect, self.near, self.far, persp_mode
    )

    self._view: Mat4 = look_at(self.eye, self.eye + self.front, self.up)

__repr__()

Representation showing eye, look, up, and fov.

Source code in ncca/ngl/first_person_camera.py
81
82
83
def __repr__(self) -> str:
    """Representation showing eye, look, up, and fov."""
    return f"Camera {self.eye} {self.look} {self.world_up} {self.fov}"

__str__()

Pretty representation showing eye, look, up, and fov.

Source code in ncca/ngl/first_person_camera.py
77
78
79
def __str__(self) -> str:
    """Pretty representation showing eye, look, up, and fov."""
    return f"Camera {self.eye} {self.look} {self.world_up} {self.fov}"

get_vp()

Get the view-projection matrix.

Returns:
  • Mat4( Mat4 ) –

    The view-projection matrix.

Source code in ncca/ngl/first_person_camera.py
172
173
174
175
176
177
178
def get_vp(self) -> Mat4:
    """Get the view-projection matrix.

    Returns:
        Mat4: The view-projection matrix.
    """
    return self._projection @ self._view

move(x, y, delta)

Move the camera based on input directions.

Parameters:
  • x (float) –

    The movement in the x-direction.

  • y (float) –

    The movement in the y-direction.

  • delta (float) –

    The amount to move the camera.

Source code in ncca/ngl/first_person_camera.py
159
160
161
162
163
164
165
166
167
168
169
170
def move(self, x: float, y: float, delta: float) -> None:
    """Move the camera based on input directions.

    Args:
        x (float): The movement in the x-direction.
        y (float): The movement in the y-direction.
        delta (float): The amount to move the camera.
    """
    velocity = self.speed * delta
    self.eye += self.front * velocity * x
    self.eye += self.right * velocity * y
    self._update_camera_vectors()

process_mouse_movement(diffx, diffy, _constrain_pitch=True)

Process mouse movement to update the camera's direction vectors.

Parameters:
  • diffx (float) –

    The difference in the x-coordinate of the mouse movement.

  • diffy (float) –

    The difference in the y-coordinate of the mouse movement.

  • _constrain_pitch (bool, default: True ) –

    Whether to constrain the pitch angle. Defaults to True.

Source code in ncca/ngl/first_person_camera.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def process_mouse_movement(
    self, diffx: float, diffy: float, _constrain_pitch: bool = True
) -> None:
    """Process mouse movement to update the camera's direction vectors.

    Args:
        diffx (float): The difference in the x-coordinate of the mouse movement.
        diffy (float): The difference in the y-coordinate of the mouse movement.
        _constrain_pitch (bool, optional): Whether to constrain the pitch angle. Defaults to True.
    """
    diffx *= self.sensitivity
    diffy *= self.sensitivity

    self.yaw += diffx
    self.pitch += diffy

    # Make sure that when pitch is out of bounds, screen doesn't get flipped
    if _constrain_pitch:
        if self.pitch > 89.0:
            self.pitch = 89.0
        if self.pitch < -89.0:
            self.pitch = -89.0

    self._update_camera_vectors()

process_mouse_scroll(y_offset)

Process mouse scroll events.

Parameters:
  • y_offset (float) –

    The scroll offset.

Source code in ncca/ngl/first_person_camera.py
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def process_mouse_scroll(self, y_offset: float) -> None:
    """Process mouse scroll events.

    Args:
        y_offset (float): The scroll offset.
    """
    if self.zoom >= 1.0 and self.zoom <= 45.0:
        self.zoom -= y_offset
    if self.zoom <= 1.0:
        self.zoom = 1.0
    if self.zoom >= 45.0:
        self.zoom = 45.0
    self._projection = perspective(
        self.zoom, self.aspect, self.near, self.far, self.persp_mode
    )

set_projection(fov, aspect, near, far, persp_mode=PerspMode.OpenGL)

Set the projection matrix for the camera.

Parameters:
  • fov (float) –

    The field of view.

  • aspect (float) –

    The aspect ratio.

  • near (float) –

    The near clipping plane.

  • far (float) –

    The far clipping plane.

  • persp_mode (PerspMode, default: OpenGL ) –

    The target graphics API clip-space convention.

Returns:
  • Mat4( Mat4 ) –

    The projection matrix.

Source code in ncca/ngl/first_person_camera.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def set_projection(
    self,
    fov: float,
    aspect: float,
    near: float,
    far: float,
    persp_mode: PerspMode = PerspMode.OpenGL,
) -> Mat4:
    """Set the projection matrix for the camera.

    Args:
        fov (float): The field of view.
        aspect (float): The aspect ratio.
        near (float): The near clipping plane.
        far (float): The far clipping plane.
        persp_mode (PerspMode): The target graphics API clip-space convention.

    Returns:
        Mat4: The projection matrix.
    """
    return perspective(fov, aspect, near, far, persp_mode)