Three.js如何获取网格的位置?

11

使用下面的代码,返回网格的位置为(0, 0, 0),但实际上并不是。因此,位置向量是在渲染过程后计算的吗?

me.scene.add(objMesh); //me is a project class
objMesh.updateMatrixWorld(true);
alert(objMesh.position.x + ',' + objMesh.position.y + ',' + objMesh.position.z);

从objfile创建了objMesh,正确将其添加到场景中,重心近似为(-8, 3, 0),但是objMesh的位置向量为(0, 0, 0)。我们需要自动计算一些东西吗?还是应该手动从网格的几何顶点计算它?

http://81.214.75.32:8181/admin 是该网站的链接。

该网站使用土耳其语,因此我将翻译UI选项。

在网站上有一个名为“Dosya”的菜单项,请打开该菜单并选择“Proje Aç”,然后会出现一个对话框,在该对话框中选择MUTFAK_1,就会出现场景。在该场景中,每个网格的位置都是(0, 0, 0),这可能吗? :)

7个回答

29
更新:
函数getPositionFromMatrix()已更名为setFromMatrixPosition()

r58

object.position始终是相对于对象的本地坐标。如果你想要获取世界坐标系中的位置,你需要从object.matrixWorld中获取。

试试这个:

scene.add(objMesh);
scene.updateMatrixWorld(true);
var position = new THREE.Vector3();
position.getPositionFromMatrix( objMesh.matrixWorld );
alert(position.x + ',' + position.y + ',' + position.z);

2
mrdoob,这是我之前尝试过的东西... 这段代码也返回(0, 0, 0)。你能否请检查一下上面网址中的应用程序?在拼花地面上应该有一个用于反射的cubeCamera。场景的导入是通过FileManager.js完成的。您将在第290行的if块内看到添加网格的代码。我无法获得任何网格的世界位置。我更新了项目以自动加载场景。在右侧窗格("Nesne Ozellikleri")中,有"Yansima Merkez"文本框。这些值会改变cubeCamera的位置。 - Tezcan
地面平面大约在(-8, 3, 0)位置,因此立方体相机必须位于该点。 - Tezcan
那么问题必须是,要么几何体已经应用了偏移量,要么您正在尝试获取错误对象的位置。 - mrdoob
我确定这不是错误的对象。因为场景中的每个对象pisution都返回0。我为每个网格创建自定义几何体,并将顶点赋予该几何体。这些顶点指向使得对象位于场景中的其位置。 - Tezcan
@Tezcan:下面没有内容吗?你找到解决方案了吗? - Timo Kähkönen
显示剩余4条评论

16

要找到几何中心在世界空间中的位置,请尝试以下方法:

objMesh.geometry.computeBoundingBox();

var boundingBox = objMesh.geometry.boundingBox;

var position = new THREE.Vector3();
position.subVectors( boundingBox.max, boundingBox.min );
position.multiplyScalar( 0.5 );
position.add( boundingBox.min );

position.applyMatrix4( objMesh.matrixWorld );

alert(position.x + ',' + position.y + ',' + position.z);

r58


r58:Matrix4的.multiplyVector3()已被移除。请改用vector.applyMatrix4(matrix)或vector.applyProjection(matrix)。上述代码是用来做什么的? - Timo Kähkönen
@mrdoob,您能解释一下上面这些步骤的含义吗?至少这个步骤position.multiplyScalar(0.5)。 - Rajkamal Subramanian
@rajkamal 将某物乘以0.5意味着获得其一半。实际上,将任何东西乘以介于0和1之间的数字意味着获得其百分比;0.5是50%,0.85是85%。 - Absulit

5

是的。在与mrdoob交谈后,我意识到物体的位置是局部的。我的情况是考虑顶点找到网格的中心点。以下是获取重心的代码,来自答案#447(https://github.com/mrdoob/three.js/issues/447)。

geom.centroid = new THREE.Vector3();
for (var i = 0, l = geom.vertices.length; i < l; i++) {
    geom.centroid.addSelf(geom.vertices[i]);
}
geom.centroid.divideScalar(geom.vertices.length);

现在我们有几何中心点...
更新 根据https://github.com/mrdoob/three.js/wiki/Migration,在r55之后.addSelf已被重命名为.add

我很好奇你是否可以使用 geom.boundingSphere.center 代替?在这种情况下,这对我有效。 - Jon Rose

2
alert(objMesh.matrixWorld.getPosition().x + ',' + objMesh.matrixWorld.getPosition().y + ',' + objMesh.matrixWorld.getPosition().z);

2
请解释一下你的解决方案,不要只粘贴代码。 - Julien Lafont
4
不是的,我的朋友。我尝试使用objMesh.matrixWorld.getPosition(),但仍然返回(0, 0, 0),没有正确返回模型的位置。我会将整个项目上传到服务器上,或许这样更容易检查。 - Tezcan

1

0
根据这篇文章,网格的重心C可以通过以下公式找到:
C = [所有(A*R)之和] / [所有A之和] A = (面积*2) R = 面心 = 构成该面的顶点的平均值
下面是在three.js中的代码:
function calculateCenterOfMass( mesh ){

    var centroid = new THREE.Vector3();

    // centroid = centroidNominator / centroidDenominator;
    var centroidNominator = new THREE.Vector3(); 
    var centroidDenominator = 0;

    for(var i = 0; i < mesh.geometry.faces.length; i++){

        var Pi = mesh.geometry.faces[i].a;
        var Qi = mesh.geometry.faces[i].b;
        var Ri = mesh.geometry.faces[i].c;

        var a = new THREE.Vector3(mesh.geometry.vertices[Pi].x, mesh.geometry.vertices[Pi].y, mesh.geometry.vertices[Pi].z);
        var b = new THREE.Vector3(mesh.geometry.vertices[Qi].x, mesh.geometry.vertices[Qi].y, mesh.geometry.vertices[Qi].z);
        var c = new THREE.Vector3(mesh.geometry.vertices[Ri].x, mesh.geometry.vertices[Ri].y, mesh.geometry.vertices[Ri].z);

        var ab = b.clone().sub(a);
        var ac = c.clone().sub(a);

        var cross = new THREE.Vector3();
        cross.crossVectors( ab, ac );

        var faceArea = cross.lengthSq() / 2;
        var faceCentroid = new THREE.Vector3( (a.x + b.x + c.x)/3, (a.y + b.y + c.y)/3, (a.z + b.z + c.z)/3 );

        if (!isNaN(faceArea)){
            centroidNominator.add(faceCentroid.multiplyScalar(faceArea));
            centroidDenominator += faceArea;
        }
    }


    centroid = centroidNominator.divideScalar(centroidDenominator);

    return centroid;
}

0

提示。如果您正在获取导入模型(例如GLTF)中网格的位置,请确保在导出之前将网格的原点设置为其自己的中心,即不要对其应用变换。否则,它的世界中心将是gltf的中心而不是网格本身的中心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接