robolib.camera

camera.py - raylib camera wrapper Import level: 2

 1"""
 2camera.py - raylib camera wrapper
 3Import level: 2
 4"""
 5from __future__ import annotations
 6import math
 7
 8import raylib as rl
 9import numpy as np
10
11from robolib.utils import Point3D, vec3_from, make_arr
12from robolib.traits import Serializable
13
14WORLD_CAMERA_SPEED = 0.3
15WORLD_CAMERA_SENSITIVITY = 0.3
16WORLD_CAMERA_ZOOM_SPEED = 1
17TOPDOWN_CAMERA_SPEED = 1
18TOPDOWN_CAMERA_ZOOM_SPEED = 1
19TOPDOWN_LOG_CONSTANT = math.log(2, 1.2) # convert from base 2 to base 1.2 for smooth and height-aware scrolling
20
21class Camera(Serializable):
22    """Raylib camera rapper. Parameters: [position, target, up, fovy, projection]"""
23    def __init__(self, position: Point3D, target: Point3D, up: Point3D, fovy: float, projection: int):
24        self.camera = rl.ffi.new("Camera3D *", [vec3_from(position), vec3_from(target),
25                                                vec3_from(up), fovy, projection])
26        self._key2move = {rl.KEY_W: make_arr(1, 0, 0), rl.KEY_S: make_arr(-1, 0, 0),
27                          rl.KEY_D: make_arr(0, 1, 0), rl.KEY_A: make_arr(0, -1, 0)}
28
29    def to_dict(self) -> dict:
30        """returns the dict representation of a raylib camera"""
31        return {
32            "position": (self.camera.position.x, self.camera.position.y, self.camera.position.z),
33            "target": (self.camera.target.x, self.camera.target.y, self.camera.target.z),
34            "up": (self.camera.up.x, self.camera.up.y, self.camera.up.z),
35            "fovy": self.camera.fovy,
36            "projection": ["perspective", "orthographic"][self.camera.projection]
37        }
38
39    @staticmethod
40    def from_dict(state: dict) -> Camera:
41        """Creates a raylib camera from a dict representation."""
42        projection = {"perspective": rl.CAMERA_PERSPECTIVE, "orthographic": rl.CAMERA_ORTHOGRAPHIC}[state["projection"]]
43        return Camera(position=np.float32(state["position"]), target=np.float32(state["target"]),
44                      up=np.float32(state["up"]), fovy=state["fovy"], projection=projection)
45
46    def set_position(self, position: Point3D, target: Point3D, up: Point3D):
47        """sets the camera position given a position and 2 vectors: target and up"""
48        self.camera[0].position = vec3_from(position)
49        self.camera[0].target = vec3_from(target)
50        self.camera[0].up = vec3_from(up)
51
52    def manual_movement(self):
53        """Moves the simulator's active camera manually. Only valid for world camera and topdown camera."""
54        if self.camera[0].projection not in (rl.CAMERA_PERSPECTIVE, rl.CAMERA_ORTHOGRAPHIC):
55            return
56
57        if self.camera[0].projection == rl.CAMERA_PERSPECTIVE: # world camera
58            movement = (sum(v * rl.IsKeyDown(k) * WORLD_CAMERA_SPEED for k, v in self._key2move.items())).view(Point3D)
59
60            rotation = (0, 0, 0)  # (pitch, yaw, roll)
61            if rl.IsMouseButtonDown(rl.MOUSE_BUTTON_LEFT):  # only when clicked
62                mouse = rl.GetMouseDelta()
63                rotation = (mouse.x * WORLD_CAMERA_SENSITIVITY, mouse.y * WORLD_CAMERA_SENSITIVITY, 0)
64
65            zoom = -rl.GetMouseWheelMove() * WORLD_CAMERA_ZOOM_SPEED
66
67            rl.UpdateCameraPro(self.camera, vec3_from(movement), rotation, zoom)
68        else: # topdown camera
69            speed = math.log2(1 + self.camera[0].fovy) / TOPDOWN_LOG_CONSTANT # height-aware topdown movemenmt speed
70            delta = sum(v * rl.IsKeyDown(k) * speed for k, v in self._key2move.items())
71
72            self.camera[0].position.x += delta[1] # left/right
73            self.camera[0].target.x += delta[1] # left/right
74            self.camera[0].position.z -= delta[0] # up/down
75            self.camera[0].target.z -= delta[0] # up/down
76            self.camera[0].fovy = max(1.0, self.camera[0].fovy - rl.GetMouseWheelMove() * TOPDOWN_CAMERA_ZOOM_SPEED)
WORLD_CAMERA_SPEED = 0.3
WORLD_CAMERA_SENSITIVITY = 0.3
WORLD_CAMERA_ZOOM_SPEED = 1
TOPDOWN_CAMERA_SPEED = 1
TOPDOWN_CAMERA_ZOOM_SPEED = 1
TOPDOWN_LOG_CONSTANT = 3.8017840169239308
class Camera(robolib.traits.Serializable):
22class Camera(Serializable):
23    """Raylib camera rapper. Parameters: [position, target, up, fovy, projection]"""
24    def __init__(self, position: Point3D, target: Point3D, up: Point3D, fovy: float, projection: int):
25        self.camera = rl.ffi.new("Camera3D *", [vec3_from(position), vec3_from(target),
26                                                vec3_from(up), fovy, projection])
27        self._key2move = {rl.KEY_W: make_arr(1, 0, 0), rl.KEY_S: make_arr(-1, 0, 0),
28                          rl.KEY_D: make_arr(0, 1, 0), rl.KEY_A: make_arr(0, -1, 0)}
29
30    def to_dict(self) -> dict:
31        """returns the dict representation of a raylib camera"""
32        return {
33            "position": (self.camera.position.x, self.camera.position.y, self.camera.position.z),
34            "target": (self.camera.target.x, self.camera.target.y, self.camera.target.z),
35            "up": (self.camera.up.x, self.camera.up.y, self.camera.up.z),
36            "fovy": self.camera.fovy,
37            "projection": ["perspective", "orthographic"][self.camera.projection]
38        }
39
40    @staticmethod
41    def from_dict(state: dict) -> Camera:
42        """Creates a raylib camera from a dict representation."""
43        projection = {"perspective": rl.CAMERA_PERSPECTIVE, "orthographic": rl.CAMERA_ORTHOGRAPHIC}[state["projection"]]
44        return Camera(position=np.float32(state["position"]), target=np.float32(state["target"]),
45                      up=np.float32(state["up"]), fovy=state["fovy"], projection=projection)
46
47    def set_position(self, position: Point3D, target: Point3D, up: Point3D):
48        """sets the camera position given a position and 2 vectors: target and up"""
49        self.camera[0].position = vec3_from(position)
50        self.camera[0].target = vec3_from(target)
51        self.camera[0].up = vec3_from(up)
52
53    def manual_movement(self):
54        """Moves the simulator's active camera manually. Only valid for world camera and topdown camera."""
55        if self.camera[0].projection not in (rl.CAMERA_PERSPECTIVE, rl.CAMERA_ORTHOGRAPHIC):
56            return
57
58        if self.camera[0].projection == rl.CAMERA_PERSPECTIVE: # world camera
59            movement = (sum(v * rl.IsKeyDown(k) * WORLD_CAMERA_SPEED for k, v in self._key2move.items())).view(Point3D)
60
61            rotation = (0, 0, 0)  # (pitch, yaw, roll)
62            if rl.IsMouseButtonDown(rl.MOUSE_BUTTON_LEFT):  # only when clicked
63                mouse = rl.GetMouseDelta()
64                rotation = (mouse.x * WORLD_CAMERA_SENSITIVITY, mouse.y * WORLD_CAMERA_SENSITIVITY, 0)
65
66            zoom = -rl.GetMouseWheelMove() * WORLD_CAMERA_ZOOM_SPEED
67
68            rl.UpdateCameraPro(self.camera, vec3_from(movement), rotation, zoom)
69        else: # topdown camera
70            speed = math.log2(1 + self.camera[0].fovy) / TOPDOWN_LOG_CONSTANT # height-aware topdown movemenmt speed
71            delta = sum(v * rl.IsKeyDown(k) * speed for k, v in self._key2move.items())
72
73            self.camera[0].position.x += delta[1] # left/right
74            self.camera[0].target.x += delta[1] # left/right
75            self.camera[0].position.z -= delta[0] # up/down
76            self.camera[0].target.z -= delta[0] # up/down
77            self.camera[0].fovy = max(1.0, self.camera[0].fovy - rl.GetMouseWheelMove() * TOPDOWN_CAMERA_ZOOM_SPEED)

Raylib camera rapper. Parameters: [position, target, up, fovy, projection]

Camera( position: numpy.ndarray, target: numpy.ndarray, up: numpy.ndarray, fovy: float, projection: int)
24    def __init__(self, position: Point3D, target: Point3D, up: Point3D, fovy: float, projection: int):
25        self.camera = rl.ffi.new("Camera3D *", [vec3_from(position), vec3_from(target),
26                                                vec3_from(up), fovy, projection])
27        self._key2move = {rl.KEY_W: make_arr(1, 0, 0), rl.KEY_S: make_arr(-1, 0, 0),
28                          rl.KEY_D: make_arr(0, 1, 0), rl.KEY_A: make_arr(0, -1, 0)}
camera
def to_dict(self) -> dict:
30    def to_dict(self) -> dict:
31        """returns the dict representation of a raylib camera"""
32        return {
33            "position": (self.camera.position.x, self.camera.position.y, self.camera.position.z),
34            "target": (self.camera.target.x, self.camera.target.y, self.camera.target.z),
35            "up": (self.camera.up.x, self.camera.up.y, self.camera.up.z),
36            "fovy": self.camera.fovy,
37            "projection": ["perspective", "orthographic"][self.camera.projection]
38        }

returns the dict representation of a raylib camera

@staticmethod
def from_dict(state: dict) -> Camera:
40    @staticmethod
41    def from_dict(state: dict) -> Camera:
42        """Creates a raylib camera from a dict representation."""
43        projection = {"perspective": rl.CAMERA_PERSPECTIVE, "orthographic": rl.CAMERA_ORTHOGRAPHIC}[state["projection"]]
44        return Camera(position=np.float32(state["position"]), target=np.float32(state["target"]),
45                      up=np.float32(state["up"]), fovy=state["fovy"], projection=projection)

Creates a raylib camera from a dict representation.

def set_position( self, position: numpy.ndarray, target: numpy.ndarray, up: numpy.ndarray):
47    def set_position(self, position: Point3D, target: Point3D, up: Point3D):
48        """sets the camera position given a position and 2 vectors: target and up"""
49        self.camera[0].position = vec3_from(position)
50        self.camera[0].target = vec3_from(target)
51        self.camera[0].up = vec3_from(up)

sets the camera position given a position and 2 vectors: target and up

def manual_movement(self):
53    def manual_movement(self):
54        """Moves the simulator's active camera manually. Only valid for world camera and topdown camera."""
55        if self.camera[0].projection not in (rl.CAMERA_PERSPECTIVE, rl.CAMERA_ORTHOGRAPHIC):
56            return
57
58        if self.camera[0].projection == rl.CAMERA_PERSPECTIVE: # world camera
59            movement = (sum(v * rl.IsKeyDown(k) * WORLD_CAMERA_SPEED for k, v in self._key2move.items())).view(Point3D)
60
61            rotation = (0, 0, 0)  # (pitch, yaw, roll)
62            if rl.IsMouseButtonDown(rl.MOUSE_BUTTON_LEFT):  # only when clicked
63                mouse = rl.GetMouseDelta()
64                rotation = (mouse.x * WORLD_CAMERA_SENSITIVITY, mouse.y * WORLD_CAMERA_SENSITIVITY, 0)
65
66            zoom = -rl.GetMouseWheelMove() * WORLD_CAMERA_ZOOM_SPEED
67
68            rl.UpdateCameraPro(self.camera, vec3_from(movement), rotation, zoom)
69        else: # topdown camera
70            speed = math.log2(1 + self.camera[0].fovy) / TOPDOWN_LOG_CONSTANT # height-aware topdown movemenmt speed
71            delta = sum(v * rl.IsKeyDown(k) * speed for k, v in self._key2move.items())
72
73            self.camera[0].position.x += delta[1] # left/right
74            self.camera[0].target.x += delta[1] # left/right
75            self.camera[0].position.z -= delta[0] # up/down
76            self.camera[0].target.z -= delta[0] # up/down
77            self.camera[0].fovy = max(1.0, self.camera[0].fovy - rl.GetMouseWheelMove() * TOPDOWN_CAMERA_ZOOM_SPEED)

Moves the simulator's active camera manually. Only valid for world camera and topdown camera.