Skip to content

Scripting

Everything the window does is available without it. The scene layer never imports Qt, so a shelf button, a batch job or another tool can drive the whole feature set with no window ever built.

from Am_landmark.core import shaders, symmetry, tools, landmark_io

jaw = shaders.create_landmark("jaw_line", (0.90, 0.35, 0.20), "surfaceShader",
                              group="head")
shaders.assign(jaw["shadingGroup"])                     # to the current selection

symmetry.mirror_assignments(axis="X", space="Object",
                            direction=symmetry.DIR_POS_TO_NEG)

print(tools.coverage_report()["none"], "faces still bare")
landmark_io.export_landmarks(shaders.landmark_shaders(), "d:/head.json",
                             include_uv=True, include_point=True)

The layers

Package Imports Use it for
Am_landmark.core maya.cmds, maya.api.OpenMaya Everything. Safe in batch, safe in a test, safe from another tool.
Am_landmark.ui Qt as well Opening and driving the window.

Am_landmark.load() is the only thing most scripts need from the UI layer.

The modules

Module Contains
core.shaders Create, tag, colour, assign, query, convert and delete landmarks.
core.symmetry Mirror maps, mirror_assignments, symmetry reports, Maya's own symmetry.
core.tools Coverage, shells, palette application, transfer, vertex-colour bake, previews.
core.landmark_io The file format, in both directions.
core.mesh_utils Face centres, UVs, colours, per-face shader lookup, component parsing.
core.color_utils Palette generation and colour-space conversion. No Maya at all.
core.naming Side tokens, namespaces, search/replace rules. No Maya at all.

Conventions

Names, not objects. Everything takes and returns Maya node names as strings. There is no wrapper class to keep in sync with the scene.

Faces are ids. Assignments are {shape_name: set_of_face_ids}. None instead of a set means the whole mesh, which is how an object-level assignment is represented.

{"|char|headShape": {0, 1, 2, 88}, "|char|bodyShape": None}

Colours are display-space triplets. (r, g, b) floats in 0..1, in the space you see on screen. core.color_utils converts to and from linear if your scene is colour-managed.

Every write is one undo step. The public operations open an undo chunk, so a script that creates thirty landmarks is one Ctrl+Z for the user — including if it fails half-way.

Nothing raises at you by surprise. Scene queries return empty rather than throwing when a node has gone; operations refuse to touch default, referenced or locked nodes and tell you by returning nothing.

Running head-less

core works in mayapy with maya.standalone initialised — no window, no QApplication:

import maya.standalone
maya.standalone.initialize(name="python")

import maya.cmds as cmds
from Am_landmark.core import landmark_io, tools

cmds.file("//assets/char/head.ma", open=True, force=True)
landmark_io.import_landmarks("//assets/char/head_landmarks.json")
tools.bake_to_vertex_colors()
cmds.file(save=True)

That is a complete batch step: load a pass onto a published model and bake it for the engine, with no UI involved.

Reloading while you work

from Am_landmark.reload_package import reload_am_landmark
reload_am_landmark()

See Install for what it does and why it is not importlib.reload.