#include <string.h>
#include <maya/MIOStream.h>
#include <math.h>
#include <maya/MPxNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MFnPlugin.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#define EPSILON 0.001
#define ROTATE_ORDER_XYZ 0
#define ROTATE_ORDER_YZX 1
#define ROTATE_ORDER_ZXY 2
#define ROTATE_ORDER_XZY 3
#define ROTATE_ORDER_YXZ 4
#define ROTATE_ORDER_ZYX 5
#define McheckErr(stat,msg) \
if ( MS::kSuccess != stat ) { \
cerr << msg; \
return MS::kFailure; \
}
class buildRotation : public MPxNode
{
public:
buildRotation();
virtual ~buildRotation();
virtual MStatus compute( const MPlug& plug, MDataBlock& data );
static void* creator();
static MStatus initialize();
public:
static MObject up;
static MObject upX;
static MObject upY;
static MObject upZ;
static MObject forward;
static MObject forwardX;
static MObject forwardY;
static MObject forwardZ;
static MObject rotateOrder;
static MObject rotate;
static MObject rotateX;
static MObject rotateY;
static MObject rotateZ;
static MObject rotateMatrix;
static MTypeId id;
};
MTypeId buildRotation::id( 0x80004 );
MObject buildRotation::up;
MObject buildRotation::upX;
MObject buildRotation::upY;
MObject buildRotation::upZ;
MObject buildRotation::forward;
MObject buildRotation::forwardX;
MObject buildRotation::forwardY;
MObject buildRotation::forwardZ;
MObject buildRotation::rotateOrder;
MObject buildRotation::rotate;
MObject buildRotation::rotateX;
MObject buildRotation::rotateY;
MObject buildRotation::rotateZ;
MObject buildRotation::rotateMatrix;
buildRotation::buildRotation() {}
buildRotation::~buildRotation() {}
MStatus buildRotation::compute( const MPlug& plug, MDataBlock& data )
{
MStatus returnStatus;
if ( ( plug == rotate ) || ( plug == rotateMatrix ) ) {
MDataHandle upData = data.inputValue( up, &returnStatus );
McheckErr(returnStatus,"ERROR getting up vector data");
MDataHandle forwardData = data.inputValue( forward, &returnStatus );
McheckErr(returnStatus,"ERROR getting forward vector data");
MVector up = upData.asVector();
MVector forward = forwardData.asVector();
if ( fabs( up * forward ) > EPSILON ) {
MVector orthoVec = up ^ forward;
MVector newForward = orthoVec ^ up;
if ( forward * newForward < 0.0 ) {
newForward *= -1.0;
}
forward = newForward;
}
MTransformationMatrix firstRot;
MVector rotAxis = MVector::yAxis ^ up;
rotAxis.normalize();
firstRot.setToRotationAxis( rotAxis, MVector::yAxis.angle( up ) );
MTransformationMatrix secondRot;
MVector transformedForward = firstRot.asMatrix() * forward;
transformedForward.normalize();
double angle = transformedForward.angle( MVector::zAxis );
if ( transformedForward.x < 0.0 ) {
angle *= -1.0;
}
secondRot.setToRotationAxis( up, angle );
MDataHandle orderHandle = data.inputValue( rotateOrder );
short order = orderHandle.asShort();
MTransformationMatrix::RotationOrder rotOrder;
switch ( order ) {
case ROTATE_ORDER_XYZ:
rotOrder = MTransformationMatrix::kXYZ; break;
case ROTATE_ORDER_YZX:
rotOrder = MTransformationMatrix::kYZX; break;
case ROTATE_ORDER_ZXY:
rotOrder = MTransformationMatrix::kZXY; break;
case ROTATE_ORDER_XZY:
rotOrder = MTransformationMatrix::kXZY; break;
case ROTATE_ORDER_YXZ:
rotOrder = MTransformationMatrix::kYXZ; break;
case ROTATE_ORDER_ZYX:
rotOrder = MTransformationMatrix::kZYX; break;
default:
rotOrder = MTransformationMatrix::kInvalid; break;
}
MTransformationMatrix result = firstRot.asMatrix() * secondRot.asMatrix();
result.reorderRotation( rotOrder );
double rotation[3];
result.getRotation( rotation, rotOrder, MSpace::kTransform );
MDataHandle outputRot = data.outputValue( rotate );
outputRot.set( rotation[0], rotation[1], rotation[2] );
outputRot.setClean();
MDataHandle outputMatrix = data.outputValue( rotateMatrix );
outputMatrix.set( result.asMatrix() );
outputMatrix.setClean();
} else
return MS::kUnknownParameter;
return MS::kSuccess;
}
void* buildRotation::creator()
{
return new buildRotation();
}
MStatus buildRotation::initialize()
{
MFnNumericAttribute nAttr;
MFnMatrixAttribute mAttr;
MFnUnitAttribute uAttr;
MFnEnumAttribute eAttr;
MStatus stat;
upX = nAttr.create( "upX", "ux", MFnNumericData::kDouble );
nAttr.setStorable(false);
upY = nAttr.create( "upY", "uy", MFnNumericData::kDouble );
nAttr.setStorable(false);
upZ = nAttr.create( "upZ", "uz", MFnNumericData::kDouble );
nAttr.setStorable(false);
up = nAttr.create( "up", "u", upX, upY, upZ );
nAttr.setDefault( 0.0, 1.0, 0.0 );
nAttr.setStorable(false);
forwardX = nAttr.create( "forwardX", "fx", MFnNumericData::kDouble, 0.0 );
nAttr.setStorable(false);
forwardY = nAttr.create( "forwardY", "fy", MFnNumericData::kDouble, 0.0 );
nAttr.setStorable(false);
forwardZ = nAttr.create( "forwardZ", "fz", MFnNumericData::kDouble, 1.0 );
nAttr.setStorable(false);
forward = nAttr.create( "forward", "f", forwardX, forwardY, forwardZ );
nAttr.setDefault( 0.0, 0.0, 1.0 );
nAttr.setStorable(false);
rotateOrder = eAttr.create( "rotateOrder", "ro", ROTATE_ORDER_XYZ);
eAttr.addField("xyz", ROTATE_ORDER_XYZ);
eAttr.addField("yzx", ROTATE_ORDER_YZX);
eAttr.addField("zxy", ROTATE_ORDER_ZXY);
eAttr.addField("xzy", ROTATE_ORDER_XZY);
eAttr.addField("yxz", ROTATE_ORDER_YXZ);
eAttr.addField("zyx", ROTATE_ORDER_ZYX);
eAttr.setStorable(false);
rotateX = uAttr.create( "rotateX", "rx", MFnUnitAttribute::kAngle, 0.0 );
nAttr.setStorable(false);
rotateY = uAttr.create( "rotateY", "ry", MFnUnitAttribute::kAngle, 0.0 );
nAttr.setStorable(false);
rotateZ = uAttr.create( "rotateZ", "rz", MFnUnitAttribute::kAngle, 0.0 );
nAttr.setStorable(false);
rotate = nAttr.create( "rotate", "r", rotateX, rotateY, rotateZ );
nAttr.setStorable(false);
rotateMatrix = mAttr.create( "rotateMatrix", "rm" );
nAttr.setStorable(false);
nAttr.setConnectable(true);
stat = addAttribute( up );
if (!stat) { stat.perror("addAttribute"); return stat;}
stat = addAttribute( forward );
if (!stat) { stat.perror("addAttribute"); return stat;}
stat = addAttribute( rotate );
if (!stat) { stat.perror("addAttribute"); return stat;}
stat = addAttribute( rotateOrder );
if (!stat) { stat.perror("addAttribute"); return stat;}
stat = addAttribute( rotateMatrix );
if (!stat) { stat.perror("addAttribute"); return stat;}
stat = attributeAffects( up, rotate );
if (!stat) { stat.perror("attributeAffects"); return stat;}
stat = attributeAffects( up, rotateMatrix );
if (!stat) { stat.perror("attributeAffects"); return stat;}
stat = attributeAffects( forward, rotate );
if (!stat) { stat.perror("attributeAffects"); return stat;}
stat = attributeAffects( forward, rotateMatrix );
if (!stat) { stat.perror("attributeAffects"); return stat;}
stat = attributeAffects( rotateOrder, rotate );
if (!stat) { stat.perror("attributeAffects"); return stat;}
stat = attributeAffects( rotateOrder, rotateMatrix );
if (!stat) { stat.perror("attributeAffects"); return stat;}
return MS::kSuccess;
}
MStatus initializePlugin( MObject obj )
{
MStatus status;
MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
status = plugin.registerNode( "buildRotation", buildRotation::id,
buildRotation::creator, buildRotation::initialize );
if (!status) {
status.perror("registerNode");
return status;
}
return status;
}
MStatus uninitializePlugin( MObject obj)
{
MStatus status;
MFnPlugin plugin( obj );
status = plugin.deregisterNode( buildRotation::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
return status;
}