У меня есть решение, которое работает, как ожидалось. Все выходы по-прежнему должны проходить через compute()
, но только один выход будет выполнять тяжелые вычисления.
Проходя через compute
, он проверяет все выходные разъемы, если они чистые. Если все грязные, то нам нужно пересчитать, иначе, если мы найдем один чистый плагин, мы можем просто использовать сохраненные ранее кэшированные значения.
Вот пример:
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMaya as OpenMaya
class MyAwesomeNode(OpenMayaMPx.MPxNode):
# Define node properties.
kname = "myAwesomeNode"
kplugin_id = OpenMaya.MTypeId(0x90000005)
# Define node attributes.
in_val = OpenMaya.MObject()
output1 = OpenMaya.MObject()
output2 = OpenMaya.MObject()
def __init__(self):
OpenMayaMPx.MPxNode.__init__(self)
# Store value here.
self.cached_value = 0
def compute(self, plug, data):
# Include all outputs here.
if plug != self.output1 and plug != self.output2:
return OpenMaya.kUnknownParameter
# Get plugs.
val = data.inputValue(MyAwesomeNode.in_val).asFloat()
out_plug_1 = data.outputValue(self.output1)
out_plug_2 = data.outputValue(self.output2)
dep_node = OpenMaya.MFnDependencyNode(self.thisMObject())
# Determine if this output needs to recalculate or simply use cached values.
use_cache_values = False
for name in ["output1", "output2"]:
mplug = dep_node.findPlug(name)
if data.isClean(mplug):
# If we find a clean plug then just use cached values.
use_cache_values = True
break
if use_cache_values:
# Use cached value.
value = self.cached_value
else:
# Calculate value.
# We potentially can make big computations here.
self.cached_value = val
value = val
# Set output 1.
if plug == self.output1:
out_plug_1.setFloat(value)
out_plug_1.setClean()
# Set output 2.
if plug == self.output2:
if value > 0:
out_plug_2.setFloat(1)
else:
out_plug_2.setFloat(0)
out_plug_2.setClean()
data.setClean(plug)
return True
def creator():
return OpenMayaMPx.asMPxPtr(MyAwesomeNode())
def initialize():
nattr = OpenMaya.MFnNumericAttribute()
MyAwesomeNode.output2 = nattr.create("output2", "output2", OpenMaya.MFnNumericData.kFloat)
nattr.setWritable(False)
nattr.setStorable(False)
MyAwesomeNode.addAttribute(MyAwesomeNode.output2)
MyAwesomeNode.output1 = nattr.create("output1", "output1", OpenMaya.MFnNumericData.kFloat)
nattr.setWritable(False)
nattr.setStorable(False)
MyAwesomeNode.addAttribute(MyAwesomeNode.output1)
MyAwesomeNode.in_val = nattr.create("input", "input", OpenMaya.MFnNumericData.kFloat, -1)
nattr.setKeyable(True)
MyAwesomeNode.addAttribute(MyAwesomeNode.in_val)
# Include both outputs.
MyAwesomeNode.attributeAffects(MyAwesomeNode.in_val, MyAwesomeNode.output1)
MyAwesomeNode.attributeAffects(MyAwesomeNode.in_val, MyAwesomeNode.output2)
def initializePlugin(obj):
plugin = OpenMayaMPx.MFnPlugin(obj, "Me", "1.0", "Any")
try:
plugin.registerNode(MyAwesomeNode.kname, MyAwesomeNode.kplugin_id, creator, initialize)
except:
raise RuntimeError, "Failed to register node: '{}'".format(MyAwesomeNode.kname)
def uninitializePlugin(obj):
plugin = OpenMayaMPx.MFnPlugin(obj)
try:
plugin.deregisterNode(MyAwesomeNode.kplugin_id)
except:
raise RuntimeError, "Failed to register node: '{}'".format(MyAwesomeNode.kname)
# Example usage of node
if __name__ == "__main__":
import maya.cmds as cmds
cmds.createNode("transform", name="result")
cmds.setAttr("result.displayLocalAxis", True)
cmds.createNode("myAwesomeNode", name="myAwesomeNode")
cmds.connectAttr("myAwesomeNode.output1", "result.translateX")
# This output fails.
cmds.polyCube(name="cube")
cmds.setAttr("cube.translate", 0, 3, 0)
cmds.connectAttr("myAwesomeNode.output2", "cube.scaleX")
cmds.connectAttr("myAwesomeNode.output2", "cube.scaleY")
cmds.connectAttr("myAwesomeNode.output2", "cube.scaleZ")
Выводы, кажется, реагируют нормально при повторном открытии файла, при импорте его в новую сцену и обращении к нему. Мне просто нужно перенести ту же идею на c ++, тогда она будет золотой.