Es ist leicht, den Workflow für die Implementierung benutzerdefinierter Knoten in Maya zu vergessen, daher schreibe ich ihn als Erinnerung.
Dieses Mal werde ich einen Knoten mit einfacher Eingabe / Ausgabe, einen Knoten, der Arrays verarbeiten kann, und einen Knoten, der zusammengesetzte Attribute verarbeiten kann, vorstellen und schließlich einen Knoten erstellen, der die Mittelpositionen mehrerer Punkte ausgibt.
Informationen zu benutzerdefinierten Knoten (Abhängigkeitsknoten, Knoten mit Eingabe / Ausgabe) finden Sie auf den folgenden offiziellen Seiten. Grundlagen des Abhängigkeitsdiagramm-Plugins Abhängigkeitsdiagramm-Plugin
Zumindest im Drehbuch
Eine leere Funktion, die Sie auffordert, die Maya Python API 2.0 zu verwenden Wenn Sie eine Funktion namens "maya_useNewAPI ()" definieren, können Sie klar angeben, dass API 2.0 auf der Maya-Seite verwendet wird.
Plugin-Ein- / Ausstiegspunkte Sie müssen "initializePlugin (mobject)" und "uninitializePlugin (mobject)" aufrufen, wenn Sie das Plugin laden und beenden. Hier definieren wir ** Knotenname **, ** Knoten-ID **, ** die folgenden 4/5 Funktionen **, ** Knotentyp **, ** Knotenklassifizierung ** (siehe unten).
Erstellen Sie eine Funktion, die eine Instanz des Knotens zurückgibt
Funktion, die die Attribute des Knotens initialisiert
Knotenkörperklasse
Wird benötigt werden.
Der Beispielknoten, den ich tatsächlich geschrieben habe, ist wie folgt. Es ist ein Knoten, der den im Eingabeattribut eingegebenen Float-Wert mit der sin-Funktion multipliziert und vom Ausgabeattribut ausgibt. Ich werde eins nach dem anderen erklären.
# -*- coding: utf-8 -*-
import maya.api.OpenMaya as om
import maya.api.OpenMayaUI as omui
import math, sys
# Maya API 2.Für die Verwendung von 0 erforderliche Funktionen
def maya_useNewAPI():
pass
#Tatsächliche Klasse
class sampleNode(om.MPxNode):
id = om.MTypeId(0x7f001) #Eindeutige ID https://download.autodesk.com/us/maya/2011help/API/class_m_type_id.html
input = om.MObject()
output = om.MObject()
#Methode zum Zurückgeben einer Instanz
@staticmethod
def creator():
return sampleNode()
#Methode, die Maya bei der Initialisierung aufgerufen hat
#Attribute festlegen
@staticmethod
def initialize():
#Attribute werden mit der create-Methode einer Unterklasse der MFnAttribute-Klasse definiert.
nAttr = om.MFnNumericAttribute()
sampleNode.input = nAttr.create(
'input', 'i', om.MFnNumericData.kFloat, 0.0)
nAttr.storable = True
nAttr.writable = True
nAttr = om.MFnNumericAttribute()
sampleNode.output = nAttr.create('output', 'o', om.MFnNumericData.kFloat, 0.0)
nAttr.storable = True
nAttr.writable = True
#Führen Sie nach dem Definieren addAttribute von MPxNode aus
sampleNode.addAttribute(sampleNode.input)
sampleNode.addAttribute(sampleNode.output)
#Stellen Sie außerdem den Ausgang so ein, dass er neu berechnet wird, wenn der Eingang geändert wird.
sampleNode.attributeAffects( sampleNode.input, sampleNode.output)
#Der Konstruktor ruft den übergeordneten Konstruktor auf
def __init__(self):
om.MPxNode.__init__(self)
#Eine Methode, die von Maya aufgerufen wird, wenn der Wert eines Attributs berechnet wird
def compute(self, plug, dataBlock):
if(plug == sampleNode.output):
dataHandle = dataBlock.inputValue(sampleNode.input)
inputFloat = dataHandle.asFloat()
result = math.sin(inputFloat) * 10.0
outputHandle = dataBlock.outputValue(sampleNode.output)
outputHandle.setFloat(result)
dataBlock.setClean(plug)
# http://help.autodesk.com/view/MAYAUL/2016/ENU/
# api1.0 bedeutet MStatus, es sei denn, Sie weisen uns ausdrücklich an, den Stecker nicht zu verarbeiten.kUnknownParameter wird nicht zurückgegeben
# api2.Bei 0 gibt es überhaupt keinen MStatus, sodass Sie ihn ignorieren können.
#Eine von Maya aufgerufene Funktion, die einen neuen Knoten registriert
def initializePlugin(obj):
mplugin = om.MFnPlugin(obj)
try:
mplugin.registerNode('sampleNode', sampleNode.id, sampleNode.creator,
sampleNode.initialize, om.MPxNode.kDependNode)
except:
sys.stderr.write('Faled to register node: %s' % 'sampleNode')
raise
#Von Maya beim Beenden des Plug-Ins aufgerufene Funktionen
def uninitializePlugin(mobject):
mplugin = om.MFnPlugin(mobject)
try:
mplugin.deregisterNode(sampleNode.id)
except:
sys.stderr.write('Faled to uninitialize node: %s' % 'sampleNode')
raise
Zuerst aus der Klassendefinition
class sampleNode(om.MPxNode):
id = om.MTypeId(0x7f001) #Eindeutige ID https://download.autodesk.com/us/maya/2011help/API/class_m_type_id.html
input = om.MObject()
output = om.MObject()
Entscheiden Sie die ID des Plug-Ins. Weitere Informationen finden Sie unter Autodesk-Site. Normalerweise können Sie jedoch einen beliebigen Wert von 0x00000 bis 0x verwenden. Ich werde. Und ich habe die Eingabe- und Ausgabeattribute als Klassenfeld "intput" "output" vorbereitet.
#Methode zum Zurückgeben einer Instanz
@staticmethod
def creator():
return sampleNode()
Eine Funktion, die eine Instanz eines Knotens erstellt. Sie können es außerhalb der Klasse schreiben, aber dieses Mal habe ich es als statische Methode der Klasse geschrieben.
#Methode, die Maya bei der Initialisierung aufgerufen hat
#Attribute festlegen
@staticmethod
def initialize():
#Attribute werden mit der create-Methode einer Unterklasse der MFnAttribute-Klasse definiert.
nAttr = om.MFnNumericAttribute()
sampleNode.input = nAttr.create(
'input', 'i', om.MFnNumericData.kFloat, 0.0)
nAttr.storable = True
nAttr.writable = True
nAttr = om.MFnNumericAttribute()
sampleNode.output = nAttr.create('output', 'o', om.MFnNumericData.kFloat, 0.0)
nAttr.storable = True
nAttr.writable = True
#Führen Sie nach dem Definieren addAttribute von MPxNode aus
sampleNode.addAttribute(sampleNode.input)
sampleNode.addAttribute(sampleNode.output)
#Stellen Sie außerdem den Ausgang so ein, dass er neu berechnet wird, wenn der Eingang geändert wird.
sampleNode.attributeAffects( sampleNode.input, sampleNode.output)
Dies ist der Teil, der in der vorherigen Liste "4. Funktionen zum Initialisieren von Knotenattributen" entspricht. Sie können es außerhalb der Klasse schreiben, aber es ist überladen, deshalb habe ich es als statische Methode geschrieben. Attribute werden unter Verwendung der entsprechenden Unterklassen der Klasse "MFnAttribute" definiert. Diesmal ist es ein Float-Wert, daher verwende ich "MFnNumericAttribute". Dreidimensionale Gleitkommawerte (Koordinaten usw.) und Bool-Werte sind ebenfalls dieses "MFnNumericAttribute". Den Winkel, die Entfernung und die Zeit finden Sie in "MFnUnitAttribute", die Matrix in "MFnMatrixAttribute" und die anderen in der folgenden Referenz. MFnAttribute Class Reference OpenMaya.MFnAttribute Class Reference
Geben Sie den Attributnamen, die Abkürzung, den Typ und den Anfangswert mit nAttr.create
an.
Ob nAttr.storable
den Wert des Attributs in die Sicherungsdatei schreibt. Es gibt andere Eigenschaften wie "beschreibbar" und "lesbar". Stellen Sie sie daher entsprechend ein.
sampleNode.addAttribute (sampleNode.input)
Fügt das erstellte Attribut dem Knoten hinzu.
sampleNode.attributeAffects (sampleNode.input, sampleNode.output)
Wenn sich der Wert des Eingabeattributs ändert, wird das Ausgabeattribut aktualisiert.
#Eine Methode, die von Maya aufgerufen wird, wenn der Wert eines Attributs berechnet wird
def compute(self, plug, dataBlock):
if(plug == sampleNode.output):
dataHandle = dataBlock.inputValue(sampleNode.input)
inputFloat = dataHandle.asFloat()
result = math.sin(inputFloat) * 10.0
outputHandle = dataBlock.outputValue(sampleNode.output)
outputHandle.setFloat(result)
dataBlock.setClean(plug)
Die Berechnungsmethode ist die Methode, die aufgerufen wird, wenn die Berechnung abgeschlossen ist. Dieser Knoten berechnet Sin. Der Wert wird in Form eines Steckers übergeben. Weitere Informationen zu Steckern finden Sie in der Autodesk-Hilfe. Es ist lang, weil der DataBlock ein Handle benötigt, um die Eingabe abzurufen und der Ausgabe zuzuweisen, aber tatsächlich wird nur die Sin-Funktion berechnet.
#Eine von Maya aufgerufene Funktion, die einen neuen Knoten registriert
def initializePlugin(obj):
mplugin = om.MFnPlugin(obj)
try:
mplugin.registerNode('sampleNode', sampleNode.id, sampleNode.creator,
sampleNode.initialize, om.MPxNode.kDependNode)
except:
sys.stderr.write('Faled to register node: %s' % 'sampleNode')
raise
Ein Einstiegspunkt außerhalb der Klasse. Geben Sie den Knotennamen und die ID, die in der Klasse definierte Instanzmethode und den Knotentyp an.
Laden Sie das Skript, das Sie aus Mayas Plug-in-Manager erstellt haben. Erstellen Sie einen Knoten mit "cmds.createNode (" sampleNode ")" oder "cmds.shadingNode (" sampleNode ", asUtility = True)" in Mayas Befehlszeile oder Skripteditor. Wenn Sie es mit letzterem erstellt haben, wird Ihr eigener Knoten auf der Registerkarte "Dienstprogramme" im Hypershade-Fenster angezeigt.
Es gibt zwei Methoden: Die eine besteht darin, die Array-Daten als ein Attribut mit dem Plug zu verbinden, und die andere darin, den ** Array-Plug ** zu verwenden, in dem der Plug selbst ein Array ist.
Ändern Sie die Attributdefinition in der Methode "initialize" früher wie folgt. Sie können "nAttr.array = True" sehen, aber Sie können "-nextAvailable" mit dem Befehl "connectAttr" verwenden, indem Sie "nAttr.indexMatters = False" auf "False" setzen. Im Gegenteil, wenn es True ist, muss anscheinend der einzufügende Index angegeben werden.
@staticmethod
def initialize():
nAttr = om.MFnNumericAttribute()
sampleArrayNode.input = nAttr.create(
'input', 'i', om.MFnNumericData.kFloat, 0.0)
nAttr.storable = True
nAttr.writable = True
nAttr.readable = True
nAttr.array = True #hinzufügen
nAttr.indexMatters = False #hinzufügen
Als nächstes die Berechnungsmethode, die die eigentliche Berechnung übernimmt. Dieses Mal wird der Gesamtwert des Eingabearrays ausgegeben.
def compute(self, plug, dataBlock):
arrayDataHandle = dataBlock.inputArrayValue(
sampleArrayNode.input
)
sum = 0
while not arrayDataHandle.isDone():
handle = arrayDataHandle.inputValue()
v = handle.asFloat()
sum += v
arrayDataHandle.next()
outhandle = dataBlock.outputValue( sampleArrayNode.output )
outhandle.setFloat(sum)
dataBlock.setClean(plug)
Wenn Sie einen Array-Plug verwenden, rufen Sie den "MArrayDataHandle" einmal mit "inputArrayValue" anstelle von "inputValue" ab. Da dies ein Iterator ist, erweitern Sie den Iterator mit "next ()" oder "jumpToLogicalElement ()" und ermitteln Sie den Wert des Elements des Arrays mit "arrayDataHandle.inputValue ()". Danach wird es in einen numerischen Wert umgewandelt und wie ein normaler Stecker berechnet.
↑ Die Konstante 1 + 2 + 3 + 4 = 10 wurde korrekt berechnet.
Ein zusammengesetztes Attribut ist eine Sammlung mehrerer Attribute. Komplexe dynamische Attribute ](https://help.autodesk.com/view/MAYAUL/2016/JPN/?guid=__files_Dependency_graph_plugins_Complex_Attributes_htm) In diesem Beispiel werden "Koordinaten und Gewichte" als zusammengesetzte Attribute und als Array-Stecker verwendet.
Es sieht aus wie das Bild unten im Knoteneditor. Die Implementierung des Klassenteils ist wie folgt. Die Einstiegspunkte usw. sind die gleichen wie im vorherigen Code (weggelassen).
class sampleArrayNode(om.MPxNode):
#Eindeutige ID https://download.autodesk.com/us/maya/2011help/API/class_m_type_id.html
id = om.MTypeId(0x7f011)
input = om.MObject()
output = om.MObject()
#Untergeordnete Attribute
position = om.MObject()
weight = om.MObject()
#Methode zum Zurückgeben einer Instanz
@staticmethod
def creator():
return sampleArrayNode()
#Methode, die Maya bei der Initialisierung aufgerufen hat
#Attribute festlegen
@staticmethod
def initialize():
#Untergeordnete Attribute
#Koordinate
nAttr = om.MFnNumericAttribute()
sampleArrayNode.position = nAttr.create(
'position', 'pos', om.MFnNumericData.k3Float, 0
)
nAttr.readable = True
#Gewicht
nAttr = om.MFnNumericAttribute()
sampleArrayNode.weight = nAttr.create(
'weight', 'w', om.MFnNumericData.kFloat, 1
)
nAttr.readable = True
nAttr.setMax(1) # Min,Max kann auch angegeben werden
nAttr.setMin(0)
#Zusammengesetzte Attribute
nAttr = om.MFnCompoundAttribute()
sampleArrayNode.input = nAttr.create(
'input', 'i')
nAttr.readable = True
nAttr.array = True
nAttr.indexMatters = False
nAttr.addChild(sampleArrayNode.position)
nAttr.addChild(sampleArrayNode.weight)
#Die Ausgabe sind diesmal die Koordinaten (3D Float)
nAttr = om.MFnNumericAttribute()
sampleArrayNode.output = nAttr.create(
'output', 'o', om.MFnNumericData.k3Float)
nAttr.storable = True
nAttr.writable = True
nAttr.readable = True
#Führen Sie nach dem Definieren addAttribute von MPxNode aus
sampleArrayNode.addAttribute(sampleArrayNode.input)
sampleArrayNode.addAttribute(sampleArrayNode.output)
#Stellen Sie außerdem den Ausgang so ein, dass er neu berechnet wird, wenn der Eingang geändert wird.
sampleArrayNode.attributeAffects(
sampleArrayNode.input, sampleArrayNode.output)
#Der Konstruktor ruft den übergeordneten Konstruktor auf
def __init__(self):
om.MPxNode.__init__(self)
#Eine Methode, die von Maya aufgerufen wird, wenn der Wert eines Attributs berechnet wird
def compute(self, plug, dataBlock):
arrayDataHandle = dataBlock.inputArrayValue(
sampleArrayNode.input
)
sumX = 0
sumY = 0
sumZ = 0
num = len(arrayDataHandle)
while not arrayDataHandle.isDone():
#Zusammengesetztes Attributdatenhandle
dataHandle = arrayDataHandle.inputValue()
# .Sie können untergeordnete Attribute mit untergeordnetem Element abrufen
childHandle = dataHandle.child(
sampleArrayNode.position
)
pos = childHandle.asFloat3()
childHandle = dataHandle.child(
sampleArrayNode.weight
)
w = childHandle.asFloat()
sumX += pos[0] * w
sumY += pos[1] * w
sumZ += pos[2] * w
arrayDataHandle.next()
outhandle = dataBlock.outputValue(sampleArrayNode.output)
if(num != 0):
outhandle.set3Float(sumX / num, sumY / num, sumZ / num)
else:
outhandle.set3Float(0, 0, 0)
dataBlock.setClean(plug)
# http://help.autodesk.com/view/MAYAUL/2016/ENU/
# api1.0 bedeutet MStatus, es sei denn, Sie weisen uns ausdrücklich an, den Stecker nicht zu verarbeiten.kUnknownParameter wird nicht zurückgegeben
# api2.Bei 0 gibt es überhaupt keinen MStatus, sodass Sie ihn ignorieren können.
#Eine von Maya aufgerufene Funktion, die einen neuen Knoten registriert
Was sich geändert hat, ist, dass die Variablen "Position" und "Gewicht" als Felder der Klasse vorbereitet werden. Da diese als untergeordnete Attribute von zusammengesetzten Attributen verwendet werden, werden sie in der Methode "initialize" genauso wie normale Attribute definiert. Das zusammengesetzte Attribut, das diese zusammenfügt, ist "Eingabe".
#Zusammengesetzte Attribute
nAttr = om.MFnCompoundAttribute()
sampleArrayNode.input = nAttr.create(
'input', 'i')
nAttr.readable = True
nAttr.array = True
nAttr.indexMatters = False
nAttr.addChild(sampleArrayNode.position) #← Das ist der Punkt
nAttr.addChild(sampleArrayNode.weight)
Der Unterschied zu normalen Attributen besteht darin, dass die Klasse des Attributs "MFnCompoundAttribute" ist und das oben in ".addChild" definierte untergeordnete Attribut hinzugefügt wird.
So verwenden Sie zusammengesetzte Attribute innerhalb der Berechnungsmethode
#Zusammengesetztes Attributdatenhandle
dataHandle = arrayDataHandle.inputValue()
# .Sie können untergeordnete Attribute mit untergeordnetem Element abrufen
childHandle = dataHandle.child(
sampleArrayNode.position
)
pos = childHandle.asFloat3()
childHandle = dataHandle.child(
sampleArrayNode.weight
)
w = childHandle.asFloat()
Verwenden Sie die Methode ".child" aus dem Handle für zusammengesetzte Attributdaten, um das Handle für untergeordnete Attributdaten abzurufen und darauf zuzugreifen.
Wenn Sie den erstellten Knoten tatsächlich verwenden, sieht es so aus. Verbinden Sie die Positionen mehrerer Objekte mit einem Knoten. Versuchen Sie, den Ausgang mit dem Locator zu verbinden. Der Locator hat sich in die Mitte der Kugel, des Kegels und des Würfels bewegt. Dieses Mal habe ich zusätzlich zu den Koordinaten einen Gewichtungswert als zusammengesetztes Attribut hinzugefügt. Verwenden wir ihn also. Wenn Sie das Gewicht der Kugel senken ... Der Einfluss der Kugel ist verschwunden und der Locator hat sich in die Mitte des Kegels und des Würfels bewegt.
Recommended Posts