シェーディング ノード プラグインは、複合アトリビュート(Compound Attributes)と単純なアトリビュート(Simple Attributes)の使用に依存します。レンダリング サンプラとシェーディング ネットワーク間のデータ マッピングは、アトリビュート名で行います。この方法は直接的で習得しやすく、十分に一般的で、現在のレンダリング要件と将来の拡張に対処できます。
プラグインが必要とするすべてのレンダリング アトリビュートは、現在のサンプリングの前に計算されています。プラグインの compute() メソッドに渡される「datablock」引数には、ノードが要求するレンダリング アトリビュート情報が含まれています。ディペンデンシー グラフによってプラグインが評価されると、評価する特定アトリビュートの「plug」引数も渡されます。評価を最適化するには、プラグイン内で定義した出力アトリビュートのみをチェックします。
このプラグイン ノードの例には、id アトリビュート以外に 20 個のアトリビュートが含まれています。
このノードは、データ ブロックから取得したサーフェス法線の方向に基づいて 2 つのカラー間を補間し、そのクラスの compute() メソッドを使用して、出力カラー アトリビュートに配置するカラーを派生させます。
class InterpNode : public MPxNode { public: InterpNode(); virtual ~InterpNode(); virtual MStatus compute( const MPlug&, MDataBlock& ); static void * creator(); static MStatus initialize(); static MTypeId id; protected: static MObject InputValue; static MObject color1R,color1G,color1B,color1; static MObject color2R,color2G,color2B,color2; static MObject aNormalCameraX, aNormalCameraY, aNormalCameraZ, aNormalCamera; static MObject aPointCameraX, aPointCameraY, aPointCameraZ, aPointCamera; static MObject aOutColorR, aOutColorG, aOutColorB, aOutColor; }; MObject InterpNode::InputValue; MObject InterpNode::color1R; MObject InterpNode::color1G; MObject InterpNode::color1B; MObject InterpNode::color1; MObject InterpNode::color2R; MObject InterpNode::color2G; MObject InterpNode::color2B; MObject InterpNode::color2; MObject InterpNode::aNormalCameraX; MObject InterpNode::aNormalCameraY; MObject InterpNode::aNormalCameraZ; MObject InterpNode::aNormalCamera; MObject InterpNode::aPointCameraX; MObject InterpNode::aPointCameraY; MObject InterpNode::aPointCameraZ; MObject InterpNode::aPointCamera; MObject InterpNode::aOutColorR; MObject InterpNode::aOutColorG; MObject InterpNode::aOutColorB; MObject InterpNode::aOutColor;
MStatus initializePlugin( MObject obj ) { const MString UserClassify( "utility/general" ); MFnPlugin plugin( obj, "Autodesk", "1.0", "Any"); plugin.registerNode( "Interp", InterpNode::id, InterpNode::creator, InterpNode::initialize, MPxNode::kDependNode, &UserClassify); return MS::kSuccess; } MStatus uninitializePlugin( MObject obj) { MFnPlugin plugin( obj ); plugin.deregisterNode( InterpNode::id ); return MS::kSuccess; }
MStatus InterpNode::initialize() { MFnNumericAttribute nAttr; // Inputs and Attributes // // User defined attributes require a long-name and short- // name that are required to be unique within the node. // (See the compound attribute color1 named "Sides".) // // Rendering attributes that your node wants to get from // the sampler require them to be defined given the pre- // defined unique long-name.(See the compound attribute // aNormalCamera named "normalCamera".) // // User defined Attributes are generally something that you // want to store in the Maya file. The setStorable(true) // method enables an attribute to be stored into the Maya // scene file. // // Rendering attributes are primarily data that is // generated per sample and not something that you want to // store in a file. To disable an attribute from being // recorded to the Maya scene file use the // setStorable(false) method. // // Simple attributes that represent a range of values can // enable a slider on the Attribute Editor by using the // methods setMin() and setMax(). // (See the simple attribute InputValue named "Power".) // // Compound attributes that represent a vector of 3 floats // can enable a color swatch on the Attribute Editor that // will launch a color picker tool by using the method // setUsedAsColor(true). // (See the compound attribute color1 name "Sides".) // // Both Simple and Compound attributes can be initialized // with a default value using the method setDefault(). // // Attributes by default show up in the Attribute Editor // and in the Connection Editor unless they are specified // as being hidden by using the method setHidden(true). // // Attributes by default have both read/write access in the // dependency graph. To change an attributes behaviour you // can use the methods setReadable() and setWritable(). The // method setReadable(true) indicates that the attribute // can be used as the source in a dependency graph // connection. The method setWritable(true) indicates that // the attribute can be used as the destination in a // dependency graph connection. // (See the compound attribute aOutColor named "outColor" // below. It has been marked as a read-only attribute since // it is the computed result of the node, it is not stored // in the Maya file since it is always computed, and it is // marked as hidden to prevent it from being displayed in // the user interface.) // // // User defined input value InputValue = nAttr.create( "Power", "pow", MFnNumericData::kFloat); nAttr.setDefault(1.0f); nAttr.setMin(0.0f); nAttr.setMax(3.0f); nAttr.setStorable(true); // User defined color attribute color1R = nAttr.create( "color1R", "c1r", MFnNumericData::kFloat); color1G = nAttr.create( "color1G", "c1g", MFnNumericData::kFloat); color1B = nAttr.create( "color1B", "c1b", MFnNumericData::kFloat); color1 = nAttr.create( "Sides", "c1", color1R, color1G, color1B); nAttr.setStorable(true); nAttr.setUsedAsColor(true); nAttr.setDefault(1.0f, 1.0f, 1.0f); color2R = nAttr.create( "color2R", "c2r", MFnNumericData::kFloat); color2G = nAttr.create( "color2G", "c2g", MFnNumericData::kFloat); color2B = nAttr.create( "color2B", "c2b", MFnNumericData::kFloat); color2 = nAttr.create( "Facing", "c2", color2R, color2G, color2B); nAttr.setStorable(true); nAttr.setUsedAsColor(true); nAttr.setDefault(0.0f, 0.0f, 0.0f); // Surface Normal supplied by the render sampler aNormalCameraX = nAttr.create( "normalCameraX", "nx", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aNormalCameraY = nAttr.create( "normalCameraY", "ny", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aNormalCameraZ = nAttr.create( "normalCameraZ", "nz", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aNormalCamera = nAttr.create( "normalCamera","n", aNormalCameraX, aNormalCameraY, aNormalCameraZ); nAttr.setStorable(false); nAttr.setHidden(true); // Point on surface in camera space, will be used to compute view vector aPointCameraX = nAttr.create( "pointCameraX", "px", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aPointCameraY = nAttr.create( "pointCameraY", "py", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aPointCameraZ = nAttr.create( "pointCameraZ", "pz", MFnNumericData::kFloat); nAttr.setStorable(false); nAttr.setDefault(1.0f); aPointCamera = nAttr.create( "pointCamera","p", aPointCameraX, aPointCameraY, aPointCameraZ); nAttr.setStorable(false); nAttr.setHidden(true); // Outputs aOutColorR = nAttr.create( "outColorR", "ocr", MFnNumericData::kFloat); aOutColorG = nAttr.create( "outColorG", "ocg", MFnNumericData::kFloat); aOutColorB = nAttr.create( "outColorB", "ocb", MFnNumericData::kFloat); aOutColor = nAttr.create( "outColor", "oc", aOutColorR, aOutColorG, aOutColorB); nAttr.setStorable(false); nAttr.setHidden(false); nAttr.setReadable(true); nAttr.setWritable(false); addAttribute(InputValue); addAttribute(color1R); addAttribute(color1G); addAttribute(color1B); addAttribute(color1); addAttribute(color2R); addAttribute(color2G); addAttribute(color2B); addAttribute(color2); addAttribute(aNormalCameraX); addAttribute(aNormalCameraY); addAttribute(aNormalCameraZ); addAttribute(aNormalCamera); addAttribute(aPointCameraX); addAttribute(aPointCameraY); addAttribute(aPointCameraZ); addAttribute(aPointCamera); addAttribute(aOutColorR); addAttribute(aOutColorG); addAttribute(aOutColorB); addAttribute(aOutColor); attributeAffects (InputValue, aOutColor); attributeAffects (color1R, color1); attributeAffects (color1G, color1); attributeAffects (color1B, color1); attributeAffects (color1, aOutColor); attributeAffects (color2R, color2); attributeAffects (color2G, color2); attributeAffects (color2B, color2); attributeAffects (color2, aOutColor); attributeAffects (aNormalCameraX, aOutColor); attributeAffects (aNormalCameraY, aOutColor); attributeAffects (aNormalCameraZ, aOutColor); attributeAffects (aNormalCamera, aOutColor); attributeAffects (aPointCameraX, aOutColor); attributeAffects (aPointCameraY, aOutColor); attributeAffects (aPointCameraZ, aOutColor); attributeAffects (aPointCamera, aOutColor); return MS::kSuccess; }
MStatus InterpNode::compute( const MPlug& plug, MDataBlock& block ) { int k=0; float gamma,scalar; k |= (plug == aOutColor); k |= (plug == aOutColorR); k |= (plug == aOutColorG); k |= (plug == aOutColorB); if (!k) return MS::kUnknownParameter; MFloatVector resultColor(0.0,0.0,0.0); MFloatVector& Side = block.inputValue( color1 ). asFloatVector(); MFloatVector& Face = block.inputValue( color2 ). asFloatVector(); MFloatVector& surfaceNormal = block. inputValue( aNormalCamera ). asFloatVector(); MFloatVector& viewVector = block. inputValue( aPointCamera ). asFloatVector(); float power = block.inputValue( InputValue ).asFloat(); // Normalize the view vector double d = sqrt((viewVector[0] * viewVector[0]) + (viewVector[1] * viewVector[1]) + (viewVector[2] * viewVector[2])); if (d != (double)0.0) { viewVector[0] /= d; viewVector[1] /= d; viewVector[2] /= d; } // find dot product float scalarNormal = ((viewVector[0]*surfaceNormal[0]) + (viewVector[1]*surfaceNormal[1]) + (viewVector[2]*surfaceNormal[2])); // take the absolute value if (scalarNormal < 0.0) scalarNormal *= -1.0; // Use InputValue to change interpolation // power == 1.0 linear // power >= 0.0 use gamma function // if (power > 0.0) { gamma = 1.0 / power; scalar = pow(scalarNormal,gamma); } else { scalar = 0.0; } // Interpolate the colors MFloatVector interp(0.0,0.0,0.0); interp[0] = scalar * (Face[0] - Side[0]); interp[1] = scalar * (Face[1] - Side[1]); interp[2] = scalar * (Face[2] - Side[2]); resultColor[0] = Side[0] + interp[0]; resultColor[1] = Side[1] + interp[1]; resultColor[2] = Side[2] + interp[2]; // set ouput color attribute MDataHandle outColorHandle = block. outputValue( aOutColor ); MFloatVector& outColor = outColorHandle. asFloatVector(); outColor = resultColor; outColorHandle.setClean(); return MS::kSuccess; }