一半君的总结纸

听话只听一半君

#05 如何得到多边形(polygon)的面(face)或点(vertex)的法线向量?

Querying Per-Vertex Per-Face Normals

polyNormalPerVertex” 命令可以查询点的法线:

polyNormalPerVertex -q -xyz;
// Result: 0 1 0 0 0 1 -1 0 0 //

上面的结果表示该vertex被3个face共享,该vertex在这3个face上的normal分别是:

{ 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { -1.0, 0.0, 0.0 }

如果需要的话,你可以把这3个normal平均一下得到 shared vertex normal.

但是上面的结果并不能告诉你哪个normal对应哪个face . 如果想知道对应关系,必须查询 .vtxFace components.

// Convert a .vtx component to .vtxFace components.
string $plcc[] = `polyListComponentConversion -fv -tvf pCube1.vtx[2]`;

// Expand the list to avoid Maya's component compression
$plcc = `filterExpand -sm 70 -ex true $plcc`;

for ( $vtxFace in $plcc )
{
  // Get the per-vertex per-face normal for this component
  float $normal[3] = `polyNormalPerVertex -q -xyz $vtxFace`;
  print(  $vtxFace + ": { " + $normal[0] + ", " + $normal[1] + ", " + $normal[2] + " }\n" );
}

运行结果:

pCube1.vtxFace[2][0]: { 0, 0, 1 }
pCube1.vtxFace[2][1]: { 0, 1, 0 }
pCube1.vtxFace[2][5]: { -1, 0, 0 }

Using ‘polyInfo’

下面的方法是由 Joseph A. Hansen (Beyond Games)提供的.

polyInfo 命令有个 ‘-faceNormal’ flag 可以得到face的normal vector. 注意事项:

  1. 返回的结果是个复杂的字符串 (annotated string) (其实是个字符串数组);
  2. 返回的 normal 不是 normalized的 (不是unit vector).

为了解决上面两个问题我们需要自己写一个辅助的 procedure.

polyInfo -fn pSphere1.f[7];
// Result: FACE_NORMAL      7: -0.090404 -0.135299 0.017982 //

polyInfo -fn pCube1.f[0];
// Result: FACE_NORMAL      0: 0.000000 0.000000 2.000000 //

下面是我们的辅助脚本:

proc vector translatePolyInfoNormal( string $pin )
{
  vector $normal;
  float $x;
  float $y;
  float $z;

  string $tokens[];
  int $numTokens = `tokenize $pin " " $tokens`;

  // Make sure we're looking at polyInfo data:
  if ( ( $numTokens > 3 ) && ( $tokens[0] == "FACE_NORMAL" ) )
  {
    // Maya performs data-type conversion here.
    $x = ($tokens[$numTokens-3]);
    $y = ($tokens[$numTokens-2]);
    $z = ($tokens[$numTokens-1]);

    $normal = << $x, $y, $z >>;

    // Normalize it.
    $normal = `unit $normal`;
  }

  // Return it.
  return $normal;
}

实际运行效果:

string $sphereInfo[] = `polyInfo -fn pSphere1.f[7]`;
// Result: FACE_NORMAL      7: -0.090404 -0.135299 0.017982

vector $sphereNormal = translatePolyInfoNormal( $sphereInfo[0] );
// Result: <<-0.552209, -0.826438, 0.109838>>  //

string $cubeInfo[] = `polyInfo -fn pCube1.f[7]`;
// Result: FACE_NORMAL      5: -2.000000 0.000000 0.000000

vector $cubeNormal = translatePolyInfoNormal( $cubeInfo[0] );
// Result: <<-1, 0, 0>>  //

使用叉乘

// Pick a face, any face
string $node = "polySurface1";
int $face = 0;

// Get vertex list for face
int $vertices[] = facetVertices( $node + ".f[" + $face + "]" );

// Get coordinates for each of the three vertices
vector $vector[3];
for ( $p = 0; $p < 3; $p++ )
{
  float $coord[3];

  $command = "xform -q -ws -t " + $node + ".vtx[" + $vertices[$p] + "]";
  $coord = `eval $command`;
  $vector[$p] = << $coord[0], $coord[1], $coord[2] >>;
}

vector $v0, $v1, $v2;
// Reassign to non-array variables to allow access
// to vector components (e.g. vector.x)
$v0 = $vector[0];
$v1 = $vector[1];
$v2 = $vector[2];

// Get two vectors for surface definition, from the 3 verts.
vector $def[2];
$def[0] =
  <<     $v0.x - $v2.x,     $v0.y - $v2.y,     $v0.z - $v2.z   >>;

$def[1] =
  <<     $v1.x - $v2.x,     $v1.y - $v2.y,     $v1.z - $v2.z   >>;

// Get normal
vector $normal;

// The cross product provides the normal for the surface defined from these two vectors
$normal = `cross $def[0] $def[1]`;

上面的脚本只考虑了指定的face的前3个vertex. 如果你的face是个平面, 那没有问题. 但是如果你的面上有超过3个vertex并且不是平的,那上面计算出来的结果可能就不对了.

需要注意的是surface normal的方向是和edge vectors的方向相关的. 所以你得确保你查询vertex的时候,是按render order来的,这样才能计算出你想要的结果(surface normal的方向).

Querying The ‘mesh’ Node

我想试试看(乱搞)直接查询 DG节点上的’vertexNormal’ 属性看能不能直接拿到vertex normal:

  getAttr pSphere1.vn[0].vfnl[0].fnxy;
  // Result: 100000002004087730000 100000002004087730000 100000002004087730000 //

根据结果的数值来看,显然这样不可以.

References for Cross Product

Vectors and Vector Arithmetic

Eric Weisstein’s World of Mathematics – Cross Product

Acknowledgement

Joseph A. Hansen, Tools Manager, Beyond Games

Related How-To’s

22 February 2003

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 博主赞过: