【问题标题】:Calculating the volume of a mesh in ThreeJS is greater than bounding box volume在 ThreeJS 中计算网格的体积大于边界框体积
【发布时间】:2021-08-16 16:33:25
【问题描述】:

问题:

边界框体积小于从网格计算的体积。

我的尝试:

首先我使用以下代码计算边界框的体积:

//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 solutionthis solution 以及下面包含的“calculateVolume”方法中的旧几何对象来计算网格的体积:

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

calculateVolume 是类的一部分。我的类方法如下:

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 和 stack 上进行了几次搜索,这就是我找到上面的 signedVolumeOfTriangle 函数的方法。这似乎是最普遍接受的方法。

【问题讨论】:

    标签: javascript 3d three.js


    【解决方案1】:

    可能是缠绕顺序的问题,您可以尝试对已签名卷的结果取反,或重新排序参数。

    缠绕顺序将是顺时针或逆时针,并确定多边形的朝向(法线),

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

    交换PR 反转正常,

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

    这可能会因triangle strips 等存储技术而变得复杂,其中顶点由相邻三角形共享,从而导致缠绕顺序交替。

    另一个问题可能是 - 特别是如果它对简单网格正常工作 - 是退化顶点。如果您从编辑器中获取网格,并且网格已经修改和调整了一百万次(通常是这种情况),那么几乎可以保证它会退化。

    可能有一个选项可以在编辑器中焊接闭合顶点,这可能会有所帮助,或者使用已知良好的网格进行测试,例如斯坦福兔。

    【讨论】:

    • 仅在零凹特征的封闭网格中?
    • 对不起,我对此一无所知:缠绕顺序。在这种情况下,如何检测错误的绕组顺序以重新排序参数?
    • 可能这也可以解释为什么我的一些更简单的网格看起来还不错...
    • 我看到您的编辑,并会尝试焊接选项。我正在使用 Rhino 并编写了一个带有 Weld 的 Python 导出器。谢谢你的指导!我很犹豫是否要宣布这个答案,因为如果它不正确,我不想误导其他人。但我会投票。如果是这个问题,我会接受的!再次感谢!
    猜你喜欢
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-01
    • 1970-01-01
    • 2013-01-09
    相关资源
    最近更新 更多