HEXA BLOG
ヘキサブログ
研究・開発
今日のMaya Python API 2.0
こんにちは
Houdini信者となった🎄ヨセミテ🎄です。ブログはMayaです。
Houdiniは最高なので皆さんもHoudiniを使いましょう。
―――――――――――――――――――――――――――――――――――――――
今回はAPI 2.0でノードプラグインを作成してみます。
ノードプラグインをAPI 2.0で作成したことは現状、全くありません。
理解不十分な点が随所で見受けられるかも知れませんが温かいまなざしで見守って下さい。
テンプレートは前回同様、Autodesk公式のヘルプページで配布してくれています。
呼びだし時の挙動などをコメントでメモしつつ、とりあえず動くものを目標に作成します。
今回はMPxNodeクラスを継承したクラスを作成してみます。
継承元の分類などは公式ドキュメントに詳細が載っています。
―――――――――――――――――――――――――――――――――――――――
以下スクリプトです。
内容としては接続された値に応じて接続先の移動値をsin波で出力するというもの。
現状では利用価値とかはほぼ皆無です。
# coding: UTF-8
# ブログ用 OpenMayAPI2.0を利用したノード作成のテスト
import sys
import maya.api.OpenMaya as om
import math
def maya_useNewAPI():
"""
このスクリプトはMayaプラグインの生産のためのもので、API2.0で利用しています。(英語翻訳)
説明用の項目かな?
"""
pass
# Plug-in information:
# サンプルのリンク先、Maya プラグイン エントリ/エグジット ポイント項目の各項目に詳細が記載
kPluginNodeName = 'blog_test_node' # ノードの名前(1.ノード名参照)
kPluginNodeClassify = 'utility/general' # ノードの分類(6.ノードの分類参照)
kPluginNodeId = om.MTypeId(0x07EFE) # ノードごとのユニークな値、MTypeIDを作成。(2.ノードID参照)
# 内部開発用のプラグインは[x00000 - 0x7ffff#」の範囲を指定することを推奨している模様。社内で管理しましょう。
# 各アトリビュートに初期値として入れてる値
sampleDefaultValue = 1
##########################################################
# Plug-in
##########################################################
class BlogTestNode(om.MPxNode):
# データハンドル設定用のMObject。computeメソッドにノード入出力先を受け渡すために利用されている
in_attribute_offset_x = om.MObject()
in_attribute_offset_y = om.MObject()
in_attribute_offset_z = om.MObject()
in_attribute_position_x = om.MObject()
in_attribute_position_y = om.MObject()
in_attribute_position_z = om.MObject()
out_attribute_result_x = om.MObject()
out_attribute_result_y = om.MObject()
out_attribute_result_z = om.MObject()
def __init__(self):
"""
コンストラクタ
"""
om.MPxNode.__init__(self)
def compute(self, pPlug, pDataBlock):
"""
:brief 計算処理用の関数(ノードの動作(Node Behavior参照)
mayaはMPlugの接続ごとにcomputeを呼び出して、MPlugとMDataBlock(接続先とデータ内容?)を受け渡して
ドキュメントに含まれている、「ダーティなプラグ」という表現は、
多分だがデータの関連性が正しくないものをさしていると思われる
:param pPlug 一つのノードアトリビュートに関連した接続先
:param pDataBlock 計算用のデータを含むもの
"""
# 出力が刺さっているときの処理をif分で追加していくみたい
if (pPlug == BlogTestNode.out_attribute_result_x or
pPlug == BlogTestNode.out_attribute_result_y or
pPlug == BlogTestNode.out_attribute_result_z):
# 各々のアトリビュートに対するデータハンドルの取得
in_offset_data_handle_x = pDataBlock.inputValue(BlogTestNode.in_attribute_offset_x)
in_offset_data_handle_y = pDataBlock.inputValue(BlogTestNode.in_attribute_offset_y)
in_offset_data_handle_z = pDataBlock.inputValue(BlogTestNode.in_attribute_offset_z)
in_position_data_handle_x = pDataBlock.inputValue(BlogTestNode.in_attribute_position_x)
in_position_data_handle_y = pDataBlock.inputValue(BlogTestNode.in_attribute_position_y)
in_position_data_handle_z = pDataBlock.inputValue(BlogTestNode.in_attribute_position_z)
out_result_data_handle_x = pDataBlock.outputValue(BlogTestNode.out_attribute_result_x)
out_result_data_handle_y = pDataBlock.outputValue(BlogTestNode.out_attribute_result_y)
out_result_data_handle_z = pDataBlock.outputValue(BlogTestNode.out_attribute_result_z)
# ======================= 計算式 =======================
result_x = math.sin(in_offset_data_handle_x.asFloat() + in_position_data_handle_x.asFloat())
result_y = math.sin(in_offset_data_handle_y.asFloat() + in_position_data_handle_y.asFloat())
result_z = math.sin(in_offset_data_handle_z.asFloat() + in_position_data_handle_z.asFloat())
# ======================================================
# 出力値を設定
out_result_data_handle_x.setFloat(result_x)
out_result_data_handle_y.setFloat(result_y)
out_result_data_handle_z.setFloat(result_z)
# データハンドルが正常な値であることの記載(?) 計算が不要であることの説明らしい
out_result_data_handle_x.setClean()
out_result_data_handle_y.setClean()
out_result_data_handle_z.setClean()
else:
# エラー時の処理。接続したのに接続先が見つからないときに呼び出されていた
return om.kUnknownParameter
##########################################################
# プラグインの定義
# クラス外にあるのね
##########################################################
def nodeCreator():
"""
createNode時に呼び出される場所
"""
return BlogTestNode()
def nodeInitializer():
"""
loadPluginを行った際に呼び出される模様
入出力アトリビュートセット作成するらしいのでここで全入出力を用意する
データハンドルの関連付けしなくてもここで定義しとけばとりあえずノード表面に入出力先として出てきた
"""
print("called nodeInitializer define")
# 同一のMFnNumericAttributeインスタンス内で複数の数値をもてるようだったので、
# インスタンスは書き込み可能などの設定別に分ければいいのだと思う
# …と思ったけどサンプルだとoutputでも使いまわしてた。とりあえず今回は設定ごとにインスタンスを作る
# 使いまわしはミス発生元案件な気がするけど沢山インスタンス作ると処理遅くなっちゃったりするんだろうか
MFnNAIns_input_offset = om.MFnNumericAttribute()
MFnNAIns_input_position = om.MFnNumericAttribute()
MFnNAIns_output_position = om.MFnNumericAttribute()
# 定数
default_value = 0.0
# ==================================
# 入力アトリビュート
# ==================================
# numericAttributeFn:ノード上への数値入力の出来るアトリビュート longName、shortName等を引数として与えている
BlogTestNode.in_attribute_offset_x = MFnNAIns_input_offset.create('offset_x', 'ox',
om.MFnNumericData.kFloat, default_value)
BlogTestNode.in_attribute_offset_y = MFnNAIns_input_offset.create('offset_y', 'oy',
om.MFnNumericData.kFloat, default_value)
BlogTestNode.in_attribute_offset_z = MFnNAIns_input_offset.create('offset_z', 'oz',
om.MFnNumericData.kFloat, default_value)
BlogTestNode.in_attribute_position_x = MFnNAIns_input_position.create('position_x', 'px',
om.MFnNumericData.kFloat, default_value)
BlogTestNode.in_attribute_position_y = MFnNAIns_input_position.create('position_y', 'py',
om.MFnNumericData.kFloat, default_value)
BlogTestNode.in_attribute_position_z = MFnNAIns_input_position.create('position_z', 'pz',
om.MFnNumericData.kFloat, default_value)
# アトリビュートの属性設定
# どうやら最後に作成したアトリビュートのみに適用されるみたい。インスタンス分けてない理由はこれか
# MFnNAIns_input_offset.connectable = False # 綺麗にかけていないので一旦コメントアウト
# 作成したアトリビュートを追加
BlogTestNode.addAttribute(BlogTestNode.in_attribute_offset_x)
BlogTestNode.addAttribute(BlogTestNode.in_attribute_offset_y)
BlogTestNode.addAttribute(BlogTestNode.in_attribute_offset_z)
BlogTestNode.addAttribute(BlogTestNode.in_attribute_position_x)
BlogTestNode.addAttribute(BlogTestNode.in_attribute_position_y)
BlogTestNode.addAttribute(BlogTestNode.in_attribute_position_z)
# ==================================
# OUTPUT NODE ATTRIBUTE(S)
# 出力アトリビュート
# ==================================
BlogTestNode.out_attribute_result_x = MFnNAIns_output_position.create('result_x', 'rx', om.MFnNumericData.kFloat)
MFnNAIns_output_position.writable = False # writeble = Falseを設定しないと出力ノードとして認識してくれない模様
BlogTestNode.out_attribute_result_y = MFnNAIns_output_position.create('result_y', 'ry', om.MFnNumericData.kFloat)
MFnNAIns_output_position.writable = False # 最後に作成したもののみに適用されるので何度も書いてる
BlogTestNode.out_attribute_result_z = MFnNAIns_output_position.create('result_z', 'rz', om.MFnNumericData.kFloat)
MFnNAIns_output_position.writable = False # 最後に作成したもののみに適用されるので何度も書いてる
# 作成したアトリビュートを追加
BlogTestNode.addAttribute(BlogTestNode.out_attribute_result_x)
BlogTestNode.addAttribute(BlogTestNode.out_attribute_result_y)
BlogTestNode.addAttribute(BlogTestNode.out_attribute_result_z)
# ==================================
# アトリビュートの依存関係(?)
# 恐らく計算処理の流れに関連する設定項目だと思う
# ==================================
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_offset_x, BlogTestNode.out_attribute_result_x)
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_offset_y, BlogTestNode.out_attribute_result_y)
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_offset_z, BlogTestNode.out_attribute_result_z)
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_position_x, BlogTestNode.out_attribute_result_x)
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_position_y, BlogTestNode.out_attribute_result_y)
BlogTestNode.attributeAffects(BlogTestNode.in_attribute_position_z, BlogTestNode.out_attribute_result_z)
# ここから下のイニシャライズ系はドキュメントで触れていなかったので、特殊な動作を必要としない現状は
# 触る必要性は無さそう
def initializePlugin(mobject):
''' Initialize the plug-in '''
# プラグインの初期化
mplugin = om.MFnPlugin(mobject)
try:
mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator,
nodeInitializer, om.MPxNode.kDependNode, kPluginNodeClassify)
except:
sys.stderr.write('Failed to register node: ' + kPluginNodeName)
raise
def uninitializePlugin(mobject):
''' Uninitializes the plug-in '''
# プラグインの停止
mplugin = om.MFnPlugin(mobject)
try:
mplugin.deregisterNode(kPluginNodeId)
except:
sys.stderr.write('Failed to deregister node: ' + kPluginNodeName)
raise
―――――――――――――――――――――――――――――――――――――――
画像だけだと判りづらいですが、触っているオブジェクトを動かすと接続先も動きます。うん、まぁ一応使えそうです。
作ってみたの感想ですが、
・最初からアトリビュートをノードエディタに表示させる方法がわからなかった
・アトリビュートごとに設定を書く必要があるので現状、そのまま書いてるだけだとかなり冗長
・アトリビュートをまとめる方法を判らないと接続が大変
と現状、実用には程遠いポンコツな出来です。
―――――――――――――――――――――――――――――――――――――――
1回分でまとまる量でもなかったので次回は整理しながらの書き方を模索しつつ
ちゃんと実用性を考えたノードを作成したいと思います。
では。🎄
CATEGORY
- about ヘキサ (166)
- 部活動 (6)
- CG (18)
- プロジェクトマネジメント (1)
- 研修 (5)
- 美学 (1)
- いいモノづくり道 (227)
- 採用 -お役立ち情報も- (149)
- プログラム (189)
- デザイン (99)
- ゲーム (273)
- 日記 (1,104)
- 書籍紹介 (113)
- その他 (891)
- 就活アドバイス (20)
- ラーメン (3)
- ライフハック (25)
- イベント紹介 (10)
- 料理 (23)
- TIPS (7)
- 怖い話 (3)
- サウンド (6)
- 子育て (1)
- 筋トレ (1)
- NicO (3)
- MakeS (9)
- 商品紹介 (21)
- アプリ紹介 (31)
- ソフトウェア紹介 (33)
- ガジェット紹介 (12)
- サイト紹介 (10)
- 研究・開発 (35)
- 回路図 (4)
- アナログゲーム (40)
- 交流会 (21)
- 報告会 (3)
- インフラ (25)
- グリとブラン (6)
- カメラ (9)
- クラフト (27)
- 部活 (14)
- 画伯 (15)
- カレー (6)
- 音楽(洋楽) (6)
- 映画・舞台鑑賞 (43)
- 飼育 (5)
- いぬ (8)
- ねこ (19)
ARCHIVE
- 2025年
- 2024年
- 2023年
- 2022年
- 2021年
- 2020年
- 2019年
- 2018年
- 2017年
- 2016年
- 2015年
- 2014年
- 2013年
- 2012年
- 2011年
- 2010年
- 2009年
- 2008年
- 2007年





