Пример #1
0
  def test_get_barycentric_coordinates_normalized(self):
    """Tests whether the barycentric coordinates are normalized."""
    tensor_size = np.random.randint(3)
    tensor_shape = np.random.randint(1, 10, size=(tensor_size)).tolist()
    num_pixels = np.random.randint(1, 10)
    pixels_shape = tensor_shape + [num_pixels]
    triangle_vertices = np.random.random(tensor_shape + [3, 2])
    pixels = np.random.random(pixels_shape + [2])

    barycentric_coordinates, _ = weighted.get_barycentric_coordinates(
        triangle_vertices, pixels)
    barycentric_coordinates_sum = tf.reduce_sum(
        input_tensor=barycentric_coordinates, axis=-1)

    self.assertAllClose(barycentric_coordinates_sum, np.full(pixels_shape, 1.0))
Пример #2
0
  def test_get_barycentric_coordinates_jacobian_random(self):
    """Tests the Jacobian of get_barycentric_coordinates."""
    tensor_size = np.random.randint(2)
    tensor_shape = np.random.randint(1, 2, size=(tensor_size)).tolist()
    triangle_vertices_init = 0.4 * np.random.random(
        tensor_shape + [3, 2]).astype(np.float64) - 0.2
    triangle_vertices_init += np.array(
        ((0.25, 0.25), (0.5, 0.75), (0.75, 0.25)))
    pixels_init = np.random.random(tensor_shape + [3, 2]).astype(np.float64)
    triangle_vertices = tf.convert_to_tensor(
        value=triangle_vertices_init, dtype=tf.float64)
    pixels = tf.convert_to_tensor(value=pixels_init, dtype=tf.float64)

    barycentric_coord, _ = weighted.get_barycentric_coordinates(
        triangle_vertices, pixels)

    with self.subTest(name="pixels_jacobian"):
      self.assert_jacobian_is_correct(pixels, pixels_init, barycentric_coord)

    with self.subTest(name="vertices_jacobian"):
      self.assert_jacobian_is_correct(triangle_vertices, triangle_vertices_init,
                                      barycentric_coord)
Пример #3
0
def perspective_correct_barycentrics(triangle_vertices_model_space,
                                     pixel_position,
                                     model_to_eye_matrix,
                                     perspective_matrix,
                                     screen_dimensions,
                                     lower_left_corner=(0.0, 0.0),
                                     name=None):
    """Computes perspective correct barycentrics.

  Note:
    In the following, A1 to An are optional batch dimensions.

  Args:
    triangle_vertices_model_space: A tensor of shape `[A1, ..., An, 3, 3]`,
      where the last dimension represents the vertices of a triangle in model
      space.
    pixel_position: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension stores the position (in pixels) where the interpolation is
      requested.
    model_to_eye_matrix: A tensor of shape `[A1, ..., An, 4, 4]`, where the last
      two dimension represent matrices to transform points from model to eye
      coordinates.
    perspective_matrix: A tensor of shape `[A1, ..., An, 4, 4]`, where the last
      two dimension represent matrices to transform points from eye to clip
      coordinates.
    screen_dimensions: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension is expressed in pixels and captures the width and the height (in
      pixels) of the screen.
    lower_left_corner: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension captures the position (in pixels) of the lower left corner of
      the screen.
    name: A name for this op. Defaults to 'perspective_correct_barycentrics'.

  Raises:
    InvalidArgumentError: if any input contains data not in the specified range
      of valid values.
    ValueError: If any input is of an unsupported shape.

  Returns:
    A tensor of shape `[A1, ..., An, 3]`, containing perspective correct
    barycentric coordinates.
  """
    with tf.compat.v1.name_scope(name, "perspective_correct_barycentrics", [
            triangle_vertices_model_space, pixel_position, model_to_eye_matrix,
            perspective_matrix, screen_dimensions, lower_left_corner
    ]):
        pixel_position = tf.convert_to_tensor(value=pixel_position)
        triangle_vertices_model_space = tf.convert_to_tensor(
            value=triangle_vertices_model_space)
        shape.check_static(tensor=pixel_position,
                           tensor_name="pixel_position",
                           has_dim_equals=(-1, 2))
        shape.check_static(tensor=triangle_vertices_model_space,
                           tensor_name="triangle_vertices_model_space",
                           has_dim_equals=((-2, 3), (-1, 3)))

        lower_left_corner = tf.convert_to_tensor(value=lower_left_corner)
        screen_dimensions = tf.convert_to_tensor(value=screen_dimensions)
        lower_left_corner = shape.add_batch_dimensions(
            lower_left_corner,
            "lower_left_corner",
            model_to_eye_matrix.shape[:-2],
            last_axis=-2)
        screen_dimensions = shape.add_batch_dimensions(
            screen_dimensions,
            "screen_dimensions",
            model_to_eye_matrix.shape[:-2],
            last_axis=-2)

        vertices_screen, vertices_w = model_to_screen(
            triangle_vertices_model_space, model_to_eye_matrix,
            perspective_matrix, screen_dimensions, lower_left_corner)
        vertices_w = tf.squeeze(vertices_w, axis=-1)
        pixel_position = tf.expand_dims(pixel_position, axis=-2)
        barycentric_coordinates, _ = weighted.get_barycentric_coordinates(
            vertices_screen[..., :2], pixel_position)
        barycentric_coordinates = tf.squeeze(barycentric_coordinates, axis=-2)
        coeffs = barycentric_coordinates / vertices_w
        return tf.linalg.normalize(coeffs, ord=1, axis=-1)[0]
Пример #4
0
def perspective_correct_interpolation(triangle_vertices_model_space,
                                      attribute,
                                      pixel_position,
                                      camera_position,
                                      look_at,
                                      up_vector,
                                      vertical_field_of_view,
                                      screen_dimensions,
                                      near,
                                      far,
                                      lower_left_corner,
                                      name=None):
  """Returns perspective corrected interpolation of attributes over triangles.

  Note:
    In the following, A1 to An are optional batch dimensions.

  Args:
    triangle_vertices_model_space: A tensor of shape `[A1, ..., An, 3, 3]`,
      where the last dimension represents the vertices of a triangle in model
      space.
    attribute: A tensor of shape `[A1, ..., An, 3, B]`, where the last dimension
      stores a per-vertex `B`-dimensional attribute.
    pixel_position: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension stores the position (in pixels) where the interpolation is
      requested.
    camera_position: A tensor of shape `[A1, ..., An, 3]`, where the last
      dimension represents the 3D position of the camera.
    look_at: A tensor of shape `[A1, ..., An, 3, 3]`, with the last dimension
      storing the position where the camera is looking at.
    up_vector: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      defines the up vector of the camera.
    vertical_field_of_view: A tensor of shape `[A1, ..., An, 1]`, where the last
      dimension represents the vertical field of view of the frustum. Note that
      values for `vertical_field_of_view` must be in the range ]0,pi[.
    screen_dimensions: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension is expressed in pixels and captures the width and the height (in
      pixels) of the screen.
    near:  A tensor of shape `[A1, ..., An, 1]`, where the last dimension
      captures the distance between the viewer and the near clipping plane. Note
      that values for `near` must be non-negative.
    far:  A tensor of shape `[A1, ..., An, 1]`, where the last dimension
      captures the distance between the viewer and the far clipping plane. Note
      that values for `far` must be greater than those of `near`.
    lower_left_corner: A tensor of shape `[A1, ..., An, 2]`, where the last
      dimension captures the position (in pixels) of the lower left corner of
      the screen.
    name: A name for this op. Defaults to 'perspective_correct_interpolation'.

  Raises:
    InvalidArgumentError: if any input contains data not in the specified range
      of valid values.
    ValueError: If any input is of an unsupported shape.

  Returns:
    A tensor of shape `[A1, ..., An, B]`, containing interpolated attributes.
  """
  with tf.compat.v1.name_scope(name, "perspective_correct_interpolation", [
      triangle_vertices_model_space, attribute, pixel_position, camera_position,
      look_at, up_vector, vertical_field_of_view, screen_dimensions, near, far,
      lower_left_corner
  ]):
    attribute = tf.convert_to_tensor(value=attribute)
    shape.check_static(
        tensor=attribute, tensor_name="attribute", has_dim_equals=(-2, 3))

    vertices_screen, vertices_w = model_to_screen(
        triangle_vertices_model_space, camera_position, look_at, up_vector,
        vertical_field_of_view, screen_dimensions, near, far, lower_left_corner)
    vertices_w = tf.squeeze(vertices_w, axis=-1)
    pixel_position = tf.expand_dims(pixel_position, axis=-2)
    barycentric_coordinates, _ = weighted.get_barycentric_coordinates(
        vertices_screen[..., :2], pixel_position)
    barycentric_coordinates = tf.squeeze(barycentric_coordinates, axis=-2)
    coeffs = barycentric_coordinates / vertices_w
    denominator = tf.reduce_sum(input_tensor=coeffs, axis=-1, keepdims=True)
    numerator = tf.reduce_sum(
        input_tensor=tf.expand_dims(coeffs, axis=-1) * attribute, axis=-2)
    return numerator / denominator