ちょっと育児でバタバタしていたり、結構前に99%完成はしていたのに詳細は後述しますが
Mayaが落ちる致命的な挙動が解決できなかったりして、なかなか記事にできませんでしたが、
別のスクリプトを制作中にスクリプトのリファレンスを見ていて偶然その打開策を発見したので
ようやく記事にすることができました。
今回作ったのはSoftimageでは標準であった「選択しているオブジェクトの名前を
ディスプレイ上に表示する」という機能ですが、残念ながらMayaにはなかったので作ってみました。
ただ、Mirageさん(@MirageYM)が書いて下さったサンプルを元に拡張していっただけなんですけどもね・・・(;´∀`)
改めてMirageさん、サンプル大変参考になりました。ありがとうございました!
使い方は、まずこちらからファイルをDLしてもらい、Mayaのプラグインパスの通っている所(よく分からない方は C:\Users\ユーザー名\Documents\maya\2016\ja_JP\plug-ins など)にファイルを入れて下さい。
Mayaを起動して、メインメニュー>ウィンドウ>プラグインマネージャー を開いてその中のkkDisplaySelectedNameのロードのチェックをONにして下さい。
そうすると、メインメニュー>ディスプレイ の一番下にDisplay Selected Nameが追加されていると思います。
(※もしプラグインマネージャーに表示されていない場合はプラグインのファイルを置く場所がパス通ってないか、
もしくはプラグインのTypeIdが他のモノと被っている可能性があるのでコードの18行目を 0xF0F0F1 とは違うものに変えてみて下さい。)
さらにそこのチェックボックスをONにするとONになっている場合のみ、
選択したオブジェクトの名前がディスプレイ上に表示されるようになります。
モノによってはその表示される名前の色が見づらい場合があると思います。
その場合は先程のDisplay Selected Nameメニューの右側の四角いボックスをクリックしてもらうと
色変更のメニューが出てきますのでお好きな色に変更して下さい。
このDisplay Selected NameメニューのONOFFをショートカットで変更したい方は
ホットキーエディタに下記のように登録して下さい。
これだけでONOFFをトグルできます。
import maya.cmds as mc
dsn = "MayaWindow|mainDisplayMenu|DisplaySelectedName"
if(mc.menuItem(dsn, exists=True)):
mc.menuItem(dsn, e=True, checkBox = not mc.menuItem(dsn, q=True, checkBox=True))
コードはDLして見てもらってもいいのですが、一応こちらにも載せておきます。
簡単に処理内容を言いますと、SelectionChangedイベントのscriptJobに、
「専用ノード生成しそれに選択したオブジェクトの名前をセットしてペアレントコンストレイントする」
というのを登録しています。
冒頭で書いたMayaが落ちてしまうのを回避できた解決策は
265行目のscriptJobの登録時にcompressUndoフラグをTrueにしたことです。(+UndoInfo)
これがないときは選択したオブジェクトがdeleteされていた場合にUndoすると削除されてもう存在しないモノに
名前を表示するノードを作ろうとしたためか落ちたり、逆にこのスクリプトの挙動がUndoに残ってしまい戻れなくなるなど起きていました。
一応今の状態でプリミティブのキューブ1000個全選択して、
名前を表示し終わるまでの時間を計測した所、平均0.8秒でした。
(※Maya2016 : CPU Corei7-4790K : GPU GeForce GTX 980 で計測)
undoInfoのopenChunk/closeChunkで多少早くはなっていますが、
もっと処理が早くなりそうな書き方をご存知の方いらっしゃいましたらご教授下さい。
あと、色々と自分でも試してはいますが、
不具合が出ても責任は取れませんので自己責任でお試し下さい。
(ちなみに2016でしか試せていませんがたぶん他のバージョンでも大丈夫かと…)
# -*- coding: utf-8 -*-
import sys
import maya.api.OpenMaya as om2
import maya.api.OpenMayaUI as om2u
import maya.api.OpenMayaRender as om2r
import maya.cmds as mc
maya_useNewAPI = True
#===============================================================
class kkDisplaySelectedNameNode( om2u.MPxLocatorNode ):
kPluginNodeTypeName = "kkDisplaySelectedNameNode"
# TypeIdは適当な番号 (0x00000000以上、0x0007ffff以下で指定。他のプラグインとかぶってはいけない)
NodeId = om2.MTypeId( 0xF0F0F1 )
# ノードがDrawOverrideを使うためにはOverrideをMayaに登録しておく必要がある。以下2つはそのためのID
classfication = 'drawdb/geometry/kkDisplaySelectedName'
registrantId = 'kkDisplaySelectedNamePlugin'
# ノードのアトリビュート。aStringにセットした文字列が描画される
aString = om2.MObject()
ColorR = om2.MObject()
ColorG = om2.MObject()
ColorB = om2.MObject()
#===============================================================
def __init__( self ):
om2u.MPxLocatorNode.__init__( self )
#===============================================================
def draw( self, view, path, style, status ):
pass
#===============================================================
def isBounded( self ):
return True
#===============================================================
def boundingBox( self ):
return om2.MBoundingBox( om2.MPoint( -0.5, -0.5, -0.5 ), om2.MPoint( 0.5, 0.5, 0.5 ) )
#===============================================================
# creator
@staticmethod
def nodeCreator():
return kkDisplaySelectedNameNode()
#===============================================================
# initializer
@staticmethod
def nodeInitializer():
fnTypedAttr = om2.MFnTypedAttribute()
fnNumericAttr1 = om2.MFnNumericAttribute()
fnNumericAttr2 = om2.MFnNumericAttribute()
fnNumericAttr3 = om2.MFnNumericAttribute()
kkDisplaySelectedNameNode.aString = fnTypedAttr.create( "String", "str", om2.MFnData.kString )
kkDisplaySelectedNameNode.addAttribute( kkDisplaySelectedNameNode.aString )
kkDisplaySelectedNameNode.ColorR = fnNumericAttr1.create( "ColorR", "colR", om2.MFnNumericData.kFloat, 1.0 )
kkDisplaySelectedNameNode.addAttribute( kkDisplaySelectedNameNode.ColorR )
kkDisplaySelectedNameNode.ColorG = fnNumericAttr2.create( "ColorG", "colG", om2.MFnNumericData.kFloat, 1.0 )
kkDisplaySelectedNameNode.addAttribute( kkDisplaySelectedNameNode.ColorG )
kkDisplaySelectedNameNode.ColorB = fnNumericAttr3.create( "ColorB", "colB", om2.MFnNumericData.kFloat, 1.0 )
kkDisplaySelectedNameNode.addAttribute( kkDisplaySelectedNameNode.ColorB )
return True
#===============================================================
class UserData( om2.MUserData ):
"""
DrawOverrideにユーザー定義の情報を供給する為のデータ構造
"""
#===============================================================
def __init__( self ):
om2.MUserData.__init__( self, False )
self.datas = []
#===============================================================
class api_annotationLoc2Override( om2r.MPxDrawOverride ):
"""
注釈のDrawOverride
"""
#===============================================================
def __init__( self, obj ):
om2r.MPxDrawOverride.__init__( self, obj, api_annotationLoc2Override.draw )
#===============================================================
@staticmethod
def draw( context, data ):
pass
#===============================================================
def supportedDrawAPIs( self ):
"""
OpenGLとDirextX11をサポート
"""
return om2r.MRenderer.kOpenGL | om2r.MRenderer.kDirectX11
#===============================================================
def hasUIDrawables( self ):
"""
addUIDrawablesを使うために必要
"""
return True
#===============================================================
def isBounded( self, objPath, cameraPath ):
return True
#===============================================================
def boundingBox( self, objPath, cameraPath ):
bbox = om2.MBoundingBox( om2.MPoint( -0.5, -0.5, -0.5 ),
om2.MPoint( 0.5, 0.5, 0.5 ) )
return bbox
#===============================================================
def disableInternalBoundingBoxDraw( self ):
return True
#===============================================================
def prepareForDraw( self, objPath, cameraPath, frameContext, oldData ):
# ロケーターからアトリビュートを読んでUserDataとして返す
if( objPath ):
newData = None
# oldDataがあった場合はoldDataをnewDataに入れて、UserDataのdatasを初期化する
if( oldData ):
newData = oldData
newData.datas = []
else:
newData = UserData()
thisNode = objPath.node()
fnNode = om2.MFnDependencyNode( thisNode )
strPlug = fnNode.findPlug( 'String', False )
colRPlug = fnNode.findPlug( 'ColorR', False )
colGPlug = fnNode.findPlug( 'ColorG', False )
colBPlug = fnNode.findPlug( 'ColorB', False )
# asStringやasFloatがget関数
newData.datas.append( strPlug.asString() )
newData.datas.append( colRPlug.asFloat() )
newData.datas.append( colGPlug.asFloat() )
newData.datas.append( colBPlug.asFloat() )
return newData
return None
#===============================================================
def addUIDrawables( self, objPath, drawManager, frameContext, data ):
# UI描画。MUIDrawManagerを使うことで簡単なライン描画とかもできる
if( data ):
drawManager.beginDrawable()
dColor = om2.MColor()
dColor[0] = mc.optionVar(q = "kkDisplaySelectedName_ColorR") #data.datas[1] #Red
dColor[1] = mc.optionVar(q = "kkDisplaySelectedName_ColorG") #data.datas[2] #Green
dColor[2] = mc.optionVar(q = "kkDisplaySelectedName_ColorB") #data.datas[3] #Blue
drawManager.setColor( dColor )
drawManager.setFontSize( om2r.MUIDrawManager.kDefaultFontSize )
drawManager.text( om2.MPoint( 0.5, 0.5 ), data.datas[0] )
drawManager.endDrawable()
return True
#===============================================================
# creator
@staticmethod
def creator( obj ):
return api_annotationLoc2Override( obj )
#===============================================================
def changeColorUI(*args):
if mc.window("dispSelName_ColorWin", exists=True):
mc.deleteUI("dispSelName_ColorWin")
mc.window("dispSelName_ColorWin", title='Colors' )
mc.columnLayout()
mc.colorInputWidgetGrp("dispSelName_ColorInpWG",
label='Color',
rgb=(1, 1, 1),
changeCommand = changeColorAttr
)
mc.showWindow()
def changeColorAttr(*args):
changCol = mc.colorInputWidgetGrp("dispSelName_ColorInpWG", q=True, rgbValue=True)
if mc.optionVar(exists = "kkDisplaySelectedName_ColorR") == True:
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorR", changCol[0]])
if mc.optionVar(exists = "kkDisplaySelectedName_ColorG") == True:
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorG", changCol[1]])
if mc.optionVar(exists = "kkDisplaySelectedName_ColorB") == True:
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorB", changCol[2]])
try:
annotateList = om2.MGlobal.getSelectionListByName("kkDisplaySelectedNameNode*")
for x in range(annotateList.length()):
annotateDepNode = om2.MFnDependencyNode().setObject( annotateList.getDependNode(x) )
colR = annotateDepNode.findPlug('ColorR', False )
colG = annotateDepNode.findPlug('ColorG', False )
colB = annotateDepNode.findPlug('ColorB', False )
colR.setFloat( changCol[0] )
colG.setFloat( changCol[1] )
colB.setFloat( changCol[2] )
except:
pass
#===============================================================
# initialize the script plug-in
def initializePlugin( obj ):
mplugin = om2.MFnPlugin( obj )
try:
# Overrideを使うためにはオーバーロードされた専用のredisterNode関数を使う必要がある
mplugin.registerNode( kkDisplaySelectedNameNode.kPluginNodeTypeName,
kkDisplaySelectedNameNode.NodeId,
kkDisplaySelectedNameNode.nodeCreator,
kkDisplaySelectedNameNode.nodeInitializer,
om2.MPxNode.kLocatorNode,
kkDisplaySelectedNameNode.classfication
)
# DrawOverride登録
om2r.MDrawRegistry.registerDrawOverrideCreator( kkDisplaySelectedNameNode.classfication,
kkDisplaySelectedNameNode.registrantId,
api_annotationLoc2Override.creator
)
# ディスプレイメニューに追加 チェックボックスはデフォルトOFF
mc.menuItem("DisplaySelectedName",
label="Display Selected Name",
checkBox=False,
parent="MayaWindow|mainDisplayMenu"
)
mc.menuItem(optionBox = True,
command = changeColorUI,
parent="MayaWindow|mainDisplayMenu"
)
mc.scriptJob( event = ["SelectionChanged", createAnnotation] , compressUndo=True)
# optionVarに文字カラー用の変数を作成
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorR", 1])
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorG", 1])
mc.optionVar(intValue = ["kkDisplaySelectedName_ColorB", 1])
except:
sys.stderr.write( "Failed to register node: %s" % kkDisplaySelectedNameNode.kPluginNodeTypeName )
raise
#===============================================================
# uninitialize the script plug-in
def uninitializePlugin( obj ):
mplugin = om2.MFnPlugin( obj )
try:
mplugin.deregisterNode( kkDisplaySelectedNameNode.NodeId )
om2r.MDrawRegistry.deregisterDrawOverrideCreator( kkDisplaySelectedNameNode.classfication,
kkDisplaySelectedNameNode.registrantId
)
if mc.menuItem("MayaWindow|mainDisplayMenu|DisplaySelectedName", exists=True):
mc.deleteUI("MayaWindow|mainDisplayMenu|DisplaySelectedName", menuItem=True)
mc.undoInfo(stateWithoutFlush=False)
mc.delete( mc.ls( 'annotationDSN_*' ) )
mc.undoInfo(stateWithoutFlush=True)
# optionVarから文字カラー用の変数を削除
mc.optionVar(remove="kkDisplaySelectedName_ColorR")
mc.optionVar(remove="kkDisplaySelectedName_ColorR")
mc.optionVar(remove="kkDisplaySelectedName_ColorR")
jobList = mc.scriptJob(listJobs=True)
jobNum = 0
for job in jobList :
# ジョブリストから登録したジョブの内容を検索する
# 単純にそのインデックスを使えばいいと思ったら
# インデックスとジョブ番号が違うことがあるのでスライスで取得する
if 'conditionTrue = ["SomethingSelected", createAnnotation]' in job :
jobNum = job [0 : job .find(":")]
# 上の処理でjobNumに数値が入っていたらそのスクリプトジョブを停止させる
if jobNum > 0:
print("killing_jobNum__%s " %jobNum)
mc.scriptJob( kill=jobNum, force=True)
print(" Unload >> old_kDisplaySelName Plugin ")
except:
sys.stderr.write( "Failed to deregister node: %s" % kkDisplaySelectedNameNode.kPluginNodeTypeName )
raise
#=======================================================================================================================
def createAnnotation( *args ):
try:
# Undoのチャンクを開く. これをすることで速度が早くなる
mc.undoInfo(openChunk=True)
# すでに annotationDSN_ が付いているものがある場合、削除しておく
annotationList = mc.ls( "annotationDSN_*" )
if len( annotationList ) > 0:
mc.delete( annotationList )
if mc.menuItem("MayaWindow|mainDisplayMenu|DisplaySelectedName", q=True, checkBox=True):
# 選択しているリスト
selList = om2.MGlobal.getActiveSelectionList()
if selList.length() > 0:
# Transformのみのフィルターをする
selListIter = om2.MItSelectionList(selList, om2.MFn.kTransform)
while not selListIter.isDone():
mObj2 = selListIter.getDependNode()
selDagFn = om2.MFnDagNode( mObj2 )
if not "annotationDSN" in selDagFn.name():
ant = mc.createNode("kkDisplaySelectedNameNode")
antDagPath = om2.MGlobal.getSelectionListByName( ant ).getDagPath(0)
antDagFn = om2.MFnDagNode( antDagPath )
antParent = om2.MFnDependencyNode().setObject( antDagFn.parent(0) )
antStrPlug = antDagFn.findPlug( 'String', False )
antStrPlug.setString( selDagFn.name() )
dgmf = om2.MDGModifier()
dgmf.renameNode(antDagFn.parent(0), "annotationDSN_1")
dgmf.doIt()
mc.parentConstraint(selDagFn.fullPathName(), antParent.name(), skipRotate="none")
selListIter.next()
# 選択をオブジェクトに戻す
om2.MGlobal.setActiveSelectionList(selList)
except Exception as e:
print(e.args)
pass
finally:
# Undoのチャンクを閉じる
mc.undoInfo(closeChunk=True)

コメントをお書きください
aaa (火曜日, 22 1月 2019 10:28)
2018で動かず。
ブログ管理者 (月曜日, 29 4月 2019 01:23)
aaaさん、ご返信遅くなり大変申し訳無いです。
2018では試せてないのですが、2019では問題なく動くのを確認できました。
もし宜しければ、もう少し動かなかったaaaさんの実行環境の状況(Mayaの2018のUpdateのバージョンいくつだとか、プリファレンス>ディスプレイのレンダリングエンジンの設定など)を教えてもらえますでしょうか?
Velciraal (火曜日, 26 5月 2026 18:55)
モンクレール コピー 激安は、この専門店の販売ラインにおいて、手に取りやすい価格帯と高品質な仕上がりを同時に実感できる点で高い評価を集めています。激安という条件でありながら、全体の完成度は非常に整っており、細部に至るまで自然な見え方が意識された設計がなされています。視覚的なバランスや統一感も優良なレベルで維持されており、日常の中に無理なく溶け込む上質感を楽しむことができます。この専門店ならではの厳選されたラインナップは、再現性の高さを重視しており、見た目の印象においても安心感があります。通販でも選びやすく、画像から伝わる完成度の高さが選択のしやすさにつながっている点も魅力です。また、偽物という言葉にとらわれず、あくまで仕上がりと再現性を基準に評価することで、この専門店で選ぶ価値がより明確に感じられます。価格を抑えつつもここまでの完成度を実現している点は、多くの利用者に支持される理由となっています。
アルバムのURL:
https://www.aaakopi.com/category-298-b16.html モンクレール コピー 激安
https://www.levelkopi.jp/b-kopi_moncler.html モンクレール コピー Tシャツ
https://www.forkopi.jp/brand/alexander-wang-copy/ アレキサンダーワンコピー
https://lunavex.hamazo.tv/