#include <math.h>
#include <maya/MPxNode.h>
#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MPointArray.h>
#include <maya/MFnPlugin.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFnMesh.h>
#include <maya/MItMeshVertex.h>
#include <maya/MDagPath.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MMutexLock.h>
#include <maya/MRenderUtil.h>
#include <maya/MSelectionList.h>
class cvColorShader : public MPxNode
{
public:
cvColorShader();
virtual ~cvColorShader();
virtual MStatus compute( const MPlug&, MDataBlock& );
virtual void postConstructor();
static void * creator();
static MStatus initialize();
static MTypeId id;
private:
static inline float dotProd(const MFloatVector &, const MFloatVector &);
static MStatus getTriangleInfo(
const MDagPath& meshPath,
long triangleId,
MPointArray& vertPositions,
MColorArray& vertColours
);
static MMutexLock fCriticalSection;
static MObject aReverseAlpha;
static MObject aPointObj;
static MObject aPrimitiveId;
static MObject aObjectId;
static MObject aOutColor;
static MObject aOutAlpha;
};
MTypeId cvColorShader::id( 0x8000f );
MMutexLock cvColorShader::fCriticalSection;
MObject cvColorShader::aReverseAlpha;
MObject cvColorShader::aPointObj;
MObject cvColorShader::aPrimitiveId;
MObject cvColorShader::aObjectId;
MObject cvColorShader::aOutColor;
MObject cvColorShader::aOutAlpha;
void cvColorShader::postConstructor( )
{
setMPSafe(true);
}
cvColorShader::cvColorShader()
{
}
cvColorShader::~cvColorShader()
{
}
void * cvColorShader::creator()
{
return new cvColorShader();
}
MStatus cvColorShader::initialize()
{
MFnNumericAttribute nAttr;
aReverseAlpha = nAttr.create( "reverseAlpha", "ra",
MFnNumericData::kBoolean);
CHECK_MSTATUS ( nAttr.setDefault( true ) );
aPointObj = nAttr.createPoint( "pointObj", "po" );
CHECK_MSTATUS ( nAttr.setStorable(false) );
CHECK_MSTATUS ( nAttr.setHidden(true) );
aPrimitiveId = nAttr.create( "primitiveId", "pi", MFnNumericData::kLong);
CHECK_MSTATUS ( nAttr.setHidden(true) );
aObjectId = nAttr.createAddr("objectId", "oi");
CHECK_MSTATUS ( nAttr.setHidden(true) );
aOutColor = nAttr.createColor( "outColor", "oc" );
CHECK_MSTATUS ( nAttr.setStorable(false) );
CHECK_MSTATUS ( nAttr.setReadable(true) );
CHECK_MSTATUS ( nAttr.setWritable(false) );
aOutAlpha = nAttr.create( "outAlpha", "oa", MFnNumericData::kFloat);
CHECK_MSTATUS ( nAttr.setDisconnectBehavior(MFnAttribute::kReset) );
CHECK_MSTATUS ( nAttr.setStorable(false) );
CHECK_MSTATUS ( nAttr.setReadable(true) );
CHECK_MSTATUS ( nAttr.setWritable(false) );
CHECK_MSTATUS ( addAttribute(aPointObj) );
CHECK_MSTATUS ( addAttribute(aOutColor) );
CHECK_MSTATUS ( addAttribute(aOutAlpha) );
CHECK_MSTATUS ( addAttribute(aReverseAlpha) );
CHECK_MSTATUS ( addAttribute(aPrimitiveId) );
CHECK_MSTATUS ( addAttribute(aObjectId) );
CHECK_MSTATUS ( attributeAffects(aPointObj, aOutColor) );
CHECK_MSTATUS ( attributeAffects(aPrimitiveId, aOutColor) );
CHECK_MSTATUS ( attributeAffects(aObjectId, aOutColor) );
CHECK_MSTATUS ( attributeAffects(aReverseAlpha, aOutAlpha) );
CHECK_MSTATUS ( attributeAffects(aPointObj, aOutAlpha) );
CHECK_MSTATUS ( attributeAffects(aPrimitiveId, aOutAlpha) );
CHECK_MSTATUS ( attributeAffects(aObjectId, aOutAlpha) );
return MS::kSuccess;
}
inline float cvColorShader::dotProd(
const MFloatVector & v1,
const MFloatVector & v2)
{
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}
MStatus cvColorShader::compute( const MPlug& plug, MDataBlock& block )
{
if ((plug != aOutColor) && (plug.parent() != aOutColor) &&
(plug != aOutAlpha))
return MS::kUnknownParameter;
MStatus status;
MObject thisNode = thisMObject();
bool rev_flag = block.inputValue(aReverseAlpha).asBool();
long triangleId = block.inputValue(aPrimitiveId).asLong();
void* objectId = block.inputValue(aObjectId).asAddr();
MFloatVector& pointObj = block.inputValue( aPointObj ).asFloatVector();
MColor resultColor;
if (objectId != NULL) {
MDagPath meshPath;
MSelectionList list;
status = MRenderUtil::renderObjectItem(objectId, list);
list.getDagPath(0, meshPath);
MPointArray pos;
MColorArray colours;
status = getTriangleInfo(meshPath, triangleId, pos, colours);
MFloatVector pos1((float)pos[0].x, (float)pos[0].y, (float)pos[0].z);
MFloatVector pos2((float)pos[1].x, (float)pos[1].y, (float)pos[1].z);
MFloatVector pos3((float)pos[2].x, (float)pos[2].y, (float)pos[2].z);
pointObj = pointObj - pos3;
pos1 = pos1 - pos3;
pos2 = pos2 - pos3;
MFloatVector norm = pos1 ^ pos2;
float len = dotProd(norm, norm);
len = dotProd(norm, pointObj)/len;
pointObj = pointObj - (len * norm);
float aa = dotProd(pos1, pos1);
float bb = dotProd(pos2, pos2);
float ab = dotProd(pos1, pos2);
float am = dotProd(pos1, pointObj);
float bm = dotProd(pos2, pointObj);
float det = aa*bb - ab*ab;
float a = (am*bb - bm*ab) / det;
float b = (bm*aa - am*ab) / det;
float c = 1-a-b;
resultColor = (a*colours[0]) + (b*colours[1]) + (c*colours[2]);
if( rev_flag == true )
resultColor.a = 1.0f - resultColor.a;
}
MDataHandle outColorHandle = block.outputValue( aOutColor );
MFloatVector& outColor = outColorHandle.asFloatVector();
outColor.x = resultColor.r;
outColor.y = resultColor.g;
outColor.z = resultColor.b;
outColorHandle.setClean();
MDataHandle outAlphaHandle = block.outputValue( aOutAlpha );
float& outAlpha = outAlphaHandle.asFloat();
outAlpha = resultColor.a;
outAlphaHandle.setClean();
return MS::kSuccess;
}
MStatus cvColorShader::getTriangleInfo(
const MDagPath& meshPath,
long triangleId,
MPointArray& vertPositions,
MColorArray& vertColours
) {
MStatus st;
MFnMesh meshFn(meshPath);
MObjectArray shaders;
MObjectArray components;
meshFn.getConnectedSetsAndMembers(
meshPath.instanceNumber(), shaders, components, true
);
int polygonId = -1;
int triangleCount = 0;
MIntArray vertIndices;
for (unsigned int s = 0; (polygonId < 0) && (s < shaders.length()); ++s) {
bool isLocked = true;
fCriticalSection.lock();
MItMeshPolygon faceIter(meshPath, components[s]);
for (; !faceIter.isDone(); faceIter.next()) {
if (faceIter.hasValidTriangulation()) {
int nTri;
faceIter.numTriangles(nTri);
if (triangleId < triangleCount + nTri) {
polygonId = faceIter.index();
st = faceIter.getTriangle(
triangleId - triangleCount,
vertPositions,
vertIndices,
MSpace::kObject
);
break;
}
triangleCount += nTri;
}
if (isLocked) {
fCriticalSection.unlock();
isLocked = false;
}
}
if (isLocked) {
fCriticalSection.unlock();
}
}
if ((polygonId == -1) || !st) {
return MS::kFailure;
}
MItMeshVertex vertIter(meshPath);
int preIndex = 0;
vertColours.setLength(3);
CHECK_MSTATUS ( vertIter.setIndex( vertIndices[0], preIndex) );
CHECK_MSTATUS ( vertIter.getColor( vertColours[0], polygonId ) );
CHECK_MSTATUS ( vertIter.setIndex( vertIndices[1], preIndex) );
CHECK_MSTATUS ( vertIter.getColor( vertColours[1], polygonId ) );
CHECK_MSTATUS ( vertIter.setIndex( vertIndices[2], preIndex) );
CHECK_MSTATUS ( vertIter.getColor( vertColours[2], polygonId ) );
return MS::kSuccess;
}
MStatus initializePlugin( MObject obj )
{
const MString UserClassify( "utility/color" );
MFnPlugin plugin( obj, PLUGIN_COMPANY, "5.0", "Any");
CHECK_MSTATUS ( plugin.registerNode( "cvColorShader", cvColorShader::id,
cvColorShader::creator,
cvColorShader::initialize,
MPxNode::kDependNode, &UserClassify ) );
return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
MFnPlugin plugin( obj );
CHECK_MSTATUS ( plugin.deregisterNode( cvColorShader::id ) );
return MS::kSuccess;
}