Beispiel #1
0
    def test_perspective_right_handed_cross_jacobian_preset(self):
        """Tests the Jacobian of perspective_right_handed."""
        vertical_field_of_view_init = np.array((1.0, ))
        aspect_ratio_init = np.array((1.0, ))
        near_init = np.array((1.0, ))
        far_init = np.array((10.0, ))

        # Wrap with tf.identity because some assert_* ops look at the constant
        # tensor value and mark it as unfeedable.
        vertical_field_of_view_tensor = tf.identity(
            tf.convert_to_tensor(value=vertical_field_of_view_init))
        aspect_ratio_tensor = tf.identity(
            tf.convert_to_tensor(value=aspect_ratio_init))
        near_tensor = tf.identity(tf.convert_to_tensor(value=near_init))
        far_tensor = tf.identity(tf.convert_to_tensor(value=far_init))

        y = glm.perspective_right_handed(vertical_field_of_view_tensor,
                                         aspect_ratio_tensor, near_tensor,
                                         far_tensor)

        self.assert_jacobian_is_correct(vertical_field_of_view_tensor,
                                        vertical_field_of_view_init, y)
        self.assert_jacobian_is_correct(aspect_ratio_tensor, aspect_ratio_init,
                                        y)
        self.assert_jacobian_is_correct(near_tensor, near_init, y)
        self.assert_jacobian_is_correct(far_tensor, far_init, y)
Beispiel #2
0
 def test_perspective_right_handed_valid_range_exception_raised(
         self, vertical_field_of_view, aspect_ratio, near, far):
     """Tests that an exception is raised with out of bounds values."""
     with self.assertRaises(tf.errors.InvalidArgumentError):
         self.evaluate(
             glm.perspective_right_handed(vertical_field_of_view,
                                          aspect_ratio, near, far))
Beispiel #3
0
    def test_perspective_right_handed_cross_jacobian_random(self):
        """Tests the Jacobian of perspective_right_handed."""
        tensor_size = np.random.randint(1, 3)
        tensor_shape = np.random.randint(1, 5, size=(tensor_size)).tolist()
        eps = np.finfo(np.float64).eps
        vertical_field_of_view_init = np.random.uniform(eps,
                                                        math.pi - eps,
                                                        size=tensor_shape)
        aspect_ratio_init = np.random.uniform(eps, 100.0, size=tensor_shape)
        near_init = np.random.uniform(eps, 10.0, size=tensor_shape)
        far_init = np.random.uniform(10 + eps, 100.0, size=tensor_shape)

        # Wrap with tf.identity because some assert_* ops look at the constant
        # tensor value and mark it as unfeedable.
        vertical_field_of_view_tensor = tf.identity(
            tf.convert_to_tensor(value=vertical_field_of_view_init))
        aspect_ratio_tensor = tf.identity(
            tf.convert_to_tensor(value=aspect_ratio_init))
        near_tensor = tf.identity(tf.convert_to_tensor(value=near_init))
        far_tensor = tf.identity(tf.convert_to_tensor(value=far_init))

        y = glm.perspective_right_handed(vertical_field_of_view_tensor,
                                         aspect_ratio_tensor, near_tensor,
                                         far_tensor)

        self.assert_jacobian_is_correct(vertical_field_of_view_tensor,
                                        vertical_field_of_view_init, y)
        self.assert_jacobian_is_correct(aspect_ratio_tensor, aspect_ratio_init,
                                        y)
        self.assert_jacobian_is_correct(near_tensor, near_init, y)
        self.assert_jacobian_is_correct(far_tensor, far_init, y)
Beispiel #4
0
    def test_perspective_right_handed_preset(self):
        """Tests that perspective_right_handed generates expected results.."""
        vertical_field_of_view = (60.0 * math.pi / 180.0,
                                  50.0 * math.pi / 180.0)
        aspect_ratio = (1.5, 1.1)
        near = (1.0, 1.2)
        far = (10.0, 5.0)

        pred = glm.perspective_right_handed(vertical_field_of_view,
                                            aspect_ratio, near, far)
        gt = (((1.15470052, 0.0, 0.0, 0.0), (0.0, 1.73205066, 0.0, 0.0),
               (0.0, 0.0, -1.22222221, -2.22222233), (0.0, 0.0, -1.0, 0.0)),
              ((1.9495517, 0.0, 0.0, 0.0), (0.0, 2.14450693, 0.0, 0.0),
               (0.0, 0.0, -1.63157892, -3.15789485), (0.0, 0.0, -1.0, 0.0)))
        self.assertAllClose(pred, gt)
Beispiel #5
0
    def test_rasterize(self):
        height = 500
        width = 500
        camera_origin = (0.0, 0.0, 0.0)
        camera_up = (0.0, 1.0, 0.0)
        look_at = (0.0, 0.0, 1.0)
        fov = (60.0 * np.math.pi / 180, )
        near_plane = (1.0, )
        far_plane = (10.0, )

        world_to_camera = glm.look_at_right_handed(camera_origin, look_at,
                                                   camera_up)
        perspective_matrix = glm.perspective_right_handed(
            fov, (float(width) / float(height), ), near_plane, far_plane)
        view_projection_matrix = tf.matmul(perspective_matrix, world_to_camera)
        view_projection_matrix = tf.squeeze(view_projection_matrix)

        for depth in range(2, 5):
            tris = np.array([[-10.0, 10.0, depth], [10.0, 10.0, depth],
                             [0.0, -10.0, depth]],
                            dtype=np.float32)
            tris_tf = tf.reshape(tris, [-1])

            render_parameters = {
                "view_projection_matrix": ("mat", view_projection_matrix),
                "triangular_mesh": ("buffer", tris_tf)
            }

            render_parameters = list(six.iteritems(render_parameters))
            variable_names = [v[0] for v in render_parameters]
            variable_kinds = [v[1][0] for v in render_parameters]
            variable_values = [v[1][1] for v in render_parameters]

            result = rasterizer.rasterize(
                num_points=tris.shape[0],
                variable_names=variable_names,
                variable_kinds=variable_kinds,
                variable_values=variable_values,
                output_resolution=(width, height),
                vertex_shader=test_vertex_shader,
                geometry_shader=test_geometry_shader,
                fragment_shader=test_fragment_shader,
            )

            gt = np.tile((0, depth), (width, height, 1))
            self.assertAllClose(result[..., 2:4], gt)
  def test_rasterize(self):
    max_depth = 10
    min_depth = 2
    height = 480
    width = 640
    camera_origin = (0.0, 0.0, 0.0)
    camera_up = (0.0, 1.0, 0.0)
    look_at = (0.0, 0.0, 1.0)
    fov = (60.0 * np.math.pi / 180,)
    near_plane = (1.0,)
    far_plane = (10.0,)
    batch_shape = tf.convert_to_tensor(
        value=(2, (max_depth - min_depth) // 2), dtype=tf.int32)

    world_to_camera = glm.look_at_right_handed(camera_origin, look_at,
                                               camera_up)
    perspective_matrix = glm.perspective_right_handed(
        fov, (float(width) / float(height),), near_plane, far_plane)
    view_projection_matrix = tf.matmul(perspective_matrix, world_to_camera)
    view_projection_matrix = tf.squeeze(view_projection_matrix)

    # Generate triangles at different depths and associated ground truth.
    tris = np.zeros((max_depth - min_depth, 9), dtype=np.float32)
    gt = np.zeros((max_depth - min_depth, width, height, 2), dtype=np.float32)
    for idx in range(max_depth - min_depth):
      tris[idx, :] = (-100.0, 100.0, idx + min_depth, 100.0, 100.0,
                      idx + min_depth, 0.0, -100.0, idx + min_depth)
      gt[idx, :, :, :] = (0, idx + min_depth)

    # Broadcast the variables.
    render_parameters = {
        "view_projection_matrix":
            ("mat",
             tf.broadcast_to(
                 input=view_projection_matrix,
                 shape=tf.concat(
                     values=(batch_shape,
                             tf.shape(input=view_projection_matrix)[-2:]),
                     axis=0))),
        "triangular_mesh":
            ("buffer",
             tf.reshape(
                 tris, shape=tf.concat(values=(batch_shape, (9,)), axis=0)))
    }
    # Reshape the ground truth.
    gt = tf.reshape(
        gt, shape=tf.concat(values=(batch_shape, (height, width, 2)), axis=0))

    render_parameters = list(six.iteritems(render_parameters))
    variable_names = [v[0] for v in render_parameters]
    variable_kinds = [v[1][0] for v in render_parameters]
    variable_values = [v[1][1] for v in render_parameters]

    def rasterize():
      return rasterizer.rasterize(
          num_points=3,
          variable_names=variable_names,
          variable_kinds=variable_kinds,
          variable_values=variable_values,
          output_resolution=(width, height),
          vertex_shader=test_vertex_shader,
          geometry_shader=test_geometry_shader,
          fragment_shader=test_fragment_shader,
      )

    result = rasterize()
    self.assertAllClose(result[..., 2:4], gt)

    @tf.function
    def check_lazy_shape():
      # Within @tf.function, the tensor shape is determined by SetShapeFn
      # callback. Ensure that the shape of non-batch axes matches that of of
      # the actual tensor evaluated in eager mode above.
      lazy_shape = rasterize().shape
      self.assertEqual(lazy_shape[-3:], list(result.shape)[-3:])

    check_lazy_shape()
  def __init__(self,
               background_vertices,
               background_attributes,
               background_triangles,
               camera_origin,
               look_at,
               camera_up,
               field_of_view,
               image_size,
               near_plane,
               far_plane,
               bottom_left=(0.0, 0.0),
               name=None):
    """Initializes TriangleRasterizer with OpenGL parameters and the background.

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

    Args:
      background_vertices: A tensor of shape `[V, 3]` containing `V` 3D
        vertices. Note that these background vertices will be used in every
        rasterized image.
      background_attributes: A tensor of shape `[V, K]` containing `V` vertices
        associated with K-dimensional attributes. Pixels for which the first
        visible surface is in the background geometry will make use of
        `background_attribute` for estimating their own attribute. Note that
        these background attributes will be use in every rasterized image.
      background_triangles: An integer tensor of shape `[T, 3]` containing `T`
        triangles, each associated with 3 vertices from `background_vertices`.
        Note that these background triangles will be used in every rasterized
        image.
      camera_origin: A Tensor of shape `[A1, ..., An, 3]`, where the last axis
        represents the 3D position of the camera.
      look_at: A Tensor of shape `[A1, ..., An, 3]`, with the last axis storing
        the position where the camera is looking at.
      camera_up: A Tensor of shape `[A1, ..., An, 3]`, where the last axis
        defines the up vector of the camera.
      field_of_view:  A Tensor of shape `[A1, ..., An, 1]`, where the last axis
        represents the vertical field of view of the frustum expressed in
        radians. Note that values for `field_of_view` must be in the range (0,
        pi).
      image_size: A tuple (height, width) containing the dimensions in pixels of
        the rasterized image".
      near_plane: A Tensor of shape `[A1, ..., An, 1]`, where the last axis
        captures the distance between the viewer and the near clipping plane.
        Note that values for `near_plane` must be non-negative.
      far_plane: A Tensor of shape `[A1, ..., An, 1]`, where the last axis
        captures the distance between the viewer and the far clipping plane.
        Note that values for `far_plane` must be non-negative.
      bottom_left: A Tensor of shape `[A1, ..., An, 2]`, where the last axis
        captures the position (in pixels) of the lower left corner of the
        screen. Defaults to (0.0, 0.0).
        name: A name for this op. Defaults to 'triangle_rasterizer_init'.
    """
    with tf.compat.v1.name_scope(
        name, "triangle_rasterizer_init",
        (background_vertices, background_attributes, background_triangles,
         camera_origin, look_at, camera_up, field_of_view, near_plane,
         far_plane, bottom_left)):

      background_vertices = tf.convert_to_tensor(value=background_vertices)
      background_attributes = tf.convert_to_tensor(value=background_attributes)
      background_triangles = tf.convert_to_tensor(value=background_triangles)

      shape.check_static(
          tensor=background_vertices,
          tensor_name="background_vertices",
          has_rank=2,
          has_dim_equals=(-1, 3))
      shape.check_static(
          tensor=background_attributes,
          tensor_name="background_attributes",
          has_rank=2)
      shape.check_static(
          tensor=background_triangles,
          tensor_name="background_triangles",
          # has_rank=2,
          has_dim_equals=(-1, 3))
      shape.compare_batch_dimensions(
          tensors=(background_vertices, background_attributes),
          last_axes=-2,
          tensor_names=("background_geometry", "background_attribute"),
          broadcast_compatible=False)

      background_vertices = tf.expand_dims(background_vertices, axis=0)
      background_attributes = tf.expand_dims(background_attributes, axis=0)

      height = float(image_size[0])
      width = float(image_size[1])

      self._background_geometry = tf.gather(
          background_vertices, background_triangles, axis=-2)
      self._background_attribute = tf.gather(
          background_attributes, background_triangles, axis=-2)

      self._camera_origin = tf.convert_to_tensor(value=camera_origin)
      self._look_at = tf.convert_to_tensor(value=look_at)
      self._camera_up = tf.convert_to_tensor(value=camera_up)
      self._field_of_view = tf.convert_to_tensor(value=field_of_view)
      self._image_size_glm = tf.convert_to_tensor(value=(width, height))
      self._image_size_int = (int(width), int(height))
      self._near_plane = tf.convert_to_tensor(value=near_plane)
      self._far_plane = tf.convert_to_tensor(value=far_plane)
      self._bottom_left = tf.convert_to_tensor(value=bottom_left)

      # Construct the pixel grid. Note that OpenGL uses half-integer pixel
      # centers.
      px = tf.linspace(0.5, width - 0.5, num=int(width))
      py = tf.linspace(0.5, height - 0.5, num=int(height))
      xv, yv = tf.meshgrid(px, py)
      self._pixel_position = tf.stack((xv, yv), axis=-1)

      # Construct the view projection matrix.
      world_to_camera = glm.look_at_right_handed(camera_origin, look_at,
                                                 camera_up)
      perspective_matrix = glm.perspective_right_handed(field_of_view,
                                                        (width / height,),
                                                        near_plane, far_plane)
      perspective_matrix = tf.squeeze(perspective_matrix)
      self._view_projection_matrix = tf.linalg.matmul(perspective_matrix,
                                                      world_to_camera)