three-bvh-csg
Version:
A fast, flexible, dynamic CSG implementation on top of three-mesh-bvh
99 lines (70 loc) • 2.37 kB
JavaScript
import { Vector3 } from 'three';
import { Triangle } from 'three';
import { getTriCount } from '../core/utils/geometryUtils.js';
// https://stackoverflow.com/questions/1406029/how-to-calculate-the-volume-of-a-3d-mesh-object-the-surface-of-which-is-made-up
const _tri = new Triangle();
const _normal = new Vector3();
const _relPoint = new Vector3();
export function computeMeshVolume( mesh ) {
// grab the matrix and the geometry
let geometry;
let matrix;
if ( mesh.isBufferGeometry ) {
geometry = mesh;
matrix = null;
} else {
geometry = mesh.geometry;
matrix = Math.abs( mesh.matrixWorld.determinant() - 1.0 ) < 1e-15 ? null : mesh.matrixWorld;
}
// determine the number of relevant draw range elements to use
const index = geometry.index;
const pos = geometry.attributes.position;
const drawRange = geometry.drawRange;
const triCount = Math.min( getTriCount( geometry ), drawRange.count / 3 );
// get a point relative to the position of the geometry to avoid floating point error
_tri.setFromAttributeAndIndices( pos, 0, 1, 2 );
applyMatrix4ToTri( _tri, matrix );
_tri.getNormal( _normal );
_tri.getMidpoint( _relPoint ).add( _normal );
// iterate over all triangles
let volume = 0;
const startIndex = drawRange.start / 3;
for ( let i = startIndex, l = startIndex + triCount; i < l; i ++ ) {
let i0 = 3 * i + 0;
let i1 = 3 * i + 1;
let i2 = 3 * i + 2;
if ( index ) {
i0 = index.getX( i0 );
i1 = index.getX( i1 );
i2 = index.getX( i2 );
}
// get the triangle
_tri.setFromAttributeAndIndices( pos, i0, i1, i2 );
applyMatrix4ToTri( _tri, matrix );
subVectorFromTri( _tri, _relPoint );
// add the signed volume
volume += signedVolumeOfTriangle( _tri.a, _tri.b, _tri.c );
}
return Math.abs( volume );
}
function signedVolumeOfTriangle( p1, p2, p3 ) {
const v321 = p3.x * p2.y * p1.z;
const v231 = p2.x * p3.y * p1.z;
const v312 = p3.x * p1.y * p2.z;
const v132 = p1.x * p3.y * p2.z;
const v213 = p2.x * p1.y * p3.z;
const v123 = p1.x * p2.y * p3.z;
return ( 1 / 6 ) * ( - v321 + v231 + v312 - v132 - v213 + v123 );
}
function subVectorFromTri( tri, pos ) {
tri.a.sub( pos );
tri.b.sub( pos );
tri.c.sub( pos );
}
function applyMatrix4ToTri( tri, mat = null ) {
if ( mat !== null ) {
tri.a.applyMatrix4( mat );
tri.b.applyMatrix4( mat );
tri.c.applyMatrix4( mat );
}
}