Python API¶
The functions the window calls. Signatures are the real ones; defaults are what you get if you leave the argument out.
from Am_landmark.core import shaders, symmetry, tools, landmark_io
from Am_landmark.core import mesh_utils, color_utils, naming
Opening the window¶
import Am_landmark
Am_landmark.load() # open (or raise) the window
Am_landmark.reload(open_window=None) # re-import the package; see Install
Am_landmark.__version__
shaders¶
Create, tag, colour, assign and delete landmarks.
Creating and editing¶
create_landmark(name, rgb=(0.8, 0.2, 0.2), shader_type="surfaceShader",
group="", notes="", reuse_existing=True)
{"shader": name, "shadingGroup": name, "color": rgb}. With reuse_existing, a
landmark that already has this name is updated rather than duplicated.
rename_landmark(shader, new_name) # renames the shading group too
duplicate_landmark(shader, new_name=None) # copy, own shading group, unassigned
change_shader_type(shader, new_type) # keeps the assignment; see Shaders
delete_landmarks(shaders, restore_to_default=True)
delete_unused(include_untagged=False, pattern="")
Colour¶
get_color(shader, linearize=None) # display-space (r, g, b)
set_color(shader, rgb, linearize=None)
color_attr(shader) # "color", "outColor", "baseColor" …
get_transparency(shader) # 0..1
set_transparency(shader, amount)
transparency_attr(shader)
linearize overrides the sRGB→linear preference for one call.
Metadata¶
is_landmark(node)
tag_landmark(shader, group="", notes="", landmark_id=None)
untag_landmark(shader)
landmark_group(shader) / set_landmark_group(shader, group)
landmark_notes(shader) / set_landmark_notes(shader, notes)
landmark_id(shader) / set_landmark_id(shader, value)
Finding¶
landmark_shaders(include_untagged=False, pattern="") # every landmark, sorted
landmark_groups() # group names in use
landmark_info(shader) # everything, one pass
landmarks_on_selection(targets=None)
is_unused(shader) / unused_landmarks(...)
available_shader_types(candidates=SHADER_TYPES) # what this Maya can make
is_protected(node) # default / referenced / locked
landmark_info returns shader, type, shadingGroup, color, group,
notes, id, faces, meshes, tagged.
Assigning¶
assign(shader_or_group, targets=None) # targets default to the selection
assign_faces(shader_or_group, mapping) # {shape: ids or None}
clear_assignment(shader_or_group, targets=None)
assigned_faces(shader_or_group) # {shape: set_of_ids}
assigned_face_count(shader_or_group)
select_assigned(shaders, replace=True)
Shading groups and nodes¶
shading_group(shader) / ensure_shading_group(shader) / shader_of(group)
select_nodes(shaders, include_shading_group=False, replace=True)
show_in_attribute_editor(shader)
show_in_hypershade(shaders)
Constants¶
SHADER_TYPES, COLOR_PLUGS, PROTECTED_MATERIALS, PROTECTED_SETS,
ATTR_LANDMARK, ATTR_GROUP, ATTR_NOTES, ATTR_ID, PREF_LINEARIZE.
symmetry¶
The operation¶
mirror_assignments(shapes=None, mode=MODE_SPATIAL, axis="X", space="Object",
pivot=0.0, tolerance=0.001, direction=DIR_POS_TO_NEG,
selected_faces_only=False, landmarks_only=True,
cross_mesh=True, side_pairs=None)
{"mirrored": n, "unmatched": n, "shapes": {shape: [ids]},
"messages": [...]}.
mirror_face_selection(mode=MODE_SPATIAL, axis="X", space="Object", pivot=0.0,
tolerance=0.001, add=False)
symmetry_report(shapes=None, axis="X", space="Object", pivot=0.0,
tolerance=0.001, mode=MODE_SPATIAL)
select_unmatched(report)
Maya's own symmetry¶
maya_symmetry_state() # (enabled, axis, space, topological)
set_maya_symmetry(enabled=True, axis="X", space="Object", topological=False)
maya_symmetry_faces(shape, face_ids)
The maps¶
face_mirror_map(shape, mode=MODE_SPATIAL, axis="X", space="Object",
pivot=0.0, tolerance=0.001) # ({face: face}, info)
cross_mesh_mirror_map(source_shape, target_shape, axis="X", space="World", ...)
counterpart_shape(shape, pairs=None) # L_arm_geo -> R_arm_geo
Pure, Maya-free, and unit tested — useful if you are building your own tool:
spatial_map(source_points, target_points, axis=0, pivot=0.0,
tolerance=0.001, mirror=True) # {index: index}
build_edge_face_table(face_vertices)
find_seam_seed(face_vertices, vertex_points, face_centers, axis=0,
pivot=0.0, tolerance=0.001)
build_topological_map(face_vertices, seed_face_a, seed_face_b, vertex_seed)
mirror_point(point, axis=0, pivot=0.0)
Constants¶
MODES — MODE_SPATIAL, MODE_MAYA_TOPO, MODE_SEAM_TOPO.
DIRECTIONS — DIR_POS_TO_NEG, DIR_NEG_TO_POS, DIR_SWAP.
AXES, SPACES, DEFAULT_TOLERANCE.
tools¶
coverage_report(shapes=None)
select_unassigned(shapes=None)
select_landmark_faces(shapes=None)
apply_palette(shaders, targets=None, spread="Per Object") # or "Per Shell", "All"
landmarks_from_shells(shape=None, prefix="shell",
shader_type="surfaceShader", group="", colors=None)
recolor(shaders, mode="Distinct", **generator_kwargs)
sort_by_hue(shaders)
transfer_landmarks(source_shape, target_shapes, mode="Face Index",
tolerance=0.01, space="World", landmarks_only=True)
bake_to_vertex_colors(shapes=None, landmarks_only=True, display=True)
clear_vertex_colors(shapes=None)
create_preview_spheres(shaders, radius=0.5, spacing=1.3)
delete_preview_spheres()
isolate_landmarks(shaders, enable=True)
frame_landmarks(shaders)
connected_shells(face_vertices) # pure: faces -> [[face ids], …]
mesh_shells(shape)
coverage_report returns total, landmark, other, none and a per-shape
breakdown with the actual face ids.
landmark_io¶
export_landmarks(shaders, path, include_assignments=True,
include_attributes=True, include_uv=False,
include_point=False, point_space="Object", meta=None)
import_landmarks(path, create_missing=True, apply_assignments=True,
apply_attributes=True, search="", replace="",
match_mode="Contains", namespace="", strip_namespaces=False,
recolor_existing=True, match_method=MATCH_FACE_INDEX,
tolerance=None, color_set=None)
import_landmarks returns created, updated, assigned, landmarks,
unmatched, method, missing_meshes, messages, and error if the file
could not be read.
Lower level, if you are building files yourself:
collect_entries(shaders, ...) # scene -> entries
build_document(entries, meta=None)# entries -> document
parse_document(data) # document -> entries (v1, v2 and v3)
read_file(path) / write_file(path, document)
remap_assignments(assignments, transform, namespace=None, strip_namespaces=False)
Constants¶
MATCH_METHODS — MATCH_FACE_INDEX, MATCH_UV, MATCH_POINT,
MATCH_COLOR_SET. DEFAULT_TOLERANCE (a dict, per method), POINT_SPACES,
FORMAT_NAME, FORMAT_VERSION, ATTRIBUTE_WHITELIST.
mesh_utils¶
mesh_shapes(nodes=None, selection_fallback=True)
shape_of(node) / long_name(node) / face_count(shape)
parse_selection(items=None, convert_components=True) # {shape: ids or None}
resolve_faces(shape, ids)
select_faces(mapping, replace=True)
face_centers(shape, space="object") # [(x, y, z), …] by face id
face_vertices(shape) # [(v, v, v, v), …] winding order
vertex_positions(shape, space="object")
face_uv_centers(shape, uv_set=None) # [(u, v) or None, …]
face_colors(shape, color_set=None) # [(r, g, b) or None, …]
bounding_box(shape, space="object")
uv_sets(shape) / current_uv_set(shape)
color_sets(shape) / current_color_set(shape)
connected_shaders(shape) # (names, per-face index)
faces_by_shading_group(shape) # {group: set_of_ids}
unassigned_faces(shape)
compress_ids(ids) # {0,1,2,5} -> [(0,2),(5,5)]
expand_ranges(ranges)
component_strings(node, ids, attr="f") # chunked "shape.f[0:2]" lists
parse_component_string(text)
color_utils¶
No Maya import at all — usable anywhere.
hue_wheel(count, saturation=0.72, value=0.95, offset=0.0)
distinct(count, saturation=0.72, value=0.95, offset=0.0)
ramp(start_rgb, end_rgb, count, space="HSV", shortest_hue=True)
harmony(base_rgb, kind="Complementary", count=5)
random_palette(count, seed=None, saturation=0.72, value=0.95,
min_distance=0.22, jitter=0.18)
preview_swatches(mode, count, **kwargs) # the dispatch the UI uses
rgb_to_hex(rgb) / hex_to_rgb(text, default=(0.5, 0.5, 0.5))
hsv_to_rgb(h, s, v) / rgb_to_hsv(r, g, b)
srgb_to_linear(value) / linear_to_srgb(value)
display_to_rendering(rgb) / rendering_to_display(rgb)
relative_luminance(rgb) / readable_ink(rgb) / color_distance(a, b)
GENERATOR_MODES, HARMONY_KINDS and RAMP_SPACES are the lists the UI shows.
naming¶
Also Maya-free.
swap_side(name, pairs=None) # L_arm_geo <-> R_arm_geo
side_of(name, pairs=None) # "left" / "right" / ""
has_side_token(name, pairs=None)
side_pairs(left_raw=None, right_raw=None)
build_name_transform(search, replace, mode="Contains") # -> fn(name) -> name
strip_namespace(name) / apply_namespace(name, namespace) / namespace_of(name)
node_name(path) / sanitize(name) / numbered(base, index, pad=2)
next_free_name(base, taken)
MATCH_MODES is ("Contains", "Prefix", "Suffix", "Regex");
DEFAULT_SIDE_PAIRS is the left/right token table.
Undo¶
from Am_landmark.core.undo import undo_chunk, preserve_selection
with undo_chunk("My tool: mark up head"):
... # several landmark operations, one Ctrl+Z for the user
with preserve_selection():
... # restores the user's selection afterwards
The public operations already do this; you need it only when combining several into one action of your own.