PYTHON | MAYA

Python trong Maya là gì?

Python trong Maya không chỉ là một ngôn ngữ lập trình, mà là “chiếc chìa khóa” giúp người nghệ sĩ 3D vượt qua giới hạn của giao diện đồ họa thông thường. Thay vì thực hiện hàng trăm cú nhấp chuột lặp đi lặp lại để dựng hình, bạn sử dụng các dòng lệnh (Script) để điều khiển trực tiếp nhân đồ họa của Maya.

Trong kỹ thuật Modeling, Python đóng vai trò:

  • Tự động hóa (Automation): Thực hiện các tác vụ phức tạp (như tạo hệ thống vảy rồng, rải sỏi, hay dọn dẹp mesh) chỉ với một nút bấm.

  • Độ chính xác tuyệt đối: Tính toán vị trí Vertex, Edge, Face dựa trên các công thức toán học, đảm bảo sự hoàn hảo mà mắt thường khó điều chỉnh được.

  • Tùy biến công cụ (Custom Tools): Tự tạo ra các bộ công cụ cá nhân hóa, phù hợp với quy trình làm việc riêng của từng Artist hoặc Studio.

Cốt lõi: Học Python trong Maya là học cách chuyển tư duy từ “người dùng phần mềm” sang “người tạo ra giải pháp”.

Cấu trúc mã code cơ bản để bạn bắt đầu:

Để mã code Python có thể giao tiếp được với Maya, mọi Script đều phải bắt đầu bằng việc gọi thư viện lệnh của AutodesK.

import maya.cmds as cmds

# ‘import’: Nạp thư viện vào bộ nhớ.
# ‘maya.cmds’: Thư viện chứa tất cả các lệnh thao tác trong Maya (tương đương với các menu trên màn hình).
# ‘as cmds’: Đặt tên viết tắt là ‘cmds’ để khi viết code nhanh hơn và gọn hơn.

# Ví dụ: Lệnh tạo một khối lập phương (Cube)
cmds.polyCube(name=”MyCube_01″)

Logic vận hành:

  1. Thư viện cmds: Là cầu nối. Khi bạn viết cmds.polyCube(), Python sẽ “ra lệnh” cho Maya thực hiện chức năng tạo khối đã được lập trình sẵn.

  2. Tham số (Arguments): Như name="MyCube_01", giúp bạn định nghĩa chi tiết thuộc tính của đối tượng ngay khi nó vừa được sinh ra.

Tài liệu tra cứu chính 

Đừng bao giờ quên “sách gối đầu giường” từ nhà phát hành:

  • Autodesk Maya Python Command Reference: Đây là bảng tra cứu mọi lệnh Python trong Maya.

    • Mẹo: Khi bạn dùng lệnh gì trên giao diện Maya, hãy nhìn vào Script Editor, sau đó lấy lệnh đó tra cứu trên trang này để biết các tham số (flags) đi kèm.

  • Maya Python API 2.0 Reference: Dành cho việc can thiệp sâu vào nhân của Maya với tốc độ xử lý nhanh hơn maya.cmds.

3. Cộng đồng hỗ trợ và Giải đáp

Khi gặp lỗi (bug) mà không tự giải quyết được, bạn nên tìm đến:

Việc học Python trong Maya (thường được gọi là Maya Python hay maya.cmds) yêu cầu các nguồn tài liệu kết hợp giữa tư duy lập trình và kiến thức về cấu trúc dữ liệu của phần mềm 3D.

Dưới đây là các trang web và nguồn học tập tốt nhất Các trang Web & Khóa học chuyên sâu (Tiếng Anh)

  • Zurbrigg: Đây là “tiêu chuẩn vàng” cho người mới bắt đầu. Tác giả giải thích cực kỳ cặn kẽ về Maya Python API và cách xây dựng công cụ (Tool Building). Video chất lượng, dễ hiểu ngay cả khi bạn chỉ mới biết Python cơ bản.

  • Chris Zurbrigg (Teachable): Nơi cung cấp các khóa học chuyên sâu hơn về PySide2/PyQt5 để thiết kế giao diện (UI) chuyên nghiệp trong Maya.

  • Alexander Richter (The Tech Art Tutorials): Tập trung vào quy trình làm việc thực tế trong các studio lớn (VFX/Games). Các bài viết ở đây giúp bạn hiểu cách Python vận hành trong một Pipeline sản xuất thực thụ.

  • Chad Vernon: Nếu bạn muốn tiến xa hơn vào việc viết Plugin bằng Maya API (C++ và Python), đây là địa chỉ không thể bỏ qua. Nội dung ở đây khá nâng cao, dành cho người muốn tối ưu hiệu suất vượt qua giới hạn của Script thông thường.

  • Jettelly: Cung cấp các hướng dẫn mang tính trực quan (Visual Guide), rất phù hợp cho những bạn xuất thân là Artist muốn tiếp cận lập trình mà không bị ngợp bởi các dòng code khô khan.

Python Code (Free)

Kiểm tra Vertex thừa | không kết nối :

Khi model bât kỳ một đối tượng nào, một khi bạn đã sử dụng các lệnh mặc định đã tích hợp trong Maya như : Boolean , Multi-Cut hoặc bạn chọn edge và delete .Thướng gây ra  lỗi , Edge đã bị delete nhưng Vertex vẫn còn , một sô vertex tự phát sinh rãi rác quanh viền cãnh đã được boolean , Vì vậy bạn sẽ gặp rắc rối khi dùng lệnh khác như Mesh smooth hoặc tiến hành UVW.

Đây là code python (Script tôi tự soạn để remoce tất cả các Vertex gây phiền phức đó . Các bạn có thể tham khảo nhé.Bạn có thể  xem hương dẫn cách để cho code này chạy theo link đển kênh Youtube của tôi.

    [import maya.cmds as cmds
import maya.mel as mel

def remove_isolated_vertices(mesh):
    count = 0
    try:
        total_verts = cmds.polyEvaluate(mesh, vertex=True)
        verts_to_delete = []

        for i in range(total_verts):
            vert = "{}.vtx[{}]".format(mesh, i)
            connected_edges = cmds.polyListComponentConversion(
                vert,
                fromVertex=True,
                toEdge=True
            )
            if not connected_edges:
                verts_to_delete.append(vert)
                count += 1

        if verts_to_delete:
            cmds.delete(verts_to_delete)
            print(">>> DA XOA: {} isolated vertices".format(count))

    except Exception as e:
        print("LOI:", e)

    return count


def remove_nonmanifold_vertices(mesh):
    count = 0
    try:
        cmds.select(mesh, replace=True)
        cmds.selectMode(component=True)
        cmds.selectType(vertex=True)

        mel.eval('polySelectConstraint -mode 3 -type 0x0001 -topology 2')
        nonmanifold_verts = cmds.ls(selection=True, flatten=True)
        mel.eval('polySelectConstraint -mode 0')

        if nonmanifold_verts:
            count = len(nonmanifold_verts)
            cmds.delete(nonmanifold_verts)
            print(">>> DA XOA: {} non-manifold vertices".format(count))

        cmds.selectMode(object=True)

    except Exception as e:
        print("LOI:", e)
        cmds.selectMode(object=True)

    return count


def remove_zero_length_edges_vertices(mesh):
    count = 0
    tolerance = 0.0001

    try:
        total_edges = cmds.polyEvaluate(mesh, edge=True)
        edges_to_delete = []

        for i in range(total_edges):
            edge = "{}.e[{}]".format(mesh, i)
            info = cmds.polyInfo(edge, edgeLength=True)

            if info:
                length = float(info[0].split(':')[-1].strip())
                if length < tolerance:
                    edges_to_delete.append(edge)

        if edges_to_delete:
            count = len(edges_to_delete)
            cmds.delete(edges_to_delete)
            print(">>> DA XOA: {} zero-length edges".format(count))

    except Exception as e:
        print("LOI:", e)

    return count


def merge_duplicate_vertices(mesh, distance=0.001):
    count = 0
    try:
        initial_verts = cmds.polyEvaluate(mesh, vertex=True)
        cmds.select(mesh, replace=True)

        cmds.polyMergeVertex(
            mesh,
            distance=distance,
            alwaysMergeTwoVertices=False,
            constructionHistory=False
        )

        final_verts = cmds.polyEvaluate(mesh, vertex=True)
        count = initial_verts - final_verts

        if count > 0:
            print(">>> DA MERGE: {} vertices".format(count))

    except Exception as e:
        print("LOI:", e)

    return count


def full_vertex_cleanup(mesh):
    print("\nCLEANUP:", mesh)

    results = {
        'merged': 0,
        'zero_edges': 0,
        'isolated': 0,
        'nonmanifold': 0
    }

    try:
        results['merged'] = merge_duplicate_vertices(mesh, 0.001)
        results['zero_edges'] = remove_zero_length_edges_vertices(mesh)
        results['isolated'] = remove_isolated_vertices(mesh)
        results['nonmanifold'] = remove_nonmanifold_vertices(mesh)

    except Exception as e:
        print("LOI:", e)

    return results


def main():
    selected = cmds.ls(selection=True, transforms=True)

    if not selected:
        all_transforms = cmds.ls(type='transform')
        selected = []
        for obj in all_transforms:
            shapes = cmds.listRelatives(obj, shapes=True, noIntermediate=True)
            if shapes and cmds.nodeType(shapes[0]) == 'mesh':
                selected.append(obj)

    if not selected:
        cmds.confirmDialog(
            title='Loi',
            message='Khong tim thay mesh',
            button=['OK']
        )
        return

    total_results = {
        'merged': 0,
        'zero_edges': 0,
        'isolated': 0,
        'nonmanifold': 0
    }

    for mesh in selected:
        shapes = cmds.listRelatives(mesh, shapes=True, noIntermediate=True)
        if not shapes or cmds.nodeType(shapes[0]) != 'mesh':
            continue

        results = full_vertex_cleanup(mesh)

        for k in total_results:
            total_results[k] += results[k]

    total_fixed = sum(total_results.values())

    if total_fixed > 0:
        cmds.confirmDialog(
            title='Hoan tat',
            message='DA SUA {} vertices'.format(total_fixed),
            button=['OK'],
            icon='information'
        )
    else:
        cmds.confirmDialog(
            title='Ket qua',
            message='Mesh sach se',
            button=['OK'],
            icon='information'
        )


main()
]