Last active
March 21, 2024 06:18
-
-
Save BigRoy/60883eff23f73a34c4671395b32d858d to your computer and use it in GitHub Desktop.
Query the used UDIM tiles for the UVs of an input mesh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from maya import cmds | |
def get_bounding_box_tiles(bb): | |
u_minmax, v_minmax = bb | |
# If the max is exactly on the integer boundary we allow it to be | |
# part of the tile of the previos integer so we can subtract one. | |
# But since we'll need to add one to iterate "up to" the maximum for | |
# the `range` function we will instead add one to the opposite cases. | |
# Inputs are tuples so don't assign elements but override tuple | |
if u_minmax[1] != int(u_minmax[1]): | |
u_minmax = (u_minmax[0], u_minmax[1] + 1) | |
if v_minmax[1] != int(v_minmax[1]): | |
v_minmax = (v_minmax[0], v_minmax[1] + 1) | |
tiles = [] | |
for v in range(*map(int, v_minmax)): | |
for u in range(*map(int, u_minmax)): | |
tiles.append((u, v)) | |
return tiles | |
def get_uv_udim_tiles(mesh, uv_set=None): | |
"""Return the UV tiles used by the UVs of the input mesh. | |
Warning: | |
This does not capture the case where a single UV shell | |
might be layout in such a way that all its UV points are | |
around another tile since it uses the UV shell bounding | |
box to compute the used tiles. In the image below imagine | |
the lines being the UVs of a single shell and the `x` being | |
an emtpy UV tile. It will not detect the empty tile. | |
/ - \ | |
| x | | |
Args: | |
mesh (str): Mesh node name. | |
uv_set (str): The UV set to sample. When not | |
provided the current UV map is used. | |
Returns: | |
list: sorted list of uv tiles | |
""" | |
kwargs = {} | |
if uv_set is not None: | |
kwargs["uvSetName"] = uv_set | |
bb = cmds.polyEvaluate(mesh, boundingBox2d=True, **kwargs) | |
tiles = get_bounding_box_tiles(bb) | |
if len(tiles) == 1: | |
# If there's only a single tile for the bounding box | |
# it'll be impossible for there to be empty tiles | |
# in-between so we just return the given tiles | |
return tiles | |
# Get the bounding box per UV shell | |
uv_shells = cmds.polyEvaluate(mesh, uvShell=True, **kwargs) | |
if uv_shells == 1: | |
# If there's only a single UV shell it must span | |
# all the UV tiles | |
return tiles | |
tiles = set() | |
for i in range(uv_shells): | |
shell_uvs = cmds.polyEvaluate(mesh, uvsInShell=i, **kwargs) | |
shell_bb = cmds.polyEvaluate(shell_uvs, boundingBoxComponent2d=True, **kwargs) | |
shell_tiles = get_bounding_box_tiles(shell_bb) | |
tiles.update(shell_tiles) | |
return sorted(tiles, key=uv2udim) | |
def uv2udim(tile): | |
"""UV tile to UDIM number. | |
Note that an input integer of 2 means it's | |
the UV tile range using 2.0-3.0. | |
Examples: | |
>>> uv2udim((0, 0) | |
# 1001 | |
>>> uv2udim((0, 1) | |
# 1011 | |
>>> uv2udim((2, 0) | |
# 1003 | |
>>> uv2udim(8, 899) | |
# 9999 | |
Returns: | |
int: UDIM tile number | |
""" | |
u, v = tile | |
return 1001 + u + 10 * v | |
# Example usage | |
for mesh in cmds.ls(selection=True): | |
tiles = get_uv_udim_tiles(mesh) | |
print mesh | |
print tiles | |
for tile in tiles: | |
print uv2udim(tile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's one that uses
polyUVCoverage
to remove the false positives from the bounding box queries: