Ejemplo n.º 1
0
class Camera:
    """The Camera class.

    You should not instantiate this class by calling the `__init__` method
    directly, please use the helper function :func:`~taichi.ui.make_camera()`
    instead.

    Args:
        ptr (:class:`~taichi._ti_core.PyCamera`): An instance of the `PyCamera` \
            class from the C++ level.

    Example::

        >>> scene = ti.ui.Scene()  # assume you have a scene
        >>>
        >>> camera = ti.ui.make_camera()
        >>> camera.position(1, 1, 1)  # set camera position
        >>> camera.lookat(0, 0, 0)  # set camera lookat
        >>> camera.up(0, 1, 0)  # set camera up vector
        >>> scene.set_camera(camera)
        >>>
        >>> # you can also control camera movement in a window
        >>> window = ti.ui.Window("GGUI Camera", res=(640, 480), vsync=True)
        >>> camera.track_user_inputs(window, movement_speed=0.03, hold_key=ti.ui.RMB)
    """
    def __init__(self, ptr):
        self.ptr = ptr

        self.position(0.0, 0.0, 0.0)
        self.lookat(0.0, 0.0, 1.0)
        self.up(0.0, 1.0, 0.0)

        # used for tracking user inputs
        self.last_mouse_x = None
        self.last_mouse_y = None

    def position(self, x, y, z):
        """Set the camera position.

        Args:
            args (:mod:`taichi.types.primitive_types`): 3D coordinates.

        Example::

            >>> camera.position(1, 1, 1)
        """
        self.curr_position = Vector([x, y, z])
        self.ptr.position(x, y, z)

    def lookat(self, x, y, z):
        """Set the camera lookat.

        Args:
            args (:mod:`taichi.types.primitive_types`): 3D coordinates.

        Example::

            >>> camera.lookat(0, 0, 0)
        """
        self.curr_lookat = Vector([x, y, z])
        self.ptr.lookat(x, y, z)

    def up(self, x, y, z):
        """Set the camera up vector.

        Args:
            args (:mod:`taichi.types.primitive_types`): 3D coordinates.

        Example::

            >>> camera.up(0, 1, 0)
        """
        self.curr_up = Vector([x, y, z])
        self.ptr.up(x, y, z)

    def projection_mode(self, mode):
        """Camera projection mode, 0 for perspective and 1 for orthogonal.
        """
        self.ptr.projection_mode(mode)

    def fov(self, fov):
        """Set the camera fov angle (field of view) in degrees.

        Args:
            fov (:mod:`taichi.types.primitive_types`): Angle in range (0, 180).

        Example::

            >>> camera.fov(45)
        """
        self.ptr.fov(fov)

    def left(self, left):
        """Set the offset of the left clipping plane in camera frustum.

        Args:
            left (:mod:`taichi.types.primitive_types`): \
                offset of the left clipping plane.

        Example::

            >>> camera.left(-1.0)
        """
        self.ptr.left(left)

    def right(self, right):
        """Set the offset of the right clipping plane in camera frustum.

        Args:
            right (:mod:`taichi.types.primitive_types`): \
                offset of the right clipping plane.

        Example::

            >>> camera.right(1.0)
        """
        self.ptr.right(right)

    def top(self, top):
        """Set the offset of the top clipping plane in camera frustum.

        Args:
            top (:mod:`taichi.types.primitive_types`): \
                offset of the top clipping plane.

        Example::

            >>> camera.top(-1.0)
        """
        self.ptr.top(top)

    def bottom(self, bottom):
        """Set the offset of the bottom clipping plane in camera frustum.

        Args:
            bottom (:mod:`taichi.types.primitive_types`): \
                offset of the bottom clipping plane.

        Example::

            >>> camera.bottom(1.0)
        """
        self.ptr.bottom(bottom)

    def z_near(self, z_near):
        """Set the offset of the near clipping plane in camera frustum.

        Args:
            near (:mod:`taichi.types.primitive_types`): \
                offset of the near clipping plane.

        Example::

            >>> camera.near(0.1)
        """
        self.ptr.z_near(z_near)

    def z_far(self, z_far):
        """Set the offset of the far clipping plane in camera frustum.

        Args:
            far (:mod:`taichi.types.primitive_types`): \
                offset of the far clipping plane.

        Example::

            >>> camera.left(1000.0)
        """
        self.ptr.z_far(z_far)

    def get_view_matrix(self):
        """Get the view matrix(in row major) of the camera.

        Example::

            >>> camera.get_view_matrix()
        """
        return self.ptr.get_view_matrix()

    def get_projection_matrix(self, aspect):
        """Get the projection matrix(in row major) of the camera.

        Args:
            aspect (:mod:`taichi.types.primitive_types`): \
                aspect ratio of the camera

        Example::

            >>> camera.get_projection_matrix(1080/720)
        """
        return self.ptr.get_projection_matrix(aspect)

    def track_user_inputs(self,
                          window,
                          movement_speed=1.0,
                          yaw_speed=2,
                          pitch_speed=2,
                          hold_key=None):
        """Move the camera according to user inputs.
        Press `w`, `s`, `a`, `d`, `e`, `q` to move the camera
        `formard`, `back`, `left`, `right`, `head up`, `head down`, accordingly.

        Args:

            window (:class:`~taichi.ui.Window`): a windown instance.
            movement_speed (:mod:`~taichi.types.primitive_types`): camera movement speed.
            yaw_speed (:mod:`~taichi.types.primitive_types`): speed of changes in yaw angle.
            pitch_speed (:mod:`~taichi.types.primitive_types`): speed of changes in pitch angle.
            hold_key (:mod:`~taichi.ui`): User defined key for holding the camera movement.
        """
        front = (self.curr_lookat - self.curr_position).normalized()
        position_change = Vector([0.0, 0.0, 0.0])
        left = self.curr_up.cross(front)
        up = self.curr_up
        if window.is_pressed('w'):
            position_change = front * movement_speed
        if window.is_pressed('s'):
            position_change = -front * movement_speed
        if window.is_pressed('a'):
            position_change = left * movement_speed
        if window.is_pressed('d'):
            position_change = -left * movement_speed
        if window.is_pressed('e'):
            position_change = up * movement_speed
        if window.is_pressed('q'):
            position_change = -up * movement_speed
        self.position(*(self.curr_position + position_change))
        self.lookat(*(self.curr_lookat + position_change))

        if hold_key is not None:
            if not window.is_pressed(hold_key):
                self.last_mouse_x = None
                self.last_mouse_y = None
                return

        curr_mouse_x, curr_mouse_y = window.get_cursor_pos()
        if self.last_mouse_x is None or self.last_mouse_y is None:
            self.last_mouse_x, self.last_mouse_y = curr_mouse_x, curr_mouse_y
            return

        dx = curr_mouse_x - self.last_mouse_x
        dy = curr_mouse_y - self.last_mouse_y

        yaw, pitch = vec_to_euler(front)
        yaw_speed = 2
        pitch_speed = 2

        yaw -= dx * yaw_speed
        pitch += dy * pitch_speed

        pitch_limit = pi / 2 * 0.99
        if pitch > pitch_limit:
            pitch = pitch_limit
        elif pitch < -pitch_limit:
            pitch = -pitch_limit

        front = euler_to_vec(yaw, pitch)
        self.lookat(*(self.curr_position + front))
        self.up(0, 1, 0)

        self.last_mouse_x, self.last_mouse_y = curr_mouse_x, curr_mouse_y
Ejemplo n.º 2
0
class Camera:
    def __init__(self, ptr):
        self.ptr = ptr

        self.position(0.0, 0.0, 0.0)
        self.lookat(0.0, 0.0, 1.0)
        self.up(0.0, 1.0, 0.0)

        # used for tracking user inputs
        self.last_mouse_x = None
        self.last_mouse_y = None

    def position(self, x, y, z):
        self.curr_position = Vector([x, y, z])
        self.ptr.position(x, y, z)

    def lookat(self, x, y, z):
        self.curr_lookat = Vector([x, y, z])
        self.ptr.lookat(x, y, z)

    def up(self, x, y, z):
        self.curr_up = Vector([x, y, z])
        self.ptr.up(x, y, z)

    def projection_mode(self, mode):
        self.ptr.projection_mode(mode)

    def fov(self, fov):
        self.ptr.fov(fov)

    def left(self, left):
        self.ptr.left(left)

    def right(self, right):
        self.ptr.right(right)

    def top(self, top):
        self.ptr.top(top)

    def bottom(self, bottom):
        self.ptr.bottom(bottom)

    def z_near(self, z_near):
        self.ptr.z_near(z_near)

    def z_far(self, z_far):
        self.ptr.z_far(z_far)

    # move the camera according to user inputs, FPS game style.
    def track_user_inputs(self,
                          window,
                          movement_speed=1.0,
                          yaw_speed=2,
                          pitch_speed=2,
                          hold_key=None):
        front = (self.curr_lookat - self.curr_position).normalized()
        position_change = Vector([0.0, 0.0, 0.0])
        left = self.curr_up.cross(front)
        if window.is_pressed('w'):
            position_change = front * movement_speed
        if window.is_pressed('s'):
            position_change = -front * movement_speed
        if window.is_pressed('a'):
            position_change = left * movement_speed
        if window.is_pressed('d'):
            position_change = -left * movement_speed
        self.position(*(self.curr_position + position_change))
        self.lookat(*(self.curr_lookat + position_change))

        if hold_key is not None:
            if not window.is_pressed(hold_key):
                self.last_mouse_x = None
                self.last_mouse_y = None
                return

        curr_mouse_x, curr_mouse_y = window.get_cursor_pos()
        if self.last_mouse_x is None or self.last_mouse_y is None:
            self.last_mouse_x, self.last_mouse_y = curr_mouse_x, curr_mouse_y
            return

        dx = curr_mouse_x - self.last_mouse_x
        dy = curr_mouse_y - self.last_mouse_y

        yaw, pitch = vec_to_euler(front)
        yaw_speed = 2
        pitch_speed = 2

        yaw -= dx * yaw_speed
        pitch += dy * pitch_speed

        pitch_limit = pi / 2 * 0.99
        if pitch > pitch_limit:
            pitch = pitch_limit
        elif pitch < -pitch_limit:
            pitch = -pitch_limit

        front = euler_to_vec(yaw, pitch)
        self.lookat(*(self.curr_position + front))
        self.up(0, 1, 0)

        self.last_mouse_x, self.last_mouse_y = curr_mouse_x, curr_mouse_y