//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void ConnectIntWeld( vm::CUndo &undo, const MObject &weldNodeObj, const MDagPath &toWeldPath, int nType, int nIntValue, const MMatrix &offsetMatrix ) { MFnDependencyNode weldFn( weldNodeObj ); MFnDagNode toWeldFn( toWeldPath ); MPlug wiAP = weldFn.findPlug( CVstWeldNode::m_iaWeldInput ); const uint nWeldIndex = vm::NextAvailable( wiAP ); MPlug wiP = wiAP.elementByLogicalIndex( nWeldIndex ); undo.SetAttr( wiP.child( CVstWeldNode::m_iaType ), nType ); undo.SetAttr( wiP.child( CVstWeldNode::m_iaInt ), nIntValue ); MFnMatrixData dFn; MObject mdObj = dFn.create( offsetMatrix ); undo.SetAttr( wiP.child( CVstWeldNode::m_iaOffsetMatrix ), mdObj ); undo.Connect( toWeldFn.findPlug( "parentInverseMatrix" ).elementByLogicalIndex( toWeldPath.instanceNumber() ), wiP.child( CVstWeldNode::m_iaInverseParentSpace ), true ); undo.Connect( toWeldFn.findPlug( "rotateOrder" ), wiP.child( CVstWeldNode::m_iaRotateOrder ), true ); MPlug woAP = weldFn.findPlug( CVstWeldNode::m_oaWeldOutput ); MPlug woP = woAP.elementByLogicalIndex( nWeldIndex ); MPlug tP = woP.child( CVstWeldNode::m_oaTranslate ); undo.Connect( tP.child( CVstWeldNode::m_oaTranslateX ), toWeldFn.findPlug( "translateX" ) ); undo.Connect( tP.child( CVstWeldNode::m_oaTranslateY ), toWeldFn.findPlug( "translateY" ) ); undo.Connect( tP.child( CVstWeldNode::m_oaTranslateZ ), toWeldFn.findPlug( "translateZ" ) ); MPlug rP = woP.child( CVstWeldNode::m_oaRotate ); undo.Connect( rP.child( CVstWeldNode::m_oaRotateX ), toWeldFn.findPlug( "rotateX" ) ); undo.Connect( rP.child( CVstWeldNode::m_oaRotateY ), toWeldFn.findPlug( "rotateY" ) ); undo.Connect( rP.child( CVstWeldNode::m_oaRotateZ ), toWeldFn.findPlug( "rotateZ" ) ); }
//############################################### tima: bool polyModifierCmd::setZeroTweaks() { MFnNumericData numDataFn; MObject nullVector; MFnDependencyNode depNodeFn; numDataFn.create( MFnNumericData::k3Float ); numDataFn.setData( 0, 0, 0 ); nullVector = numDataFn.object(); MObject object = fDagPath.node(); depNodeFn.setObject( object); MPlug meshTweakPlug = depNodeFn.findPlug( "pnts" ); MPlug tweak; unsigned numTweaks = fTweakIndexArray.length(); if( !meshTweakPlug.isNull() ) { for( unsigned i = 0; i < numTweaks; i++ ) { tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } } return true; }
//----------------------------------------------------------------------------- // This is here for reference. It isn't currently used //----------------------------------------------------------------------------- void CVsSkinnerCmd::DoConnectGeometry( const MDagPath &skinnerPath, const MDagPath &gDagPath ) { MObject skinnerObj( skinnerPath.node() ); const MFnDependencyNode vsSkinnerFn( skinnerObj ); const MFnMesh meshFn( gDagPath ); // Connect things up MPlug sP; MPlug dP; MDagModifier &mDagModifier( m_undo.DagModifier() ); // Connect mesh.worldMatrix[#] vsSkinner.geometryWorldMatrix sP = meshFn.findPlug( "worldMatrix" ); sP = sP.elementByLogicalIndex( gDagPath.instanceNumber() ); dP = vsSkinnerFn.findPlug( "geometryWorldMatrix" ); mDagModifier.connect( sP, dP ); sP = meshFn.findPlug( "outMesh" ); dP = vsSkinnerFn.findPlug( "inputGeometry" ); mDagModifier.connect( sP, dP ); mDagModifier.doIt(); // Add the default volume MSelectionList emptyList; MGlobal::setActiveSelectionList( DoNewVolumes( skinnerPath, emptyList ), MGlobal::kReplaceList ); }
//--------------------------------------------------- bool DagHelper::connectToList ( const MPlug& source, const MObject& destination, const MString& destinationAttribute, int* _index ) { MStatus status; MFnDependencyNode destFn ( destination ); MPlug dest = destFn.findPlug ( destinationAttribute, &status ); if ( status != MStatus::kSuccess ) return false; if ( !dest.isArray() ) return false; int index = ( _index != NULL ) ? *_index : -1; if ( index < 0 ) { index = getNextAvailableIndex ( dest, ( int ) dest.evaluateNumElements() ); if ( _index != NULL ) *_index = index; } MPlug d = dest.elementByLogicalIndex ( index ); MDGModifier modifier; modifier.connect ( source, d ); status = modifier.doIt(); return status == MStatus::kSuccess; }
//--------------------------------------------------- // Retrieve the bind pose for a controller/joint std::pair // MMatrix DagHelper::getBindPoseInverse ( const MObject& controller, const MObject& influence ) { MStatus status; if ( controller.apiType() == MFn::kSkinClusterFilter ) { MFnSkinCluster controllerFn ( controller ); // Find the correct index for the pre-bind matrix uint index = controllerFn.indexForInfluenceObject ( MDagPath::getAPathTo ( influence ), &status ); if ( status != MStatus::kSuccess ) return MMatrix::identity; MPlug preBindMatrixPlug = controllerFn.findPlug ( "bindPreMatrix", &status ); preBindMatrixPlug = preBindMatrixPlug.elementByLogicalIndex ( index, &status ); if ( status != MStatus::kSuccess ) return MMatrix::identity; // Get the plug's matrix MMatrix ret; if ( !DagHelper::getPlugValue ( preBindMatrixPlug, ret ) ) return MMatrix::identity; return ret; } else if ( controller.apiType() == MFn::kJointCluster ) { MMatrix ret; DagHelper::getPlugValue ( influence, "bindPose", ret ); return ret.inverse(); } else return MMatrix::identity; }
//--------------------------------------------------- MObject DagHelper::createExpression ( const MPlug& plug, const MString& expression ) { MFnDependencyNode expressionFn; MObject expressionObj = expressionFn.create ( "expression" ); DagHelper::setPlugValue ( expressionObj, "expression", expression ); MPlug output = expressionFn.findPlug ( "output" ); MPlug firstOutput = output.elementByLogicalIndex ( 0 ); DagHelper::connect ( firstOutput, plug ); return expressionObj; }
// ------------------------------------------- MPlug AnimationHelper::getTargetedPlug ( MPlug parentPlug, int index ) { if ( index >= 0 && parentPlug.isCompound() ) { return parentPlug.child ( index ); } else if ( index >= 0 && parentPlug.isArray() ) { return parentPlug.elementByLogicalIndex ( index ); } else return parentPlug; }
//--------------------------------------------------- // set the bind pose for a transform // MStatus DagHelper::setBindPoseInverse ( const MObject& node, const MMatrix& bindPoseInverse ) { MStatus status; MFnDependencyNode dgFn ( node ); MPlug bindPosePlug = dgFn.findPlug ( "bindPose", &status ); if ( status != MS::kSuccess ) { MGlobal::displayWarning ( MString ( "No bindPose found on node " ) + dgFn.name() ); return status; } MFnMatrixData matrixFn; MObject val = matrixFn.create ( bindPoseInverse.inverse(), &status ); MObject invval = matrixFn.create ( bindPoseInverse, &status ); if ( status != MS::kSuccess ) { MGlobal::displayWarning ( MString ( "Error setting bindPose on node " ) + dgFn.name() ); return status; } // set the bind pose on the joint itself bindPosePlug.setValue ( val ); // Now, perhaps more significantly, see if there's a // skinCluster using this bone and update its bind // pose (as the joint bind pose is not connected to // the skin - it's set at bind time from the joint's // current position, and our importer may not want to // disturb the current scene state just to put bones // in a bind position before creating skin clusters) MObject _node ( node ); MItDependencyGraph it ( _node, MFn::kSkinClusterFilter ); while ( !it.isDone() ) { MPlug plug = it.thisPlug(); unsigned int idx = plug.logicalIndex(); MFnDependencyNode skinFn ( plug.node() ); MPlug skinBindPosePlug = skinFn.findPlug ( "bindPreMatrix", &status ); if ( status == MS::kSuccess ) { // The skinCluster stores inverse inclusive matrix // so notice we use invval (the MObject created off // the inverse matrix here) skinBindPosePlug = skinBindPosePlug.elementByLogicalIndex ( idx ); skinBindPosePlug.setValue ( invval ); } it.next(); } return status; }
void SurfaceAttach::inUVs(MFnDependencyNode &fn) { MPlug inUVPlug = fn.findPlug("inUV"); const std::uint32_t numElements = inUVPlug.numElements(); this->uInputs.resize((size_t)(numElements)); this->vInputs.resize((size_t)(numElements)); for (std::uint32_t i=0; i < numElements; i++){ MPlug uvPlug = inUVPlug.elementByLogicalIndex(i); this->uInputs[i] = uvPlug.child(0).asDouble(); this->vInputs[i] = uvPlug.child(1).asDouble(); } }
//--------------------------------------------------- // get the first empty item in the named array plug unsigned DagHelper::getFirstEmptyElementId ( const MPlug& parent ) { unsigned num_element = 1; if ( parent.numElements() > num_element ) num_element = parent.numElements(); for ( unsigned i = 0; i< num_element; i++ ) { if ( !parent.elementByLogicalIndex ( i ).isConnected() ) return i; } return parent.numElements() +1; }
IECore::ObjectPtr FromMayaTransformConverter::doConversion( const MDagPath &dagPath, IECore::ConstCompoundObjectPtr operands ) const { MTransformationMatrix transform; if( m_spaceParameter->getNumericValue()==Local ) { MFnTransform fnT( dagPath ); transform = fnT.transformation(); } else { unsigned instIndex = dagPath.instanceNumber(); MObject dagNode = dagPath.node(); MFnDependencyNode fnN( dagNode ); MPlug plug = fnN.findPlug( "worldMatrix" ); MPlug instPlug = plug.elementByLogicalIndex( instIndex ); MObject matrix; instPlug.getValue( matrix ); MFnMatrixData fnM( matrix ); transform = fnM.transformation(); if ( m_spaceParameter->getNumericValue() == Custom ) { // multiply world transform by the inverse of the custom space matrix. transform = transform.asMatrix() * IECore::convert< MMatrix, Imath::M44f >( operands->member< IECore::M44fData >("customSpace", true)->readable().inverse() ); } } if( m_zeroPivotsParameter->getTypedValue() ) { transform.setScalePivot( MPoint( 0, 0, 0 ), MSpace::kTransform, true ); transform.setRotatePivot( MPoint( 0, 0, 0 ), MSpace::kTransform, true ); } if( m_eulerFilterParameter->getTypedValue() && m_lastRotationValid ) { transform.rotateTo( transform.eulerRotation().closestSolution( m_lastRotation ) ); } m_lastRotation = transform.eulerRotation(); m_lastRotationValid = true; return new IECore::TransformationMatrixdData( IECore::convert<IECore::TransformationMatrixd, MTransformationMatrix>( transform ) ); }
//--------------------------------------------------- int DagHelper::getNextAvailableIndex ( const MPlug& p, int startIndex ) { if ( startIndex < 0 ) startIndex = 0; // Look for the next available plug for ( uint i = ( uint ) startIndex; i < ( uint ) startIndex + 100; ++i ) { MPlug possibleDestination = p.elementByLogicalIndex ( i ); if ( !DagHelper::hasConnection ( possibleDestination ) ) { return i; } } return -1; }
void V3Manipulator::getPlugValues( MPlug &plug, double *values ) { if( plug.numChildren() == 3 ) { for( unsigned i = 0; i<3; i++ ) { MPlug child = plug.child( i ); *values = child.asDouble(); values++; } } else { for( unsigned i = 0; i<3; i++ ) { MPlug element = plug.elementByLogicalIndex( i ); *values = element.asDouble(); values++; } } }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::undoTweakProcessing() // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; if( fHasTweaks ) { MFnDependencyNode depNodeFn; MObject meshNodeShape; MPlug meshTweakPlug; MPlug tweak; MObject tweakData; meshNodeShape = fDagPath.node(); depNodeFn.setObject( meshNodeShape ); meshTweakPlug = depNodeFn.findPlug( "pnts" ); MStatusAssert( (meshTweakPlug.isArray()), "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" ); unsigned i; unsigned numElements = fTweakIndexArray.length(); for( i = 0; i < numElements; i++ ) { tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); getFloat3asMObject( fTweakVectorArray[i], tweakData ); tweak.setValue( tweakData ); } // In the case of no history, the duplicate node shape will be disconnected on undo // so, there is no need to undo the tweak processing on it. // } return status; }
PXR_NAMESPACE_OPEN_SCOPE /* static */ bool PxrUsdMayaTranslatorMesh::Create( const UsdGeomMesh& mesh, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (!mesh) { return false; } const UsdPrim& prim = mesh.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (!PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<GfVec3f> normals; VtArray<int> faceVertexCounts; VtArray<int> faceVertexIndices; UsdAttribute fvc = mesh.GetFaceVertexCountsAttr(); if (fvc.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexCounts). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvc.Get(&faceVertexCounts, 0); } UsdAttribute fvi = mesh.GetFaceVertexIndicesAttr(); if (fvi.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexIndices). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvi.Get(&faceVertexIndices, 0); } // Sanity Checks. If the vertex arrays are empty, skip this mesh if (faceVertexCounts.size() == 0 || faceVertexIndices.size() == 0) { MGlobal::displayError( TfStringPrintf("FaceVertex arrays are empty [Count:%zu Indices:%zu] on Mesh <%s>. Skipping...", faceVertexCounts.size(), faceVertexIndices.size(), prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // Gather points and normals // If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); UsdTimeCode normalsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t pointsNumTimeSamples = 0; if (args.GetReadAnimData()) { PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetPointsAttr(), args, &pointsTimeSamples); pointsNumTimeSamples = pointsTimeSamples.size(); if (pointsNumTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } std::vector<double> normalsTimeSamples; PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetNormalsAttr(), args, &normalsTimeSamples); if (normalsTimeSamples.size()) { normalsTimeSample = normalsTimeSamples[0]; } } mesh.GetPointsAttr().Get(&points, pointsTimeSample); mesh.GetNormalsAttr().Get(&normals, normalsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on Mesh <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } MIntArray polygonCounts( faceVertexCounts.cdata(), faceVertexCounts.size() ); MIntArray polygonConnects( faceVertexIndices.cdata(), faceVertexIndices.size() ); // == Create Mesh Shape Node MFnMesh meshFn; MObject meshObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } // Since we are "decollapsing", we will create a xform and a shape node for each USD prim std::string usdPrimName(prim.GetName().GetText()); std::string shapeName(usdPrimName); shapeName += "Shape"; // Set mesh name and register meshFn.setName(MString(shapeName.c_str()), false, &status); if (context) { std::string usdPrimPath(prim.GetPath().GetText()); std::string shapePath(usdPrimPath); shapePath += "/"; shapePath += shapeName; context->RegisterNewMayaNode( shapePath, meshObj ); // used for undo/redo } // If a material is bound, create (or reuse if already present) and assign it // If no binding is present, assign the mesh to the default shader const TfToken& shadingMode = args.GetShadingMode(); PxrUsdMayaTranslatorMaterial::AssignMaterial(shadingMode, mesh, meshObj, context); // Mesh is a shape, so read Gprim properties PxrUsdMayaTranslatorGprim::Read(mesh, meshObj, context); // Set normals if supplied MIntArray normalsFaceIds; if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { for (size_t i=0; i < polygonCounts.length(); i++) { for (int j=0; j < polygonCounts[i]; j++) { normalsFaceIds.append(i); } } if (normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } } // Determine if PolyMesh or SubdivMesh TfToken subdScheme = PxrUsdMayaMeshUtil::setSubdivScheme(mesh, meshFn, args.GetDefaultMeshScheme()); // If we are dealing with polys, check if there are normals // If we are dealing with SubdivMesh, read additional attributes and SubdivMesh properties if (subdScheme == UsdGeomTokens->none) { if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { PxrUsdMayaMeshUtil::setEmitNormals(mesh, meshFn, UsdGeomTokens->none); } } else { PxrUsdMayaMeshUtil::setSubdivInterpBoundary(mesh, meshFn, UsdGeomTokens->edgeAndCorner); PxrUsdMayaMeshUtil::setSubdivFVLinearInterpolation(mesh, meshFn); _AssignSubDivTagsToMesh(mesh, meshObj, meshFn); } // Set Holes VtArray<int> holeIndices; mesh.GetHoleIndicesAttr().Get(&holeIndices); // not animatable if ( holeIndices.size() != 0 ) { MUintArray mayaHoleIndices; mayaHoleIndices.setLength( holeIndices.size() ); for (size_t i=0; i < holeIndices.size(); i++) { mayaHoleIndices[i] = holeIndices[i]; } if (meshFn.setInvisibleFaces(mayaHoleIndices) == MS::kFailure) { MGlobal::displayError(TfStringPrintf("Unable to set Invisible Faces on <%s>", meshFn.fullPathName().asChar()).c_str()); } } // GETTING PRIMVARS std::vector<UsdGeomPrimvar> primvars = mesh.GetPrimvars(); TF_FOR_ALL(iter, primvars) { const UsdGeomPrimvar& primvar = *iter; const TfToken& name = primvar.GetBaseName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); // If the primvar is called either displayColor or displayOpacity check // if it was really authored from the user. It may not have been // authored by the user, for example if it was generated by shader // values and not an authored colorset/entity. // If it was not really authored, we skip the primvar. if (name == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName || name == PxrUsdMayaMeshColorSetTokens->DisplayOpacityColorSetName) { if (!PxrUsdMayaRoundTripUtil::IsAttributeUserAuthored(primvar)) { continue; } } // XXX: Maya stores UVs in MFloatArrays and color set data in MColors // which store floats, so we currently only import primvars holding // float-typed arrays. Should we still consider other precisions // (double, half, ...) and/or numeric types (int)? if (typeName == SdfValueTypeNames->Float2Array) { // We assume that Float2Array primvars are UV sets. if (!_AssignUVSetPrimvarToMesh(primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for UV set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } else if (typeName == SdfValueTypeNames->FloatArray || typeName == SdfValueTypeNames->Float3Array || typeName == SdfValueTypeNames->Color3fArray || typeName == SdfValueTypeNames->Float4Array || typeName == SdfValueTypeNames->Color4fArray) { if (!_AssignColorSetPrimvarToMesh(mesh, primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for color set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } } // We only vizualize the colorset by default if it is "displayColor". MStringArray colorSetNames; if (meshFn.getColorSetNames(colorSetNames)==MS::kSuccess) { for (unsigned int i=0; i < colorSetNames.length(); i++) { const MString colorSetName = colorSetNames[i]; if (std::string(colorSetName.asChar()) == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetString()) { MFnMesh::MColorRepresentation csRep= meshFn.getColorRepresentation(colorSetName); if (csRep==MFnMesh::kRGB || csRep==MFnMesh::kRGBA) { // both of these are needed to show the colorset. MPlug plg=meshFn.findPlug("displayColors"); if ( !plg.isNull() ) { plg.setBool(true); } meshFn.setCurrentColorSetName(colorSetName); } break; } } } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // if (pointsNumTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject meshAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(meshObj); if (context) { context->RegisterNewMayaNode( blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { mesh.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create Mesh Shape Node MFnMesh meshFn; if ( meshAnimObj.isNull() ) { meshAnimObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created mesh by copying it and then setting the points meshAnimObj = meshFn.copy(meshAnimObj, mayaNodeTransformObj, &status); meshFn.setPoints(mayaPoints); } // Set normals if supplied // // NOTE: This normal information is not propagated through the blendShapes, only the controlPoints. // mesh.GetNormalsAttr().Get(&normals, pointsTimeSamples[ti]); if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices()) && normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } // Add as target and set as an intermediate object blendFn.addTarget(meshObj, ti, meshAnimObj, 1.0); meshFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( meshFn.fullPathName().asChar(), meshAnimObj ); // used for undo/redo } } // Animate the weights so that mesh0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(pointsNumTimeSamples); for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(pointsNumTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this mesh's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
MStatus componentScaleManip::connectToDependNode(const MObject &node) { MStatus stat; MFnComponent componentFn(component); if (componentFn.elementCount() > numComponents) { delete [] initialPositions; delete [] initialControlPoint; numComponents = componentFn.elementCount(); initialPositions = new MPoint[numComponents]; initialControlPoint = new MPoint[numComponents]; } // Iterate through the components, storing initial positions and find the // centroid. Add manipToPlug callbacks for each component. // int i = 0; for (MItSurfaceCV iter(surfaceDagPath, component); !iter.isDone(); iter.next(), i++) { if (i >= numComponents) { MGlobal::displayWarning("More components found than expected."); break; } initialPositions[i] = iter.position(MSpace::kWorld); centroid += initialPositions[i]; // // Create a manipToPlug callback that is invoked whenever the manipVal // changes. The callback is added for every selected CV. // MFnDependencyNode nodeFn(node); MPlug controlPointArrayPlug = nodeFn.findPlug("controlPoints", &stat); if (controlPointArrayPlug.isNull()) { MGlobal::displayError("Control point plug not found on node."); return MS::kFailure; } // The logical index from the component iterator is the same as the // logical index into the control points array. // MPlug controlPointPlug = controlPointArrayPlug.elementByLogicalIndex(iter.index(), &stat); if (controlPointPlug.isNull()) { MGlobal::displayError("Control point element not found."); return MS::kFailure; } // Store the initial value of the control point. // initialControlPoint[i] = vectorPlugValue(controlPointPlug); unsigned plugIndex = addManipToPlugConversion(controlPointPlug); // Plug indices should be allocated sequentially, starting at 0. Each // manip container will have its own set of plug indices. This code // relies on the sequential allocation of indices, so trigger an error // if the indices are found to be different. // if (plugIndex != (unsigned)i) { MGlobal::displayError("Unexpected plug index returned."); return MS::kFailure; } } centroid = centroid / numComponents; MFnScaleManip scaleManip(fScaleManip); // Create a plugToManip callback that places the manipulator at the // centroid of the CVs. // addPlugToManipConversion(scaleManip.scaleCenterIndex()); finishAddingManips(); MPxManipContainer::connectToDependNode(node); return stat; }
bool FxAttributeFiller::FillPlug( DXCCEffectPath& parameter, MPlug& plug ) { HRESULT hr= S_OK; LPDXCCRESOURCE pResource= NULL; LPDIRECT3DBASETEXTURE9 pTexture= NULL; D3DXPARAMETER_DESC desc= parameter.End->Description; float NumericVals[16]= {0.0f}; MString StringVal; LPCSTR StringValStr= ""; bool RestoreFound= false; LPCVOID pRestoreData= NULL; size_t RestoreSize= 0; CComPtr<IDXCCPropertyCollection> pCollection; DXCCPROPERTY_KEY key= 0; if(Restore) { if( DXCC_SUCCEEDED( Restore->GetPath( parameter.End->LongPathName, &pCollection, &key) ) ) { pCollection->GetPropertyValueAsData(key, &pRestoreData); DXCCPROPERTY_DESC desc= pCollection->GetPropertyDesc(key); if(desc == DXCCPD_STRING) { StringVal= (LPCSTR)pRestoreData; StringValStr= (LPCSTR)pRestoreData; RestoreFound= true; } else { size_t RestoreSize= DXCCPropertySize( desc, pRestoreData ); memcpy( NumericVals, pRestoreData, RestoreSize); RestoreFound= true; } } } if((desc.Type == D3DXPT_BOOL) ||(desc.Type == D3DXPT_INT) ||(desc.Type == D3DXPT_FLOAT)) { if(!RestoreFound) { if(plug.isArray()) { hr= Shader->Effect->GetFloatArray(parameter.End->Handle, NumericVals, 16); if(DXCC_FAILED(hr)) DXCC_GOTO_EXIT(e_Exit, TRUE); } else { hr= Shader->Effect->GetFloat(parameter.End->Handle, NumericVals); if(DXCC_FAILED(hr)) DXCC_GOTO_EXIT(e_Exit, TRUE); } } if(plug.isArray()) { int count= desc.Rows * desc.Columns; for(int i= 0; i < count; i++) { MPlug subPlug= plug.elementByLogicalIndex(i); DXCHECK_MSTATUS(subPlug.setValue( NumericVals[i] )); } } else { DXCHECK_MSTATUS(plug.setValue( NumericVals[0] )); } } else if((desc.Type == D3DXPT_TEXTURE) ||(desc.Type == D3DXPT_TEXTURE1D) ||(desc.Type == D3DXPT_TEXTURE2D) ||(desc.Type == D3DXPT_TEXTURE3D) ||(desc.Type == D3DXPT_TEXTURECUBE)) { if(!RestoreFound) { hr= Shader->Effect->GetTexture(parameter.End->Handle, &pTexture); if(DXCC_SUCCEEDED(hr) && pTexture != NULL) { hr= g_PreviewPipeline.AccessManager()->FindResourceByPointer( (LPUNKNOWN)pTexture, NULL, &pResource); if(DXCC_SUCCEEDED(hr)) { StringVal= pResource->GetResourcePath(); } } else { D3DXHANDLE hResourceAddy= Shader->Effect->GetAnnotationByName( parameter.End->Handle, "SasResourceAddress"); if(hResourceAddy) { LPCSTR resourceAddressStr= NULL; Shader->Effect->GetString(hResourceAddy, &resourceAddressStr); StringVal= resourceAddressStr; } } } DXCHECK_MSTATUS(plug.setValue( StringVal )); } else if(desc.Type == D3DXPT_STRING) { if(!RestoreFound) { hr= Shader->Effect->GetString(parameter.End->Handle, &StringValStr); StringVal= StringValStr; } DXCHECK_MSTATUS(plug.setValue( StringVal )); } else { DXCC_STATUS_EXIT(hr, E_FAIL, e_Exit, TRUE); } e_Exit: DXCC_RELEASE(pResource); DXCC_RELEASE(pTexture); return DXCC_SUCCEEDED(hr); }
MStatus ColorSplineParameterHandler<S>::doSetValue( IECore::ConstParameterPtr parameter, MPlug &plug ) const { assert( parameter ); typename IECore::TypedParameter< S >::ConstPtr p = IECore::runTimeCast<const IECore::TypedParameter< S > >( parameter ); if( !p ) { return MS::kFailure; } MRampAttribute fnRAttr( plug ); if ( !fnRAttr.isColorRamp() ) { return MS::kFailure; } const S &spline = p->getTypedValue(); MStatus s; MIntArray indicesToReuse; plug.getExistingArrayAttributeIndices( indicesToReuse, &s ); assert( s ); int nextNewLogicalIndex = 0; if( indicesToReuse.length() ) { nextNewLogicalIndex = 1 + *std::max_element( MArrayIter<MIntArray>::begin( indicesToReuse ), MArrayIter<MIntArray>::end( indicesToReuse ) ); } assert( indicesToReuse.length() == fnRAttr.getNumEntries() ); size_t pointsSizeMinus2 = spline.points.size() - 2; unsigned pointIndex = 0; unsigned numExpectedPoints = 0; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end(); ++it, ++pointIndex ) { // we commonly double up the endpoints on cortex splines to force interpolation to the end. // maya does this implicitly, so we skip duplicated endpoints when passing the splines into maya. // this avoids users having to be responsible for managing the duplicates, and gives them some consistency // with the splines they edit elsewhere in maya. if( ( pointIndex==1 && *it == *spline.points.begin() ) || ( pointIndex==pointsSizeMinus2 && *it == *spline.points.rbegin() ) ) { continue; } MPlug pointPlug; if( indicesToReuse.length() ) { pointPlug = plug.elementByLogicalIndex( indicesToReuse[0] ); indicesToReuse.remove( 0 ); } else { pointPlug = plug.elementByLogicalIndex( nextNewLogicalIndex++ ); } s = pointPlug.child( 0 ).setValue( it->first ); assert( s ); MPlug colorPlug = pointPlug.child( 1 ); colorPlug.child( 0 ).setValue( it->second[0] ); colorPlug.child( 1 ).setValue( it->second[1] ); colorPlug.child( 2 ).setValue( it->second[2] ); // hardcoding interpolation of 3 (spline) because the MRampAttribute::MInterpolation enum values don't actually // correspond to the necessary plug values at all. s = pointPlug.child( 2 ).setValue( 3 ); assert( s ); numExpectedPoints++; } // delete any of the original indices which we didn't reuse. we can't use MRampAttribute::deleteEntries // here as it's utterly unreliable. if( indicesToReuse.length() ) { MString plugName = plug.name(); MObject node = plug.node(); MFnDagNode fnDAGN( node ); if( fnDAGN.hasObj( node ) ) { plugName = fnDAGN.fullPathName() + "." + plug.partialName(); } for( unsigned i=0; i<indicesToReuse.length(); i++ ) { // using mel because there's no equivalant api method as far as i know. MString command = "removeMultiInstance -b true \"" + plugName + "[" + indicesToReuse[i] + "]\""; s = MGlobal::executeCommand( command ); assert( s ); if( !s ) { return s; } } } #ifndef NDEBUG { assert( fnRAttr.getNumEntries() == numExpectedPoints ); MIntArray indices; MFloatArray positions; MColorArray colors; MIntArray interps; fnRAttr.getEntries( indices, positions, colors, interps, &s ); assert( s ); assert( numExpectedPoints == positions.length() ); assert( numExpectedPoints == colors.length() ); assert( numExpectedPoints == interps.length() ); assert( numExpectedPoints == indices.length() ); for ( unsigned i = 0; i < positions.length(); i++ ) { float position = positions[ i ]; const MVector color( colors[ i ][ 0 ], colors[ i ][ 1 ], colors[ i ][ 2 ] ); bool found = false; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end() && !found; ++it ) { MVector color2( it->second[0], it->second[1], it->second[2] ); if ( fabs( it->first - position ) < 1.e-3f && ( color2 - color ).length() < 1.e-3f ) { found = true; } } assert( found ); } } #endif return MS::kSuccess; }
MStatus CVstAimCmd::redoIt() { MStatus mStatus; if ( !mStatus ) { setResult( MString( "Cannot parse command line" ) + mStatus.errorString() ); return MS::kFailure; } if ( m_mArgDatabase->isFlagSet( kHelp ) ) { PrintHelp(); } else { // See if there are two object specified MDagPath mDagPath; MSelectionList optSelectionList; // Validate specified items to whole dag nodes { MSelectionList tmpSelectionList; m_mArgDatabase->getObjects( tmpSelectionList ); for ( MItSelectionList sIt( tmpSelectionList, MFn::kDagNode ); !sIt.isDone(); sIt.next() ) { if ( sIt.getDagPath( mDagPath ) ) { optSelectionList.add( mDagPath, MObject::kNullObj, true ); } } } if ( m_mArgDatabase->isFlagSet( "create" ) || optSelectionList.length() >= 2 && m_mArgDatabase->numberOfFlagsUsed() == 0 ) { // Error if there aren't at least two if ( optSelectionList.length() < 2 ) { displayError( GetName() + " needs at least two objects specified or selected when -create is used" ); return MS::kFailure; } // Get name command line arg MString optName; if ( m_mArgDatabase->isFlagSet( "name" ) ) { m_mArgDatabase->getFlagArgument( "name", 0, optName ); } m_undoable = true; m_mDagModifier = new MDagModifier; MObject vstAimObj( m_mDagModifier->MDGModifier::createNode( GetName() ) ); if ( m_mDagModifier->doIt() != MS::kSuccess ) { displayError( MString( "Couldn't create " ) + GetName() + " node" ); m_mDagModifier->undoIt(); delete m_mDagModifier; m_mDagModifier = NULL; m_undoable = false; return MS::kFailure; } m_mDagModifier->renameNode( vstAimObj, optName.length() ? optName : GetName() ); if ( m_mDagModifier->doIt() != MS::kSuccess ) { if ( optName.length() ) { displayWarning( MString( "Couldn't rename newly created vstNode \"" ) + optName + "\"" ); } } // Set options on the newly create vstAim node MFnDependencyNode vstAimFn( vstAimObj ); MPlug sP; MPlug dP; if ( m_mArgDatabase->isFlagSet( kAim ) ) { MVector aim; m_mArgDatabase->getFlagArgument( kAim, 0, aim.x ); m_mArgDatabase->getFlagArgument( kAim, 1, aim.y ); m_mArgDatabase->getFlagArgument( kAim, 2, aim.z ); sP = vstAimFn.findPlug( "aimX" ); sP.setValue( aim.x ); sP = vstAimFn.findPlug( "aimY" ); sP.setValue( aim.y ); sP = vstAimFn.findPlug( "aimZ" ); sP.setValue( aim.z ); } if ( m_mArgDatabase->isFlagSet( kUp ) ) { MVector up; m_mArgDatabase->getFlagArgument( kUp, 0, up.x ); m_mArgDatabase->getFlagArgument( kUp, 1, up.y ); m_mArgDatabase->getFlagArgument( kUp, 2, up.z ); sP = vstAimFn.findPlug( "upX" ); sP.setValue( up.x ); sP = vstAimFn.findPlug( "upY" ); sP.setValue( up.y ); sP = vstAimFn.findPlug( "upZ" ); sP.setValue( up.z ); } // Now connect up the newly created vstAim node MDagPath toAim; optSelectionList.getDagPath( 1, toAim ); const MFnDagNode toAimFn( toAim ); if ( toAim.hasFn( MFn::kJoint ) ) { MPlug joP( toAimFn.findPlug( "jointOrient" ) ); if ( !joP.isNull() ) { MAngle jox, joy, joz; joP.child( 0 ).getValue( jox ); joP.child( 1 ).getValue( joy ); joP.child( 2 ).getValue( joz ); if ( abs( jox.value() ) > FLT_EPSILON || abs( joy.value() ) > FLT_EPSILON || abs( joz.value() ) > FLT_EPSILON ) { mwarn << "Joint orient on node being constrained is non-zero ( " << jox.asDegrees() << " " << joy.asDegrees() << " " << joz.asDegrees() << " ), setting to 0" << std::endl; joP.child( 0 ).setValue( MAngle( 0.0 ) ); joP.child( 1 ).setValue( MAngle( 0.0 ) ); joP.child( 2 ).setValue( MAngle( 0.0 ) ); } } } if ( toAim.hasFn( MFn::kTransform ) ) { MPlug mP( toAimFn.findPlug( "rotateAxis" ) ); if ( !mP.isNull() ) { MAngle rx, ry, rz; mP.child( 0 ).getValue( rx ); mP.child( 1 ).getValue( ry ); mP.child( 2 ).getValue( rz ); if ( abs( rx.value() ) > FLT_EPSILON || abs( ry.value() ) > FLT_EPSILON || abs( rz.value() ) > FLT_EPSILON ) { mwarn << "Rotate Axis on node being constrained is non-zero ( " << rx.asDegrees() << " " << ry.asDegrees() << " " << rz.asDegrees() << " ), setting to 0" << std::endl; mP.child( 0 ).setValue( MAngle( 0.0 ) ); mP.child( 1 ).setValue( MAngle( 0.0 ) ); mP.child( 2 ).setValue( MAngle( 0.0 ) ); } } } MDagPath aimAt; optSelectionList.getDagPath( 0, aimAt ); const MFnDagNode aimAtFn( aimAt ); // toAim.rotateOrder -> vstAim.rotateOrder sP = toAimFn.findPlug( "rotateOrder" ); dP = vstAimFn.findPlug( "rotateOrder" ); m_mDagModifier->connect( sP, dP ); // toAim.translate -> vstAim.translate sP = toAimFn.findPlug( "translate" ); dP = vstAimFn.findPlug( "translate" ); m_mDagModifier->connect( sP, dP ); // toAim.parentMatrix[ instance ] -> vstAim.parentSpace sP = toAimFn.findPlug( "parentMatrix" ); sP = sP.elementByLogicalIndex( toAim.instanceNumber() ); dP = vstAimFn.findPlug( "parentSpace" ); m_mDagModifier->connect( sP, dP ); // aimAt.worldMatrix[ instance ] -> vstAim.aimSpace sP = aimAtFn.findPlug( "worldMatrix" ); sP = sP.elementByLogicalIndex( aimAt.instanceNumber() ); dP = vstAimFn.findPlug( "aimSpace" ); m_mDagModifier->connect( sP, dP ); // vstAim.rotation -> toAim.rotation // These have to be connected individually because Maya plays stupid tricks // with rotateOrder if they aren't sP = vstAimFn.findPlug( "rotateX" ); dP = toAimFn.findPlug( "rotateX" ); m_mDagModifier->connect( sP, dP ); sP = vstAimFn.findPlug( "rotateY" ); dP = toAimFn.findPlug( "rotateY" ); m_mDagModifier->connect( sP, dP ); sP = vstAimFn.findPlug( "rotateZ" ); dP = toAimFn.findPlug( "rotateZ" ); m_mDagModifier->connect( sP, dP ); if ( m_mDagModifier->doIt() != MS::kSuccess ) { displayWarning( MString( GetName() ) + ": Couldn't connect everything when creating" ); } // Save the current selection just in case we want to undo stuff MGlobal::getActiveSelectionList( m_mSelectionList ); MGlobal::select( vstAimObj, MGlobal::kReplaceList ); setResult( vstAimFn.name() ); } else if ( m_mArgDatabase->isFlagSet( "select" ) ) { MSelectionList mSelectionList; MDagPath mDagPath; for ( MItDag dagIt; !dagIt.isDone(); dagIt.next() ) { if ( MFnDependencyNode( dagIt.item() ).typeName() == GetName() ) { dagIt.getPath( mDagPath ); mSelectionList.add( mDagPath, MObject::kNullObj, true ); } } if ( mSelectionList.length() ) { m_undoable = true; // Save the current selection just in case we want to undo stuff MGlobal::getActiveSelectionList( m_mSelectionList ); MGlobal::setActiveSelectionList( mSelectionList, MGlobal::kReplaceList ); } } else { displayError( GetName() + ": No valid operation specified via command line arguments\n" ); } } return MS::kSuccess; }
/* static */ bool PxrUsdMayaTranslatorCurves::Create( const UsdGeomCurves& curves, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (not curves) { return false; } const UsdPrim& prim = curves.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (not PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<int> curveOrder; VtArray<int> curveVertexCounts; VtArray<float> curveWidths; VtArray<GfVec2d> curveRanges; VtArray<double> curveKnots; // LIMITATION: xxx REVISIT xxx // Non-animated Attrs // Assuming that a number of these USD attributes are assumed to not be animated // Some we may want to expose as animatable later. // curves.GetCurveVertexCountsAttr().Get(&curveVertexCounts); // not animatable // XXX: // Only supporting single curve for now. // Sanity Checks if (curveVertexCounts.size() == 0) { MGlobal::displayError( TfStringPrintf("VertexCount arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // No verts for the curve, so exit } else if (curveVertexCounts.size() > 1) { MGlobal::displayWarning( TfStringPrintf("Multiple curves in <%s>. Reading first one...", prim.GetPath().GetText()).c_str()); } int curveIndex = 0; curves.GetWidthsAttr().Get(&curveWidths); // not animatable // Gather points. If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t numTimeSamples = 0; if (args.GetReadAnimData()) { curves.GetPointsAttr().GetTimeSamples(&pointsTimeSamples); numTimeSamples = pointsTimeSamples.size(); if (numTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } } curves.GetPointsAttr().Get(&points, pointsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid nurbscurves, so exit } if (UsdGeomNurbsCurves nurbsSchema = UsdGeomNurbsCurves(prim)) { nurbsSchema.GetOrderAttr().Get(&curveOrder); // not animatable nurbsSchema.GetKnotsAttr().Get(&curveKnots); // not animatable nurbsSchema.GetRangesAttr().Get(&curveRanges); // not animatable } else { // Handle basis curves originally modelled in Maya as nurbs. curveOrder.resize(1); UsdGeomBasisCurves basisSchema = UsdGeomBasisCurves(prim); TfToken typeToken; basisSchema.GetTypeAttr().Get(&typeToken); if (typeToken == UsdGeomTokens->linear) { curveOrder[0] = 2; curveKnots.resize(points.size()); for (size_t i=0; i < curveKnots.size(); ++i) { curveKnots[i] = i; } } else { curveOrder[0] = 4; // Strip off extra end points; assuming this is non-periodic. VtArray<GfVec3f> tmpPts(points.size() - 2); std::copy(points.begin() + 1, points.end() - 1, tmpPts.begin()); points.swap(tmpPts); // Cubic curves in Maya have numSpans + 2*3 - 1, and for geometry // that came in as basis curves, we have numCV's - 3 spans. See the // MFnNurbsCurve documentation and the nurbs curve export // implementation in mojitoplugmaya for more details. curveKnots.resize(points.size() -3 + 5); int knotIdx = 0; for (size_t i=0; i < curveKnots.size(); ++i) { if (i < 3) { curveKnots[i] = 0.0; } else { if (i <= curveKnots.size() - 3) { ++knotIdx; } curveKnots[i] = double(knotIdx); } } } } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } double *knots=curveKnots.data(); MDoubleArray mayaKnots( knots, curveKnots.size()); int mayaDegree = curveOrder[curveIndex] - 1; MFnNurbsCurve::Form mayaCurveForm = MFnNurbsCurve::kOpen; // HARDCODED bool mayaCurveCreate2D = false; bool mayaCurveCreateRational = true; // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; MObject curveObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } MString nodeName( prim.GetName().GetText() ); nodeName += "Shape"; curveFn.setName(nodeName, false, &status); std::string nodePath( prim.GetPath().GetText() ); nodePath += "/"; nodePath += nodeName.asChar(); if (context) { context->RegisterNewMayaNode( nodePath, curveObj ); // used for undo/redo } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // Almost identical code as used with MayaMeshReader.cpp // if (numTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject curveAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(curveObj); if (context) { context->RegisterNewMayaNode(blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < numTimeSamples; ++ti) { curves.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; if ( curveAnimObj.isNull() ) { curveAnimObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created curve by copying it and then setting the points curveAnimObj = curveFn.copy(curveAnimObj, mayaNodeTransformObj, &status); curveFn.setCVs(mayaPoints); } blendFn.addTarget(curveObj, ti, curveAnimObj, 1.0); curveFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( curveFn.fullPathName().asChar(), curveAnimObj ); // used for undo/redo } } // Animate the weights so that curve0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(numTimeSamples); for (unsigned int ti=0; ti < numTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < numTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(numTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this curve's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
MStatus ColorSplineParameterHandler<S>::doSetValue( const MPlug &plug, IECore::ParameterPtr parameter ) const { assert( parameter ); typename IECore::TypedParameter< S >::Ptr p = IECore::runTimeCast<IECore::TypedParameter< S > >( parameter ); if( !p ) { return MS::kFailure; } S spline; MStatus s; MRampAttribute fnRAttr( plug, &s ); assert( s ); if ( !fnRAttr.isColorRamp() ) { return MS::kFailure; } MIntArray indices; (const_cast<MPlug &>( plug )).getExistingArrayAttributeIndices( indices, &s ); for( unsigned i = 0; i < indices.length(); i++ ) { MPlug pointPlug = plug.elementByLogicalIndex( indices[i] ); MPlug colorPlug = pointPlug.child( 1 ); typename S::YType y( 1 ); y[0] = colorPlug.child( 0 ).asDouble(); y[1] = colorPlug.child( 1 ).asDouble(); y[2] = colorPlug.child( 2 ).asDouble(); spline.points.insert( typename S::PointContainer::value_type( pointPlug.child( 0 ).asDouble(), y ) ); } // maya seems to do an implicit doubling up of the end points to cause interpolation to the ends. // our spline has no such implicit behaviour so we explicitly double up. if( spline.points.size() ) { #ifndef NDEBUG size_t oldSplineSize = spline.points.size(); #endif assert( spline.points.begin()->first <= spline.points.rbegin()->first ); spline.points.insert( *spline.points.begin() ); spline.points.insert( *spline.points.rbegin() ); assert( spline.points.size() == oldSplineSize + 2 ); } p->setTypedValue( spline ); if( spline.points.size() ) { assert( spline.points.size() >= 2 ); assert( spline.points.size() == fnRAttr.getNumEntries() + 2 ); } return MS::kSuccess; }
bool ToMayaSkinClusterConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstSmoothSkinningDataPtr skinningData = IECore::runTimeCast<const IECore::SmoothSkinningData>( from ); assert( skinningData ); const std::vector<std::string> &influenceNames = skinningData->influenceNames()->readable(); const std::vector<Imath::M44f> &influencePoseData = skinningData->influencePose()->readable(); const std::vector<int> &pointIndexOffsets = skinningData->pointIndexOffsets()->readable(); const std::vector<int> &pointInfluenceCounts = skinningData->pointInfluenceCounts()->readable(); const std::vector<int> &pointInfluenceIndices = skinningData->pointInfluenceIndices()->readable(); const std::vector<float> &pointInfluenceWeights = skinningData->pointInfluenceWeights()->readable(); MFnDependencyNode fnSkinClusterNode( to, &s ); MFnSkinCluster fnSkinCluster( to, &s ); if ( s != MS::kSuccess ) { /// \todo: optional parameter to allow custom node types and checks for the necessary attributes /// \todo: create a new skinCluster if we want a kSkinClusterFilter and this isn't one throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid skinCluster" ) % fnSkinClusterNode.name() ).str() ); } const unsigned origNumInfluences = influenceNames.size(); unsigned numInfluences = origNumInfluences; std::vector<bool> ignoreInfluence( origNumInfluences, false ); std::vector<int> indexMap( origNumInfluences, -1 ); const bool ignoreMissingInfluences = m_ignoreMissingInfluencesParameter->getTypedValue(); const bool ignoreBindPose = m_ignoreBindPoseParameter->getTypedValue(); // gather the influence objects MObject mObj; MDagPath path; MSelectionList influenceList; MDagPathArray influencePaths; for ( unsigned i=0, index=0; i < origNumInfluences; i++ ) { MString influenceName( influenceNames[i].c_str() ); s = influenceList.add( influenceName ); if ( !s ) { if ( ignoreMissingInfluences ) { ignoreInfluence[i] = true; MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) ); continue; } throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() ); } influenceList.getDependNode( index, mObj ); MFnIkJoint fnInfluence( mObj, &s ); if ( !s ) { if ( ignoreMissingInfluences ) { ignoreInfluence[i] = true; influenceList.remove( index ); MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) ); continue; } throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() ); } fnInfluence.getPath( path ); influencePaths.append( path ); indexMap[i] = index; index++; } MPlugArray connectedPlugs; bool existingBindPose = true; MPlug bindPlug = fnSkinClusterNode.findPlug( "bindPose", true, &s ); if ( !bindPlug.connectedTo( connectedPlugs, true, false ) ) { existingBindPose = false; if ( !ignoreBindPose ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" does not have a valid bindPose" ) % fnSkinClusterNode.name() ).str() ); } } MPlug bindPoseMatrixArrayPlug; MPlug bindPoseMemberArrayPlug; if ( existingBindPose ) { MFnDependencyNode fnBindPose( connectedPlugs[0].node() ); if ( fnBindPose.typeName() != "dagPose" ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid bindPose" ) % fnBindPose.name() ).str() ); } bindPoseMatrixArrayPlug = fnBindPose.findPlug( "worldMatrix", true, &s ); bindPoseMemberArrayPlug = fnBindPose.findPlug( "members", true, &s ); } /// \todo: optional parameter to reset the skinCluster's geomMatrix plug // break existing influence connections to the skinCluster MDGModifier dgModifier; MMatrixArray ignoredPreMatrices; MPlug matrixArrayPlug = fnSkinClusterNode.findPlug( "matrix", true, &s ); MPlug bindPreMatrixArrayPlug = fnSkinClusterNode.findPlug( "bindPreMatrix", true, &s ); for ( unsigned i=0; i < matrixArrayPlug.numConnectedElements(); i++ ) { MPlug matrixPlug = matrixArrayPlug.connectionByPhysicalIndex( i, &s ); matrixPlug.connectedTo( connectedPlugs, true, false ); if ( !connectedPlugs.length() ) { continue; } MFnIkJoint fnInfluence( connectedPlugs[0].node() ); fnInfluence.getPath( path ); if ( ignoreMissingInfluences && !influenceList.hasItem( path ) ) { MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i ); preMatrixPlug.getValue( mObj ); MFnMatrixData matFn( mObj ); ignoredPreMatrices.append( matFn.matrix() ); ignoreInfluence.push_back( false ); indexMap.push_back( influenceList.length() ); influenceList.add( connectedPlugs[0].node() ); numInfluences++; } dgModifier.disconnect( connectedPlugs[0], matrixPlug ); } MPlug lockArrayPlug = fnSkinClusterNode.findPlug( "lockWeights", true, &s ); for ( unsigned i=0; i < lockArrayPlug.numConnectedElements(); i++ ) { MPlug lockPlug = lockArrayPlug.connectionByPhysicalIndex( i, &s ); lockPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], lockPlug ); } } MPlug paintPlug = fnSkinClusterNode.findPlug( "paintTrans", true, &s ); paintPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], paintPlug ); } // break existing influence connections to the bind pose if ( existingBindPose ) { for ( unsigned i=0; i < bindPoseMatrixArrayPlug.numConnectedElements(); i++ ) { MPlug matrixPlug = bindPoseMatrixArrayPlug.connectionByPhysicalIndex( i, &s ); matrixPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], matrixPlug ); } } for ( unsigned i=0; i < bindPoseMemberArrayPlug.numConnectedElements(); i++ ) { MPlug memberPlug = bindPoseMemberArrayPlug.connectionByPhysicalIndex( i, &s ); memberPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], memberPlug ); } } } if ( !dgModifier.doIt() ) { dgModifier.undoIt(); throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to break the influence connections" ); } // make connections from influences to skinCluster and bindPose for ( unsigned i=0; i < numInfluences; i++ ) { if ( ignoreInfluence[i] ) { continue; } int index = indexMap[i]; s = influenceList.getDependNode( index, mObj ); MFnIkJoint fnInfluence( mObj, &s ); MPlug influenceMatrixPlug = fnInfluence.findPlug( "worldMatrix", true, &s ).elementByLogicalIndex( 0, &s ); MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s ); MPlug influenceBindPosePlug = fnInfluence.findPlug( "bindPose", true, &s ); MPlug influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s ); if ( !s ) { // add the lockInfluenceWeights attribute if it doesn't exist MFnNumericAttribute nAttr; MObject attribute = nAttr.create( "lockInfluenceWeights", "liw", MFnNumericData::kBoolean, false ); fnInfluence.addAttribute( attribute ); influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s ); } // connect influence to the skinCluster MPlug matrixPlug = matrixArrayPlug.elementByLogicalIndex( index ); MPlug lockPlug = lockArrayPlug.elementByLogicalIndex( index ); dgModifier.connect( influenceMatrixPlug, matrixPlug ); dgModifier.connect( influenceLockPlug, lockPlug ); // connect influence to the bindPose if ( !ignoreBindPose ) { MPlug bindPoseMatrixPlug = bindPoseMatrixArrayPlug.elementByLogicalIndex( index ); MPlug memberPlug = bindPoseMemberArrayPlug.elementByLogicalIndex( index ); dgModifier.connect( influenceMessagePlug, bindPoseMatrixPlug ); dgModifier.connect( influenceBindPosePlug, memberPlug ); } } unsigned firstIndex = find( ignoreInfluence.begin(), ignoreInfluence.end(), false ) - ignoreInfluence.begin(); influenceList.getDependNode( firstIndex, mObj ); MFnDependencyNode fnInfluence( mObj ); MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s ); dgModifier.connect( influenceMessagePlug, paintPlug ); if ( !dgModifier.doIt() ) { dgModifier.undoIt(); throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to create the influence connections" ); } // use influencePoseData as bindPreMatrix for ( unsigned i=0; i < numInfluences; i++ ) { if ( ignoreInfluence[i] ) { continue; } MMatrix preMatrix = ( i < origNumInfluences ) ? IECore::convert<MMatrix>( influencePoseData[i] ) : ignoredPreMatrices[i-origNumInfluences]; MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( indexMap[i], &s ); s = preMatrixPlug.getValue( mObj ); if ( s ) { MFnMatrixData matFn( mObj ); matFn.set( preMatrix ); mObj = matFn.object(); } else { MFnMatrixData matFn; mObj = matFn.create( preMatrix ); } preMatrixPlug.setValue( mObj ); } // remove unneeded bindPreMatrix children unsigned existingElements = bindPreMatrixArrayPlug.numElements(); for ( unsigned i=influenceList.length(); i < existingElements; i++ ) { MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i, &s ); /// \todo: surely there is a way to accomplish this in c++... MGlobal::executeCommand( ( boost::format( "removeMultiInstance %s" ) % preMatrixPlug.name() ).str().c_str() ); } // get the geometry MObjectArray outputGeoObjs; if ( !fnSkinCluster.getOutputGeometry( outputGeoObjs ) ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: skinCluster \"%s\" does not have any output geometry!" ) % fnSkinCluster.name() ).str() ); } MFnDagNode dagFn( outputGeoObjs[0] ); MDagPath geoPath; dagFn.getPath( geoPath ); // loop through all the points of the geometry and set the weights MItGeometry geoIt( outputGeoObjs[0] ); MPlug weightListArrayPlug = fnSkinClusterNode.findPlug( "weightList", true, &s ); for ( unsigned pIndex=0; !geoIt.isDone(); geoIt.next(), pIndex++ ) { MPlug pointWeightsPlug = weightListArrayPlug.elementByLogicalIndex( pIndex, &s ).child( 0 ); // remove existing influence weight plugs MIntArray existingInfluenceIndices; pointWeightsPlug.getExistingArrayAttributeIndices( existingInfluenceIndices ); for( unsigned i=0; i < existingInfluenceIndices.length(); i++ ) { MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( existingInfluenceIndices[i], &s ); MGlobal::executeCommand( ( boost::format( "removeMultiInstance -break 1 %s" ) % influenceWeightPlug.name() ).str().c_str() ); } // add new influence weight plugs int firstIndex = pointIndexOffsets[pIndex]; for( int i=0; i < pointInfluenceCounts[pIndex]; i++ ) { int influenceIndex = pointInfluenceIndices[ firstIndex + i ]; if ( ignoreInfluence[ influenceIndex ] ) { continue; } int skinClusterInfluenceIndex = fnSkinCluster.indexForInfluenceObject( influencePaths[ indexMap[ influenceIndex ] ] ); MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( skinClusterInfluenceIndex, &s ); influenceWeightPlug.setValue( pointInfluenceWeights[ firstIndex + i ] ); } } return true; }
// // Deform computation // MStatus jhMeshBlur::deform( MDataBlock& block,MItGeometry& iter,const MMatrix& m,unsigned int multiIndex) { MStatus returnStatus; // Envelope float envData = block.inputValue(envelope, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); if(envData == 0) return MS::kFailure; /* VARIABLES */ //float factor = block.inputValue(aShapeFactor, &returnStatus).asFloat(); float fStrength = block.inputValue(aStrength, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); if (fStrength == 0) return MS::kFailure; float fThreshold = block.inputValue(aTreshhold, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); float fW = 0.0f; // weight float fDistance; fStrength *= envData; double dKracht = block.inputValue(aInterpPower, &returnStatus).asDouble(); CHECK_MSTATUS(returnStatus); double dDotProduct; // Dotproduct of the point bool bTweakblur = block.inputValue(aTweakBlur, &returnStatus).asBool(); CHECK_MSTATUS(returnStatus); bool bQuad = block.inputValue(aQuadInterp, &returnStatus).asBool(); CHECK_MSTATUS(returnStatus); MTime inTime = block.inputValue(aTime).asTime(); int nTijd = (int)inTime.as(MTime::kFilm); MFloatVectorArray currentNormals; // normals of mesh MFnPointArrayData fnPoints; // help converting to MPointArrays MFloatVector dirVector; // direction vector of the point MFloatVector normal; // normal of the point MPointArray savedPoints; // save all point before edited MMatrix matInv = m.inverse(); // inversed matrix MPoint ptA; // current point (iter mesh) MPoint ptB; // previous point (iter mesh) MPoint ptC; // mesh before previous point (iter mesh) // get node, use node to get inputGeom, use inputGeom to get mesh data, use mesh data to get normal data MFnDependencyNode nodeFn(this->thisMObject()); MPlug inGeomPlug(nodeFn.findPlug(this->inputGeom,true)); MObject inputObject(inGeomPlug.asMObject()); MFnMesh inMesh(inputObject); inMesh.getVertexNormals(true, currentNormals); // get the previous mesh data MPlug oldMeshPlug = nodeFn.findPlug(MString("oldMesh")); MPlug oldMeshPositionsAPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 0); MPlug oldMeshPositionsBPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 1); MPlug oldMeshPositionsCPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 2); // cache for tweak mode MPlug oldMeshPositionsDPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 3); // cache for tweak mode // convert to MPointArrays MObject objOldMeshA; MObject objOldMeshB; MObject objOldMeshC; // cache MObject objOldMeshD; // cache oldMeshPositionsAPlug.getValue(objOldMeshA); oldMeshPositionsBPlug.getValue(objOldMeshB); oldMeshPositionsCPlug.getValue(objOldMeshC); // cache oldMeshPositionsDPlug.getValue(objOldMeshD); // cache fnPoints.setObject(objOldMeshA); MPointArray oldMeshPositionsA = fnPoints.array(); fnPoints.setObject(objOldMeshB); MPointArray oldMeshPositionsB = fnPoints.array(); fnPoints.setObject(objOldMeshC); MPointArray oldMeshPositionsC = fnPoints.array(); // cache fnPoints.setObject(objOldMeshD); MPointArray oldMeshPositionsD = fnPoints.array(); // cache // If mesh position variables are empty,fill them with default values if(oldMeshPositionsA.length() == 0 || nTijd <= 1){ iter.allPositions(oldMeshPositionsA); for(int i=0; i < oldMeshPositionsA.length(); i++) { // convert to world oldMeshPositionsA[i] = oldMeshPositionsA[i] * m; } oldMeshPositionsB.copy(oldMeshPositionsA); oldMeshPositionsC.copy(oldMeshPositionsA); // cache oldMeshPositionsD.copy(oldMeshPositionsA); // cache } // get back old date again if (bTweakblur == true) { // restore cache oldMeshPositionsA.copy(oldMeshPositionsC); oldMeshPositionsB.copy(oldMeshPositionsD); } iter.allPositions(savedPoints); for(int i=0; i < savedPoints.length(); i++) { // convert points to world points savedPoints[i] = savedPoints[i] * m; } // Actual Iteration through points for (; !iter.isDone(); iter.next()){ // get current position ptA = iter.position(); // get old positions ptB = oldMeshPositionsA[iter.index()] * matInv; ptC = oldMeshPositionsB[iter.index()] * matInv; fDistance = ptA.distanceTo(ptB); fW = weightValue(block,multiIndex,iter.index()); if (fDistance * (fStrength*fW) < fThreshold && fThreshold > 0){ iter.setPosition(ptA); } else { // aim/direction vector to calculate strength dirVector = (ptA - ptB); // (per punt) dirVector.normalize(); normal = currentNormals[iter.index()]; dDotProduct = normal.x * dirVector.x + normal.y * dirVector.y + normal.z * dirVector.z; if(bQuad == true){ MVector vecA(((ptB - ptC) + (ptA - ptB)) / 2); vecA.normalize(); MPoint hiddenPt(ptB + (vecA * fDistance) * dKracht); ptA = quadInterpBetween(ptB, hiddenPt, ptA, (1 - fStrength * fW) + (linearInterp(dDotProduct, -1, 1) * (fStrength * fW) ) ); } else { MPoint halfway = (ptA - ptB) * 0.5; MPoint offset = halfway * dDotProduct * (fStrength*fW); ptA = ptA - ((halfway * (fStrength*fW)) - offset); // + (offset * strength); } // set new value iter.setPosition(ptA); } } if(bTweakblur == false){ oldMeshPositionsD.copy(oldMeshPositionsB); oldMeshPositionsC.copy(oldMeshPositionsA); oldMeshPositionsB.copy(oldMeshPositionsA); oldMeshPositionsA.copy(savedPoints); // Save back to plugs objOldMeshA = fnPoints.create(oldMeshPositionsA); objOldMeshB = fnPoints.create(oldMeshPositionsB); objOldMeshC = fnPoints.create(oldMeshPositionsC); objOldMeshD = fnPoints.create(oldMeshPositionsD); oldMeshPositionsAPlug.setValue(objOldMeshA); oldMeshPositionsBPlug.setValue(objOldMeshB); oldMeshPositionsCPlug.setValue(objOldMeshC); oldMeshPositionsDPlug.setValue(objOldMeshD); } return returnStatus; }
//THIS FUNCTION IS QUITE COMPLICATED BECAUSE //IT HAS TO DEAL WITH MAYA NAME MANGLING! //tokenize the path. //add each token into the element list which tracks the attributes and indices //for each entry added make sure there are no parents left out from maya name mangling. //after the list is populated and missing elements area added //we reiterate and produce the final result. MPlug FxInternal::DecodePlug(const CStringA& plugStr) { MPlug result; MFnDependencyNode depNode(GetSite()); CAtlList<PathDecodeElement> elementList; //tokenize the path int iLastPos=0; int iThisPos=0; CStringA subStr; while( iLastPos= iThisPos, subStr=plugStr.Tokenize(".[]", iThisPos), iThisPos != -1 ) { //char lastChar= subStr[iLastPos]; //char thisChar= subStr[iThisPos]; //are we looking at a named portion? if(iLastPos == 0 || plugStr[iLastPos-1]=='.' || (plugStr[iLastPos-1]==']' && plugStr[iLastPos]=='.')) { //if the name is length zero then it must be the case when // you do last[#]. The situation is caused by the sequence "]." //if we dont have a name we can skip since only 1d arrays are allowed. if(subStr.GetLength() > 0) { //everything we add is going to be based on the current tail. //because we are adding parents, as we find parents we can continue //to add them to this position so that they will order themselves properly POSITION insertPos= elementList.GetTailPosition(); //calculate the cancel condition. //it is the current tail's object if a tail exists otherwise NULL //NULL indicates go all the way to the root MObject cancelObj= MObject::kNullObj; if(elementList.GetCount() > 0) { cancelObj= elementList.GetTail().Attribute.object(); } //get the object we are currently working with MObject thisObj= depNode.attribute(subStr.GetString()); if(thisObj.isNull()) return MPlug();//Critical element of the path was not found...return NULL //add it to the list so that we have something to insertBefore elementList.AddTail(); elementList.GetTail().Name= subStr; elementList.GetTail().Attribute.setObject(thisObj); //walk through all of the parents until we reach cancel condition. //we can add the current element onto the list in the same way. for( MFnAttribute itrAttr( elementList.GetTail().Attribute.parent() ); !itrAttr.object().isNull() && (cancelObj != itrAttr.object()); itrAttr.setObject(itrAttr.parent())) { PathDecodeElement element; element.Attribute.setObject( itrAttr.object() ); //we change the position so that the grandparent is inserted before the parent insertPos= elementList.InsertBefore( insertPos, element); } } } //are we looking at a numbered portion? else if(plugStr[iLastPos-1]=='[' && plugStr[iThisPos-1]==']') { //if so change the array index. elementList.GetTail().IsArray= true; elementList.GetTail().Index = atoi( subStr.GetString() ); } else DXCC_ASSERT(false);//VERY POORLY FORMED STRING } //produce the result plug off of the elementList. bool first= true; for(POSITION pos= elementList.GetHeadPosition(); pos != NULL; elementList.GetNext(pos)) { PathDecodeElement& element= elementList.GetAt(pos); if(first) {//on first one we initialize the result first= false; result= MPlug( GetSite(), element.Attribute.object() ); } else { result= result.child( element.Attribute.object() ); } if(element.IsArray) { result= result.elementByLogicalIndex(element.Index); } if(result.isNull()) return MPlug();//Critical element of the path was not found...return NULL } return result; }
MStatus CmpMeshModifierCmd::transferTweaks( const MDagPath &shapePath, MObject &tweakNode, MDagModifier &dagMod ) { // Get the tweaks from the mesh shape and apply them to the // to the tweak node MFnDagNode shapeNodeFn( shapePath ); MPlug srcTweaksPlug = shapeNodeFn.findPlug( "pnts" ); MFnDependencyNode tweakNodeFn( tweakNode ); MPlug dstTweaksPlug = tweakNodeFn.findPlug( "tweak" ); //MGlobal::displayInfo( MString( "storing tweaks from " ) + shapePath.fullPathName() + "\n" ); MPlugArray plugs; MPlug srcTweakPlug; MPlug dstTweakPlug; MObject dataObj; MFloatVector tweak; unsigned int nTweaks = srcTweaksPlug.numElements(); unsigned int i, j, ci, logicalIndex; for( i=0; i < nTweaks; i++ ) { srcTweakPlug = srcTweaksPlug.elementByPhysicalIndex( i ); if( !srcTweakPlug.isNull() ) { logicalIndex = srcTweakPlug.logicalIndex(); // Set tweak node tweak element srcTweakPlug.getValue( dataObj ); MFnNumericData numDataFn( dataObj ); numDataFn.getData( tweak[0], tweak[1], tweak[2] ); dagMod.commandToExecute( MString( "setAttr " ) + tweakNodeFn.name() + ".tweak[" + logicalIndex + "] " + tweak[0] + " " + tweak[1] + " " + tweak[2] ); // Handle transfer of incoming and outgoing connections to "pnts" elements dstTweakPlug = dstTweaksPlug.elementByLogicalIndex(logicalIndex); if( srcTweakPlug.isConnected() ) { // As source, transfer source to tweak node tweak srcTweakPlug.connectedTo( plugs, false, true ); for( j=0; j < plugs.length(); j++ ) { dagMod.disconnect( srcTweakPlug, plugs[j] ); dagMod.connect( dstTweakPlug, plugs[j] ); } // As destination, transfer destination to tweak node tweak srcTweakPlug.connectedTo( plugs, true, false ); if( plugs.length() == 1 ) // There can only be one input connection { dagMod.disconnect( plugs[0], srcTweakPlug ); dagMod.connect( plugs[0], dstTweakPlug ); } } else // Check children { MPlug srcTweakChildPlug; MPlug dstTweakChildPlug; for( ci=0; ci < srcTweakPlug.numChildren(); ci++ ) { srcTweakChildPlug = srcTweakPlug.child(ci); dstTweakChildPlug = dstTweakPlug.child(ci); if( srcTweakChildPlug.isConnected() ) { // As souce, transfer source to tweak node tweak srcTweakChildPlug.connectedTo( plugs, false, true ); for( j=0; j < plugs.length(); j++ ) { dagMod.disconnect( srcTweakChildPlug, plugs[j] ); dagMod.connect( dstTweakChildPlug, plugs[j] ); } // As destination, transfer destination to tweak node tweak srcTweakChildPlug.connectedTo( plugs, true, false ); if( plugs.length() == 1 ) // There can only be one input connection { dagMod.disconnect( plugs[0], srcTweakChildPlug ); dagMod.connect( plugs[0], dstTweakChildPlug ); } } } } // With the tweak values and any connections now transferred to // the tweak node's tweak element, this source element can be reset dagMod.commandToExecute( MString( "setAttr " ) + shapePath.fullPathName() + ".pnts[" + logicalIndex + "] 0 0 0" ); //MGlobal::displayInfo( MString(" tweak: ") + tweakIndices[i] + ": " + tweaks[i].x + ", " + tweaks[i].y + ", " + tweaks[i].z + "\n" ); } } return MS::kSuccess; }
IECore::ObjectPtr FromMayaSkinClusterConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const { MStatus stat; // our data storage objects IECore::StringVectorDataPtr influenceNamesData = new IECore::StringVectorData(); IECore::M44fVectorDataPtr influencePoseData = new IECore::M44fVectorData(); IECore::IntVectorDataPtr pointIndexOffsetsData = new IECore::IntVectorData(); IECore::IntVectorDataPtr pointInfluenceCountsData = new IECore::IntVectorData(); IECore::IntVectorDataPtr pointInfluenceIndicesData = new IECore::IntVectorData(); IECore::FloatVectorDataPtr pointInfluenceWeightsData = new IECore::FloatVectorData(); // get a skin cluster fn MFnSkinCluster skinClusterFn(object); MDagPathArray influencePaths; skinClusterFn.influenceObjects(influencePaths); // get the influence names int influencesCount = influencePaths.length(); influenceNamesData->writable().reserve( influencesCount ); InfluenceName in = (InfluenceName)m_influenceNameParameter->getNumericValue(); switch( in ) { case Partial : { for (int i=0; i < influencesCount; i++) { influenceNamesData->writable().push_back( influencePaths[i].partialPathName(&stat).asChar() ); } break; } case Full : { for (int i=0; i < influencesCount; i++) { influenceNamesData->writable().push_back( influencePaths[i].fullPathName(&stat).asChar() ); } break; } } // extract bind pose MFnDependencyNode skinClusterNodeFn( object ); MPlug bindPreMatrixArrayPlug = skinClusterNodeFn.findPlug( "bindPreMatrix", true, &stat ); for (int i=0; i < influencesCount; i++) { MPlug bindPreMatrixElementPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( skinClusterFn.indexForInfluenceObject( influencePaths[i], NULL ), &stat); MObject matObj; bindPreMatrixElementPlug.getValue( matObj ); MFnMatrixData matFn( matObj, &stat ); MMatrix mat = matFn.matrix(); Imath::M44f cmat = IECore::convert<Imath::M44f>( mat ); influencePoseData->writable().push_back( cmat ); } // extract the skinning information // get the first input geometry to the skin cluster // TODO: if needed, extend this to retrieve more than one output geometry MObjectArray outputGeoObjs; stat = skinClusterFn.getOutputGeometry( outputGeoObjs ); if (! stat) { throw IECore::Exception( "FromMayaSkinClusterConverter: skinCluster node does not have any output geometry!" ); } // get the dag path to the first object MFnDagNode dagFn( outputGeoObjs[0] ); MDagPath geoPath; dagFn.getPath( geoPath ); // generate a geo iterator for the components MItGeometry geoIt( outputGeoObjs[0] ); int currentOffset = 0; // loop through all the points of the geometry to extract their bind information for ( ; !geoIt.isDone(); geoIt.next() ) { MObject pointObj = geoIt.currentItem( &stat ); MDoubleArray weights; unsigned int weightsCount; skinClusterFn.getWeights( geoPath, pointObj, weights, weightsCount ); int pointInfluencesCount = 0; for ( int influenceId = 0; influenceId < int( weightsCount ); influenceId++ ) { // ignore zero weights, we are generating a compressed (non-sparse) representation of the weights /// \todo: use a parameter to specify a threshold value rather than 0.0 if ( weights[influenceId] != 0.0 ) { pointInfluencesCount++; pointInfluenceWeightsData->writable().push_back( float( weights[influenceId] ) ); pointInfluenceIndicesData->writable().push_back( influenceId ); } } pointIndexOffsetsData->writable().push_back( currentOffset ); pointInfluenceCountsData->writable().push_back( pointInfluencesCount ); currentOffset += pointInfluencesCount; } // put all our results in a smooth skinning data object return new IECore::SmoothSkinningData( influenceNamesData, influencePoseData, pointIndexOffsetsData, pointInfluenceCountsData, pointInfluenceIndicesData, pointInfluenceWeightsData ); }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::processTweaks( modifyPolyData& data ) // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; // Clear tweak undo information (to be rebuilt) // fTweakIndexArray.clear(); fTweakVectorArray.clear(); // Extract the tweaks and place them into a polyTweak node. This polyTweak node // will be placed ahead of the modifier node to maintain the order of operations. // Special care must be taken into recreating the tweaks: // // 1) Copy tweak info (including connections!) // 2) Remove tweak info from both meshNode and a duplicate meshNode (if applicable) // 3) Cache tweak info for undo operations // //if( fHasTweaks && fHasHistory && !speedupTweakProcessing()) if( fHasTweaks && fHasHistory ) { // Declare our function sets // MFnDependencyNode depNodeFn; // Declare our attributes and plugs // MPlug meshTweakPlug; MPlug upstreamTweakPlug; MObject tweakNodeTweakAttr; // Declare our tweak processing variables // MPlug tweak; MPlug tweakChild; MObject tweakData; MObjectArray tweakDataArray; MFloatVector tweakVector; MIntArray tweakSrcConnectionCountArray; MPlugArray tweakSrcConnectionPlugArray; MIntArray tweakDstConnectionCountArray; MPlugArray tweakDstConnectionPlugArray; MPlugArray tempPlugArray; unsigned i; unsigned j; unsigned k; // Create the tweak node and get its attributes // data.tweakNode = fDGModifier.MDGModifier::createNode( "polyTweak" ); depNodeFn.setObject( data.tweakNode ); data.tweakNodeSrcAttr = depNodeFn.attribute( "output" ); data.tweakNodeDestAttr = depNodeFn.attribute( "inputPolymesh" ); tweakNodeTweakAttr = depNodeFn.attribute( "tweak" ); depNodeFn.setObject( data.meshNodeShape ); meshTweakPlug = depNodeFn.findPlug( "pnts" ); // ASSERT: meshTweakPlug should be an array plug! // MStatusAssert( (meshTweakPlug.isArray()), "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" ); unsigned numElements = meshTweakPlug.numElements(); // Gather meshTweakPlug data // for( i = 0; i < numElements; i++ ) { // MPlug::numElements() only returns the number of physical elements // in the array plug. Thus we must use elementByPhysical index when using // the index i. // tweak = meshTweakPlug.elementByPhysicalIndex(i); // If the method fails, the element is NULL. Only append the index // if it is a valid plug. // if( !tweak.isNull() ) { // Cache the logical index of this element plug // unsigned logicalIndex = tweak.logicalIndex(); // Collect tweak data and cache the indices and float vectors // tweak.getValue( tweakData ); tweakDataArray.append( tweakData ); getFloat3PlugValue( tweak, tweakVector ); fTweakIndexArray.append( logicalIndex ); fTweakVectorArray.append( tweakVector ); // Collect tweak connection data // // Parse down to the deepest level of the plug tree and check // for connections - look at the child nodes of the element plugs. // If any connections are found, record the connection and disconnect // it. // // ASSERT: The element plug should be compound! // MStatusAssert( (tweak.isCompound()), "tweak.isCompound() -- Element tweak plug is not compound" ); unsigned numChildren = tweak.numChildren(); for( j = 0; j < numChildren; j++ ) { tweakChild = tweak.child(j); if( tweakChild.isConnected() ) { // Get all connections with this plug as source, if they exist // tempPlugArray.clear(); if( tweakChild.connectedTo( tempPlugArray, false, true ) ) { unsigned numSrcConnections = tempPlugArray.length(); tweakSrcConnectionCountArray.append( numSrcConnections ); for( k = 0; k < numSrcConnections; k++ ) { tweakSrcConnectionPlugArray.append( tempPlugArray[k] ); fDGModifier.disconnect( tweakChild, tempPlugArray[k] ); } } else { tweakSrcConnectionCountArray.append(0); } // Get the connection with this plug as destination, if it exists // tempPlugArray.clear(); if( tweakChild.connectedTo( tempPlugArray, true, false ) ) { // ASSERT: tweakChild should only have one connection as destination! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on tweakChild" ); tweakDstConnectionCountArray.append(1); tweakDstConnectionPlugArray.append( tempPlugArray[0] ); fDGModifier.disconnect( tempPlugArray[0], tweakChild ); } else { tweakDstConnectionCountArray.append(0); } } else { tweakSrcConnectionCountArray.append(0); tweakDstConnectionCountArray.append(0); } } } } // Apply meshTweakPlug data to our polyTweak node // MPlug polyTweakPlug( data.tweakNode, tweakNodeTweakAttr ); unsigned numTweaks = fTweakIndexArray.length(); int srcOffset = 0; int dstOffset = 0; //Progress initialisieren progressBar progress("Processing Tweaks", numTweaks); for( i = 0; i < numTweaks; i++ ) { // Apply tweak data // tweak = polyTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( tweakDataArray[i] ); // ASSERT: Element plug should be compound! // MStatusAssert( (tweak.isCompound()), "tweak.isCompound() -- Element plug, 'tweak', is not compound" ); unsigned numChildren = tweak.numChildren(); for( j = 0; j < numChildren; j++ ) { tweakChild = tweak.child(j); // Apply tweak source connection data // if( 0 < tweakSrcConnectionCountArray[i*numChildren + j] ) { for( k = 0; k < (unsigned) tweakSrcConnectionCountArray[i*numChildren + j]; k++ ) { fDGModifier.connect( tweakChild, tweakSrcConnectionPlugArray[srcOffset] ); srcOffset++; } } // Apply tweak destination connection data // if( 0 < tweakDstConnectionCountArray[i*numChildren + j] ) { fDGModifier.connect( tweakDstConnectionPlugArray[dstOffset], tweakChild ); dstOffset++; } } if(i%50 == 0) { progress.set(i); } } // Now, set the tweak values on the meshNode(s) to zero (History dependent) // MFnNumericData numDataFn; MObject nullVector; // Create a NULL vector (0,0,0) using MFnNumericData to pass into the plug // numDataFn.create( MFnNumericData::k3Float ); numDataFn.setData( 0, 0, 0 ); nullVector = numDataFn.object(); for( i = 0; i < numTweaks; i++ ) { // Access using logical indices since they are the only plugs guaranteed // to hold tweak data. // tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } // Only have to clear the tweaks off the duplicate mesh if we do not have history // and we want history. // if( !fHasHistory && fHasRecordHistory ) { depNodeFn.setObject( data.upstreamNodeShape ); upstreamTweakPlug = depNodeFn.findPlug( "pnts" ); if( !upstreamTweakPlug.isNull() ) { for( i = 0; i < numTweaks; i++ ) { tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } } } } else fHasTweaks = false; return status; }
MStatus ribGenCmd::doIt( const MArgList& args) { /*=========================================* * the parameters of command * =========================================*/ MString ribPath, shaderPath; unsigned index; index = args.flagIndex("p", "ribPath"); if(MArgList::kInvalidArgIndex != index) args.get(index+1, ribPath); index = args.flagIndex("sp", "shaderPath"); if(MArgList::kInvalidArgIndex != index) args.get(index+1, shaderPath); /*=========================================* * shaderPath & ribPath *=========================================*/ RtToken shader= new char[50] , path=new char[50]; strcpy(shader, shaderPath.asChar()); strcpy(path, ribPath.asChar()); char *curve[] = {"curves"}; RtMatrix identityMatrix = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 }}; RtInt ustep, vstep; ustep = vstep =1; /*=====================================* * Begenning of writting out the .rib file. *=====================================*/ RiBegin(path); RiAttributeBegin(); RiTransformBegin(); //RiSurface(shader); RiTransformEnd(); //RiAttribute("identifier", "name", curve); RiConcatTransform(identityMatrix); RiShadingInterpolation(RI_SMOOTH); RiBasis(RiBezierBasis, ustep, RiBezierBasis, vstep); int nodeId = 0, knotNum = 0; float baseWidth = 0.0f, tipWidth = 0.0f; MObject surface, node; /*=========================================* * get the informations of selected Objects in scene. *=========================================*/ MSelectionList selection; MGlobal::getActiveSelectionList(selection); MItSelectionList iter(selection, MFn::kNurbsSurface ); for(; !iter.isDone(); iter.next()) { RtInt numCurves = 0; RtInt numVertexs = 0; /*======================================* * get the drawHairNode from selected NurbsSurface. *======================================*/ iter.getDependNode(surface); MFnDependencyNode surfaceFn(surface); MStatus state; MPlug plug = surfaceFn.findPlug("worldSpace",false, &state); plug = plug.elementByLogicalIndex(0); MPlugArray desPlugs; plug.connectedTo(desPlugs,false,true); plug = desPlugs[0]; node = plug.node(); //drawHairNode has found here!! /*=====================================* * get the attributes of drawHairNode. *=====================================*/ MFnDependencyNode hairNodeFn(node); plug = hairNodeFn.findPlug("nodeId"); plug.getValue(nodeId); MGlobal::displayInfo(MString(" nodeId: ")+nodeId); plug = hairNodeFn.findPlug("number"); plug.getValue(numCurves); plug= hairNodeFn.findPlug("smooth"); plug.getValue(knotNum); plug = hairNodeFn.findPlug("baseWidth"); plug.getValue(baseWidth); plug = hairNodeFn.findPlug("tipWidth"); plug.getValue(tipWidth); /*=====================================* * caculate the linear interpolate of the width of the curve. *=====================================*/ numVertexs = numCurves * knotNum; int widthNum = numCurves * (knotNum -2 ); float *curveWidth = new float[widthNum]; float widthStep = 0.0f; for(int c=0; c<widthNum; ++c){ widthStep = ((c%(knotNum-2)) / (float)(knotNum-3)) *(tipWidth - baseWidth); if(widthStep < epslion) widthStep = 0.0f; curveWidth[c] = baseWidth + widthStep; } RtInt *nvertices = new RtInt[numCurves]; //the numbers of vertices on each curve. RtPoint *vertexs = new RtPoint[numVertexs]; //the total vertexs. /*=====================================* * nvertices[] assignment. *=====================================*/ for(int j=0; j<numCurves ; ++j){ nvertices[j] = knotNum; } /*=====================================* * get the hair's datas from the static member * named "nodeManager" of the drawHairNode class. *=====================================*/ nodeMap::iterator iter = drawHairNode::nodeManager.find(nodeId); vector<MPointArray> helixVec = iter->second; /*=====================================* * vertexs[] assignment. *=====================================*/ float x=0, y=0, z=0; int countVT=0; for(vector<MPointArray>::iterator it=helixVec.begin(); it != helixVec.end(); ++it){ MPointArray helixCurve = (MPointArray)(*it); for(int k=0; k < helixCurve.length() ; ++k){ x = helixCurve[k].x; if(fabs(x) < epslion) vertexs[countVT][0] = 0; else vertexs[countVT][0] = helixCurve[k].x; y = helixCurve[k].y; if(fabs(y) < epslion) vertexs[countVT][1] = 0; else vertexs[countVT][1] = helixCurve[k].y; z = helixCurve[k].z; if(fabs(z) < epslion) vertexs[countVT++][2] = 0; else vertexs[countVT++][2] = helixCurve[k].z; } } RiCurves( RI_CUBIC, numCurves, nvertices, RI_NONPERIODIC, RI_P, vertexs, RI_WIDTH, curveWidth, RI_NULL); } RiAttributeEnd(); RiEnd(); return redoIt(); }