Community
Maya Programming
Welcome to Autodesk’s Maya Forums. Share your knowledge, ask questions, and explore popular Maya SDK topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Pass attributes of node to a render override

6 REPLIES 6
SOLVED
Reply
Message 1 of 7
drsanty
1485 Views, 6 Replies

Pass attributes of node to a render override

drsanty
Contributor
Contributor

I am using a custom setting node (based on MPxNode) to store and pass values to a render override.

These values are queried, calculated and 'sent' to a render override class within the compute() method.

 

However, for this to happen, a dummy output attribute within the setting node needs to be connected with something visible in the scene to trigger the dirty propagation. Only then will the compute node run and pass the updated values to the render override.

 

Ideally, I would like to just query and pass the input attributes to the render override whenever these are changed, without having to resort to workarounds i.e., affecting a dummy output attribute just to trigger the dirty propagation and get the job done.

 

Is there any way to do this? Any help is appreciated. 

0 Likes

Pass attributes of node to a render override

I am using a custom setting node (based on MPxNode) to store and pass values to a render override.

These values are queried, calculated and 'sent' to a render override class within the compute() method.

 

However, for this to happen, a dummy output attribute within the setting node needs to be connected with something visible in the scene to trigger the dirty propagation. Only then will the compute node run and pass the updated values to the render override.

 

Ideally, I would like to just query and pass the input attributes to the render override whenever these are changed, without having to resort to workarounds i.e., affecting a dummy output attribute just to trigger the dirty propagation and get the job done.

 

Is there any way to do this? Any help is appreciated. 

6 REPLIES 6
Message 2 of 7
zewt
in reply to: drsanty

zewt
Collaborator
Collaborator

I don't think there is, since something needs to depend on the plug in the first place for it to be evaluated.  I have my render override search for the settings singleton in MRenderOverride::setup and pull data in.

 

Optimizing it so it only refreshes settings when something changes is a headache, though.  The settings node updates a sequence number that the override can compare, which happens in MPxNode::compute, connectionMade, connectionBroken and setInternalValue.  All attributes are marked internal, and affect an "evaluate" attribute.  At the start of setup() evaluate is evaluated to trigger any pending compute calls, then the sequence number is checked.

 

I'm not completely sure it still won't have issues with evaluation cache, since I haven't used that much...

 

I don't think there is, since something needs to depend on the plug in the first place for it to be evaluated.  I have my render override search for the settings singleton in MRenderOverride::setup and pull data in.

 

Optimizing it so it only refreshes settings when something changes is a headache, though.  The settings node updates a sequence number that the override can compare, which happens in MPxNode::compute, connectionMade, connectionBroken and setInternalValue.  All attributes are marked internal, and affect an "evaluate" attribute.  At the start of setup() evaluate is evaluated to trigger any pending compute calls, then the sequence number is checked.

 

I'm not completely sure it still won't have issues with evaluation cache, since I haven't used that much...

 

Message 3 of 7
drsanty
in reply to: zewt

drsanty
Contributor
Contributor

Hi zewt, thanks for your input!

 

I managed to create a cleaner solution with a hint you gave me, instead of connecting the setting node to something visible, I can just evaluate it at the beginning of the setup() method within the render override.

// check if setting node needs to be evaluated
MString cmd;
cmd.format("dgeval ^1s.evaluate", SETTINGNODE);
MGlobal::executeCommand(cmd);

If the setting node is dirty, the evaluation will trigger the compute() method and pass all the changed settings to the render override. This will only happen when attributes have changed from one specific node in the scene (SETTINGNODE)---which also solves issues we were having with referenced setting nodes.

0 Likes

Hi zewt, thanks for your input!

 

I managed to create a cleaner solution with a hint you gave me, instead of connecting the setting node to something visible, I can just evaluate it at the beginning of the setup() method within the render override.

// check if setting node needs to be evaluated
MString cmd;
cmd.format("dgeval ^1s.evaluate", SETTINGNODE);
MGlobal::executeCommand(cmd);

If the setting node is dirty, the evaluation will trigger the compute() method and pass all the changed settings to the render override. This will only happen when attributes have changed from one specific node in the scene (SETTINGNODE)---which also solves issues we were having with referenced setting nodes.

Message 4 of 7
zewt
in reply to: drsanty

zewt
Collaborator
Collaborator

The way I force evaluation for this is with MPlug::asMDataHandle, which might be a little nicer than making a MEL call: MPlug(node, evaluateAttr).asMDataHandle();

 

Be careful if you're assuming that referenced settings nodes won't be computed, since that might be hard to guarantee.  For example, simply selecting the node and causing it to be displayed in the AE or node editor might trigger a compute.

 

0 Likes

The way I force evaluation for this is with MPlug::asMDataHandle, which might be a little nicer than making a MEL call: MPlug(node, evaluateAttr).asMDataHandle();

 

Be careful if you're assuming that referenced settings nodes won't be computed, since that might be hard to guarantee.  For example, simply selecting the node and causing it to be displayed in the AE or node editor might trigger a compute.

 

Message 5 of 7
Anonymous
in reply to: zewt

Anonymous
Not applicable

That's interesting, I didn't know that you could force the evaluation by just getting the MDataHandle from a plug, thanks for your help!

 

Showing the node in the Attribute Editor does indeed trigger an evaluation. We will make sure artists can only select the right settings node in case of loading references.

 

I also noticed something odd. When you set a numeric attribute as a color with setUsedAsColor(), modifying the value in the Attribute Editor doesn't refresh the Viewport. That means that setup() is never run->the evaluation doesn't happen->the color within the render override doesn't change.

 

In case anyone else encounters this issue, I managed to solve this by forcing a refresh when these types of attributes are changed by overriding the setDependetsDirty() method within MPxNode.

MStatus SettingsNode::setDependentsDirty(const MPlug& inPlug, MPlugArray& affectedPlugs) {
    // force viewport refresh when changing attributes that are set as color
    MAnimControl animControl;
    if (!animControl.isPlaying()) {
        MFnAttribute fnAttr(inPlug.attribute());
        if (fnAttr.isUsedAsColor()) {
            MGlobal::executeCommandOnIdle("refresh;");
        }
    }
    return MS::kSuccess;
}

 

 

0 Likes

That's interesting, I didn't know that you could force the evaluation by just getting the MDataHandle from a plug, thanks for your help!

 

Showing the node in the Attribute Editor does indeed trigger an evaluation. We will make sure artists can only select the right settings node in case of loading references.

 

I also noticed something odd. When you set a numeric attribute as a color with setUsedAsColor(), modifying the value in the Attribute Editor doesn't refresh the Viewport. That means that setup() is never run->the evaluation doesn't happen->the color within the render override doesn't change.

 

In case anyone else encounters this issue, I managed to solve this by forcing a refresh when these types of attributes are changed by overriding the setDependetsDirty() method within MPxNode.

MStatus SettingsNode::setDependentsDirty(const MPlug& inPlug, MPlugArray& affectedPlugs) {
    // force viewport refresh when changing attributes that are set as color
    MAnimControl animControl;
    if (!animControl.isPlaying()) {
        MFnAttribute fnAttr(inPlug.attribute());
        if (fnAttr.isUsedAsColor()) {
            MGlobal::executeCommandOnIdle("refresh;");
        }
    }
    return MS::kSuccess;
}

 

 

Message 6 of 7
zewt
in reply to: Anonymous

zewt
Collaborator
Collaborator

Be careful, setDependentsDirty isn't called during parallel evaluation (see https://damassets.autodesk.net/content/dam/autodesk/www/Company/files/Parallel_Maya.pdf).  FYI, there's M3dView::scheduleRefreshAllViews if you really need to force a refresh.

 

It does refresh for me, though.  Actually it refreshes if I change anything, even attributes that have nothing to do with the viewport, but I guess that makes more sense than trying to eliminate a few viewport refreshes.  It seems like setAffectsAppearance on attributes does nothing and it just assumes any change needs a refresh.  I'm not sure what might be different, I don't think I'm doing anything special there...

 

0 Likes

Be careful, setDependentsDirty isn't called during parallel evaluation (see https://damassets.autodesk.net/content/dam/autodesk/www/Company/files/Parallel_Maya.pdf).  FYI, there's M3dView::scheduleRefreshAllViews if you really need to force a refresh.

 

It does refresh for me, though.  Actually it refreshes if I change anything, even attributes that have nothing to do with the viewport, but I guess that makes more sense than trying to eliminate a few viewport refreshes.  It seems like setAffectsAppearance on attributes does nothing and it just assumes any change needs a refresh.  I'm not sure what might be different, I don't think I'm doing anything special there...

 

Message 7 of 7
drsanty
in reply to: zewt

drsanty
Contributor
Contributor
Accepted solution

Hey @zewt and anyone else interested,

 

since Autodesk kindly reminded me to "resolve" this thread, this is what we are ultimately using:

MStatus ConfigNode::setDependentsDirty(const MPlug& inPlug, MPlugArray& affectedPlugs) {
    // force viewport refresh with unconnected node
    MAnimControl animControl;
    if (!animControl.isPlaying()) {
        M3dView::scheduleRefreshAllViews();  
    }
    return MS::kSuccess;
}

 

For our use purposes (just scheduling a viewport refresh) and based on our testing (Maya 2018+), `setDependetsDirty()` is being called also during parallel evaluation, so we haven't encountered any issues yet.

Hey @zewt and anyone else interested,

 

since Autodesk kindly reminded me to "resolve" this thread, this is what we are ultimately using:

MStatus ConfigNode::setDependentsDirty(const MPlug& inPlug, MPlugArray& affectedPlugs) {
    // force viewport refresh with unconnected node
    MAnimControl animControl;
    if (!animControl.isPlaying()) {
        M3dView::scheduleRefreshAllViews();  
    }
    return MS::kSuccess;
}

 

For our use purposes (just scheduling a viewport refresh) and based on our testing (Maya 2018+), `setDependetsDirty()` is being called also during parallel evaluation, so we haven't encountered any issues yet.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report