// Copyright (C) 1997-2004 Alias Systems Corp. // // The information in this file is provided for the exclusive use of the // licensees of Alias. Such users have the right to use, modify, // and incorporate this code into other products for purposes authorized // by the Alias license agreement, without fee. // // ALIAS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, // INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO // EVENT SHALL ALIAS BE LIABLE FOR ANY SPECIAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. // // Alias Script File // MODIFY THIS AT YOUR OWN RISK // // Creation Date: 2005 // // Description: reverse selected toon object surfaces // proc float triangle_Area( float $v1[], float $v2[], float $v3[] ) { float $c1[] = crossProduct( $v1, $v2, 0, 0 ); float $c2[] = crossProduct( $v2, $v3, 0, 0 ); float $c3[] = crossProduct( $v3, $v1, 0, 0 ); float $vec[3]; $vec[0] = $c1[0] + $c2[0] + $c3[0]; $vec[1] = $c1[1] + $c2[1] + $c3[1]; $vec[2] = $c1[2] + $c2[2] + $c3[2]; float $area = sqrt( $vec[0]*$vec[0] + $vec[1]*$vec[1] + $vec[2] * $vec[2])/2.0; return( $area ); } proc float quad_Area( float $v1[], float $v2[], float $v3[], float $v4[] ) { float $a1 = triangle_Area( $v1,$v2,$v3 ); // float $a2 = triangle_Area( $v3,$v4,$v1 ); float $a2 = triangle_Area( $v3,$v4,$v2 ); return( $a1 + $a2 ); } proc float computeMeshVolume(string $pobj) { // This is from computePolysetVolume.mel. // It differs in that it does not do a freeze transforms and // is designed to work on individual meshes, rather than collections. int $i; string $normalInfo[]; string $curFace; string $ni[]; string $verts[]; float $nz; float $v1[3], $v2[3], $v3[3], $v4[3]; float $A; int $numFaces[], $nVerts; float $totalVolume = 0; $numFaces = `polyEvaluate -f $pobj`; for( $i = 0; $i < $numFaces[0]; $i++ ){ $curFace = ($pobj + ".f[" + $i + "]"); $normalInfo = `polyInfo -faceNormals $curFace`; tokenize $normalInfo[0] $ni; $nz = $ni[4]; $verts = `listAttr $curFace`; $nVerts = size( $verts )/4; float $val; if( $nVerts == 3 ){ $v1 = pointPosition( $pobj + "." + $verts[0] ); $v2 = pointPosition( $pobj + "." + $verts[4] ); $v3 = pointPosition( $pobj + "." + $verts[8] ); $A = triangle_Area($v1,$v2,$v3); $val = $A * $nz * ( $v1[2] + $v2[2] + $v3[2] )/3.0; } else if( $nVerts == 4 ){ $v1 = pointPosition( $pobj + "." + $verts[0] ); $v2 = pointPosition( $pobj + "." + $verts[4] ); $v3 = pointPosition( $pobj + "." + $verts[8] ); $v4 = pointPosition( $pobj + "." + $verts[12] ); $A = quad_Area($v1,$v2,$v3, $v4); $val = $A * $nz * ( $v1[2] + $v2[2] + $v3[2] + $v4[2])/4.0; } $totalVolume += $val; } return $totalVolume; } proc string getTessMesh( string $obj ) { string $cons[]; string $nodeType = `nodeType $obj`; if( $nodeType == "nurbsSurface" ){ $cons = `listConnections ($obj + ".worldSpace[0]")`; } else if ($nodeType == "subdiv" ){ $cons = `listConnections ($obj + ".worldSubdiv[0]")`; } string $con; for( $con in $cons ){ string $type = `nodeType $con`; string $tcons[]; if( $type == "nurbsTessellate" ){ $tcons = `listConnections ($con + ".outputPolygon")`; } else if($type == "subDivToPoly1"){ $tcons = `listConnections ($con + ".outMesh")`; } if( size( $tcons ) > 0 ){ return $tcons[0]; } } return ""; } global proc reverseToonObjects( int $autoReverse ) { string $sel[] = `ls -sl`; string $objs[] = `ls -sl -dag -ni -type mesh -type nurbsSurface -type subdiv`; int $numObjs=size($objs); int $i, $j; string $tmpMesh, $tmpMeshParent; if( $autoReverse ){ $tmpMesh = `createNode "mesh"`; string $parents[] = listTransforms( $tmpMesh ); $tmpMeshParent = $parents[0]; } for( $i = 0; $i < $numObjs; $i++ ){ string $obj = $objs[$i]; string $nodeType = nodeType( $obj ); string $mesh = ""; if( $nodeType == "mesh" ){ $mesh = $obj; } else { $mesh = getTessMesh( $obj ); } if( $mesh == "" ){ continue; } for( $j = 0; $j < $i; $j++ ){ if( $mesh == $objs[$j] ){ continue; // don't compute the same obj twice } } if( $autoReverse ){ connectAttr -f ($mesh+".outMesh") ($tmpMesh + ".inMesh"); float $min[] = getAttr( $tmpMesh + ".boundingBoxMin" ); float $max[] = getAttr( $tmpMesh + ".boundingBoxMax" ); float $boxVol = ($max[0] - $min[0]) * ($max[1] - $min[1]) * ($max[2] - $min[2]); float $volumeThreshold = $boxVol * 0.0005; // If the computed volume is negative then the object is // predominantly concave. Closed objects MUST be convex, so // this should work well if the individual meshes are truly closed. // The problem is when a mesh is part of a closed object, but is // open, for example when a box is made with 6 individual flat meshes. float $objVol = computeMeshVolume($tmpMesh); disconnectAttr ($mesh+".outMesh") ($tmpMesh + ".inMesh"); if( $objVol < -$volumeThreshold ){ print( "Reversing normals for " +$mesh ); polyNormal -normalMode 0 -ch 0 $mesh; } } else { polyNormal -normalMode 0 -ch 0 $mesh; } } if( $autoReverse ){ delete $tmpMeshParent; select -r $sel; } }