2017-09-11 17 views
1

我正在使用Three.js(r86)渲染一组球体。我被从外部库调用createSphereGroup功能这样:如何根据子女的宽度将THREE.Group居中?

// External library code. 
function createSphereGroup(sphereCount) [ 
    var group = new THREE.Group(); 
    for (var i = 0; i < sphereCount; i++) { 
    var geometry = new THREE.SphereGeometry(50); 
    var material = new THREE.MeshPhongMaterial({ color: 0xFF0000 }); 
    var sphere = new THREE.Mesh(geometry, material); 
    sphere.position.x = i * 150; 
    group.add(sphere); 
    } 
    return group; 
} 

(假设外部库是不透明的,我在那里不能修改任何代码。)


// My code. 
var group = createSphereGroup(5); 
scene.add(group); 

...这看起来是这样的:

Screenshot

正如你所看到的那样,这组球体是偏离中心的。我希望组居中,第三个球体位于两条线相交处(x=0)。

那么有什么方法可以让我的小组居中?也许通过计算组的宽度,然后将其定位在x=-width/2?我知道你可以在几何呼吁computeBoundingBox以确定其宽度,但THREE.Group不具有几何形状,所以我不知道如何做到这一点?

回答

3

如果要居中的对象(或组)和它的孩子,你可以通过设置对象的位置,像这样做:

var box = new THREE.Box3().setFromObject(object).getCenter(object.position).multiplyScalar(- 1); 

scene.add(object); 

three.js所r.87

+0

好!看到它太晚哈哈。 但是,最好只调用一次,因为它会扩展每个顶点的框顶点。 – neeh

1

如果组中的所有对象都比较相同的大小,在你的例子,你可以拿儿女的位置的平均:

function computeGroupCenter(count) { 
    var center = new THREE.Vector3(); 
    var children = group.children; 
    var count = children.length; 
    for (var i = 0; i < count; i++) { 
     center.add(children[i].position); 
    } 
    center.divideScalar(count); 
    return center; 
} 

另一个(更强大的)的方式来做到这一点是创建一个包含的边框边框该团体的每个孩子。

有一些重要的事情要考虑:

  • 一个THREE.Group可以包含其他THREE.Group,因此,该算法应该是递归
  • 包围盒在局部空间计算,但是,对象可以被翻译关于其父母,所以我们需要在世界空间工作。
  • 该组本身可能会被翻译成!所以我们必须从世界空间跳回到团队的地方空间,让团队的空间定义中心。

你可以用THREE.Object3D.traverseTHREE.BufferGeometry.computeBoundingBoxTHREE.Box3.ApplyMatrix4轻松实现这一点:

/** 
* Compute the center of a THREE.Group by creating a bounding box 
* containing every children's bounding box. 
* @param {THREE.Group} group - the input group 
* @param {THREE.Vector3=} optionalTarget - an optional output point 
* @return {THREE.Vector3} the center of the group 
*/ 
var computeGroupCenter = (function() { 
    var childBox = new THREE.Box3(); 
    var groupBox = new THREE.Box3(); 
    var invMatrixWorld = new THREE.Matrix4(); 

    return function (group, optionalTarget) { 
     if (!optionalTarget) optionalTarget = new THREE.Vector3(); 

     group.traverse(function (child) { 
      if (child instanceof THREE.Mesh) { 
       if (!child.geometry.boundingBox) { 
        child.geometry.computeBoundingBox(); 
        childBox.copy(child.geometry.boundingBox); 
        child.updateMatrixWorld(true); 
        childBox.applyMatrix4(child.matrixWorld); 
        groupBox.min.min(childBox.min); 
        groupBox.max.max(childBox.max); 
       } 
      } 
     }); 

     // All computations are in world space 
     // But the group might not be in world space 
     group.matrixWorld.getInverse(invMatrixWorld); 
     groupBox.applyMatrix4(invMatrixWorld); 

     groupBox.getCenter(optionalTarget); 
     return optionalTarget; 
    } 
})(); 

Here's a fiddle

相关问题