//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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: // Inputs static MObject up; // Up vector static MObject upX; static MObject upY; static MObject upZ; static MObject forward; // Front Vector static MObject forwardX; static MObject forwardY; static MObject forwardZ; static MObject rotateOrder; // Desired rotation order // Outputs static MObject rotate; // Rotation as a 3 Double static MObject rotateX; static MObject rotateY; static MObject rotateZ; static MObject rotateMatrix; // Rotation as a matrix 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(); // Make sure that the up and forward vectors are orthogonal // if ( fabs( up * forward ) > EPSILON ) { // Non-zero dot product // MVector orthoVec = up ^ forward; MVector newForward = orthoVec ^ up; if ( forward * newForward < 0.0 ) { // Reverse the vector // newForward *= -1.0; } forward = newForward; } // Calculate the rotation required to align the y-axis with the up // vector // MTransformationMatrix firstRot; MVector rotAxis = MVector::yAxis ^ up; rotAxis.normalize(); firstRot.setToRotationAxis( rotAxis, MVector::yAxis.angle( up ) ); // Calculate the second rotation required to align the forward vector // MTransformationMatrix secondRot; MVector transformedForward = firstRot.asMatrix() * forward; transformedForward.normalize(); double angle = transformedForward.angle( MVector::zAxis ); if ( transformedForward.x < 0.0 ) { // Compensate for the fact that the angle method returns // the absolute value // angle *= -1.0; } secondRot.setToRotationAxis( up, angle ); // Get the requested rotation order // 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; // Set up inputs // 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); // Set up outputs // 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, "Alias", "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; }