Feedback

What's your question?

By: Asked

getting the volume of an arbitrary closed mesh

Hopefully using Mel in Maya, I'd like to find the volume of a closed polygonal mesh. Anyone know how to do this, or if it's even possible?

Thanks,

Matt

Add comment viewed 459 times Latest activity 7 months ago

or Cancel

3 answers

  • 1

hixster [ Editor ]

Hi Matt,

The MEL command :

 computePolysetVolume

Is what you want.

Matt

NN comments
julian
-

Thats cool. I wonder how the algorithm works. I couldn’t make head nor tail of the description in the docs.

hixster
-

Yeah, not sure how it works, I used to use it a lot when we started writing a muscle system. It’s useful to know what the volumes of your muscles are in the bind pose/T Pose , then you can check how well those volumes are behaving in compress and expanded states.

or Cancel
  • 0

julian [ Admin ]

I found some more info on this.

If you take every triangle and project it to the XY plane you get a prism. If the triangle's normal is facing away from the XY plane then the volume in the prism is positive, otherwise its negative. So you can just add up all those prism volumes to get the volume of the mesh. MEL below - although computePolysetVolume() makes it redundant ;)

global proc vector faceNormal(string $face ) {
    string $res[] = `polyInfo -fn $face`;
    string $buff[];
    tokenize($res[0] ,":" , $buff);
    tokenize($buff[1] ," " , $buff);
    return unit( << float($buff[0]) , float($buff[1]) ,float($buff[2]) >>);
}

global proc float xyArea(vector $v1,vector $v2,vector $v3 ) {
    return abs((($v1.x)*(($v3.y)-($v2.y)))+(($v2.x)*(($v1.y)-($v3.y)))+(($v3.x)*(($v2.y)-($v1.y)))) *0.5;
}


global proc float prismVolume(string $triangle) {
    string $triVerts[] = `polyListComponentConversion -tv $triangle`;
    $triVerts = `ls -flatten $triVerts`;

    if (`size $triVerts` != 3) error($triangle +" is not a triangle");

    vector $v1 = `pointPosition -w $triVerts[0]`; 
    vector $v2 = `pointPosition -w $triVerts[1]`; 
    vector $v3 = `pointPosition -w $triVerts[2]`; 

    vector $normal = faceNormal( $triangle );
    float $area = xyArea( $v1, $v2, $v3 );
    float $pVolume = ((($v1.z)+($v2.z)+($v3.z))/3.0)*$area ;
    if (($normal.z) < 0) $pVolume = -$pVolume;

    return $pVolume;
}

// pick a mesh and type meshVolume();
global proc float meshVolume() {
    string $sel[] = `ls -sl -dag -leaf -type "mesh"`;
    string $dup[] = `duplicate -rr $sel[0]`;
    polyTriangulate $dup[0];
    string $tris[] = `ls -flatten ($dup[0] +".f[*]")`;

    float $volume=0.0;
    for ($t in $tris) $volume += prismVolume($t) ;

    delete $dup;
    return $volume;
}
or Cancel
  • 0

mbakr [ Editor ]

Julian,

Your method is more accurate than computePolysetVolume - which can return outlandish values for arbitrarily faceted meshes (such as those generated via Voronoi shatter). Thanks for sharing.

EDIT:

One small optimization here for meshVolume() - unfrozen transforms can produce varied results, this tweak simply freezes the duplicate. The result is consistent volume computation and any orientation.

global proc float meshVolume() {
     string $sel[] = `ls -sl -dag -leaf -type "mesh"`;
     string $dup[] = `duplicate -rr $sel[0]`;
     makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $dup[0]; //freeze
     polyTriangulate $dup[0];
     string $tris[] = `ls -flatten ($dup[0] +".f[*]")`;

     float $volume = 0.0;
     for ($t in $tris) $volume += prismVolume($t) ;

     delete $dup;
     return $volume;
}
or Cancel