一半君的总结纸

听话只听一半君

#55 How can I get a list of all vertex or edge components from a polymesh in proper counter-clockwise or “render” order?

The image at bottom depicts a selected polymesh face component. If we were to query this face using the API we would learn that Maya constructs this face in the vertex order: 11, 4, 12, 9. From this, logic will yield an “edge construction order” of: 13, 14, 18, 17.

edges

Deriving Vertex Order From A Face

polyInfo

The “polyInfo” command, when specified with its `−faceToVertex` flag, returns a string result which lists the vertex order for a face in the proper construction order. While tokenizing a string result is not an ideal way to query numeric results, it does get the job done, and is less work than futzing with vertex-face components (as described below).

string $ftv[] = `polyInfo -faceToVertex pPlane1.f[5]`;
// Result: FACE      5:     11      4     12      9

To extract the values in order to use them, use the tokenize command on the string. In the example below the string is split by stripping its space (” “), colon (“:”), and carriage-return/newline (“\n\r”) characters. This results in six tokens – the first of which is the string “FACE”, the second being the index of the face, and the remaining four the indices for the vertices.

string $tokens[];
tokenize $ftv[0] " :\n\r" $tokens;
// Result: 6 //

int $vertexOrder[];
clear $vertexOrder;
int $t;

for ( $t = 2; $t < `size $tokens`; $t++ )
{
  $vertexOrder[`size $vertexOrder`] = $tokens[$t];
};

print $vertexOrder;
// Prints: 11 4 12 9 //

polyListComponentConversion

You can use the polyListComponentConversion command in a round-about fashion to derive the counter-clockwise order (or “render order”, or “construction order”) for the edges and vertices that comprise a polymesh face component.

Joey Ponthieux (Video Applications Group, NASA Langley Research Center) struck upon using polyListComponentConversion to query “vertexFace” components and, through a series of conversions, this will yield a list of components in the desired order.

// This face
ls -sl;
// Result: pPlane1.f[5] //

// Use polyListComponentConversion to get .vtxFace components
string $vtxFace[] = `polyListComponentConversion -fromFace
                                                 -toVertexFace pPlane1.f[5]`;
// Result: pPlane1.vtxFace[11][5]
           pPlane1.vtxFace[4][5]
           pPlane1.vtxFace[12][5]
           pPlane1.vtxFace[9][5] //

You can see the pattern in the order emerging. Now we just need to get this represented in a more direct form. Use the polyListComponentConversion again to convert each of these back to a vertex component. You must do this conversion one component at a time; a conversion en masse will revert to numerical order, defeating the intentions of this exercise.

// An array to store our result
string $vertexOrder[];

for ( $vf in $vtxFace )
{
  // Get vertex for this vtxFace
  string $vertex[] = `polyListComponentConversion -fromVertexFace -toVertex $vf`;

  // And append to our result
  $vertexOrder[ size($vertexOrder) ] = $vertex[0];
}

print $vertexOrder;
// Result: pPlane1.vtx[11]
           pPlane1.vtx[4]
           pPlane1.vtx[12]
           pPlane1.vtx[9] //

Expanding Results In “Range” Form
edges2
The polyListComponentConversion command may return its results in compressed “range” form:

ls -sl;
// Result: pPlane2.f[4] //

string $vtxFace[] = `polyListComponentConversion -fromFace
                                                 -toVertexFace pPlane2.f[4]`;
// Result: pPlane2.vtxFace[5:6][4]
           pPlane2.vtxFace[10][4]
           pPlane2.vtxFace[9][4] //

Therefore, it’s likely best to throw a filterExpand in the mix:

// Use filterExpand to individualize each .vtxFace component in $vtxFace
$vtxFace = `filterExpand -sm 70 -expand true $vtxFace`;
// Result: pPlane2.vtxFace[5][4] pPlane2.vtxFace[6][4]
           pPlane2.vtxFace[10][4] pPlane2.vtxFace[9][4] //

for ( $vf in $vtxFace )
{
  // Get vertex for this vtxFace
  string $vertex[] = `polyListComponentConversion -fromVertexFace -toVertex $vf`;

  // And append to our result
  $vertexOrder[ size($vertexOrder) ] = $vertex[0];
}

print $vertexOrder;

// Result: pPlane2.vtx[5]
           pPlane2.vtx[6]
           pPlane2.vtx[10]
           pPlane2.vtx[9] //

Deriving Edge Order From A Face

polyInfo

The “polyInfo” command, when specified with its `−faceToEdge` flag, returns a string result which lists the edge order for a face in the proper construction order. While tokenizing a string result is not an ideal way to query numeric results, it does get the job done, and is less work than futzing with vertex-face components (as described below).

string $fte[] = `polyInfo -faceToEdge pPlane1.f[5]`;
// Result: FACE      5:     13     14     18     17

To extract the values in order to use them, use the tokenize command on the string. In the example below the string is split by stripping its space (” “), colon (“:”), and carriage-return/newline (“\n\r”) characters. This results in six tokens – the first of which is the string “FACE”, the second being the index of the face, and the remaining four the indices for the vertices

string $tokens[];
tokenize $fte[0] " :\n\r" $tokens;
// Result: 6 //

int $edgeOrder[];
clear $edgeOrder;
int $t;

for ( $t = 2; $t < `size $tokens`; $t++ )
{
  $edgeOrder[`size $edgeOrder`] = $tokens[$t];
};

print $edgeOrder;
// Prints: 13 14 18 17 //

polyListComponentConversion

Using the $vtxFace array obtained in the above example, the edge construction order may be obtained from the polyListComponentConversion command by specifying its `−toEdge` flag.

// An array to store our result
string $edgeOrder[];

for ( $vf in $vtxFace )
{
  // Get edge for this vtxFace
  string $edge[] = `polyListComponentConversion -fromVertexFace -toEdge $vf`;

  // And append to our result
  $edgeOrder[ size($edgeOrder) ] = $edge[0];
}

print $edgeOrder;

// Result: pPlane2.e[9]
           pPlane2.e[12]
           pPlane2.e[18]
           pPlane2.e[10] //

Note: Joey Ponthieux explains that this conversion to edge components appears to only be reliable using Maya v3.0. In Maya 2.5 the returned edge does not necessarily correspond to the same construction order of the input vertex. In this case it is necessary to specify successive vertices and use the ‘−internal’ flag to extract the common edge.

// Modified loop to accomodate Maya v2.5
// $vertexOrder derived in method described above
for ( $v = 0; $v < size($vertexOrder); $v++ )
{
  int $nextVtx = ( $v < ( size($vertexOrder) - 1 ) ? $v + 1 : 0 );

  // Use two successive vertices to derive internal edge
  string $edge[] = `polyListComponentConversion -fromVertex -toEdge
                    -internal $vertexOrder[$v] $vertexOrder[$nextVtx]`;

  $edgeOrder[ size($edgeOrder) ] = $edge[0];
}

print $edgeOrder;

// Result: pPlane2.e[9]
           pPlane2.e[12]
           pPlane2.e[18]
           pPlane2.e[10] //

Deriving Vertex Order From An Edge

A polymesh face

The “vertex order” implied here is that which corresponds to the winding order for the face. That is, such that the indices for the vertices are ordered as required to reconstruct the face in a manner preserving its face normal.

It is possible (and likely) that an edge will be shared between two adjacent faces. Even though both faces are constructed in counter-clockwise order, their adjacent nature means that the vertex ordering for a shared edge is dependent upon for which face you are describing it. Given an edge shared by face ‘A’ and face ‘B’, the vertex order of the edge on face ‘A’ is exactly opposite to the vertex order of the edge on face ‘B’. Therefore, for meaningful results, it is necessary to specify both an edge and a face to retrieve the vertex order for the edge.

Again referring to geometry at right, the winding order for the edges is 11, 4, 12, 9. Specifying their vertex indices in similar fashion yields an ordering, per edge, of: { 11,4 }, { 4,12 }, { 12,9 }, { 9,11 }.

Using a combination of the techniques described above it is a short stone’s throw to expand the functionality of this process to derive the vertex order from an edge. The steps are as follows:

Retrieve the ordered vertices for the specified face, as described in “Deriving Vertex Order From A Face”.

Starting at the first vertex, create pairs to determine the “internal” edge that each generates, as described in “Deriving Edge Order From A Face”.

Check if the derived edge matches the specified edge. If so, then the current vertex pair, in order, describes the vertex order of the specified edge within the specified face.

If all vertex pairs are exhausted without finding a matching edge, then the specified edge is not a component of the specified face and the result is an empty set.

polyInfo

Left as an exercise for the reader. Ain’t I a stinker?

polyListComponentConversion

The following MEL procedure takes as arguments an edge component and related face component, and returns a string array containing the ordered vertex pair for the edge.

global proc string[] edgeVertexOrder( string $inputEdge, string $inputFace )
{
  string $edgeVertexOrder[];

  string $vertexOrder[];

  // Note: polyListComponentConversion will return the components relative
  //       to the TRANSFORM node.  You may want to add an assertion/conversion
  //       for the input arguments so they are relative to a transform.
  //       If the input arguments are shape-relative then this procedure will FAIL.

  // Get vertex order of face
  string $vtxFace[] = `polyListComponentConversion -fromFace -toVertexFace $inputFace`;

  // Use filterExpand to individualize each .vtxFace component in $vtxFace
  $vtxFace = `filterExpand -sm 70 -expand true $vtxFace`;

  for ( $vf in $vtxFace )
  {
    // Get vertex for this vtxFace
    string $vertex[] = `polyListComponentConversion -fromVertexFace -toVertex $vf`;

    // And append to our result
    $vertexOrder[ size($vertexOrder) ] = $vertex[0];
  }

  // Now, check each vertex pair to see if it matches the specified edge
  for ( $v = 0; $v < size($vertexOrder); $v++ )
  {
    int $nextVtx = ( $v < ( size($vertexOrder) - 1 ) ? $v + 1 : 0 );

    // Use two successive vertices to derive internal edge

    string $edge[] = `polyListComponentConversion -fromVertex -toEdge
                    -internal $vertexOrder[$v] $vertexOrder[$nextVtx]`;

    // Does this match?
    if ( $edge[0] == $inputEdge )
    {
      $edgeVertexOrder[0] = $vertexOrder[$v];
      $edgeVertexOrder[1] = $vertexOrder[$nextVtx];

      // As soon as a match is found we can stop looking.
      break;
    }
  }

  // Warn if $inputEdge not found in $inputFace
  if ( size( $edgeVertexOrder ) == 0 )
    warning ( $inputEdge + " is not part of " + $inputFace );

  return $edgeVertexOrder;
}

An example run:

edgeVertexOrder pPlane1.e[18] pPlane1.f[6];
// Result: pPlane1.vtx[9] pPlane1.vtx[12] //

// This demonstrates that the adjacent face (.f[277]) evaluates its
// vertex order in the opposite direction, as described in the text.
//
edgeVertexOrder pPlane1.e[18] pPlane1.f[5];
// Result: pPlane1.vtx[12] pPlane1.vtx[9] //

edgeVertexOrder pPlane1.e[18] pPlane1.f[7];
// Warning: pPlane1.e[18] is not part of pPlane1.f[7] //

Acknowledgements

  • Joey Ponthieux, Video Applications Group, NASA Langley Research Center, for demonstrating how to use “polyListComponentConversion”
  • David Biggs, for prompting me to update this How-To with “polyInfo”

Related How-To’s

18 Sep 2004

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: