默认 tasks 是配置了三中不同编译的选项,如果注释掉两个的话,那就可以直接在 VScode 实现 ctrl+shift+b 实现编译并运行。 教程里面主要 IDE 环境是使用 VScode 搭建的,可能会有人困惑,why not VS。 我很久以前开发 Maya C++ 就是使用 VS 进行开发的,说实话,IDE 隐藏了太多细节,一旦出错,反而是无头苍蝇,无从查起。 知乎回答 当然也同其他回答说得也对,用什么工具都无所谓,关键是懂得 C++ 的整个编译流程。
C++ 是一门很复杂的语言,像我是从 Python 开始进阶编程的。 当我将 Python 很多用法摸透之后,进入到 Python 底层,发现 C++ 还很多底层的内容等待我去学习(:з」∠) 那上面的视频,比较系统地总结了 C++ 从入门到进阶的各个不同阶段地内容,学习 C++ 有很清晰的整体图谱。 当然视频里面其实是介绍作者推出的课程的~
from maya import cmds window = cmds.window() cmds.setUITemplate("OptionsTemplate", pushTemplate=1)
column_layout = cmds.columnLayout() parent = cmds.radioButtonGrp('artAttrColorChannelChoices',q=1,parent=1) for control in cmds.layout(parent,q=1,childArray=1): cmds.control(control, e=1, p=column_layout) cmds.setUITemplate(popTemplate=1) cmds.showWindow(window)
from maya import cmds window = cmds.window() cmds.setUITemplate("OptionsTemplate", pushTemplate=1)
column_layout = cmds.columnLayout() parent = cmds.radioButtonGrp('artAttrColorChannelChoices',q=1,parent=1) for control in cmds.layout(parent,q=1,childArray=1): cmds.control(control, e=1, p=column_layout) if control == "artAttrColorChannelChoices": cmds.button(label="click me") cmds.setUITemplate(popTemplate=1) cmds.showWindow(window)
for control in cmds.layout(parent,q=1,childArray=1): cmds.control(control, e=1, p=column_layout) if control == "artAttrColorChannelChoices": cmds.button(label="click me") cmds.setUITemplate(popTemplate=1)
from maya import OpenMayaRender OpenMayaRender.MUIDrawManager # Error: AttributeError: file <maya console> line 2: 'module' object has no attribute 'MUIDrawManager' # from maya.api import OpenMayaRender OpenMayaRender.MUIDrawManager
import shiboken2 import maya.OpenMaya as om import maya.OpenMayaUI as omui
from PySide2.QtWidgets import QWidget from PySide2.QtCore import QObject
defactive_view(): """ return the active 3d view """ return omui.M3dView.active3dView()
defactive_view_wdg(): """ return the active 3d view wrapped in a QWidget """ view = active_view() active_view_widget = shiboken2.wrapInstance(long(view.widget()), QWidget) return active_view_widget
defpaintEvent(self, event): self.draw_shape(self.create_brush_cricle(), QtCore.Qt.white, 2) if self.is_press_B: self.draw_shape(self.create_brush_line(), QtCore.Qt.white, 2) self.draw_text(self._message_info) for curve, data in self.color_data.items(): self.draw_shape(data.get("points"), data.get("colors"), 10)
> 上面是绘制用到的 一些 API > 核心就是 draw_shape 里面如果传入了多个 color ,获取color每个顶点画一条渐变的线 > 多条线组合成圆形,由此有了衰变颜色的圆形曲线。
> 其他的绘制比如 绘制文字,Qt 有 drawText API > 绘制圆圈可以利用 sincos 数学函数来生成圆形的顶点进行绘制。
### 踩坑注意
> QtCore.QPoint 和 OpenMaya.MPoint 两者的 Y 轴坐标起始不一样,所以通过 M3dView 将世界坐标转换为屏幕坐标的时候需要额外的处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
defworld_to_view(position, invertY=True): """ convert the given 3d position to 2d viewport coordinates """ view = OpenMayaUI.M3dView.active3dView() arg_x = OpenMaya.MScriptUtil(0) arg_y = OpenMaya.MScriptUtil(0)
这篇文章也是参考 sonictk 大佬的提供的 pyd 开发文章。 文章也提到之前的 hot reload 方案已经解决了很多 C++ 开发困难的问题。 然而还是有很多情况需要开发一个 python 的 C++ 模块实现 Maya C++ API 的 调用。 这个情况有点像是 Unreal 暴露 C++ API 到 Python 一样。
staticconstchar MAYA_PYTHON_C_EXT_DOCSTRING[] = "An example Python C extension that makes use of Maya functionality."; staticconstchar HELLO_WORLD_MAYA_DOCSTRING[] = "Says hello world!";
staticconstchar HELLO_WORLD_MAYA_DOCSTRING[] = "Says hello world!"; staticconstchar MAYA_PYTHON_C_EXT_DOCSTRING[] = "An example Python C extension that makes use of Maya functionality.";
# Import built-in modules from collections import defaultdict import json import os
# Import local modules import unreal
DIR = os.path.dirname(os.path.abspath(__file__))
defunreal_progress(tasks, label="进度", total=None): total = total if total elselen(tasks) with unreal.ScopedSlowTask(total, label) as task: task.make_dialog(True) for i, item inenumerate(tasks): if task.should_cancel(): break task.enter_progress_frame(1, "%s %s/%s" % (label, i, total)) yield item
# NOTE: 遍历命名为 Face 的 binding for binding in unreal_progress(binding_dict.get("Face", []), "导出 Face 数据"): # NOTE: 获取关键帧 channel 数据 keys_dict = {} for track in binding.get_tracks(): for section in track.get_sections(): for channel in unreal_progress(section.get_channels(), "导出关键帧"): ifnot channel.get_num_keys(): continue keys = [] for key in channel.get_keys(): frame_time = key.get_time() frame = frame_time.frame_number.value + frame_time.sub_frame keys.append({"frame": frame, "value": key.get_value()})
keys_dict[channel.get_name()] = keys
# NOTE: 导出 json name = binding.get_parent().get_name() export_path = os.path.join(DIR, "{0}.json".format(name)) withopen(export_path, "w") as wf: json.dump(keys_dict, wf, indent=4)
# Import built-in modules import json import os import traceback
# Import third-party modules import pymel.core as pm
DIR = os.path.dirname(os.path.abspath(__file__))
defprogress(seq, status="", title=""): pm.progressWindow(status=status, title=title, progress=0.0, isInterruptable=True) total = len(seq) for i, item inenumerate(seq): try: if pm.progressWindow(query=True, isCancelled=True): break pm.progressWindow(e=True, progress=float(i) / total * 100) yield item # with body executes here except: traceback.print_exc() pm.progressWindow(ep=1) pm.progressWindow(ep=1)
defmain():
# NOTE: 读取数据 withopen(os.path.join(DIR, "BP_metahuman_001.json"), "r") as rf: data = json.load(rf)
defmodule_cleanup(module_name): """Cleanup module_name in sys.modules cache. Args: module_name (str): Module Name """ if module_name in sys.builtin_module_names: return packages = [mod for mod in sys.modules if mod.startswith("%s." % module_name)] for package in packages + [module_name]: module = sys.modules.get(package) if module isnotNone: del sys.modules[package] # noqa:WPS420
defmodule_cleanup(module_name): """Cleanup module_name in sys.modules cache. Args: module_name (str): Module Name """ if module_name in sys.builtin_module_names: return packages = [mod for mod in sys.modules if mod.startswith("%s." % module_name)] for package in packages + [module_name]: module = sys.modules.get(package) if module isnotNone: del sys.modules[package] # noqa:WPS420
classCustomFinder(object): def__init__(self): self.submodule_search_locations = [] self.has_location = False self.origin = None defcreate_module(self, spec): return self.load_module(spec.name) defexec_module(self, module): """Execute the given module in its own namespace This method is required to be present by importlib.abc.Loader, but since we know our module object is already fully-formed, this method merely no-ops. """
classPinCode(fields.Field): """Field that serializes to a string of numbers and deserializes to a list of numbers. """
def_serialize(self, value, attr, obj, **kwargs): if value isNone: return"" return"".join(str(d) for d in value)
def_deserialize(self, value, attr, data, **kwargs): try: return [int(c) for c in value] except ValueError as error: raise ValidationError("Pin codes must contain only digits.") from error