Skip to content

Commit

Permalink
Build API doc for all Camera types and functions (#2112)
Browse files Browse the repository at this point in the history
* Refactor camera data type doc so it doesn't break Sphinx

* Expose all Camera types in doc

* Add modules to update_quick_index.py

* Add generated file to doc/api_docs/arcade.rst toctree

* Fix syntax + add cross-refs in perspective.py

* Fix build error due to syntax issue in alignment

* Add cross-refs

* General touch-ups for style and phrasing
  • Loading branch information
pushfoo authored Jun 16, 2024
1 parent 58bde7e commit f426ee7
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 50 deletions.
72 changes: 45 additions & 27 deletions arcade/camera/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,6 @@ class CameraData:
"""Stores position, orientation, and zoom for a camera.
This is like where a camera is placed in 3D space.
Attributes:
position: A 3D vector which describes where the camera is located.
up: A 3D vector which describes which direction is up (+y).
forward: a 3D vector which describes which direction is forwards (+z).
zoom: A scaler that records the zoom of the camera. While this most often affects the projection matrix
it allows camera controllers access to the zoom functionality
without interacting with the projection data.
"""

__slots__ = ("position", "up", "forward", "zoom")
Expand All @@ -59,9 +51,15 @@ def __init__(self,
forward: Point3 = (0.0, 0.0, -1.0),
zoom: float = 1.0):

# View matrix data
#: A 3D vector which describes where the camera is located.
self.position: Tuple[float, float, float] = position
#: A 3D vector which describes which direction is up (+y).
self.up: Tuple[float, float, float] = up
#: A scalar which describes which direction the camera is pointing.
#:
#: While this affects the projection matrix, it also allows camera
#: controllers to access zoom functionality without interacting with
#: projection data.
self.forward: Tuple[float, float, float] = forward

# Zoom
Expand Down Expand Up @@ -104,15 +102,6 @@ class OrthographicProjectionData:
This is by default a Left-handed system. with the X axis going from left to right, The Y axis going from
bottom to top, and the Z axis going from towards the screen to away from the screen. This can be made
right-handed by making the near value greater than the far value.
Attributes:
left: The left most value, which gets mapped to x = -1.0 (anything below this value is not visible).
right: The right most value, which gets mapped to x = 1.0 (anything above this value is not visible).
bottom: The bottom most value, which gets mapped to y = -1.0 (anything below this value is not visible).
top: The top most value, which gets mapped to y = 1.0 (anything above this value is not visible).
near: The 'closest' value, which gets mapped to z = -1.0 (anything below this value is not visible).
far: The 'furthest' value, Which gets mapped to z = 1.0 (anything above this value is not visible).
viewport: The pixel bounds which will be drawn onto. (left, bottom, width, height)
"""

__slots__ = ("rect", "near", "far")
Expand All @@ -129,11 +118,23 @@ def __init__(

# Data for generating Orthographic Projection matrix
self.rect: Rect = LRBT(left, right, bottom, top)
#: The 'closest' visible position along the forward direction.
#:
#: It will get mapped to z = -1.0. Anything closer than this value
#: is not visible.
self.near: float = near
#: The 'farthest' visible position along the forward direction.
#:
#: It will get mapped to z = 1.0. Anything father than this value
#: is not visible.
self.far: float = far

@property
def left(self) -> float:
""""The left-side cutoff value, which gets mapped to x = -1.0.
Anything to the left of this value is not visible.
"""
return self.rect.left

@left.setter
Expand All @@ -153,6 +154,10 @@ def left(self, new_left: AsFloat):

@property
def right(self) -> float:
""""The right-side cutoff value, which gets mapped to x = 1.0.
Anything to the left of this value is not visible.
"""
return self.rect.right

@right.setter
Expand All @@ -172,6 +177,10 @@ def right(self, new_right: AsFloat):

@property
def bottom(self) -> float:
""""The bottom-side cutoff value, which gets mapped to -y = 1.0.
Anything to the left of this value is not visible.
"""
return self.rect.bottom

@bottom.setter
Expand All @@ -191,6 +200,10 @@ def bottom(self, new_bottom: AsFloat):

@property
def top(self) -> float:
""""The top-side cutoff value, which gets mapped to y = 1.0.
Anything to the left of this value is not visible.
"""
return self.rect.top

@top.setter
Expand Down Expand Up @@ -239,14 +252,7 @@ def orthographic_from_rect(rect: Rect, near: float, far: float) -> OrthographicP

class PerspectiveProjectionData:
"""Describes a perspective projection.
Attributes:
aspect: The aspect ratio of the screen (width over height).
fov: The field of view in degrees. With the aspect ratio defines
the size of the projection at any given depth.
near: The 'closest' value, which gets mapped to z = -1.0 (anything below this value is not visible).
far: The 'furthest' value, Which gets mapped to z = 1.0 (anything above this value is not visible).
viewport: The pixel bounds which will be drawn onto. (left, bottom, width, height)
)
"""
__slots__ = ("aspect", "fov", "near", "far")

Expand All @@ -255,10 +261,22 @@ def __init__(self,
fov: float,
near: float,
far: float):
# Data for generating Perspective Projection matrix
#: The aspect ratio of the screen (width over height).
self.aspect: float = aspect
#: The field of view in degrees.
#:
#: Together with the aspect ratio, it defines the size of the
#: perspective projection for any given depth.
self.fov: float = fov
#: The 'closest' visible position along the forward direction.
#:
#: It will get mapped to z = -1.0. Anything closer than this value
#: is not visible.
self.near: float = near
#: The 'farthest' visible position along the forward direction.
#:
#: It will get mapped to z = 1.0. Anything father than this value
#: is not visible.
self.far: float = far

def __str__(self):
Expand Down
68 changes: 45 additions & 23 deletions arcade/camera/perspective.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,34 @@ def __init__(self, *,

@property
def view(self) -> CameraData:
"""
"""Get the internal :py:class:`~arcade.camera.data_types.CameraData`.
This is a read-only property.
The CameraData. Is a read only property.
"""
return self._view

@property
def projection(self) -> PerspectiveProjectionData:
"""
The OrthographicProjectionData. Is a read only property.
"""Get the :py:class:`~arcade.camera.data_types.PerspectiveProjectionData`.
This is a read-only property.
"""
return self._projection

def generate_projection_matrix(self) -> Mat4:
"""
alias of arcade.camera.get_perspective_matrix method
"""Generates a projection matrix.
This is an alias of
:py:class:`arcade.camera.get_perspective_matrix`.
"""
return generate_perspective_matrix(self._projection, self._view.zoom)

def generate_view_matrix(self) -> Mat4:
"""
alias of arcade.camera.get_view_matrix method
"""Generates a view matrix.
This is an alias of=
:py:class:`arcade.camera.get_view_matrix`.
"""
return generate_view_matrix(self._view)

Expand Down Expand Up @@ -123,10 +130,15 @@ def activate(self) -> Generator[Self, None, None]:
previous_projector.use()

def use(self) -> None:
"""
Sets the active camera to this object.
Then generates the view and projection matrices.
Finally, the gl context viewport is set, as well as the projection and view matrices.
"""Set the active camera to this object and apply other config.
This includes the following steps:
#. Set the window's current camera to this one
#. Generate appropriate view and projection matrices
#. Set the GL context's viewport and scissorbox values
#. Apply the relevant matrices to Arcade's
:py:class:`~arcade.Window` object
"""

self._window.current_camera = self
Expand All @@ -140,8 +152,19 @@ def use(self) -> None:
self._window.view = _view

def project(self, world_coordinate: Point) -> Vec2:
"""
Take a Vec2 or Vec3 of coordinates and return the related screen coordinate
"""Convert world coordinates to pixel screen coordinates.
If a 2D :py:class:`Vec2` is provided instead of a 3D
:py:class:`Vec3`, then one will be calculated to the best of the
method's ability.
Args:
world_coordinate:
A :py:class:`Vec2` or :py:class:`Vec3` as world
coordinates.
Returns:
A 2D screen pixel coordinate.
"""
x, y, *z = world_coordinate
z = (0.5 * self.viewport.height / tan(
Expand All @@ -158,20 +181,19 @@ def project(self, world_coordinate: Point) -> Vec2:

return pos

# TODO: update args
def unproject(self, screen_coordinate: Point) -> Vec3:
"""
Take in a pixel coordinate from within
the range of the window size and returns
the world space coordinates.
"""Convert a pixel coordinate into world space.
Essentially reverses the effects of the projector.
This reverses the effects of :py:meth:`.project`.
# TODO: UPDATE
Args:
screen_coordinate: A 2D position in pixels from the bottom left of the screen.
This should ALWAYS be in the range of 0.0 - screen size.
Returns:
A 3D vector in world space.
screen_coordinate:
A 2D position in pixels from the bottom left of the screen.
This should ALWAYS be in the range of 0.0 - screen size.
Returns: A 3D vector in world space.
"""
x, y, *z = screen_coordinate
z = (0.5 * self.viewport.height / tan(
Expand Down
1 change: 1 addition & 0 deletions doc/api_docs/arcade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ for the Python Arcade library. See also:
api/joysticks
api/window
api/sound
api/advanced_cameras
api/path_finding
api/isometric
api/earclip
Expand Down
11 changes: 11 additions & 0 deletions util/update_quick_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,17 @@
"arcade.gui.experimental.password_input",
"arcade.gui.experimental.scroll_area"
]
},
"advanced_cameras.rst": {
"title": "Advanced Camera Features",
"use_declarations_in": [
"arcade.camera.data_types",
"arcade.camera.projection_functions",
"arcade.camera.orthographic",
"arcade.camera.perspective",
"arcade.camera.default",
"arcade.camera.static"
]
}
}

Expand Down

0 comments on commit f426ee7

Please sign in to comment.