-1

The problem:

Bounding box volume is smaller than volume calculated from mesh.

What I've tried:

First I calculate the volume of a bounding box with the following code:

//loaded .obj mesh object:
var sizer = new THREE.Box3().setFromObject(obj);
console.log(sizer.size().x*sizer.size().z*sizer.size().y);

log output: 197112.65382983384

Then I calculate the volume of the mesh using this solution with this solution with the legacy geometry object in the method "calculateVolume" included below:

    console.log(scope.calculateVolume(child));

calculateVolume is part of a class. My class methods are as follows:

threeDeeAsset.prototype.signedVolumeOfTriangle = function(p1, p2, p3) {
    var v321 = p3.x*p2.y*p1.z;
    var v231 = p2.x*p3.y*p1.z;
    var v312 = p3.x*p1.y*p2.z;
    var v132 = p1.x*p3.y*p2.z;
    var v213 = p2.x*p1.y*p3.z;
    var v123 = p1.x*p2.y*p3.z;
    return (-v321 + v231 + v312 - v132 - v213 + v123)/6;
}

threeDeeAsset.prototype.calculateVolume = function(object){
    var volumes = 0;

    object.legacy_geometry = new THREE.Geometry().fromBufferGeometry(object.geometry);

    for(var i = 0; i < object.legacy_geometry.faces.length; i++){
        var Pi = object.legacy_geometry.faces[i].a;
        var Qi = object.legacy_geometry.faces[i].b;
        var Ri = object.legacy_geometry.faces[i].c;

        var P = new THREE.Vector3(object.legacy_geometry.vertices[Pi].x, object.legacy_geometry.vertices[Pi].y, object.legacy_geometry.vertices[Pi].z);
        var Q = new THREE.Vector3(object.legacy_geometry.vertices[Qi].x, object.legacy_geometry.vertices[Qi].y, object.legacy_geometry.vertices[Qi].z);
        var R = new THREE.Vector3(object.legacy_geometry.vertices[Ri].x, object.legacy_geometry.vertices[Ri].y, object.legacy_geometry.vertices[Ri].z);
        volumes += this.signedVolumeOfTriangle(P, Q, R);
    }

    return Math.abs(volumes);
}

log output: 336896.1562770668

Checking the source of the vertexes:

I also tried buffergeometry and of course, it's really the same array, but a typed Float32Array and predictably gave the same result:

var vol = 0;
scope.mesh.traverse(function (child) {
    if (child instanceof THREE.Mesh) {
        var positions = child.geometry.getAttribute("position").array;
        for(var i=0;i<positions.length; i+=9){

            var t1 = {};
            t1.x = positions[i+0];
            t1.y = positions[i+1];
            t1.z = positions[i+2];

            var t2 = {};
            t2.x = positions[i+3];
            t2.y = positions[i+4];
            t2.z = positions[i+5];

            var t3 = {};
            t3.x = positions[i+6];
            t3.y = positions[i+7];
            t3.z = positions[i+8];
            //console.log(t3);

            vol += scope.signedVolumeOfTriangle(t1,t2,t3);
        }
    }
});
console.log(vol);

log output: 336896.1562770668

The question: Why is my bounding box volume smaller than the calculated volume of a closed mesh?

Perhaps I missing something such as an offset position or maybe I am calculating the bounding box volume wrong. I did several searches on google and stack, which is how I came to find the signedVolumeOfTriangle function above. it seems to be the most common accepted approach.

Community
  • 1
  • 1
Radio
  • 2,810
  • 1
  • 21
  • 43

1 Answers1

1

Could be a problem with winding order, you could try negating the result from signed volume, or reordering arguments.

The winding order will be clockwise or counterclockwise and determines the facing (normal) of the polygon,

volumes += this.signedVolumeOfTriangle(P, Q, R);

Swapping P and R inverts the normal,

volumes += this.signedVolumeOfTriangle(R, Q, P);

This can be complicated by storage techniques like triangle strips, where vertices are shared by adjacent triangles, causing winding order to alternate.

Another problem could be - especially if it works correctly for simple meshes - is degenerate vertices. If you're getting your meshes from an editor, and the mesh has been modified and tweaked a million times (usually the case), it's almost guaranteed to have degenerates.

There may be an option to weld close vertices in the editor that can help, or test with a known good mesh e.g. the Stanford bunny.

Johnny Cage
  • 528
  • 2
  • 6
  • Only in a closed mesh of zero concave features? – Radio Jun 16 '15 at 21:47
  • Sorry for my ignorance on this: Winding order. How do I go about detecting a bad winding order to reorder the arguments in this case? – Radio Jun 16 '15 at 22:19
  • Possible that this would also explain why some of my simpler meshes seem just fine... – Radio Jun 16 '15 at 22:20
  • I see your edits and will try the Weld option. I am using Rhino and wrote a Python exporter with Weld available. Thank you for the direction! I am hesitant to declare this answered yet as I don't want to mislead others if it's not right. But I will upvote. If this turned out to be the issue I will accept it! Thanks again! – Radio Jun 16 '15 at 23:42