//- // ========================================================================== // Copyright 2019 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk // license agreement provided at the time of installation or download, // or which otherwise accompanies this software in either electronic // or hard copy form. // ========================================================================== //+ // Description: // Demonstrates how to create your own custom image plane based on // Maya's internal image plane classes. This allows API users to // override the default Maya image plane behavior. This class works // like typical API nodes in that it can have a compute method and // can contain static attributes added by the API user. This // example class overrides the default image plane behavior and // allows users to add transparency to an image plane using the // transparency attribute on the node. Note, this code also // illustrates how to use MImage to control the floating point // depth buffer. When useDepthMap is set to true, depth is added // is added to the image such that half of the image is at the near // clip plane and the remaining half is at the far clip plane. // // Note, once the image plane node has been created it you must // attached it to the camera shape that is displaying the node. // You need to use the imagePlane command to attach the image plane // you created to the specified camera. // // This example works only with renderers that use node evaluation // as a part of the rendering process, e.g. Maya Software. It does // not work with 3rd party renderers that rely on a scene translation // mechanism. // // For example, // string $imageP = `createNode customImagePlane`; // imagePlane -edit -camera "persp" $imageP // #include #include #include #include #include #include #include #include #include #include class customImagePlane : public MPxImagePlane { public: customImagePlane(); virtual ~customImagePlane(); MStatus loadImageMap( const MString &fileName, int frame, MImage &image ) override; bool getInternalValue( const MPlug&, MDataHandle&) override; bool setInternalValue( const MPlug&, const MDataHandle&) override; static void* creator(); static MStatus initialize(); static MTypeId id; // The IFF type id static MObject aTransparency; static void timeChangedCallback( void * ); private: double fTransparency; MCallbackId fTimeChangedCallbackId; }; MObject customImagePlane::aTransparency; customImagePlane::customImagePlane() : MPxImagePlane() , fTransparency( 0.0 ) , fTimeChangedCallbackId( 0 ) { // Uncomment the following line if you need a workaround which updates the // transparency of the image plane during playback or srubbing with the // Time Slider. // //fTimeChangedCallbackId = MEventMessage::addEventCallback( // "timeChanged", &timeChangedCallback, this); } customImagePlane::~customImagePlane() { if (fTimeChangedCallbackId != 0) { MMessage::removeCallback(fTimeChangedCallbackId); fTimeChangedCallbackId = 0; } } bool customImagePlane::getInternalValue( const MPlug &plug, MDataHandle &handle) { if ( plug == aTransparency ) { handle.set( fTransparency ); return true; } return MPxImagePlane::getInternalValue( plug, handle ); } bool customImagePlane::setInternalValue( const MPlug &plug, const MDataHandle &handle) { if ( plug == aTransparency ) { fTransparency = handle.asDouble(); setImageDirty(); return true; } return MPxImagePlane::setInternalValue( plug, handle ); } MStatus customImagePlane::loadImageMap( const MString &fileName, int frame, MImage &image ) { image.readFromFile(fileName); unsigned int width, height; image.getSize(width, height); unsigned int size = width * height; unsigned char *pixels = image.pixels(); unsigned int i; for ( i = 0; i < size; i ++, pixels += 4 ) { pixels[3] = (unsigned char)(pixels[3] * (1.0 - fTransparency)); } MPlug depthMap( thisMObject(), useDepthMap ); bool value; depthMap.getValue( value ); if ( value ) { float *buffer = new float[width*height]; unsigned int c, j; for ( c = i = 0; i < height; i ++ ) { for ( j = 0; j < width; j ++, c++ ) { if ( i > height/2 ) { buffer[c] = -1.0f; } else { buffer[c] = 0.0f; } } } image.setDepthMap( buffer, width, height ); delete [] buffer; } return MStatus::kSuccess; } MTypeId customImagePlane::id( 0x1A19 ); void* customImagePlane::creator() { return new customImagePlane; } MStatus customImagePlane::initialize() { MFnNumericAttribute nAttr; aTransparency = nAttr.create( "transparency", "tp", MFnNumericData::kDouble, 0 ); nAttr.setStorable(true); nAttr.setInternal(true); nAttr.setMin(0.0); nAttr.setMax(1.0); nAttr.setDefault(0.0); nAttr.setKeyable(true); addAttribute( aTransparency ); return MStatus::kSuccess; } // These methods load and unload the plugin, registerNode registers the // new node type with maya // MStatus initializePlugin( MObject obj ) { MFnPlugin plugin( obj, PLUGIN_COMPANY, "7.0", "Any"); MStatus status = plugin.registerNode( "customImagePlane", customImagePlane::id, customImagePlane::creator, customImagePlane::initialize, MPxNode::kImagePlaneNode ); if (!status) { status.perror("registerNode"); } return status; } MStatus uninitializePlugin( MObject obj ) { MFnPlugin plugin( obj ); MStatus status = plugin.deregisterNode( customImagePlane::id ); if (!status) { status.perror("deregisterNode"); } return status; } void customImagePlane::timeChangedCallback(void *clientData) { customImagePlane* imagePlane = (customImagePlane *) clientData; if (imagePlane) { MString cmd = "getAttr " + imagePlane->name() + ".tp"; MGlobal::executeCommand(cmd); } }