Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
def _gauss_elimination_3x3(Ab, dt):
    for i in static(range(3)):
        max_row = i
        max_v = ops.abs(Ab[i, i])
        for j in static(range(i + 1, 3)):
            if ops.abs(Ab[j, i]) > max_v:
                max_row = j
                max_v = ops.abs(Ab[j, i])
        assert max_v != 0.0, "Matrix is singular in linear solve."
        if i != max_row:
            if max_row == 1:
                for col in static(range(4)):
                    Ab[i, col], Ab[1, col] = Ab[1, col], Ab[i, col]
            else:
                for col in static(range(4)):
                    Ab[i, col], Ab[2, col] = Ab[2, col], Ab[i, col]
        assert Ab[i, i] != 0.0, "Matrix is singular in linear solve."
        for j in static(range(i + 1, 3)):
            scale = Ab[j, i] / Ab[i, i]
            Ab[j, i] = 0.0
            for k in static(range(i + 1, 4)):
                Ab[j, k] -= Ab[i, k] * scale
    # Back substitution
    x = Vector.zero(dt, 3)
    for i in static(range(2, -1, -1)):
        x[i] = Ab[i, 3]
        for k in static(range(i + 1, 3)):
            x[i] -= Ab[i, k] * x[k]
        x[i] = x[i] / Ab[i, i]
    return x
Ejemplo n.º 3
0
def to_u8_rgba(image):
    if not hasattr(image, 'n') or image.m != 1:
        raise Exception(
            'the input image needs to be a Vector field (matrix with 1 column)'
        )
    if len(image.shape) != 2:
        raise Exception(
            "the shape of the image must be of the form (width,height)")

    if image.dtype == u8 and image.n == 4:
        # already in the desired format
        return image

    if image not in image_field_cache:
        staging_img = Vector.field(4, u8, image.shape)
        image_field_cache[image] = staging_img
    else:
        staging_img = image_field_cache[image]

    if image.dtype == u8:
        copy_image_u8_to_u8(image, staging_img, image.n)
    elif image.dtype == f32:
        copy_image_f32_to_u8(image, staging_img, image.n)
    else:
        raise Exception("dtype of input image must either be u8 or f32")
    return staging_img
Ejemplo n.º 4
0
def get_normals_field(vertices):
    if vertices not in normals_field_cache:
        N = vertices.shape[0]
        normals = Vector.field(3, f32, shape=(N, ))
        normal_weights = field(f32, shape=(N, ))
        normals_field_cache[vertices] = (normals, normal_weights)
        return (normals, normal_weights)
    return normals_field_cache[vertices]
Ejemplo n.º 5
0
def sym_eig2x2(A, dt):
    """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 2x2 real symmetric matrix.

    Mathematical concept refers to https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix.

    Args:
        A (ti.Matrix(2, 2)): input 2x2 symmetric matrix `A`.
        dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64.

    Returns:
        eigenvalues (ti.Vector(2)): The eigenvalues. Each entry store one eigen value.
        eigenvectors (ti.Matrix(2, 2)): The eigenvectors. Each column stores one eigenvector.
    """
    tr = A.trace()
    det = A.determinant()
    gap = tr**2 - 4 * det
    lambda1 = (tr + ops.sqrt(gap)) * 0.5
    lambda2 = (tr - ops.sqrt(gap)) * 0.5
    eigenvalues = Vector([lambda1, lambda2], dt=dt)

    A1 = A - lambda1 * Matrix.identity(dt, 2)
    A2 = A - lambda2 * Matrix.identity(dt, 2)
    v1 = Vector.zero(dt, 2)
    v2 = Vector.zero(dt, 2)
    if all(A1 == Matrix.zero(dt, 2, 2)) and all(A1 == Matrix.zero(dt, 2, 2)):
        v1 = Vector([0.0, 1.0]).cast(dt)
        v2 = Vector([1.0, 0.0]).cast(dt)
    else:
        v1 = Vector([A2[0, 0], A2[1, 0]], dt=dt).normalized()
        v2 = Vector([A1[0, 0], A1[1, 0]], dt=dt).normalized()
    eigenvectors = Matrix.cols([v1, v2])
    return eigenvalues, eigenvectors
Ejemplo n.º 6
0
    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)
        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.º 7
0
def get_vbo_field(vertices):
    if vertices not in vbo_field_cache:
        N = vertices.shape[0]
        pos = 3
        normal = 3
        tex_coord = 2
        color = 4
        vertex_stride = pos + normal + tex_coord + color
        vbo = Vector.field(vertex_stride, f32, shape=(N, ))
        vbo_field_cache[vertices] = vbo
        return vbo
    return vbo_field_cache[vertices]
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
def _gauss_elimination_2x2(Ab, dt):
    if ops.abs(Ab[0, 0]) < ops.abs(Ab[1, 0]):
        Ab[0, 0], Ab[1, 0] = Ab[1, 0], Ab[0, 0]
        Ab[0, 1], Ab[1, 1] = Ab[1, 1], Ab[0, 1]
        Ab[0, 2], Ab[1, 2] = Ab[1, 2], Ab[0, 2]
    assert Ab[0, 0] != 0.0, "Matrix is singular in linear solve."
    scale = Ab[1, 0] / Ab[0, 0]
    Ab[1, 0] = 0.0
    for k in static(range(1, 3)):
        Ab[1, k] -= Ab[0, k] * scale
    x = Vector.zero(dt, 2)
    # Back substitution
    x[1] = Ab[1, 2] / Ab[1, 1]
    x[0] = (Ab[0, 2] - Ab[0, 1] * x[1]) / Ab[0, 0]
    return x
Ejemplo n.º 11
0
def gen_normals_kernel_indexed(vertices: template(), indices: template(),
                               normals: template(), weights: template()):
    num_triangles = indices.shape[0] / 3
    num_vertices = vertices.shape[0]
    for i in range(num_vertices):
        normals[i] = Vector([0.0, 0.0, 0.0])
        weights[i] = 0.0
    for i in range(num_triangles):
        i_a = indices[i * 3]
        i_b = indices[i * 3 + 1]
        i_c = indices[i * 3 + 2]
        a = vertices[i_a]
        b = vertices[i_b]
        c = vertices[i_c]
        n = (a - b).cross(a - c).normalized()
        atomic_add(normals[i_a], n)
        atomic_add(normals[i_b], n)
        atomic_add(normals[i_c], n)
        atomic_add(weights[i_a], 1.0)
        atomic_add(weights[i_b], 1.0)
        atomic_add(weights[i_c], 1.0)
    for i in range(num_vertices):
        if weights[i] > 0.0:
            normals[i] = normals[i] / weights[i]
Ejemplo n.º 12
0
def sym_eig3x3(A, dt):
    """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 3x3 real symmetric matrix using Cardano's method.

    Mathematical concept refers to https://www.mpi-hd.mpg.de/personalhomes/globes/3x3/.

    Args:
        A (ti.Matrix(3, 3)): input 3x3 symmetric matrix `A`.
        dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64.

    Returns:
        eigenvalues (ti.Vector(3)): The eigenvalues. Each entry store one eigen value.
        eigenvectors (ti.Matrix(3, 3)): The eigenvectors. Each column stores one eigenvector.
    """
    M_SQRT3 = 1.73205080756887729352744634151
    m = A.trace()
    dd = A[0, 1] * A[0, 1]
    ee = A[1, 2] * A[1, 2]
    ff = A[0, 2] * A[0, 2]
    c1 = A[0, 0] * A[1, 1] + A[0, 0] * A[2, 2] + A[1, 1] * A[2, 2] - (dd + ee +
                                                                      ff)
    c0 = A[2, 2] * dd + A[0, 0] * ee + A[1, 1] * ff - A[0, 0] * A[1, 1] * A[
        2, 2] - 2.0 * A[0, 2] * A[0, 1] * A[1, 2]

    p = m * m - 3.0 * c1
    q = m * (p - 1.5 * c1) - 13.5 * c0
    sqrt_p = ops.sqrt(ops.abs(p))
    phi = 27.0 * (0.25 * c1 * c1 * (p - c1) + c0 * (q + 6.75 * c0))
    phi = (1.0 / 3.0) * ops.atan2(ops.sqrt(ops.abs(phi)), q)

    c = sqrt_p * ops.cos(phi)
    s = (1.0 / M_SQRT3) * sqrt_p * ops.sin(phi)
    eigenvalues = Vector([0.0, 0.0, 0.0], dt=dt)
    eigenvalues[2] = (1.0 / 3.0) * (m - c)
    eigenvalues[1] = eigenvalues[2] + s
    eigenvalues[0] = eigenvalues[2] + c
    eigenvalues[2] = eigenvalues[2] - s

    t = ops.abs(eigenvalues[0])
    u = ops.abs(eigenvalues[1])
    if u > t:
        t = u
    u = ops.abs(eigenvalues[2])
    if u > t:
        t = u
    if t < 1.0:
        u = t
    else:
        u = t * t
    Q = Matrix.zero(dt, 3, 3)
    Q[0, 1] = A[0, 1] * A[1, 2] - A[0, 2] * A[1, 1]
    Q[1, 1] = A[0, 2] * A[0, 1] - A[1, 2] * A[0, 0]
    Q[2, 1] = A[0, 1] * A[0, 1]

    Q[0, 0] = Q[0, 1] + A[0, 2] * eigenvalues[0]
    Q[1, 0] = Q[1, 1] + A[1, 2] * eigenvalues[0]
    Q[2, 0] = (A[0, 0] - eigenvalues[0]) * (A[1, 1] - eigenvalues[0]) - Q[2, 1]
    norm = Q[0, 0] * Q[0, 0] + Q[1, 0] * Q[1, 0] + Q[2, 0] * Q[2, 0]
    norm = ops.sqrt(1.0 / norm)
    Q[0, 0] *= norm
    Q[1, 0] *= norm
    Q[2, 0] *= norm

    Q[0, 1] = Q[0, 1] + A[0, 2] * eigenvalues[1]
    Q[1, 1] = Q[1, 1] + A[1, 2] * eigenvalues[1]
    Q[2, 1] = (A[0, 0] - eigenvalues[1]) * (A[1, 1] - eigenvalues[1]) - Q[2, 1]
    norm = Q[0, 1] * Q[0, 1] + Q[1, 1] * Q[1, 1] + Q[2, 1] * Q[2, 1]

    norm = ops.sqrt(1.0 / norm)
    Q[0, 1] *= norm
    Q[1, 1] *= norm
    Q[2, 1] *= norm

    Q[0, 2] = Q[1, 0] * Q[2, 1] - Q[2, 0] * Q[1, 1]
    Q[1, 2] = Q[2, 0] * Q[0, 1] - Q[0, 0] * Q[2, 1]
    Q[2, 2] = Q[0, 0] * Q[1, 1] - Q[1, 0] * Q[0, 1]
    return eigenvalues, Q
Ejemplo n.º 13
0
def eig2x2(A, dt):
    """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 2x2 real matrix.

    Mathematical concept refers to https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix.

    Args:
        A (ti.Matrix(2, 2)): input 2x2 matrix `A`.
        dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64.

    Returns:
        eigenvalues (ti.Matrix(2, 2)): The eigenvalues in complex form. Each row stores one eigenvalue. The first number of the eigenvalue represents the real part and the second number represents the imaginary part.
        eigenvectors: (ti.Matrix(4, 2)): The eigenvectors in complex form. Each column stores one eigenvector. Each eigenvector consists of 2 entries, each of which is represented by two numbers for its real part and imaginary part.
    """
    tr = A.trace()
    det = A.determinant()
    gap = tr**2 - 4 * det
    lambda1 = Vector.zero(dt, 2)
    lambda2 = Vector.zero(dt, 2)
    v1 = Vector.zero(dt, 4)
    v2 = Vector.zero(dt, 4)
    if gap > 0:
        lambda1 = Vector([tr + ops.sqrt(gap), 0.0], dt=dt) * 0.5
        lambda2 = Vector([tr - ops.sqrt(gap), 0.0], dt=dt) * 0.5
        A1 = A - lambda1[0] * Matrix.identity(dt, 2)
        A2 = A - lambda2[0] * Matrix.identity(dt, 2)
        if all(A1 == Matrix.zero(dt, 2, 2)) and all(
                A1 == Matrix.zero(dt, 2, 2)):
            v1 = Vector([0.0, 0.0, 1.0, 0.0]).cast(dt)
            v2 = Vector([1.0, 0.0, 0.0, 0.0]).cast(dt)
        else:
            v1 = Vector([A2[0, 0], 0.0, A2[1, 0], 0.0], dt=dt).normalized()
            v2 = Vector([A1[0, 0], 0.0, A1[1, 0], 0.0], dt=dt).normalized()
    else:
        lambda1 = Vector([tr, ops.sqrt(-gap)], dt=dt) * 0.5
        lambda2 = Vector([tr, -ops.sqrt(-gap)], dt=dt) * 0.5
        A1r = A - lambda1[0] * Matrix.identity(dt, 2)
        A1i = -lambda1[1] * Matrix.identity(dt, 2)
        A2r = A - lambda2[0] * Matrix.identity(dt, 2)
        A2i = -lambda2[1] * Matrix.identity(dt, 2)
        v1 = Vector([A2r[0, 0], A2i[0, 0], A2r[1, 0], A2i[1, 0]],
                    dt=dt).normalized()
        v2 = Vector([A1r[0, 0], A1i[0, 0], A1r[1, 0], A1i[1, 0]],
                    dt=dt).normalized()
    eigenvalues = Matrix.rows([lambda1, lambda2])
    eigenvectors = Matrix.cols([v1, v2])

    return eigenvalues, eigenvectors
Ejemplo n.º 14
0
def euler_to_vec(yaw, pitch):
    v = Vector([0.0, 0.0, 0.0])
    v[0] = -sin(yaw) * cos(pitch)
    v[1] = sin(pitch)
    v[2] = -cos(yaw) * cos(pitch)
    return v
Ejemplo n.º 15
0
 def up(self, x, y, z):
     self.curr_up = Vector([x, y, z])
     self.ptr.up(x, y, z)
Ejemplo n.º 16
0
 def position(self, x, y, z):
     self.curr_position = Vector([x, y, z])
     self.ptr.position(x, y, z)
Ejemplo n.º 17
0
    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.º 18
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
Ejemplo n.º 19
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.º 20
0
 def lookat(self, x, y, z):
     self.curr_lookat = Vector([x, y, z])
     self.ptr.lookat(x, y, z)