March 2019: ewertb.soundlinker.com is getting relocated to ewertb.mayasound.com, please update your bookmarks.

Maya API How-To #10

Back · Previous · Next Maya

How do I set and assign the UVs on a UVSet other than "map1" - MFnMesh::setUVs and MFnMesh::assignUVs work sporadically at best?

Discrepency with MFnMesh::setUVs()

Here's the scenario: You're creating a new mesh which needs two UVSets. The first set of UVs uses the default "map1" UVSet, for the other you create a new UVSet called "other". Sounds simple enough:

meshObj = fnMesh.create( 4, 2, vertexArray, polygonCounts, polygonConnects );

MDagPath::getAPathTo( meshObj, meshDag );
meshDag.extendToShape();

// Array to hold our UVs
MFloatArray         aUVu;
MFloatArray         aUVv;

// Array to hold UVSet names
MStringArray        UVSetNames;
UVSetNames.append( "map1" );
UVSetNames.append( "other" );

// Create the "other" UVSet.
// You MUST do this first!  If called after setting UVs
// the UVs mysteriously disappear!
fnMesh.createUVSet( UVSetNames[1] );

// Add 4 UVs to "map1" UV Set

aUVu.append( 0.0 );
aUVv.append( 0.0 );

aUVu.append( 1.0 );
aUVv.append( 0.0 );

aUVu.append( 0.0 );
aUVv.append( 1.0 );

aUVu.append( 1.0 );
aUVv.append( 1.0 );

status = fnMesh.setUVs( aUVu, aUVv, &UVSetNames[0] );
if ( status == MS::kSuccess )
  cout << "fnMesh::setUVs successful." << endl;

// Add 3 UVs to "other" UVSet

aUVu.clear();
aUVv.clear();

aUVu.append( 0.5F );
aUVu.append( 0.25F );

aUVv.append( 0.5F );
aUVv.append( 0.5F );

aUVu.append( 1.0F );
aUVu.append( 0.0F );

status = fnMesh.setUVs( aUVu, aUVv, &UVSetNames[1] );
if ( status == MS::kSuccess )
  cout << "fnMesh::setUVs successful." << endl;

// Hmm.. that last setUVs() didn't seem to work?
// Let's see what's going on...

int                 numUVs_map1;
int                 numUVs_other;

numUVs_map1  = fnMesh.numUVs( UVSetNames[0] );
// Result: 4 //

numUVs_other = fnMesh.numUVs( UVSetNames[1] );
// Result: 0 //

So why is the "other" UVSet empty?

I have determined (through much trial and error) that to successfully set the UVs in a UVSet that is not the default UVSet, you must be defining at least the same number of UVs as exists in the default UVSet. In other words, if the new UVSet has fewer UVs than "map1" you must inflate your UV array to be the same size as "map1".

Let's pick up from the "other" UVSet in the example above:

// Add 3 UVs to "other" UVSet
aUVu.clear();
aUVv.clear();

aUVu.append( 0.5F );
aUVv.append( 0.25F );

aUVu.append( 0.5F );
aUVv.append( 0.5F );

aUVu.append( 1.0F );
aUVv.append( 0.0F );

// And inflate this array so it has the same number of members as "map1"

aUVu.append( 0.0F );
aUVv.append( 0.0F );

status = fnMesh.setUVs( aUVu, aUVv, &UVSetNames[1] );
if ( status == MS::kSuccess )
  cout << "fnMesh::setUVs successful." << endl;

// Now let's see how we stand.

int                 numUVs_map1;
int                 numUVs_other;

numUVs_map1  = fnMesh.numUVs( UVSetNames[0] );
// Result: 4 //

numUVs_other = fnMesh.numUVs( UVSetNames[1] );
// Result: 4 //

Discrepency with MFnMesh::assignUVs

In a nutshell MFnMesh::assignUVs (note the plural form) does not seem to work with UVSets other than the default "map1". I have found that I must use MFnMesh::assignUV (in other words, assigning them one-by-one) to assign UVs in this case.

MIntArray                   aUVCounts;
MIntArray                   aUVids;

// Mapping UVs to two triangles (i.e. 3 UVs per face)
aUVCounts.append( 3 );
aUVCounts.append( 3 );

// The UV Map IDs
aUVids.append( 0 );
aUVids.append( 1 );
aUVids.append( 2 );
aUVids.append( 0 );
aUVids.append( 2 );
aUVids.append( 3 );

// You can use the bulk-mode MFnMesh::assignUVs() for the 
// default "map1" UVSet ONLY!

status = fnMesh.assignUVs( aUVCounts, aUVids, &UVSetNames[0] );
if ( status == MS::kSuccess )
  cout << "fnMesh::assignUVs successful." << endl;

// For all other UVSets, you MUST assign the UVs individually 
// per vertex, per face.

// (You can use this method for the default "map1" set, too.)

unsigned                    i, p, v;
p = 0;

for ( i = 0; i < aUVids.length(); i++ )
{
  v = i % 3;  // derive face-relative vertex index

  status = fnMesh.assignUV( p, v, aUVids[i], &UVSetNames[1] );
  if ( status != MS::kSuccess )
    cerr << " ! assignUV FAILED ! " << endl;

  if ( v == 2 ) p++;  // increment poly index if last vertex
}

Thursday, April 05, 2001