@@ -598,3 +598,117 @@ def clip_faces(
598
598
clipped_faces_neighbor_idx = clipped_faces_neighbor_idx ,
599
599
)
600
600
return clipped_faces
601
+
602
+
603
+ def convert_clipped_rasterization_to_original_faces (
604
+ pix_to_face_clipped , bary_coords_clipped , clipped_faces : ClippedFaces
605
+ ) -> Tuple [torch .Tensor , torch .Tensor ]:
606
+ """
607
+ Convert rasterization Fragments (expressed as pix_to_face_clipped,
608
+ bary_coords_clipped, dists_clipped) of clipped Meshes computed using clip_faces()
609
+ to the corresponding rasterization Fragments where barycentric coordinates and
610
+ face indices are in terms of the original unclipped Meshes. The distances are
611
+ handled in the rasterizer C++/CUDA kernels (i.e. for Cases 1/3 the distance
612
+ can be used directly and for Case 4 triangles the distance of the pixel to
613
+ the closest of the two subdivided triangles is used).
614
+
615
+ Args:
616
+ pix_to_face_clipped: LongTensor of shape (N, image_size, image_size,
617
+ faces_per_pixel) giving the indices of the nearest faces at each pixel,
618
+ sorted in ascending z-order. Concretely
619
+ ``pix_to_face_clipped[n, y, x, k] = f`` means that ``faces_verts_clipped[f]``
620
+ is the kth closest face (in the z-direction) to pixel (y, x). Pixels that
621
+ are hit by fewer than faces_per_pixel are padded with -1.
622
+ bary_coords_clipped: FloatTensor of shape
623
+ (N, image_size, image_size, faces_per_pixel, 3) giving the barycentric
624
+ coordinates in world coordinates of the nearest faces at each pixel, sorted
625
+ in ascending z-order. Concretely, if ``pix_to_face_clipped[n, y, x, k] = f``
626
+ then ``[w0, w1, w2] = bary_coords_clipped[n, y, x, k]`` gives the
627
+ barycentric coords for pixel (y, x) relative to the face defined by
628
+ ``unproject(face_verts_clipped[f])``. Pixels hit by fewer than
629
+ faces_per_pixel are padded with -1.
630
+ clipped_faces: an instance of ClippedFaces class giving the auxillary variables
631
+ for converting rasterization outputs from clipped to unclipped Meshes.
632
+
633
+ Returns:
634
+ 3-tuple: (pix_to_face_unclipped, bary_coords_unclipped, dists_unclipped) that
635
+ have the same definition as (pix_to_face_clipped, bary_coords_clipped,
636
+ dists_clipped) except that they pertain to faces_verts_unclipped instead of
637
+ faces_verts_clipped (i.e the original meshes as opposed to the modified meshes)
638
+ """
639
+ faces_clipped_to_unclipped_idx = clipped_faces .faces_clipped_to_unclipped_idx
640
+
641
+ # If no clipping or culling then return inputs
642
+ if faces_clipped_to_unclipped_idx is None :
643
+ return pix_to_face_clipped , bary_coords_clipped
644
+
645
+ device = pix_to_face_clipped .device
646
+
647
+ # Convert pix_to_face indices to now refer to the faces in the unclipped Meshes.
648
+ # Init empty tensor to fill in all the background values which have pix_to_face=-1.
649
+ empty = torch .full (pix_to_face_clipped .shape , - 1 , device = device , dtype = torch .int64 )
650
+ pix_to_face_unclipped = torch .where (
651
+ pix_to_face_clipped != - 1 ,
652
+ faces_clipped_to_unclipped_idx [pix_to_face_clipped ],
653
+ empty ,
654
+ )
655
+
656
+ # For triangles that were clipped into smaller triangle(s), convert barycentric
657
+ # coordinates from being in terms of the clipped triangle to being in terms of the
658
+ # original unclipped triangle.
659
+
660
+ # barycentric_conversion is a (T, 3, 3) tensor such that
661
+ # alpha_unclipped[i, :] = barycentric_conversion[i, :, :]*alpha_clipped[i, :]
662
+ barycentric_conversion = clipped_faces .barycentric_conversion
663
+
664
+ # faces_clipped_to_conversion_idx is an (F_clipped,) shape tensor mapping each output
665
+ # face to the applicable row of barycentric_conversion (or set to -1 if conversion is
666
+ # not needed)
667
+ faces_clipped_to_conversion_idx = clipped_faces .faces_clipped_to_conversion_idx
668
+
669
+ if barycentric_conversion is not None :
670
+ bary_coords_unclipped = bary_coords_clipped .clone ()
671
+
672
+ # Select the subset of faces that require conversion, where N is the sum
673
+ # number of case3/case4 triangles that are in the closest k triangles to some
674
+ # rasterized pixel.
675
+ pix_to_conversion_idx = torch .where (
676
+ pix_to_face_clipped != - 1 ,
677
+ faces_clipped_to_conversion_idx [pix_to_face_clipped ],
678
+ empty ,
679
+ )
680
+ faces_to_convert_mask = pix_to_conversion_idx != - 1
681
+ N = faces_to_convert_mask .sum ().item ()
682
+
683
+ # Expand to (N, H, W, K, 3) to be the same shape as barycentric coordinates
684
+ faces_to_convert_mask_expanded = faces_to_convert_mask [:, :, :, :, None ].expand (
685
+ - 1 , - 1 , - 1 , - 1 , 3
686
+ )
687
+
688
+ # An (N,) dim tensor of indices into barycentric_conversion
689
+ conversion_idx_subset = pix_to_conversion_idx [faces_to_convert_mask ]
690
+
691
+ # An (N, 3, 1) tensor of barycentric coordinates in terms of the clipped triangles
692
+ bary_coords_clipped_subset = bary_coords_clipped [faces_to_convert_mask_expanded ]
693
+ bary_coords_clipped_subset = bary_coords_clipped_subset .reshape ((N , 3 , 1 ))
694
+
695
+ # An (N, 3, 3) tensor storing matrices to convert from clipped to unclipped
696
+ # barycentric coordinates
697
+ bary_conversion_subset = barycentric_conversion [conversion_idx_subset ]
698
+
699
+ # An (N, 3, 1) tensor of barycentric coordinates in terms of the unclipped triangle
700
+ bary_coords_unclipped_subset = bary_conversion_subset .bmm (
701
+ bary_coords_clipped_subset
702
+ )
703
+
704
+ bary_coords_unclipped_subset = bary_coords_unclipped_subset .reshape ([N * 3 ])
705
+ bary_coords_unclipped [
706
+ faces_to_convert_mask_expanded
707
+ ] = bary_coords_unclipped_subset
708
+
709
+ # dists for case 4 faces will be handled in the rasterizer
710
+ # so no need to modify them here.
711
+ else :
712
+ bary_coords_unclipped = bary_coords_clipped
713
+
714
+ return pix_to_face_unclipped , bary_coords_unclipped
0 commit comments