1
# Maya Texel Density Checker
# Select mesh transforms or mesh shapes, then run.
# Density result = pixels per Maya scene unit.
# Example: if scene unit is cm, result is px/cm.
import math
import maya.cmds as cmds
import maya.api.OpenMaya as om
# ---------------- SETTINGS ----------------
TEXTURE_SIZE = 2048 # 1024, 2048, 4096, etc.
UV_SET = None # None = current UV set, or set e.g. "map1"
TARGET_TEXEL_DENSITY = None # Example: 10.24 for target px/unit. None disables target check.
TOLERANCE_PERCENT = 10.0 # Only used if TARGET_TEXEL_DENSITY is set.
# ------------------------------------------
def polygon_area_2d(us, vs):
"""Shoelace area in UV space."""
count = len(us)
if count < 3:
return 0.0
area = 0.0
for i in range(count):
j = (i + 1) % count
area += us[i] * vs[j] - us[j] * vs[i]
return abs(area) * 0.5
def get_selected_mesh_shapes():
selection = cmds.ls(sl=True, long=True, flatten=True) or []
if not selection:
return []
objects = cmds.ls(selection, objectsOnly=True, long=True) or []
shapes = []
seen = set()
for obj in objects:
if not cmds.objExists(obj):
continue
if cmds.nodeType(obj) == "mesh":
candidates = [obj]
else:
candidates = cmds.ls(
obj,
dag=True,
type="mesh",
long=True,
noIntermediate=True
) or []
for shape in candidates:
if not cmds.objExists(shape):
continue
try:
if cmds.getAttr(shape + ".intermediateObject"):
continue
except Exception:
pass
if shape not in seen:
seen.add(shape)
shapes.append(shape)
return shapes
def get_dag_path(node):
sel = om.MSelectionList()
sel.add(node)
return sel.getDagPath(0)
def get_current_uv_set(shape):
current = cmds.polyUVSet(shape, query=True, currentUVSet=True)
if current:
return current[0]
return None
def get_texel_density_data(shape, texture_size, uv_set=None):
dag = get_dag_path(shape)
mesh_fn = om.MFnMesh(dag)
uv_sets = mesh_fn.getUVSetNames()
if not uv_sets:
return {
"shape": shape,
"uv_set": None,
"face_count": 0,
"world_area": 0.0,
"uv_area": 0.0,
"texel_density": 0.0,
"missing_uv_faces": 0,
"zero_area_faces": 0,
"error": "Mesh has no UV sets."
}
used_uv_set = uv_set or get_current_uv_set(shape) or uv_sets[0]
if used_uv_set not in uv_sets:
return {
"shape": shape,
"uv_set": used_uv_set,
"face_count": 0,
"world_area": 0.0,
"uv_area": 0.0,
"texel_density": 0.0,
"missing_uv_faces": 0,
"zero_area_faces": 0,
"error": "UV set does not exist on mesh."
}
face_count = 0
world_area = 0.0
uv_area = 0.0
missing_uv_faces = 0
zero_area_faces = 0
it = om.MItMeshPolygon(dag)
while not it.isDone():
face_count += 1
try:
face_world_area = it.getArea(om.MSpace.kWorld)
except Exception:
face_world_area = 0.0
if face_world_area <= 0.000000000001:
zero_area_faces += 1
else:
world_area += face_world_area
try:
us, vs = it.getUVs(used_uv_set)
face_uv_area = polygon_area_2d(us, vs)
if face_uv_area <= 0.000000000001:
missing_uv_faces += 1
else:
uv_area += face_uv_area
except Exception:
missing_uv_faces += 1
it.next()
if world_area > 0.0 and uv_area > 0.0:
texel_density = texture_size * math.sqrt(uv_area / world_area)
else:
texel_density = 0.0
return {
"shape": shape,
"uv_set": used_uv_set,
"face_count": face_count,
"world_area": world_area,
"uv_area": uv_area,
"texel_density": texel_density,
"missing_uv_faces": missing_uv_faces,
"zero_area_faces": zero_area_faces,
"error": None
}
def target_status(texel_density):
if TARGET_TEXEL_DENSITY is None or TARGET_TEXEL_DENSITY <= 0:
return ""
diff_percent = ((texel_density - TARGET_TEXEL_DENSITY) / TARGET_TEXEL_DENSITY) * 100.0
if abs(diff_percent) <= TOLERANCE_PERCENT:
return "OK ({:+.2f}%)".format(diff_percent)
if diff_percent < 0:
return "LOW ({:+.2f}%)".format(diff_percent)
return "HIGH ({:+.2f}%)".format(diff_percent)
def run_texel_density_check():
shapes = get_selected_mesh_shapes()
if not shapes:
cmds.warning("Select one or more polygon meshes first.")
return
print("\n" + "=" * 80)
print("TEXEL DENSITY CHECK")
print("Texture size: {0}px".format(TEXTURE_SIZE))
if TARGET_TEXEL_DENSITY is not None:
print("Target texel density: {0:.4f} px/unit".format(TARGET_TEXEL_DENSITY))
print("Tolerance: +/- {0:.2f}%".format(TOLERANCE_PERCENT))
print("=" * 80)
total_world_area = 0.0
total_uv_area = 0.0
for shape in shapes:
data = get_texel_density_data(shape, TEXTURE_SIZE, UV_SET)
print("\nMesh: {0}".format(shape))
if data["error"]:
print(" ERROR: {0}".format(data["error"]))
continue
print(" UV set: {0}".format(data["uv_set"]))
print(" Faces: {0}".format(data["face_count"]))
print(" World area: {0:.6f}".format(data["world_area"]))
print(" UV area: {0:.6f}".format(data["uv_area"]))
print(" Texel density: {0:.4f} px/unit".format(data["texel_density"]))
status = target_status(data["texel_density"])
if status:
print(" Target status: {0}".format(status))
if data["missing_uv_faces"] > 0:
print(" Warning: {0} faces have missing/zero UV area".format(data["missing_uv_faces"]))
if data["zero_area_faces"] > 0:
print(" Warning: {0} faces have zero world area".format(data["zero_area_faces"]))
total_world_area += data["world_area"]
total_uv_area += data["uv_area"]
if total_world_area > 0.0 and total_uv_area > 0.0:
combined_density = TEXTURE_SIZE * math.sqrt(total_uv_area / total_world_area)
print("\n" + "-" * 80)
print("Combined selected meshes:")
print(" Total world area: {0:.6f}".format(total_world_area))
print(" Total UV area: {0:.6f}".format(total_uv_area))
print(" Texel density: {0:.4f} px/unit".format(combined_density))
status = target_status(combined_density)
if status:
print(" Target status: {0}".format(status))
print("=" * 80 + "\n")
run_texel_density_check()For immediate assistance, please email our customer support: [email protected]