API ガイド > テクニカル ノート >

# 汎用アトリビュート

Maya API マニュアルのこのセクションでは、重要ではあるが、章全体として大きくない Maya API パートについて説明します。

汎用アトリビュート(MFnGenericAttribute)は複数の異なるタイプのデータを受け付けることができます。汎用アトリビュートは、有効とみなされるタイプのリストを含む点を除いては、タイプを持つアトリビュート(MFnTypedAttribute)と同じです。

汎用アトリビュートは複数の目的に同じアトリビュートを再利用するのに便利です。たとえば、プラグイン交差ノードを書き込むとき、アトリビュートは交差するオブジェクトに関する情報を格納するために使用されます。プラグインは、論理積の計算に使用するメッシュまたはサーフェスを受け付けることができる汎用アトリビュートを作成できます。汎用アトリビュートを使用しない場合、プラグインはメッシュ用とサーフェス用の 2 つの個別のアトリビュートを作成する必要があります。汎用アトリビュートには、同じタイプの複数のノードが、独自に汎用アトリビュート タイプを設定できるという利点もあります。たとえば、記述された論理積のサンプルでは、同じタイプの 2 つのノードを作成することができます。1 つはメッシュに設定され、もう 1 つはサーフェスに設定される汎用アトリビュートです。

作成

プロキシ プラグイン ノードの汎用アトリビュートは、プラグインの initialize() メソッドを使用して作成されます。アトリビュートの作成に加えて、initialize() メソッドはノードにアトリビュートを追加して、このアトリビュートがノードの他のアトリビュートとどのように相互作用するかを指定します。

次のサンプルは、genericAttributeNode (開発キットから入手可能)が出力として汎用アトリビュートを作成する方法を例示します。

    // Adds a generic attribute that accepts a float, float2, float3
    // Called from node initialization method.
    MStatus genericAttributeNode::addComplexFloatGenericAttribute(
        MObject& attrObject,
        const char *longName, const char *shortName )
    {
        // Create the generic attribute and set the 3 accepts types
        MFnGenericAttribute gAttr;
        attrObject = gAttr.create( longName, shortName );
        MStatus status = gAttr.addAccept(MFnNumericData::kFloat);
        CHECK_MSTATUS( status );
        status = gAttr.addAccept(MFnNumericData::k2Float);
        CHECK_MSTATUS( status );
        status = gAttr.addAccept(MFnNumericData::k3Float);
        CHECK_MSTATUS( status );
        gAttr.setWritable(false);
        gAttr.setStorable( false );

        // Add the attribute to the node
        status = addAttribute( attrObject );
        CHECK_MSTATUS( status );
        return MS::kSuccess;
    }

    // Node initialization method
    MStatus genericAttributeNode::initialize()
    {
        MFnNumericAttribute nAttr;
        MStatus status;
        // single float attribute affecting a generic attribute
        gInputInt = nAttr.create( "gInputInt", "gii",
            MFnNumericData::kInt, 0, &status );
        nAttr.setStorable(true);
        nAttr.setKeyable(true);
        CHECK_MSTATUS( status );
        status = addAttribute( gInputInt );
        CHECK_MSTATUS( status );
        if ( !addComplexFloatGenericAttribute(
            gOutputFloat_2Float_3Float,
            "gOutputFloat_2Float_3Float", "gof2f3f" ) )
            return MS::kFailure;
        status = attributeAffects(
            gInputInt, gOutputFloat_2Float_3Float );
        CHECK_MSTATUS( status );

        return MS::kSuccess;
    }

このサンプルでは、入力アトリビュート gInputInt が汎用出力アトリビュート gOutputFloat_2Float_3Float に作用します。出力アトリビュートは float、float2、float3 のいずれかを格納でき、これは MFnGenericAttribute::addAccept() をコールすることで設定します。

汎用アトリビュートの計算

プラグインの汎用アトリビュートがノードに適切に追加されたと仮定すると、これをノードの計算メソッドで使用することができます。計算メソッド内では標準の Maya API コールを使用して、汎用アトリビュート情報を読み取って更新することができます。さらに、汎用アトリビュートに含まれるタイプを修正できます。以下のサンプルでは、汎用アトリビュートは float、float2、float3 のいずれかを格納することができます。計算時に、汎用アトリビュートに格納された float を float3 に変換することができます。

    //
    // Compute that will update the generic attribute
    // when requested.
    //
    MStatus genericAttributeNode::compute( const MPlug& plug, MDataBlock& data )
    {
        MStatus returnStatus;
        // Generic attribute plug
        if ( plug == gOutputFloat_2Float_3Float )
        {
            // attribute affecting generic attribute case. Based on the
            // input attribute, we modify the output generic attribute
            MDataHandle inputDataInt = data.inputValue( gInputInt );
            int inputInt = inputDataInt.asInt();

            // Get the output handle
            MDataHandle outputData = data.outputValue( plug );
            bool isGenericNumeric = false;
            bool isGenericNull = false;
            // Is the output handle generic data
            if ( outputData.isGeneric( isGenericNumeric, isGenericNull ) )
            {
                // Based on the inputHandle, update the generic
                // output handle
                if ( inputInt == 1 )
                    outputData.setGenericBool( false, true );
                else if ( inputInt == 2 )
                    outputData.setGenericBool( true, true );
                else if ( inputInt == 3 )
                    outputData.setGenericChar( 254, true );
                else if ( inputInt == 4 )
                    outputData.setGenericDouble( 3.145, true );
                else if ( inputInt == 5 )
                    outputData.setGenericFloat( 9.98, true );
                else if ( inputInt == 6 )
                    outputData.setGenericShort( 3245, true );
                else if ( inputInt == 7 )
                    outputData.setGenericInt( 32768, true );
                else if ( inputInt == 8 )
                {
                    MFnNumericData numericData;
                    MObject obj = numericData.create(
                        MFnNumericData::k2Float, &returnStatus );
                    CHECK_MSTATUS( returnStatus );
                    returnStatus = numericData.setData(
                        (float)1.5, (float)6.7 );
                    CHECK_MSTATUS( returnStatus );
                    outputData.set( obj );
                }
                else if ( inputInt == 9 )
                {
                    MFnNumericData numericData;
                    MObject obj = numericData.create(
                        MFnNumericData::k3Float, &returnStatus );
                    CHECK_MSTATUS( returnStaus );
                    returnStatus = numericData.setData( (float)2.5, (float)8.7, (float)2.3345 );
                    CHECK_MSTATUS( returnStatus );
                    outputData.set( obj );
                }
                else if ( inputInt == 10 )
                {
                    outputData.setGenericInt( 909, true );
                }
                // Mark the data clean
                outputData.setClean();
                data.setClean( gOutputFloat_2Float_3Float );
            }
        }
        else
        {
            return MS::kUnknownParameter;
        }
        return MS::kSuccess;
    }

このサンプルでは、最初に gInputInt アトリビュートの値を取得します。この整数値は、汎用出力アトリビュート gOutputFloat_2Float_3Float の値とタイプを設定するために使用されます。データ ハンドルが汎用アトリビュートのデータ ブロックから抽出されると、isGeneric() メソッドがコールされて計算コードが汎用アトリビュートを処理します。isGeneric() メソッドには 2 つのパラメータがあります。1 つは isNumeric で、これが true の場合はハンドルが char、float などの簡単な数値情報を含みます。isNumeric が false で isNull が true でない場合は、ハンドルは double や float2 などの複雑なタイプの数値情報を含み、MFnNumericData 関数セットからアクセスすることができます(isNumeric と isNull パラメータは上記のコード サンプルでは使用されていません)。

単一の汎用タイプを相互に区別することはできません。単一の汎用アトリビュートが float、char、または double などのいずれかであることを返すメソッドはありません。