Maya MPxNode несколько выходов - PullRequest
0 голосов
/ 16 мая 2018

Я пытаюсь создать MPxNode с несколькими выходами, но я могу заставить работать только один. Другой выход не устанавливается должным образом после подключения узла и во время отмены.

Возможно ли установить оба выхода одновременно в compute, как я пытаюсь? Это сработает, если я изменю первую строку в compute на if plug != self.output1 and plug != self.output2, но это означает, что он вычислит дважды, что является пустой тратой памяти. И вы можете себе представить, насколько это было бы плохо, если бы было еще больше результатов.

Мне удалось свести код к этому простому примеру. Я пишу это в Python на Maya 2018:

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)

    def compute(self, plug, data):
        # Only operate on output1 attribute.
        if plug != self.output1:
            return OpenMaya.kUnknownParameter

        # Get input value.
        val = data.inputValue(MyAwesomeNode.in_val).asFloat()

        # Set output 2.
        # This fails when setting up the node and during undos.
        out_plug_2 = data.outputValue(self.output2)
        if val > 0:
            out_plug_2.setFloat(1)
        else:
            out_plug_2.setFloat(0)
        out_plug_2.setClean()

        # Set output 1.
        # This works as expected.
        out_plug_1 = data.outputValue(self.output1)
        out_plug_1.setFloat(val)
        out_plug_1.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)
    MyAwesomeNode.attributeAffects(MyAwesomeNode.in_val, MyAwesomeNode.output2)
    MyAwesomeNode.attributeAffects(MyAwesomeNode.in_val, MyAwesomeNode.output1)


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")

1 Ответ

0 голосов
/ 17 мая 2018

У меня есть решение, которое работает, как ожидалось. Все выходы по-прежнему должны проходить через 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 ++, тогда она будет золотой.

...