Evaluation of Node only once ( compute() )

86 views
Skip to first unread message

justin hidair

unread,
Mar 3, 2018, 7:02:17 PM3/3/18
to Python Programming for Autodesk Maya

Let's say I have a Node which has an input mesh and an output mesh ,
everytime I move the input mesh , while I move it, compute() is called probably 15 times and the output is updated also 15 times,
That's great and all but what If I don't want continuous update ?

what if I want to move the input mesh from A to B , and only when it's at B, and I stop moving it, output will update ( so 1 call to compute() )
is there a way to do that ?
is the time between the total change of the input and the call to compute() as a name or a concept in the API ?
See this is important , because it allows to reduce overhead significantly , increase performance on complex calculations ...Etc.

Marcus Ottosson

unread,
Mar 4, 2018, 2:31:22 AM3/4/18
to python_in...@googlegroups.com

If there isn’t functionality for this natively, which I’d think not due to how it probably wouldn’t work that well with playback, then there is at least two things that I’d try.

  1. Add a live boolean to your node. When False, then you could bypass updating of the plug. That way, it’d be up to the user to decide whether to recieve updates directly, or on demand. It isn’t quite as nice as an update button, but nearly. And with a little logic, you could possibly set it up to automatically False itself when turned into True.
  2. On update, start or reset a timer. A timer of e.g. 1 second could, once triggered, cause the plug to update. That way, during playback or general interaction, the only overhead is that of creating or restarting an existing timer. Then, once the user has let go or Maya is idle, the timer would trigger, causing your mesh to update.

(2) wouldn’t play nicely with playback, as it would just constantly keep resetting itself. However, again with a little logic, it’s possible you could have the timer not reset when the change is coming from playback, as opposed to an attribute change or something from any context. (1) I’ve worked with before on the artist side and has worked well, though it’s been for e.g. whether or not to use multi-threading or whether to enable some effect like vertex colors. I’d expect it would work similarly with what you’ve got in mind.


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/234585c5-6c53-45d6-bb7d-9909ae263cd0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

justin hidair

unread,
Mar 4, 2018, 9:46:37 AM3/4/18
to Python Programming for Autodesk Maya
I don't cleary understand the 2. what I imagine here is that I would have a member timer , and on compute() calls I will verify if the timer is >= 1 if it is I reset it and perform the calculations if it's not I return MS::kSuccess and wait for the other computes() ...
I can see this go wrong for a misc of reasons , I investigated MEventMessage class and printed the list of events, and in there , there is this event :
// DragRelease // ,
and it's a good find because the problem is actually this dragging that users do , changing numeric attr values and such only calls compute() one time,
the user dragging/moving a shape calls it 10 more times.. however I don't know how to do good use of this callback event or if there is a better option , how come It's not a explicit feature of MPxNode ? ...
Message has been deleted

Marcus Ottosson

unread,
Mar 4, 2018, 1:07:36 PM3/4/18
to python_in...@googlegroups.com
This is the timer I had in mind.

http://doc.qt.io/qt-5/qtimer.html

It'd be able to delay a callback till later, and run it in the main thread without special treatment. Ultimately, it'd mean updating the plug outside of your `compute()` function, where your `compute()` is merely calling this timer, which is connected to something capable of updating your plug.

At the end of the day, what you're asking is to aggregate multiple calls that Maya makes to `compute()` into a single call by an arbitrary amount of time. It isn't going to be pretty. The more robust option is probably the boolean toggle. If you have a drag context involved, you could automatically set the boolean toggle to `False` when entering drag, and reset it to `True` once done. That way, you'd probably get the effect you're looking for.



On 4 March 2018 at 14:55, justin hidair <justin...@gmail.com> wrote:
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Mar 4, 2018, 1:40:27 PM3/4/18
to python_in...@googlegroups.com


On Mon, Mar 5, 2018, 3:46 AM justin hidair <justin...@gmail.com> wrote:
I don't cleary understand the 2. what I imagine here is that I would have a member timer , and on compute() calls I will verify if the timer is >= 1 if it is I reset it and perform the calculations if it's not I return MS::kSuccess and wait for the other computes() ...
I can see this go wrong for a misc of reasons , I investigated MEventMessage class and printed the list of events, and in there , there is this event :
// DragRelease // ,
and it's a good find because the problem is actually this dragging that users do , changing numeric attr values and such only calls compute() one time,
the user dragging/moving a shape calls it 10 more times.. however I don't know how to do good use of this callback event or if there is a better option , how come It's not a explicit feature of MPxNode ? ...

My guess is that MPxNode is not meant to be concerned with drag operations. That is what an MPxContext is for; an operation that takes place within some context. But a node is just concerned with its inputs and whether it is dirty or not. And if it is dirty, then downstream nodes should recompute afterwards. 



Le dimanche 4 mars 2018 07:31:22 UTC, Marcus Ottosson a écrit :

If there isn’t functionality for this natively, which I’d think not due to how it probably wouldn’t work that well with playback, then there is at least two things that I’d try.

  1. Add a live boolean to your node. When False, then you could bypass updating of the plug. That way, it’d be up to the user to decide whether to recieve updates directly, or on demand. It isn’t quite as nice as an update button, but nearly. And with a little logic, you could possibly set it up to automatically False itself when turned into True.
  2. On update, start or reset a timer. A timer of e.g. 1 second could, once triggered, cause the plug to update. That way, during playback or general interaction, the only overhead is that of creating or restarting an existing timer. Then, once the user has let go or Maya is idle, the timer would trigger, causing your mesh to update.

(2) wouldn’t play nicely with playback, as it would just constantly keep resetting itself. However, again with a little logic, it’s possible you could have the timer not reset when the change is coming from playback, as opposed to an attribute change or something from any context. (1) I’ve worked with before on the artist side and has worked well, though it’s been for e.g. whether or not to use multi-threading or whether to enable some effect like vertex colors. I’d expect it would work similarly with what you’ve got in mind.

On 4 March 2018 at 00:02, justin hidair <justin...@gmail.com> wrote:

Let's say I have a Node which has an input mesh and an output mesh ,
everytime I move the input mesh , while I move it, compute() is called probably 15 times and the output is updated also 15 times,
That's great and all but what If I don't want continuous update ?

what if I want to move the input mesh from A to B , and only when it's at B, and I stop moving it, output will update ( so 1 call to compute() )
is there a way to do that ?
is the time between the total change of the input and the call to compute() as a name or a concept in the API ?
See this is important , because it allows to reduce overhead significantly , increase performance on complex calculations ...Etc.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/de4cf9e5-3bdb-44f6-918b-ba00d4038a90%40googlegroups.com.

Justin Israel

unread,
Mar 4, 2018, 1:46:38 PM3/4/18
to python_in...@googlegroups.com


On Mon, Mar 5, 2018, 7:07 AM Marcus Ottosson <konstr...@gmail.com> wrote:
This is the timer I had in mind.

http://doc.qt.io/qt-5/qtimer.html

It'd be able to delay a callback till later, and run it in the main thread without special treatment. Ultimately, it'd mean updating the plug outside of your `compute()` function, where your `compute()` is merely calling this timer, which is connected to something capable of updating your plug.

At the end of the day, what you're asking is to aggregate multiple calls that Maya makes to `compute()` into a single call by an arbitrary amount of time. It isn't going to be pretty. The more robust option is probably the boolean toggle. If you have a drag context involved, you could automatically set the boolean toggle to `False` when entering drag, and reset it to `True` once done. That way, you'd probably get the effect you're looking for.

Could it also work to check if the mouse button is down? http://doc.qt.io/archives/qt-4.8/qapplication.html#mouseButtons
That alone would probably miss a compute. But maybe it could be combined with a QTimer. The timeout could be connected to a method that checks if the mouse is still pressed. If it is, trigger another timer to itself for 100ms. Otherwise, compute. 





On 4 March 2018 at 14:55, justin hidair <justin...@gmail.com> wrote:


Le dimanche 4 mars 2018 00:02:17 UTC, justin hidair a écrit :

Let's say I have a Node which has an input mesh and an output mesh ,
everytime I move the input mesh , while I move it, compute() is called probably 15 times and the output is updated also 15 times,
That's great and all but what If I don't want continuous update ?

what if I want to move the input mesh from A to B , and only when it's at B, and I stop moving it, output will update ( so 1 call to compute() )
is there a way to do that ?
is the time between the total change of the input and the call to compute() as a name or a concept in the API ?
See this is important , because it allows to reduce overhead significantly , increase performance on complex calculations ...Etc.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOAawKVa8E%3DOWntim%3Dro5ddFZBWdZOjh6PCtp7UXfYSjJw%40mail.gmail.com.

justin hidair

unread,
Mar 5, 2018, 11:42:28 AM3/5/18
to python_in...@googlegroups.com

Hurray , Hurray I didn’t express myself correctly ,

what I wanted is not to compute at intervals of time rather, what I wanted Really is to defer

the compute() to virtually execute only when Maya hits the Idle event, that is when the user is not actively changing a thing,

fortunately there’s MEventMessage:: addEventCallback (“idle” , …) .

 

Here’ s how made it work :

 

//override void MPxNode::postConstructor() to create the callback for this instance

void myclass::postConstructor( )

{

    MStatus st ;

 

    MCallbackId dummy ;

    dummy  = MEventMessage::addEventCallback

    ( 

     "idle",

     deferredCompute,

     this,

     &st

     );

 

    MCHECKSTATUS(st);

 

    mCallBacks.append(dummy);

 

//when the node is deleted , delete this instance ‘s callbacks

 

    dummy  = MNodeMessage::addNodePreRemovalCallback

    ( 

     thisMObject(),

     _removeCallBacks,

     this,

     &st

     );

 

    MCHECKSTATUS(st);

 

    mCallBacks.append(dummy);

 

}

 

//now in compute()

 

MStatus myclass::compute(const MPlug& plug , MDataBlock& datablock )

    if(mSloppy != ACTION )

    {

        mSloppy = BYPASS//compute gets delayed

        return MS::kSuccess;

    }

 

    //natural compute begins

    if (plug != aOut)

    {

        return MS::kUnknownParameter;

    }

 

    MGlobal::displayInfo("compute()");//just to debug

    MStatus st;

 

    auto imesh_h = datablock.inputValue(aOperands, &st);

    MCHECKSTATUS(st);

   

    auto trig_h = datablock.inputValue(aTrigger, &st);

    MCHECKSTATUS(st);

 

    auto out_h = datablock.outputValue(aOut, &st);

    MCHECKSTATUS(st);

    out_h.set(imesh_h.asMesh());

 

    st = datablock.setClean(plug);

    MCHECKSTATUS(st);

 

    //reset on sleep

    mSloppy = SLEEP;

 

    return MS::kSuccess;

}

 

Now Here’s the juiciest part , it’s sneaky ,  vicious for real

 

void myclass::deferredCompute(void *clientData)

{

    auto that = static_cast<myclass*>(clientData);

  

    if( that->mSloppy == BYPASS )

    {

 

        that->mSloppy = ACTION;

        //trigger compute()

        MPlug trig_p  = MPlug( that->thisMObject() , aTrigger );

        bool lastValue;

        trig_p.getValue(lastValue);

        trig_p.setValue(!lastValue);

    }

 

}

 

Basically I trigger compute on Idle with a special & simple attribute ‘aTrigger’ by using MPlug::setValue. There’s more details to it  but I think you understand the idea already..

 

Sent from Mail for Windows 10

Reply all
Reply to author
Forward
0 new messages