1

Following on from this discussion, I have found that refreshing a Maya scene in a loop using the python command cmds.refresh() eventually crashes the application (it runs out of memory before the loop returns).

The problem raised in the discussion related to the creation of a nurbs boolean surface by, first, taking the difference between a large sphere and a small sphere centred on the large sphere's surface, then taking the difference of the resulting nurbs surface and a second small sphere. The DAG hierarchy for this geometry was a surfaceVarGroup, nurbsBooleanSurface1, parenting three transform nodes nurbsBooleanSurface1_1, nurbsBooleanSurface1_2 and nurbsBooleanSurface1_3, each of which parented its own shape node.

The strange thing was that while the execution of

cmds.nurbsBoolean("nurbsSphere1", "nurbsSphere2", nsf=1, op=1)

(where nurbsSphere1 was the large sphere and nurbsSphere2 was the first of the two small spheres) followed by

print(cmds.ls("nurbsBooleanSurface1_*", type="transform"))

yielded [u'nurbsBooleanSurface1_1', u'nurbsBooleanSurface1_2'] as expected, the subsequent execution of

cmds.nurbsBoolean("nurbsBooleanSurface1", "nurbsSphere3", nsf=1, op=1)

(where nurbsBooleanSurface1 was the 'single-dimple' nurbs surface resulting from the above boolean computation and nurbsSphere3 was the second of the two small spheres) followed by

print(cmds.ls("nurbsBooleanSurface1_*", type="transform"))

again yielded [u'nurbsBooleanSurface1_1', u'nurbsBooleanSurface1_2']; nurbsBooleanSurface1_3 was missing.

amorten's solution involved refreshing the scene after the second boolean computation by invoking cmds.refresh(). But as I have said, this does not work in a loop (whose number of iterations is greater than 100ish).

I have since found that nurbsBooleanSurface1_3 does not appear as a DAG node during program execution; it sort of 'pops' out at the end. The following c++ API code traverses all DAG nodes in the scene:

#include <maya/MSimple.h>
#include<maya/MGlobal.h>
#include <iostream>
#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MDagPath.h>
#include<maya/MObject.h>
#include<maya/MItDag.h>
#include<maya/MFnDagNode.h>

// This command iteratively computes the boolen difference between a large nurbs surface and a set of small nurbs spheres. It first
// executes the nurbs boolean (difference) command on a pair of intersecting nurbs spheres, one of radius 10 (the large sphere) and
// the other of radius 3 (a small sphere, whose centre sits on the surface of the large sphere). The result is a transform node Maya names 
// nurbsBooleanSurface1, which has two children transform nodes, nurbsBooleanSurface1_1 and nurbsBooleanSurface1_2. The latter are the two  
// components of the dimpled large sphere.
//
// When the nurbs boolean command is executed on nurbsBooleanSurface1 and a second small sphere of radius 3, a thrid node, nurbsBooleanSurface1_3,
// is added to the list of child nodes parented by nurbsBooleanSurface1.
//
// The problem is that nurbsBooleanSurface1_3 does not appear in the DAG during program execution.

DeclareSimpleCommand( nurbsBooleanSurface, "A test of the presence in the DAG of the child nodes of a nurbs boolean surface node", "4.0");

MStatus nurbsBooleanSurface::doIt( const MArgList& args ) {

    MStatus stat = MS::kSuccess;

    // Create the large sphere
    MGlobal::executeCommand("sphere -r 10 -n sphere1");

    // Create the first small sphere, with centre on the surface of the large sphere at (10,0,0)
    MGlobal::executeCommand("sphere -r 3 -n sphere2");
    MGlobal::executeCommand("setAttr \"sphere2.translateX\" 10;");

    // First nurbs boolean computation
    stat = MGlobal::executeCommand("nurbsBoolean -nsf 1 -op 1 sphere1 sphere2;");

    // Check the boolean computation
    if(stat==MS::kSuccess) {
        std::cout << "Boolean computation success." << std::endl;
    }
    else {
        displayError("Boolean computation fail.");
    }

    // Create the second small sphere, with centre on the surface of the nurbs boolean surface at (0,10,0)
    MGlobal::executeCommand("sphere -r 3 -n sphere3");
    MGlobal::executeCommand("setAttr \"sphere3.translateY\" 10;");

    // Second nurbs boolean computation
    stat = MGlobal::executeCommand("nurbsBoolean -nsf 1 -op 1 nurbsBooleanSurface1 sphere3;");

    if(stat==MS::kSuccess) {
        std::cout << "Boolean computation success." << std::endl;
    }
    else {
        displayError("Boolean computation fail.");
    }

    // Use an iterator to traverse the DAG nodes
    MItDag it(MItDag::kDepthFirst);

    // Loop through all the DAG nodes
    while(!it.isDone()) {

        // Attach a function set for a DAG node to the
        // object. Rather than access data directly, 
        // it is accessed via the function set. 
        MFnDagNode fn(it.currentItem());

        // Get the name of the node 
        MString name = fn.name();

        // Write the node type found
        cout << "node: " << name.asChar() << endl;

        // Write the info about the children 
        cout <<"num_children " << fn.childCount() << endl;

        for(int i=0;i<fn.childCount();++i) {

            // Get the MObject for the ith child 
            MObject child = fn.child(i);

            // Attach a function set to it
            MFnDagNode fnChild(child);

            // Write the child name
            cout << "\t" << fnChild.name().asChar();
            cout << endl;
        }

        // Write the info about the parents
        cout<<"num_parents "<< fn.parentCount() << endl;

        for(int i=0;i<fn.parentCount();++i) {

            // Get the MObject for the ith parent
            MObject parent = fn.parent(i);

            // Attach a function set to it
            MFnDagNode fnParent(parent);

            // Write the parent name
            cout << "\t" << fnParent.name().asChar();
            cout << endl;
        }

        // Move to next node
        it.next();
    }

    return stat;
}     

The relevant snippet in the output window is

node: nurbsBooleanSurface1
num_children 2
    nurbsBooleanSurface1_1
    nurbsBooleanSurface1_2
num_parents 1
world

which clearly makes no reference to the elusive nurbsBooleanSurface1_3.

So my question is, where is this node or its data stored and in what form during program execution? It must be in Maya's database somewhere.

Having worked out where it is, I'd also like to know how to access it.

Community
  • 1
  • 1
svenpables
  • 99
  • 1
  • 9
  • Is there any particular reason why you execute what is essentially a mel script inside a maya api code, all you get is a headache and 10 times the extra amount of code. Anyway i do not think you can expect the boolean operation to succeed indefinitely as the computation precision you have will eventually catch up with you, expecting the boolan to work after say 20 iterations is already pushing it.. You should start with a REALLY big sphere. Also please disable undo. – joojaa Jan 17 '16 at 08:55
  • I'd love to be able to perform a nurbs boolean (difference) operation using api code. Any help here would be much appreciated. The python script I had running to dimple a large sphere by use of a bunch of small spheres on its surface included try-except blocks in the loop. This worked well to bypass the failed booleans (due, most probably, to non-intersecting surfaces), and allow execution to continue. – svenpables Jan 17 '16 at 09:59
  • Its a node, nodes arent being run by your code but by connections and the internal logic of the node after a dirty clean loop. This is also why no data is present while you are in the blocked state of a command, You can allways try to getattr a suitable output for it to update. You can manually set up the connections. In any case booleans dont necessarily fail just due to missed intersections (and thats not a failure its just a error condition). But booleans can fail also due to numerical instability and operation timeout. – joojaa Jan 17 '16 at 10:44

0 Answers0