DAG 走査の例
 
 
 

次の例は、scanDagSyntaxCmd のサンプルです。深さ優先か幅優先の方法で DAG を反復します。このコードは、多くの DAG 走査プラグイン、特にファイル トランスレータとして作成するプラグインのベースになります。

前のサンプルと同じように、簡潔にするため、インクルード ファイルのリストは省略しました。完全なサンプルは、devkit/plug-ins の scanDagSyntaxCmd.cpp ファイルを参照してください。

class scanDagSyntax: public MPxCommand
{
 public:
     scanDagSyntax() {};
     virtual ~scanDagSyntax();
     static void* creator();
     static MSyntax newSyntax();
     virtual MStatus doIt( const MArgList& );
     //This is a simple example so the undoIt() and redoIt() methods are not implemented. 
 private:
     MStatus parseArgs( const MArgList& args,
     MItDag::TraversalType& traversalType,
     MFn::Type& filter, bool & quiet);
     MStatus doScan( const MItDag::TraversalType traversalType,
     MFn::Type filter, bool quiet);
     void printTransformData(const MDagPath& dagPath, bool quiet);
};

scanDagSyntax::~scanDagSyntax() {}
void* scanDagSyntax::creator()
{
    return new scanDagSyntax;
}

MSyntax scanDagSyntax::newSyntax()
{
    MSyntax syntax;
    syntax.addFlag(kBreadthFlag, kBreadthFlagLong);
    syntax.addFlag(kDepthFlag, kDepthFlagLong);
    syntax.addFlag(kCameraFlag, kCameraFlagLong);
    syntax.addFlag(kLightFlag, kLightFlagLong);
    syntax.addFlag(kNurbsSurfaceFlag, kNurbsSurfaceFlagLong);
    syntax.addFlag(kQuietFlag, kQuietFlagLong);
    return syntax;
}

MStatus scanDagSyntax::doIt( const MArgList& args )
{
     MItDag::TraversalType traversalType = MItDag::kDepthFirst;
     MFn::Type filter = MFn::kInvalid;
     MStatus status;
     bool quiet = false;

後で使用する DAG イテレータは、特定のタイプのオブジェクトのみ(たとえばカメラのみ)で反復するように設定できます。フィルタ モードを MFn::kInvalid に設定すると、フィルタ処理は実行されず、すべての DAG ノードが反復されます。

     status = parseArgs ( args, traversalType, filter, quiet );
     if (!status)
         return status;
     return doScan( traversalType, filter, quiet);
};
//The doIt() method is simply calling a few auxiliary methods which do the real work.
MStatus scanDagSyntax::parseArgs( const MArgList& args,
                                  MItDag::TraversalType& traversalType,
                                  MFn::Type& filter,
                                  bool & quiet)
{
    MStatus stat;
    MArgDatabase argData(syntax(), args);
    MString arg;
    if (argData.isFlagSet(kBreadthFlag))
        traversalType = MItDag::kBreadthFirst;
    else if (argData.isFlagSet(kDepthFlag))
        traversalType = MItDag::kDepthFirst;
    if (argData.isFlagSet(kCameraFlag))
        filter = MFn::kCamera;
    else if (argData.isFlagSet(kLightFlag))
        filter = MFn::kLight;
    else if (argData.isFlagSet(kNurbsSurfaceFlag))
        filter = MFn::kNurbsSurface;
    if (argData.isFlagSet(kQuietFlag))
        quiet = true;
    return stat;
}

DAG イテレータは、深さ優先か幅優先で DAG を反復します。この単純なサンプルでは、カメラ、ライト、NURBS サーフェスのみでフィルタ処理を行いますが、MFn::Type で返されるすべての型で反復できます。

MStatus scanDagSyntax::doScan( const MItDag::TraversalType traversalType,
                               MFn::Type filter,
                               bool quiet)
{ 

このメソッドで、このコマンドの実際の作業をすべて実行します。走査タイプ(深さ優先か幅優先)とフィルタタイプを使用し、MItDag(DAG イテレータ)を初期化して DAG 内を走査します。

    MStatus status;
    MItDag dagIterator( traversalType, filter, &status);

DAG イテレータが、DAG を指すように初期化されます。DAG は下方向に走査されます。

    if ( !status) {
        status.perror("MItDag constructor");
        return status;
    }
 // Scan the entire DAG and output the name and depth of each node
    if (traversalType == MItDag::kBreadthFirst)
        if (!quiet)
            cout << endl << "Starting Breadth First scan of the Dag";
        else
    if (!quiet)
        cout << endl << "Starting Depth First scan of the Dag";

DAG の幅優先走査では、子より兄弟が先に走査され、深さ優先では兄弟より先に子が走査されます。

    switch (filter) {
    case MFn::kCamera:
        if (!quiet)
            cout << ": Filtering for Cameras\n";
        break;
    case MFn::kLight:
        if (!quiet)
            cout << ": Filtering for Lights\n";
        break;
    case MFn::kNurbsSurface:
        if (!quiet)
            cout << ": Filtering for Nurbs Surfaces\n";
        break;
    default:
        cout << endl;
    }
    int objectCount = 0;
    for ( ; !dagIterator.isDone(); dagIterator.next() ) {
        MDagPath dagPath;
        status = dagIterator.getPath(dagPath);
        if ( !status ) {
            status.perror("MItDag::getPath");
            continue;
        }

MItDag::getPath() によって、イテレータが現在走査しているオブジェクトの参照が取得されます。これで、この DAG パスを関数セット内で使用して、そのオブジェクトに対する演算ができます。イテレータを使用した DAG の並べ替えは行わないのが一般的です。

        MFnDagNode dagNode(dagPath, &status);
        if ( !status ) {
            status.perror("MFnDagNode constructor");
            continue;
        }
        if (!quiet)
            cout << dagNode.name() << ": " << dagNode.typeName() << endl;
        if (!quiet)
            cout << " dagPath: " << dagPath.fullPathName() << endl;
        objectCount += 1;
        if (dagPath.hasFn(MFn::kCamera)) {

イテレータが現在作業しているオブジェクトがカメラであるかどうか判断されます。カメラである場合は、以下のコードでカメラ固有の情報が出力されます。

            MFnCamera camera (dagPath, &status);
            if ( !status ) {
                status.perror("MFnCamera constructor");
                continue;
            }
            // Get the translation/rotation/scale data
            printTransformData(dagPath, quiet);
            // Extract some interesting Camera data
            if (!quiet)
            {
                cout << " eyePoint: "
                     << camera.eyePoint(MSpace::kWorld) << endl;
                cout << " upDirection: "
                     << camera.upDirection(MSpace::kWorld) << endl;
                cout << " viewDirection: "
                     << camera.viewDirection(MSpace::kWorld) << endl;
                cout << " aspectRatio: " << camera.aspectRatio() << endl;
                cout << " horizontalFilmAperture: "
                     << camera.horizontalFilmAperture() << endl;
                cout << " verticalFilmAperture: "
                     << camera.verticalFilmAperture() << endl;
            }
        } 
        else if (dagPath.hasFn(MFn::kLight)) {

オブジェクトがライトである場合は、このコードでライト固有の情報が出力されます。

            MFnLight light (dagPath, &status);
            if ( !status ) {
                    status.perror("MFnLight constructor");
                    continue;
            }
            // Get the translation/rotation/scale data
            printTransformData(dagPath, quiet);
            // Extract some interesting Light data
            MColor color;
            color = light.color();
            if (!quiet)
            {
                cout << " color: ["
                << color.r << ", "
                << color.g << ", "
                << color.b << "]\n";
            }
            color = light.shadowColor();
            if (!quiet)
            {
                cout << " shadowColor: ["
                << color.r << ", "
                << color.g << ", "
                << color.b << "]\n";
                cout << " intensity: " << light.intensity() << endl;
            }
        } 
        else if (dagPath.hasFn(MFn::kNurbsSurface)) {
            //Finally, if the object is a NURBS surface, surface specific information is output.
            MFnNurbsSurface surface (dagPath, &status);
            if ( !status ) {
                status.perror("MFnNurbsSurface constructor");
                continue;
            }
            // Get the translation/rotation/scale data
            printTransformData(dagPath, quiet);
            // Extract some interesting Surface data
            if (!quiet)
            {
                cout << " numCVs: "
                     << surface.numCVsInU()
                     << " * "
                     << surface.numCVsInV()
                     << endl;
                cout << " numKnots: "
                     << surface.numKnotsInU()
                     << " * "
                     << surface.numKnotsInV()
                     << endl;
                cout << " numSpans: "
                     << surface.numSpansInU()
                     << " * "
                     << surface.numSpansInV()
                     << endl;
            }
        } 
        else {

その他の種類の DAG ノードでは、変換情報のみが出力されます。

            // Get the translation/rotation/scale data
            printTransformData(dagPath, quiet);
        }
    }
    if (!quiet)
    {
        cout.flush();
    }
    setResult(objectCount);
    return MS::kSuccess;
}

void scanDagSyntax::printTransformData(const MDagPath& dagPath, bool quiet)
{
    //This method simply determines the transformation information on the DAG node and prints it out.
    MStatus status;
    MObject transformNode = dagPath.transform(&status);
    // This node has no transform - i.e., it’s the world node
    if (!status && status.statusCode () == MStatus::kInvalidParameter)
        return;
    MFnDagNode transform (transformNode, &status);
    if (!status) {
        status.perror("MFnDagNode constructor");
        return;
    }
    MTransformationMatrix matrix (transform.transformationMatrix());
    if (!quiet)
    {
        cout << " translation: " << matrix.translation(MSpace::kWorld)
            << endl;
    }
    double threeDoubles[3];
    MTransformationMatrix::RotationOrder rOrder;
    matrix.getRotation (threeDoubles, rOrder, MSpace::kWorld);
    if (!quiet)
    {
        cout << " rotation: ["
             << threeDoubles[0] << ", "
             << threeDoubles[1] << ", "
             << threeDoubles[2] << "]\n";
    }
    matrix.getScale (threeDoubles, MSpace::kWorld);
    if (!quiet)
    {
        cout << " scale: ["
             << threeDoubles[0] << ", "
             << threeDoubles[1] << ", "
             << threeDoubles[2] << "]\n";
    }
}

MStatus initializePlugin( MObject obj )
{ 
    MStatus status;
    MFnPlugin plugin ( obj, "Autodesk - Example", "2.0", "Any" );
    status = plugin.registerCommand( "scanDagSyntax", 
    scanDagSyntax::creator,
    scanDagSyntax::newSyntax ); 
    return status;
}

MStatus uninitializePlugin( MObject obj )
{
    MStatus status;
    MFnPlugin plugin( obj );
    status = plugin.deregisterCommand( "scanDagSyntax" );
    return status;
}

プラグインは、通常の initializePlugin メソッドと uninitializePlugin メソッドで終了します。

このプラグインは、ファイル トランスレータとして、またはモデル内の DAG ノードにアクセスするその他の種類のプラグインとして使用するように簡単に修正できます。