我使用Three.js(r86)渲染一组球体。我这样做是通过从外部库调用createSphereGroup
函数来实现的:
// 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);
......看起来像这样:
如您所见,这组球体偏离中心。我希望该组居中,第三个球体位于两条线相交的点(x=0
)。
那么我可以通过某种方式使这个群体居中吗?也许通过计算组的宽度然后将其定位在x=-width/2
?我知道你可以在几何体上调用computeBoundingBox
来确定它的宽度,但是THREE.Group
没有几何体,所以我不知道如何做到这一点...
答案 0 :(得分:8)
如果要将对象(或组)及其子对象居中,可以通过设置对象的位置来实现:
new THREE.Box3().setFromObject( object ).getCenter( object.position ).multiplyScalar( - 1 );
scene.add( object );
three.js r.92
答案 1 :(得分: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.traverse
,THREE.BufferGeometry.computeBoundingBox
和THREE.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;
}
})();