在 ThreeJS 中计算网格的体积大于边界框体积
Calculating the volume of a mesh in ThreeJS is greater than bounding box volume
问题:
边界框体积小于从网格计算的体积。
我试过的:
首先我使用以下代码计算边界框的体积:
//loaded .obj mesh object:
var sizer = new THREE.Box3().setFromObject(obj);
console.log(sizer.size().x*sizer.size().z*sizer.size().y);
日志输出:197112.65382983384
然后我使用 this solution with this solution 和下面方法 "calculateVolume" 中的遗留几何对象计算网格的体积:
console.log(scope.calculateVolume(child));
calculateVolume 是 class 的一部分。我的class方法如下:
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);
}
日志输出:336896.1562770668
检查顶点的来源:
我也尝试了 buffergeometry,当然,它实际上是同一个数组,但是一个类型化的 Float32Array 并且可以预见地给出相同的结果:
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);
日志输出:336896.1562770668
问题:为什么我的边界框体积小于封闭网格的计算体积?
也许我遗漏了诸如偏移位置之类的东西,或者我计算的边界框体积有误。我在 google 和堆栈上进行了几次搜索,这就是我找到上面的 signedVolumeOfTriangle 函数的方式。这似乎是最普遍接受的方法。
可能是缠绕顺序的问题,您可以尝试否定签名卷的结果,或者重新排序参数。
缠绕顺序将是顺时针或逆时针,并决定多边形的面向(法向),
volumes += this.signedVolumeOfTriangle(P, Q, R);
交换 P
和 R
反转正常,
volumes += this.signedVolumeOfTriangle(R, Q, P);
这可能会因 triangle strips 等存储技术而变得复杂,其中相邻三角形共享顶点,从而导致缠绕顺序交替。
另一个问题可能是 - 特别是如果它对简单网格正确工作 - 是退化顶点。如果您从编辑器中获取网格,并且网格已被修改和调整一百万次(通常是这种情况),几乎可以保证它会退化。
可能有一个选项可以在编辑器中焊接紧密的顶点,这可以提供帮助,或者使用已知良好的网格进行测试,例如斯坦福兔子。
问题:
边界框体积小于从网格计算的体积。
我试过的:
首先我使用以下代码计算边界框的体积:
//loaded .obj mesh object:
var sizer = new THREE.Box3().setFromObject(obj);
console.log(sizer.size().x*sizer.size().z*sizer.size().y);
日志输出:197112.65382983384
然后我使用 this solution with this solution 和下面方法 "calculateVolume" 中的遗留几何对象计算网格的体积:
console.log(scope.calculateVolume(child));
calculateVolume 是 class 的一部分。我的class方法如下:
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);
}
日志输出:336896.1562770668
检查顶点的来源:
我也尝试了 buffergeometry,当然,它实际上是同一个数组,但是一个类型化的 Float32Array 并且可以预见地给出相同的结果:
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);
日志输出:336896.1562770668
问题:为什么我的边界框体积小于封闭网格的计算体积?
也许我遗漏了诸如偏移位置之类的东西,或者我计算的边界框体积有误。我在 google 和堆栈上进行了几次搜索,这就是我找到上面的 signedVolumeOfTriangle 函数的方式。这似乎是最普遍接受的方法。
可能是缠绕顺序的问题,您可以尝试否定签名卷的结果,或者重新排序参数。
缠绕顺序将是顺时针或逆时针,并决定多边形的面向(法向),
volumes += this.signedVolumeOfTriangle(P, Q, R);
交换 P
和 R
反转正常,
volumes += this.signedVolumeOfTriangle(R, Q, P);
这可能会因 triangle strips 等存储技术而变得复杂,其中相邻三角形共享顶点,从而导致缠绕顺序交替。
另一个问题可能是 - 特别是如果它对简单网格正确工作 - 是退化顶点。如果您从编辑器中获取网格,并且网格已被修改和调整一百万次(通常是这种情况),几乎可以保证它会退化。
可能有一个选项可以在编辑器中焊接紧密的顶点,这可以提供帮助,或者使用已知良好的网格进行测试,例如斯坦福兔子。