// Reference: OSD shape_utils.h:: applyTags() "corner" static float getCreaseVertices( MFnMesh const & inMeshFn, Descriptor & outDesc) { MUintArray tVertexIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if ( inMeshFn.getCreaseVertices(tVertexIds, tCreaseData) ) { assert( tVertexIds.length() == tCreaseData.length() ); int ncorners = tVertexIds.length(); int * verts = new int[ncorners*2]; float * weights = new float[ncorners]; // Has crease vertices for (unsigned int j=0; j < tVertexIds.length(); j++) { assert( tCreaseData[j] >= 0.0 ); verts[j] = tVertexIds[j]; weights[j] = float(tCreaseData[j]); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } outDesc.numCorners = ncorners; outDesc.cornerVertexIndices = verts; outDesc.cornerWeights = weights; } return maxCreaseValue; }
/* ----------------------------------------- Make a degree 1 curve from the given CVs. ----------------------------------------- */ static void jMakeCurve( MPointArray cvs ) { MStatus stat; unsigned int deg = 1; MDoubleArray knots; unsigned int i; for ( i = 0; i < cvs.length(); i++ ) knots.append( (double) i ); // Now create the curve // MFnNurbsCurve curveFn; curveFn.create( cvs, knots, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &stat ); if ( MS::kSuccess != stat ) cout<<"Error creating curve."<<endl; }
bool HesperisCurveCreator::CreateACurve(Vector3F * pos, unsigned nv, MObject &target) { MPointArray vertexArray; unsigned i=0; for(; i<nv; i++) vertexArray.append( MPoint( pos[i].x, pos[i].y, pos[i].z ) ); const int degree = 2; const int spans = nv - degree; const int nknots = spans + 2 * degree - 1; MDoubleArray knotSequences; knotSequences.append(0.0); for(i = 0; i < nknots-2; i++) knotSequences.append( (double)i ); knotSequences.append(nknots-3); MFnNurbsCurve curveFn; MStatus stat; curveFn.create(vertexArray, knotSequences, degree, MFnNurbsCurve::kOpen, false, false, target, &stat ); return stat == MS::kSuccess; }
bool ToMayaMatrixVectorDataConverter<F>::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; typename F::ConstPtr data = IECore::runTimeCast<const F>( from ); if( !data ) { return false; } MFnDoubleArrayData fnData; const typename F::ValueType &v = data->readable(); MDoubleArray array; array.setLength( v.size() * 16 ); for ( unsigned i=0; i < v.size(); i++ ) { for ( unsigned j=0; j < 4; j++ ) { for ( unsigned k=0; k < 4; k++ ) { array[ i*16 + j*4 + k ] = (double)v[i][j][k]; } } } to = fnData.create( array, &s ); return s; }
bool PxrUsdMayaWriteUtil::ReadMayaAttribute( const MFnDependencyNode& depNode, const MString& name, VtFloatArray* val) { MStatus status; depNode.attribute(name, &status); if (status == MS::kSuccess) { MPlug plug = depNode.findPlug(name); MObject dataObj; if ( (plug.getValue(dataObj) == MS::kSuccess) && (dataObj.hasFn(MFn::kDoubleArrayData)) ) { MFnDoubleArrayData dData(dataObj, &status); if (status == MS::kSuccess) { MDoubleArray arrayValues = dData.array(); size_t numValues = arrayValues.length(); val->resize(numValues); for (size_t i = 0; i < numValues; ++i) { (*val)[i] = arrayValues[i]; } return true; } } } return false; }
// Reference: OSD shape_utils.h:: applyTags() "crease" static float getCreaseEdges(MFnMesh const & inMeshFn, Descriptor & outDesc) { MUintArray tEdgeIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if (inMeshFn.getCreaseEdges(tEdgeIds, tCreaseData)) { assert( tEdgeIds.length() == tCreaseData.length() ); int ncreases = tEdgeIds.length(); int * vertPairs = new int[ncreases*2]; float * weights = new float[ncreases]; int2 edgeVerts; for (unsigned int j=0; j < tEdgeIds.length(); j++) { assert( tCreaseData[j] >= 0.0 ); inMeshFn.getEdgeVertices(tEdgeIds[j], edgeVerts); vertPairs[j*2 ] = edgeVerts[0]; vertPairs[j*2+1] = edgeVerts[1]; weights[j] = float(tCreaseData[j]); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } outDesc.numCreases = ncreases; outDesc.creaseVertexIndexPairs = vertPairs; outDesc.creaseWeights = weights; } return maxCreaseValue; }
// Reference: OSD shape_utils.h:: applyTags() "corner" float applyCreaseVertices( MFnMesh const & inMeshFn, HMesh * hbrMesh ) { MUintArray tVertexIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if ( inMeshFn.getCreaseVertices(tVertexIds, tCreaseData) ) { assert( tVertexIds.length() == tCreaseData.length() ); // Has crease vertices for (unsigned int j=0; j < tVertexIds.length(); j++) { // Assumption: The OSD vert ids are identical to those of the Maya mesh HVertex * v = hbrMesh->GetVertex( tVertexIds[j] ); if(v) { assert( tCreaseData[j] >= 0.0 ); v->SetSharpness( (float)tCreaseData[j] ); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } else { fprintf(stderr, "warning: cannot find vertex for corner tag (%d)\n", tVertexIds[j] ); } } } return maxCreaseValue; }
MStatus makeSurf() { cout << ">>>> Start creation of test surface <<<<" << endl; // Set up knots // MDoubleArray knotArray; int i; // Add extra starting knots so that the first CV matches the curve start point // knotArray.append( 0.0 ); knotArray.append( 0.0 ); for ( i = 0; i <= NUM_SPANS; i++ ) { knotArray.append( (double)i ); } // Add extra ending knots so that the last CV matches the curve end point // knotArray.append( (double)i ); knotArray.append( (double)i ); // Now, Set up CVs // MPointArray cvArray; // We need a 2D array of CVs with NUM_SPANS + 3 CVs on a side // int last = NUM_SPANS + 3; for ( i = 0; i < last; i++ ) { for ( int j = 0; j < last; j++ ) { MPoint cv; cv.x = (((double)(j))/((double)(NUM_SPANS + 3)) * WIDTH) - (WIDTH/2.0); cv.z = (((double)(i))/((double)(NUM_SPANS + 3)) * WIDTH) - (WIDTH/2.0); double dist = sqrt( cv.x*cv.x + cv.z*cv.z ); cv.y = cos( dist ) * VERTICAL_SCALING; cvArray.append( cv ); } } // Create the surface // MFnNurbsSurface mfnNurbsSurf; MStatus stat; mfnNurbsSurf.create( cvArray, knotArray, knotArray, 3, 3, MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen, true, MObject::kNullObj, &stat ); if ( stat ) { cout << ">>>> Test Surface Creation Successfull <<<<\n"; } else { stat.perror("MFnNurbsSurface::create"); cout << ">>>> Test Surface Creation Failed <<<<\n"; } return stat; }
MStatus helix::doIt( const MArgList& args ) { MStatus stat; const unsigned deg = 3; // Curve Degree const unsigned ncvs = 20; // Number of CVs const unsigned spans = ncvs - deg; // Number of spans const unsigned nknots = spans+2*deg-1;// Number of knots double radius = 4.0; // Helix radius double pitch = 0.5; // Helix pitch unsigned i; // Parse the arguments. for ( i = 0; i < args.length(); i++ ) if ( MString( "-p" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) pitch = tmp; } else if ( MString( "-r" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) radius = tmp; } MPointArray controlVertices; MDoubleArray knotSequences; // Set up cvs and knots for the helix // for (i = 0; i < ncvs; i++) controlVertices.append( MPoint( radius * cos( (double)i ), pitch * (double)i, radius * sin( (double)i ) ) ); for (i = 0; i < nknots; i++) knotSequences.append( (double)i ); // Now create the curve // MFnNurbsCurve curveFn; curveFn.create( controlVertices, knotSequences, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &stat ); if ( MS::kSuccess != stat ) cout<<"Error creating curve."<<endl; return stat; }
MDoubleArray boingRbCmd::getBulletVectorAttribute(MString &name, MString &attr) { MVector vec; MDoubleArray result; shared_ptr<bSolverNode> b_solv = bSolverNode::get_bsolver_node(); MStringArray nodes; if (name == "*") { nodes = b_solv->get_all_keys(); } else { nodes.append(name); } //std::cout<<"nodes : "<<nodes<<std::endl; //std::cout<<"nodes.length() : "<<nodes.length()<<std::endl; for (int i=0; i<nodes.length(); i++) { std::cout<<"trying to get rb...."<<std::endl; rigid_body_t::pointer rb = b_solv->getdata(nodes[i])->m_rigid_body; std::cout<<"got rb : "<<b_solv->getdata(nodes[i])->name<<std::endl; //rigid_body_t::pointer rb = getPointerFromName(name); if (rb != 0) { float mass = rb->get_mass(); bool active = (mass>0.f); if(active) { if (attr=="velocity") { vec3f vel; rb->get_linear_velocity(vel); vec = MVector((double)vel[0], (double)vel[1], (double)vel[2]); } else if (attr=="position") { vec3f pos; quatf rot; rb->get_transform(pos, rot); vec = MVector((double)pos[0], (double)pos[1], (double)pos[2]); } else if (attr=="angularVelocity") { vec3f av; rb->get_angular_velocity(av); vec = MVector((double)av[0], (double)av[1], (double)av[2]); } /*else { boing *b = static_cast<boing*>( rb->impl()->body()->getUserPointer() ); MString vecStr = b->get_data(attr); MStringArray vecArray = parseArguments(vecStr, ","); vec = MVector(vecArray[0].asDouble(), vecArray[1].asDouble(), vecArray[2].asDouble()); }*/ } } for (int j=0; j<3; j++) { //std::cout<<"vec["<<j<<"] : "<<vec[j]<<std::endl; result.append(vec[j]); } } return result; }
void VertexPolyColourCommand::WriteColoursToNode(MDagPath& dagPath, MColorArray& colors, bool isSource) { MStatus status; // Try to find the colour node attached to the mesh // If it's not found, create it MObject ourNode; if (!FindNodeOnMesh(dagPath,ourNode)) { CreateNodeOnMesh(dagPath, ourNode); } // Send the selection to the node { // Pass the component list down to the node. // To do so, we create/retrieve the current plug // from the uvList attribute on the node and simply // set the value to our component list. // MDoubleArray dcols; dcols.setLength(colors.length()*4); int idx = 0; for (unsigned int i=0; i<colors.length(); i++) { dcols[idx] = (double)colors[i].r; idx++; dcols[idx] = (double)colors[i].g; idx++; dcols[idx] = (double)colors[i].b; idx++; dcols[idx] = (double)colors[i].a; idx++; } MFnDoubleArrayData wrapper; wrapper.create(dcols,&status); MPlug* colourPlug = NULL; if (isSource) { colourPlug = new MPlug(ourNode, PolyColourNode::m_colors); } else { colourPlug = new MPlug(ourNode, PolyColourNode::m_colorsDest); } // Warning, we have to do this as GCC doesn't like to pass by temporary reference MObject wrapperObjRef = wrapper.object(); status = colourPlug->setValue(wrapperObjRef); delete colourPlug; } }
void dynExprField::apply( MDataBlock &block, int receptorSize, const MDoubleArray &magnitudeArray, const MDoubleArray &magnitudeOwnerArray, const MVectorArray &directionArray, const MVectorArray &directionOwnerArray, MVectorArray &outputForce ) // // Compute output force for each particle. If there exists the // corresponding per particle attribute, use the data passed from // particle shape (stored in magnitudeArray and directionArray). // Otherwise, use the attribute value from the field. // { // get the default values MVector defaultDir = direction(block); double defaultMag = magnitude(block); int magArraySize = magnitudeArray.length(); int dirArraySize = directionArray.length(); int magOwnerArraySize = magnitudeOwnerArray.length(); int dirOwnerArraySize = directionOwnerArray.length(); int numOfOwner = magOwnerArraySize; if( dirOwnerArraySize > numOfOwner ) numOfOwner = dirOwnerArraySize; double magnitude = defaultMag; MVector direction = defaultDir; for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ ) { if(receptorSize == magArraySize) magnitude = magnitudeArray[ptIndex]; if(receptorSize == dirArraySize) direction = directionArray[ptIndex]; if( numOfOwner > 0) { for( int nthOwner = 0; nthOwner < numOfOwner; nthOwner++ ) { if(magOwnerArraySize == numOfOwner) magnitude = magnitudeOwnerArray[nthOwner]; if(dirOwnerArraySize == numOfOwner) direction = directionOwnerArray[nthOwner]; outputForce.append( direction * magnitude ); } } else { outputForce.append( direction * magnitude ); } } }
AlembicWriteJob::AlembicWriteJob(const MString &in_FileName, const MObjectArray &in_Selection, const MDoubleArray &in_Frames, bool use_ogawa, const std::vector<std::string> &in_prefixFilters, const std::set<std::string> &in_attributes, const std::vector<std::string> &in_userPrefixFilters, const std::set<std::string> &in_userAttributes) : useOgawa(use_ogawa), mPrefixFilters(in_prefixFilters), mAttributes(in_attributes), mUserPrefixFilters(in_userPrefixFilters), mUserAttributes(in_userAttributes) { // ensure to clear the isRefAnimated cache clearIsRefAnimatedCache(); mFileName = in_FileName; for (unsigned int i = 0; i < in_Selection.length(); i++) { mSelection.append(in_Selection[i]); } for (unsigned int i = 0; i < in_Frames.length(); i++) { mFrames.push_back(in_Frames[i]); } }
// Reference: OSD shape_utils.h:: applyTags() "crease" float applyCreaseEdges(MFnMesh const & inMeshFn, HMesh * hbrMesh) { MStatus returnStatus; MUintArray tEdgeIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if (inMeshFn.getCreaseEdges(tEdgeIds, tCreaseData)) { assert( tEdgeIds.length() == tCreaseData.length() ); // Has crease edges int2 edgeVerts; for (unsigned int j=0; j < tEdgeIds.length(); j++) { // Get vert ids from maya edge int edgeId = tEdgeIds[j]; returnStatus = inMeshFn.getEdgeVertices(edgeId, edgeVerts); // Assumption: The OSD vert ids are identical to those of the Maya mesh HVertex const * v = hbrMesh->GetVertex( edgeVerts[0] ), * w = hbrMesh->GetVertex( edgeVerts[1] ); HHalfedge * e = 0; if( v and w ) { if( (e = v->GetEdge(w)) == 0) { e = w->GetEdge(v); } if(e) { assert( tCreaseData[j] >= 0.0 ); e->SetSharpness( (float)tCreaseData[j] ); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } else { fprintf(stderr, "warning: cannot find edge for crease tag (%d,%d)\n", edgeVerts[0], edgeVerts[1] ); } } } } return maxCreaseValue; }
void HelixButton::createHelix() { MStatus st; const unsigned deg = 3; // Curve Degree const unsigned ncvs = 20; // Number of CVs const unsigned spans = ncvs - deg; // Number of spans const unsigned nknots = spans + 2 * deg - 1; // Number of knots double radius = 4.0; // Helix radius double pitch = 0.5; // Helix pitch unsigned i; MPointArray controlVertices; MDoubleArray knotSequences; // Set up cvs and knots for the helix for (i = 0; i < ncvs; i++) { controlVertices.append( MPoint( radius * cos((double)i), pitch * (double)i, radius * sin((double)i) ) ); } for (i = 0; i < nknots; i++) knotSequences.append((double)i); // Now create the curve MFnNurbsCurve curveFn; MObject curve = curveFn.create( controlVertices, knotSequences, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &st ); MGlobal::displayInfo("Helix curve created!"); if (!st) { MGlobal::displayError( HelixQtCmd::commandName + " - could not create helix: " + st.errorString() ); } }
void skinClusterWeights::doItQuery() { MStatus status; unsigned int i, j; MDoubleArray weights; // To allow "skinClusterWeights -q" to return empty double array setResult(weights); MSelectionList selList; for (i = 0; i < geometryArray.length(); i++) { MDagPath dagPath; MObject component; selList.clear(); selList.add(geometryArray[i]); MStatus status = selList.getDagPath(0, dagPath, component); if (status != MS::kSuccess) { continue; } if (component.isNull()) dagPath.extendToShape(); MObject skinCluster = findSkinCluster(dagPath); if (!isSkinClusterIncluded(skinCluster)) { continue; } MFnSkinCluster skinClusterFn(skinCluster, &status); if (status != MS::kSuccess) { continue; } MIntArray influenceIndexArray; populateInfluenceIndexArray(skinClusterFn, influenceIndexArray); weights.clear(); skinClusterFn.getWeights(dagPath, component, influenceIndexArray, weights); if (weights.length() > 0) { for (j = 0; j < weights.length(); j++) { appendToResult(weights[j]); } } } }
MStatus mDbl1dNoise::doIt( const MArgList& args ) { // get the arguments MDoubleArray dblA; unsigned int count; MStatus stat = getArgDbl(args, dblA, count); ERROR_FAIL(stat); // do the actual job Noise noiseGen; for (unsigned int i=0;i<dblA.length();i++) { dblA[i] = noiseGen.improvedPerlin1dS(float(dblA[i])); } setResult(dblA); return MS::kSuccess; }
MStatus mDblSignedToUnsigned::doIt( const MArgList& args ) { // get the arguments MDoubleArray dblA; unsigned int count; MStatus stat = getArgDbl(args, dblA, count); ERROR_FAIL(stat); // do the actual job for (unsigned int i=0;i<dblA.length();i++) { dblA[i] = (0.5 * dblA[i] + 0.5); } setResult(dblA); return MS::kSuccess; }
MStatus ReduceArrayNode::compute(const MPlug& plug, MDataBlock& data) { if (plug != aOutput) return MS::kUnknownParameter; MStatus status; MDataHandle inputHandle = data.inputValue(aInput, &status); CHECK_MSTATUS_AND_RETURN_IT(status); MFnDoubleArrayData inputArrayData(inputHandle.data()); MDoubleArray inputArray = inputArrayData.array(); int numInputs = inputArray.length(); short operation = data.inputValue(aOperation).asShort(); double output = numInputs > 0 ? inputArray[0] : 0.0; if (operation == kLENGTH) { output = double(numInputs); } else { for (int i = 1; i < numInputs; i++) { output = computeOutput(output, inputArray[i], operation, status); if (!status) { reportComputeError(this, operation); break; } } } MDataHandle outputHandle = data.outputValue(this->aOutput); outputHandle.setDouble(output); outputHandle.setClean(); return MS::kSuccess; }
MStatus getMDoubleArray(MObject &node, MString attrString, MDoubleArray &arr) { MStatus stat; MFnDependencyNode nodeFn(node); MObject attr = nodeFn.attribute( attrString, &stat ); MCheckStatus(stat,"ERROR node.attribute()"); MPlug plug( node, attr ); MDataHandle handle; plug.getValue( handle ); arr.copy(MFnDoubleArrayData(handle.data()).array()); plug.destructHandle(handle); return MS::kSuccess; }
void CalculateSampleWeights(const std::map<int, double>& distances, double radius, MIntArray& vertexIds, MDoubleArray& weights) { std::map<int, double>::const_iterator itDistance; std::vector<std::pair<int, double> > samples; for (itDistance = distances.begin(); itDistance != distances.end(); itDistance++) { double x = itDistance->second; double w = 1.0 - (x/radius); samples.push_back(std::pair<int, double>(itDistance->first, w)); } // Make the samples a multiple of 4 so we can use fast intrinsics! int remainder = 4 - ((samples.size()-1) % 4); if (remainder != 4) { for (int i = 0; i < remainder; ++i) { samples.push_back(std::pair<int, double>(0, 0.0)); } } unsigned int length = (unsigned int)samples.size(); weights.setLength(length); vertexIds.setLength(length); std::sort(samples.begin(), samples.end(), SampleSort); std::vector<std::pair<int, double> >::iterator iter; int ii = 0; double sum = 0.0; for (iter = samples.begin(); iter != samples.end(); ++iter, ++ii) { vertexIds[ii] = (*iter).first; weights[ii] = (*iter).second; sum += (*iter).second; } assert(sum > 0.0); // Normalize the weights for (unsigned int i = 0; i < weights.length(); ++i) { weights[i] /= sum; } }
MStatus XmlCacheFormat::readDoubleArray( MDoubleArray& array, unsigned arraySize ) { MStringArray value; readXmlTagValue(doubleArrayTag, value); assert( value.length() == arraySize ); array.setLength( arraySize ); for ( unsigned int i = 0; i < value.length(); i++ ) { array[i] = strtod( value[i].asChar(), NULL ); } return MS::kSuccess; }
MStatus XmlCacheFormat::writeDoubleArray( const MDoubleArray& array ) { int size = array.length(); assert(size != 0); writeXmlTagValue(sizeTag,size); startXmlBlock( doubleArrayTag ); for(int i = 0; i < size; i++) { writeXmlValue(array[i]); } endXmlBlock(); return MS::kSuccess; }
void GetValidUp(const MDoubleArray& weights, const MPointArray& points, const MIntArray& sampleIds, const MPoint& origin, const MVector& normal, MVector& up) { MVector unitUp = up.normal(); // Adjust up if it's parallel to normal or if it's zero length if (std::abs((unitUp * normal) - 1.0) < 0.001 || up.length() < 0.0001) { for (unsigned int j = 0; j < weights.length()-1; ++j) { up -= (points[sampleIds[j]] - origin) * weights[j]; unitUp = up.normal(); if (std::abs((unitUp * normal) - 1.0) > 0.001 && up.length() > 0.0001) { // If the up and normal vectors are no longer parallel and the up vector has a length, // then we are good to go. break; } } up.normalize(); } else { up = unitUp; } }
void CalculateBasisComponents(const MDoubleArray& weights, const BaryCoords& coords, const MIntArray& triangleVertices, const MPointArray& points, const MFloatVectorArray& normals, const MIntArray& sampleIds, double* alignedStorage, MPoint& origin, MVector& up, MVector& normal) { // Start with the recreated point and normal using the barycentric coordinates of the hit point. unsigned int hitIndex = weights.length()-1; #ifdef __AVX__ __m256d originV = Dot4<MPoint>(coords[0], coords[1], coords[2], 0.0, points[triangleVertices[0]], points[triangleVertices[1]], points[triangleVertices[2]], MPoint::origin); __m256d hitNormalV = Dot4<MVector>(coords[0], coords[1], coords[2], 0.0, normals[triangleVertices[0]], normals[triangleVertices[1]], normals[triangleVertices[2]], MVector::zero); __m256d hitWeightV = _mm256_set1_pd(weights[hitIndex]); // Create the barycentric point and normal. __m256d normalV = _mm256_mul_pd(hitNormalV, hitWeightV); // Then use the weighted adjacent data. for (unsigned int j = 0; j < hitIndex; j += 4) { __m256d tempNormal = Dot4<MVector>(weights[j], weights[j+1], weights[j+2], weights[j+3], normals[sampleIds[j]], normals[sampleIds[j+1]], normals[sampleIds[j+2]], normals[sampleIds[j+3]]); normalV = _mm256_add_pd(tempNormal, normalV); } _mm256_store_pd(alignedStorage, originV); origin.x = alignedStorage[0]; origin.y = alignedStorage[1]; origin.z = alignedStorage[2]; _mm256_store_pd(alignedStorage, normalV); normal.x = alignedStorage[0]; normal.y = alignedStorage[1]; normal.z = alignedStorage[2]; // Calculate the up vector const MPoint& pt1 = points[triangleVertices[0]]; const MPoint& pt2 = points[triangleVertices[1]]; __m256d p1 = _mm256_set_pd(pt1.w, pt1.z, pt1.y, pt1.x); __m256d p2 = _mm256_set_pd(pt2.w, pt2.z, pt2.y, pt2.x); p1 = _mm256_add_pd(p1, p2); __m256d half = _mm256_set_pd(0.5, 0.5, 0.5, 0.5); p1 = _mm256_mul_pd(p1, half); __m256d upV = _mm256_sub_pd(p1, originV); _mm256_store_pd(alignedStorage, upV); up.x = alignedStorage[0]; up.y = alignedStorage[1]; up.z = alignedStorage[2]; #else MVector hitNormal; // Create the barycentric point and normal. for (int i = 0; i < 3; ++i) { origin += points[triangleVertices[i]] * coords[i]; hitNormal += MVector(normals[triangleVertices[i]]) * coords[i]; } // Use crawl data to calculate normal normal = hitNormal * weights[hitIndex]; for (unsigned int j = 0; j < hitIndex; j++) { normal += MVector(normals[sampleIds[j]]) * weights[j]; } // Calculate the up vector // The triangle vertices are sorted by decreasing barycentric coordinates so the first two are // the two closest vertices in the triangle. up = ((points[triangleVertices[0]] + points[triangleVertices[1]]) * 0.5) - origin; #endif normal.normalize(); GetValidUp(weights, points, sampleIds, origin, normal, up); }
MStatus CreateCurves::createCurve(Model::Strand & strand) { MStatus status; std::cerr << "Working with strand defined by base: " << strand.getDefiningBase().getDagPath(status).fullPathName().asChar() << std::endl; /* * Make sure this base is an end base (5') */ Model::Strand::BackwardIterator base_it = std::find_if(strand.reverse_begin(), strand.reverse_end(), Model::Strand::BaseTypeFunc(Model::Base::FIVE_PRIME_END)); /* * If we found an end base, use it, if not, it's a loop and it wont matter but we have to close the curve */ bool isLoop = base_it == strand.reverse_end(); Model::Strand strand_(isLoop ? strand.getDefiningBase() : *base_it); std::cerr << "5' end or loop base: " << strand_.getDefiningBase().getDagPath(status).fullPathName().asChar() << std::endl; MPointArray pointArray; MDoubleArray knotSequences; /* * Notice that the first point is different, it is as if it was inserted 4 times * Also notice that radius is probably normally never changed, but is taken into account * radius is only measured on the X,Y plane */ MVector translation; for(Model::Strand::ForwardIterator it = strand_.forward_begin(); it != strand_.forward_end(); ++it) { /* * Extract our coordinates, then interpolate between the last coordinates and these m_degree times */ if (!(status = it->getTranslation(translation, MSpace::kWorld))) { status.perror("Base::getTranslation"); return status; } pointArray.append(translation); } /* * Now create the CV curve */ knotSequences.setSizeIncrement(pointArray.length() + 2 * (unsigned int) m_degree - 1); for(int i = 0; i < m_degree - 1; ++i) knotSequences.append(0); for(unsigned int i = 0; i < pointArray.length() - 2; ++i) knotSequences.append(i); for(int i = 0; i < m_degree - 1; ++i) knotSequences.append(pointArray.length() - 3); m_curve_data.push_back(Curve(pointArray, knotSequences, isLoop)); if (!(status = m_curve_data.back().create(*this))) { status.perror("Curve::create"); return status; } return MStatus::kSuccess; }
void MayaNurbsCurveWriter::write() { Alembic::AbcGeom::OCurvesSchema::Sample samp; samp.setBasis(Alembic::AbcGeom::kBsplineBasis); MStatus stat; mCVCount = 0; // if inheritTransform is on and the curve group is animated, // bake the cv positions in the world space MMatrix exclusiveMatrixInv = mRootDagPath.exclusiveMatrixInverse(&stat); std::size_t numCurves = 1; if (mIsCurveGrp) numCurves = mNurbsCurves.length(); std::vector<Alembic::Util::int32_t> nVertices(numCurves); std::vector<float> points; std::vector<float> width; std::vector<float> knots; std::vector<Alembic::Util::uint8_t> orders(numCurves); MMatrix transformMatrix; bool useConstWidth = false; MFnDependencyNode dep(mRootDagPath.transform()); MPlug constWidthPlug = dep.findPlug("width"); if (!constWidthPlug.isNull()) { useConstWidth = true; width.push_back(constWidthPlug.asFloat()); } for (unsigned int i = 0; i < numCurves; i++) { MFnNurbsCurve curve; if (mIsCurveGrp) { curve.setObject(mNurbsCurves[i]); MMatrix inclusiveMatrix = mNurbsCurves[i].inclusiveMatrix(&stat); transformMatrix = inclusiveMatrix*exclusiveMatrixInv; } else { curve.setObject(mRootDagPath.node()); } if (i == 0) { if (curve.form() == MFnNurbsCurve::kOpen) { samp.setWrap(Alembic::AbcGeom::kNonPeriodic); } else { samp.setWrap(Alembic::AbcGeom::kPeriodic); } if (curve.degree() == 3) { samp.setType(Alembic::AbcGeom::kCubic); } else if (curve.degree() == 1) { samp.setType(Alembic::AbcGeom::kLinear); } else { samp.setType(Alembic::AbcGeom::kVariableOrder); } } else { if (curve.form() == MFnNurbsCurve::kOpen) { samp.setWrap(Alembic::AbcGeom::kNonPeriodic); } if ((samp.getType() == Alembic::AbcGeom::kCubic && curve.degree() != 3) || (samp.getType() == Alembic::AbcGeom::kLinear && curve.degree() != 1)) { samp.setType(Alembic::AbcGeom::kVariableOrder); } } orders[i] = static_cast<Alembic::Util::uint8_t>(curve.degree() + 1); Alembic::Util::int32_t numCVs = curve.numCVs(&stat); MPointArray cvArray; stat = curve.getCVs(cvArray, MSpace::kObject); mCVCount += numCVs; nVertices[i] = numCVs; for (Alembic::Util::int32_t j = 0; j < numCVs; j++) { MPoint transformdPt; if (mIsCurveGrp) { transformdPt = cvArray[j]*transformMatrix; } else { transformdPt = cvArray[j]; } points.push_back(static_cast<float>(transformdPt.x)); points.push_back(static_cast<float>(transformdPt.y)); points.push_back(static_cast<float>(transformdPt.z)); } MDoubleArray knotsArray; curve.getKnots(knotsArray); knots.reserve(knotsArray.length() + 2); // need to add a knot to the start and end (M + 2N + 1) if (knotsArray.length() > 1) { unsigned int knotsLength = knotsArray.length(); if (knotsArray[0] == knotsArray[knotsLength - 1] || knotsArray[0] == knotsArray[1]) { knots.push_back(knotsArray[0]); } else { knots.push_back(2 * knotsArray[0] - knotsArray[1]); } for (unsigned int j = 0; j < knotsLength; ++j) { knots.push_back(knotsArray[j]); } if (knotsArray[0] == knotsArray[knotsLength - 1] || knotsArray[knotsLength - 1] == knotsArray[knotsLength - 2]) { knots.push_back(knotsArray[knotsLength - 1]); } else { knots.push_back(2 * knotsArray[knotsLength - 1] - knotsArray[knotsLength - 2]); } } // width MPlug widthPlug = curve.findPlug("width"); if (!useConstWidth && !widthPlug.isNull()) { MObject widthObj; MStatus status = widthPlug.getValue(widthObj); MFnDoubleArrayData fnDoubleArrayData(widthObj, &status); MDoubleArray doubleArrayData = fnDoubleArrayData.array(); Alembic::Util::int32_t arraySum = doubleArrayData.length(); if (arraySum == numCVs) { for (Alembic::Util::int32_t i = 0; i < arraySum; i++) { width.push_back(static_cast<float>(doubleArrayData[i])); } } else if (status == MS::kSuccess) { MString msg = "Curve "; msg += curve.partialPathName(); msg += " has incorrect size for the width vector."; msg += "\nUsing default constant width of 0.1."; MGlobal::displayWarning(msg); width.clear(); width.push_back(0.1f); useConstWidth = true; } else { width.push_back(widthPlug.asFloat()); useConstWidth = true; } } else if (!useConstWidth) { // pick a default value width.clear(); width.push_back(0.1f); useConstWidth = true; } } Alembic::AbcGeom::GeometryScope scope = Alembic::AbcGeom::kVertexScope; if (useConstWidth) scope = Alembic::AbcGeom::kConstantScope; samp.setCurvesNumVertices(Alembic::Abc::Int32ArraySample(nVertices)); samp.setPositions(Alembic::Abc::V3fArraySample( (const Imath::V3f *)&points.front(), points.size() / 3 )); samp.setWidths(Alembic::AbcGeom::OFloatGeomParam::Sample( Alembic::Abc::FloatArraySample(width), scope) ); if (samp.getType() == Alembic::AbcGeom::kVariableOrder) { samp.setOrders(Alembic::Abc::UcharArraySample(orders)); } if (!knots.empty()) { samp.setKnots(Alembic::Abc::FloatArraySample(knots)); } mSchema.set(samp); }
MStatus AlembicExportCommand::doIt(const MArgList &args) { ESS_PROFILE_SCOPE("AlembicExportCommand::doIt"); MStatus status = MS::kFailure; MTime currentAnimStartTime = MAnimControl::animationStartTime(), currentAnimEndTime = MAnimControl::animationEndTime(), oldCurTime = MAnimControl::currentTime(), curMinTime = MAnimControl::minTime(), curMaxTime = MAnimControl::maxTime(); MArgParser argData(syntax(), args, &status); if (argData.isFlagSet("help")) { // TODO: implement help for this command // MGlobal::displayInfo(util::getHelpText()); return MS::kSuccess; } unsigned int jobCount = argData.numberOfFlagUses("jobArg"); MStringArray jobStrings; if (jobCount == 0) { // TODO: display dialog MGlobal::displayError("[ExocortexAlembic] No jobs specified."); MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no job specified"); return status; } else { // get all of the jobstrings for (unsigned int i = 0; i < jobCount; i++) { MArgList jobArgList; argData.getFlagArgumentList("jobArg", i, jobArgList); jobStrings.append(jobArgList.asString(0)); } } // create a vector to store the jobs std::vector<AlembicWriteJob *> jobPtrs; double minFrame = 1000000.0; double maxFrame = -1000000.0; double maxSteps = 1; double maxSubsteps = 1; // init the curve accumulators AlembicCurveAccumulator::Initialize(); try { // for each job, check the arguments bool failure = false; for (unsigned int i = 0; i < jobStrings.length(); ++i) { double frameIn = 1.0; double frameOut = 1.0; double frameSteps = 1.0; double frameSubSteps = 1.0; MString filename; bool purepointcache = false; bool normals = true; bool uvs = true; bool facesets = true; bool bindpose = true; bool dynamictopology = false; bool globalspace = false; bool withouthierarchy = false; bool transformcache = false; bool useInitShadGrp = false; bool useOgawa = false; // Later, will need to be changed! MStringArray objectStrings; std::vector<std::string> prefixFilters; std::set<std::string> attributes; std::vector<std::string> userPrefixFilters; std::set<std::string> userAttributes; MObjectArray objects; std::string search_str, replace_str; // process all tokens of the job MStringArray tokens; jobStrings[i].split(';', tokens); for (unsigned int j = 0; j < tokens.length(); j++) { MStringArray valuePair; tokens[j].split('=', valuePair); if (valuePair.length() != 2) { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } const MString &lowerValue = valuePair[0].toLowerCase(); if (lowerValue == "in") { frameIn = valuePair[1].asDouble(); } else if (lowerValue == "out") { frameOut = valuePair[1].asDouble(); } else if (lowerValue == "step") { frameSteps = valuePair[1].asDouble(); } else if (lowerValue == "substep") { frameSubSteps = valuePair[1].asDouble(); } else if (lowerValue == "normals") { normals = valuePair[1].asInt() != 0; } else if (lowerValue == "uvs") { uvs = valuePair[1].asInt() != 0; } else if (lowerValue == "facesets") { facesets = valuePair[1].asInt() != 0; } else if (lowerValue == "bindpose") { bindpose = valuePair[1].asInt() != 0; } else if (lowerValue == "purepointcache") { purepointcache = valuePair[1].asInt() != 0; } else if (lowerValue == "dynamictopology") { dynamictopology = valuePair[1].asInt() != 0; } else if (lowerValue == "globalspace") { globalspace = valuePair[1].asInt() != 0; } else if (lowerValue == "withouthierarchy") { withouthierarchy = valuePair[1].asInt() != 0; } else if (lowerValue == "transformcache") { transformcache = valuePair[1].asInt() != 0; } else if (lowerValue == "filename") { filename = valuePair[1]; } else if (lowerValue == "objects") { // try to find each object valuePair[1].split(',', objectStrings); } else if (lowerValue == "useinitshadgrp") { useInitShadGrp = valuePair[1].asInt() != 0; } // search/replace else if (lowerValue == "search") { search_str = valuePair[1].asChar(); } else if (lowerValue == "replace") { replace_str = valuePair[1].asChar(); } else if (lowerValue == "ogawa") { useOgawa = valuePair[1].asInt() != 0; } else if (lowerValue == "attrprefixes") { splitListArg(valuePair[1], prefixFilters); } else if (lowerValue == "attrs") { splitListArg(valuePair[1], attributes); } else if (lowerValue == "userattrprefixes") { splitListArg(valuePair[1], userPrefixFilters); } else if (lowerValue == "userattrs") { splitListArg(valuePair[1], userAttributes); } else { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } } // now check the object strings for (unsigned int k = 0; k < objectStrings.length(); k++) { MSelectionList sl; MString objectString = objectStrings[k]; sl.add(objectString); MDagPath dag; for (unsigned int l = 0; l < sl.length(); l++) { sl.getDagPath(l, dag); MObject objRef = dag.node(); if (objRef.isNull()) { MGlobal::displayWarning("[ExocortexAlembic] Skipping object '" + objectStrings[k] + "', not found."); break; } // get all parents MObjectArray parents; // check if this is a camera bool isCamera = false; for (unsigned int m = 0; m < dag.childCount(); ++m) { MFnDagNode child(dag.child(m)); MFn::Type ctype = child.object().apiType(); if (ctype == MFn::kCamera) { isCamera = true; break; } } if (dag.node().apiType() == MFn::kTransform && !isCamera && !globalspace && !withouthierarchy) { MDagPath ppath = dag; while (!ppath.node().isNull() && ppath.length() > 0 && ppath.isValid()) { parents.append(ppath.node()); if (ppath.pop() != MStatus::kSuccess) { break; } } } else { parents.append(dag.node()); } // push all parents in while (parents.length() > 0) { bool found = false; for (unsigned int m = 0; m < objects.length(); m++) { if (objects[m] == parents[parents.length() - 1]) { found = true; break; } } if (!found) { objects.append(parents[parents.length() - 1]); } parents.remove(parents.length() - 1); } // check all of the shapes below if (!transformcache) { sl.getDagPath(l, dag); for (unsigned int m = 0; m < dag.childCount(); m++) { MFnDagNode child(dag.child(m)); if (child.isIntermediateObject()) { continue; } objects.append(child.object()); } } } } // check if we have incompatible subframes if (maxSubsteps > 1.0 && frameSubSteps > 1.0) { const double part = (frameSubSteps > maxSubsteps) ? (frameSubSteps / maxSubsteps) : (maxSubsteps / frameSubSteps); if (abs(part - floor(part)) > 0.001) { MString frameSubStepsStr, maxSubstepsStr; frameSubStepsStr.set(frameSubSteps); maxSubstepsStr.set(maxSubsteps); MGlobal::displayError( "[ExocortexAlembic] You cannot combine substeps " + frameSubStepsStr + " and " + maxSubstepsStr + " in one export. Aborting."); return MStatus::kInvalidParameter; } } // remember the min and max values for the frames if (frameIn < minFrame) { minFrame = frameIn; } if (frameOut > maxFrame) { maxFrame = frameOut; } if (frameSteps > maxSteps) { maxSteps = frameSteps; } if (frameSteps > 1.0) { frameSubSteps = 1.0; } if (frameSubSteps > maxSubsteps) { maxSubsteps = frameSubSteps; } // check if we have a filename if (filename.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No filename specified."); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no filename " "specified"); return MStatus::kFailure; } // construct the frames MDoubleArray frames; { const double frameIncr = frameSteps / frameSubSteps; for (double frame = frameIn; frame <= frameOut; frame += frameIncr) { frames.append(frame); } } AlembicWriteJob *job = new AlembicWriteJob(filename, objects, frames, useOgawa, prefixFilters, attributes, userPrefixFilters, userAttributes); job->SetOption("exportNormals", normals ? "1" : "0"); job->SetOption("exportUVs", uvs ? "1" : "0"); job->SetOption("exportFaceSets", facesets ? "1" : "0"); job->SetOption("exportInitShadGrp", useInitShadGrp ? "1" : "0"); job->SetOption("exportBindPose", bindpose ? "1" : "0"); job->SetOption("exportPurePointCache", purepointcache ? "1" : "0"); job->SetOption("exportDynamicTopology", dynamictopology ? "1" : "0"); job->SetOption("indexedNormals", "1"); job->SetOption("indexedUVs", "1"); job->SetOption("exportInGlobalSpace", globalspace ? "1" : "0"); job->SetOption("flattenHierarchy", withouthierarchy ? "1" : "0"); job->SetOption("transformCache", transformcache ? "1" : "0"); // check if the search/replace strings are valid! if (search_str.length() ? !replace_str.length() : replace_str.length()) // either search or // replace string is // missing or empty! { ESS_LOG_WARNING( "Missing search or replace parameter. No strings will be " "replaced."); job->replacer = SearchReplace::createReplacer(); } else { job->replacer = SearchReplace::createReplacer(search_str, replace_str); } // check if the job is satifsied if (job->PreProcess() != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job skipped. Not satisfied."); delete (job); failure = true; break; } // push the job to our registry MGlobal::displayInfo("[ExocortexAlembic] Using WriteJob:" + jobStrings[i]); jobPtrs.push_back(job); } if (failure) { for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } return MS::kFailure; } // compute the job count unsigned int jobFrameCount = 0; for (size_t i = 0; i < jobPtrs.size(); i++) jobFrameCount += (unsigned int)jobPtrs[i]->GetNbObjects() * (unsigned int)jobPtrs[i]->GetFrames().size(); // now, let's run through all frames, and process the jobs const double frameRate = MTime(1.0, MTime::kSeconds).as(MTime::uiUnit()); const double incrSteps = maxSteps / maxSubsteps; double nextFrame = minFrame + incrSteps; for (double frame = minFrame; frame <= maxFrame; frame += incrSteps, nextFrame += incrSteps) { MAnimControl::setCurrentTime(MTime(frame / frameRate, MTime::kSeconds)); MAnimControl::setAnimationEndTime( MTime(nextFrame / frameRate, MTime::kSeconds)); MAnimControl::playForward(); // this way, it forces Maya to play exactly // one frame! and particles are updated! AlembicCurveAccumulator::StartRecordingFrame(); for (size_t i = 0; i < jobPtrs.size(); i++) { MStatus status = jobPtrs[i]->Process(frame); if (status != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job aborted :" + jobPtrs[i]->GetFileName()); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); return status; } } AlembicCurveAccumulator::StopRecordingFrame(); } } catch (...) { MGlobal::displayError( "[ExocortexAlembic] Jobs aborted, force closing all archives!"); for (std::vector<AlembicWriteJob *>::iterator beg = jobPtrs.begin(); beg != jobPtrs.end(); ++beg) { (*beg)->forceCloseArchive(); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); MPxCommand::setResult("Error caught in AlembicExportCommand::doIt"); status = MS::kFailure; } MAnimControl::stop(); AlembicCurveAccumulator::Destroy(); // restore the animation start/end time and the current time! restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); // delete all jobs for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } // remove all known archives deleteAllArchives(); return status; }
IECore::DataPtr convert( const MCommandResult &result ) { MStatus s; switch (result.resultType()) { case MCommandResult::kInvalid: { // No result return 0; } case MCommandResult::kInt: { int i; s = result.getResult(i); assert(s); IECore::IntDataPtr data = new IECore::IntData(); data->writable() = i; return data; } case MCommandResult::kIntArray: { MIntArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::IntVectorDataPtr data = new IECore::IntVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { (data->writable())[i] = v[i]; } return data; } case MCommandResult::kDouble: { double d; s = result.getResult(d); assert(s); IECore::FloatDataPtr data = new IECore::FloatData(); data->writable() = static_cast<float>(d); return data; } case MCommandResult::kDoubleArray: { MDoubleArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::DoubleVectorDataPtr data = new IECore::DoubleVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = v[i]; } return data; } case MCommandResult::kString: { MString str; s = result.getResult(str); assert(s); IECore::StringDataPtr data = new IECore::StringData(); data->writable() = std::string(str.asChar()); return data; } case MCommandResult::kStringArray: { MStringArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::StringVectorDataPtr data = new IECore::StringVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = std::string(v[i].asChar()); } return data; } case MCommandResult::kVector: { MVector v; s = result.getResult(v); assert(s); IECore::V3fDataPtr data = new IECore::V3fData(); data->writable() = Imath::V3f(v.x, v.y, v.z); return data; } case MCommandResult::kVectorArray: { MVectorArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::V3fVectorDataPtr data = new IECore::V3fVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = Imath::V3f(v[i].x, v[i].y, v[i].z); } return data; } case MCommandResult::kMatrix: { MDoubleArray v; int numRows, numColumns; s = result.getResult(v, numRows, numColumns); assert(s); if (numRows > 4 || numColumns > 4) { throw IECoreMaya::StatusException( MS::kFailure ); } IECore::M44fDataPtr data = new IECore::M44fData(); for (int i = 0; i < numColumns; i++) { for (int j = 0; j < numRows; j++) { (data->writable())[i][j] = v[i*numRows+j]; } } return data; } case MCommandResult::kMatrixArray: { return 0; } default: assert( false ); return 0; } }
MObject createSubD(double iFrame, SubDAndColors & iNode, MObject & iParent) { Alembic::AbcGeom::ISubDSchema schema = iNode.mMesh.getSchema(); Alembic::AbcCoreAbstract::index_t index, ceilIndex; getWeightAndIndex(iFrame, schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex); Alembic::AbcGeom::ISubDSchema::Sample samp; schema.get(samp, Alembic::Abc::ISampleSelector(index)); MString name(iNode.mMesh.getName().c_str()); MFnMesh fnMesh; MFloatPointArray pointArray; Alembic::Abc::P3fArraySamplePtr emptyPtr; fillPoints(pointArray, samp.getPositions(), emptyPtr, 0.0); fillTopology(fnMesh, iParent, pointArray, samp.getFaceIndices(), samp.getFaceCounts()); fnMesh.setName(iNode.mMesh.getName().c_str()); setInitialShadingGroup(fnMesh.partialPathName()); MObject obj = fnMesh.object(); setUVs(iFrame, fnMesh, schema.getUVsParam()); setColors(iFrame, fnMesh, iNode.mC3s, iNode.mC4s, true); // add the mFn-specific attributes to fnMesh node MFnNumericAttribute numAttr; MString attrName("SubDivisionMesh"); MObject attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, 1); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); if (samp.getInterpolateBoundary() > 0) { attrName = MString("interpolateBoundary"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getInterpolateBoundary()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } if (samp.getFaceVaryingInterpolateBoundary() > 0) { attrName = MString("faceVaryingInterpolateBoundary"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getFaceVaryingInterpolateBoundary()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } if (samp.getFaceVaryingPropagateCorners() > 0) { attrName = MString("faceVaryingPropagateCorners"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getFaceVaryingPropagateCorners()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } #if MAYA_API_VERSION >= 201100 Alembic::Abc::Int32ArraySamplePtr holes = samp.getHoles(); if (holes && !holes->size() == 0) { unsigned int numHoles = (unsigned int)holes->size(); MUintArray holeData(numHoles); for (unsigned int i = 0; i < numHoles; ++i) { holeData[i] = (*holes)[i]; } if (fnMesh.setInvisibleFaces(holeData) != MS::kSuccess) { MString warn = "Failed to set holes on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } #endif Alembic::Abc::FloatArraySamplePtr creases = samp.getCreaseSharpnesses(); if (creases && !creases->size() == 0) { Alembic::Abc::Int32ArraySamplePtr indices = samp.getCreaseIndices(); Alembic::Abc::Int32ArraySamplePtr lengths = samp.getCreaseLengths(); std::size_t numLengths = lengths->size(); MUintArray edgeIds; MDoubleArray creaseData; std::size_t curIndex = 0; // curIndex incremented here to move on to the next crease length for (std::size_t i = 0; i < numLengths; ++i, ++curIndex) { std::size_t len = (*lengths)[i] - 1; float creaseSharpness = (*creases)[i]; // curIndex incremented here to go between all the edges that make // up a given length for (std::size_t j = 0; j < len; ++j, ++curIndex) { Alembic::Util::int32_t vertA = (*indices)[curIndex]; Alembic::Util::int32_t vertB = (*indices)[curIndex+1]; MItMeshVertex itv(obj); int prev; itv.setIndex(vertA, prev); MIntArray edges; itv.getConnectedEdges(edges); std::size_t numEdges = edges.length(); for (unsigned int k = 0; k < numEdges; ++k) { int oppVert = -1; itv.getOppositeVertex(oppVert, edges[k]); if (oppVert == vertB) { creaseData.append(creaseSharpness); edgeIds.append(edges[k]); break; } } } } if (fnMesh.setCreaseEdges(edgeIds, creaseData) != MS::kSuccess) { MString warn = "Failed to set creases on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } Alembic::Abc::FloatArraySamplePtr corners = samp.getCornerSharpnesses(); if (corners && !corners->size() == 0) { Alembic::Abc::Int32ArraySamplePtr cornerVerts = samp.getCornerIndices(); unsigned int numCorners = static_cast<unsigned int>(corners->size()); MUintArray vertIds(numCorners); MDoubleArray cornerData(numCorners); for (unsigned int i = 0; i < numCorners; ++i) { cornerData[i] = (*corners)[i]; vertIds[i] = (*cornerVerts)[i]; } if (fnMesh.setCreaseVertices(vertIds, cornerData) != MS::kSuccess) { MString warn = "Failed to set corners on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } return obj; }