From f426ee78bbb26fe7fb19e7959bb15e2417d91013 Mon Sep 17 00:00:00 2001 From: Paul <36696816+pushfoo@users.noreply.github.com> Date: Sun, 16 Jun 2024 00:42:12 -0400 Subject: [PATCH] Build API doc for all Camera types and functions (#2112) * 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 --- arcade/camera/data_types.py | 72 ++++++++++++++++++++++-------------- arcade/camera/perspective.py | 68 ++++++++++++++++++++++------------ doc/api_docs/arcade.rst | 1 + util/update_quick_index.py | 11 ++++++ 4 files changed, 102 insertions(+), 50 deletions(-) diff --git a/arcade/camera/data_types.py b/arcade/camera/data_types.py index c9896d0e5..6988f44e3 100644 --- a/arcade/camera/data_types.py +++ b/arcade/camera/data_types.py @@ -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") @@ -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 @@ -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") @@ -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 @@ -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 @@ -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 @@ -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 @@ -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") @@ -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): diff --git a/arcade/camera/perspective.py b/arcade/camera/perspective.py index e0a4371c0..a182acabb 100644 --- a/arcade/camera/perspective.py +++ b/arcade/camera/perspective.py @@ -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) @@ -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 @@ -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( @@ -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( diff --git a/doc/api_docs/arcade.rst b/doc/api_docs/arcade.rst index 21081ca57..dba60b271 100644 --- a/doc/api_docs/arcade.rst +++ b/doc/api_docs/arcade.rst @@ -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 diff --git a/util/update_quick_index.py b/util/update_quick_index.py index 5f7621313..6b6508b0d 100644 --- a/util/update_quick_index.py +++ b/util/update_quick_index.py @@ -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" + ] } }