在three.js中计算边界框水平边缘的屏幕坐标

时间:2015-01-06 09:50:36

标签: javascript html three.js

我有一个three.js页面,它呈现一组粒子(可运行的演示和代码:https://dl.dropboxusercontent.com/u/31495717/cubemaker/index.html)。

这是默认视图的快照,我们基本上是在查看以(0,0,0)为中心的单位立方体:

Default view

我在这个单位立方体内的每个粒子上都有透明的边界框。如果我修改不透明度,我们可以看到每个粒子周围的框:

var bounding_box = new THREE.Mesh(
    bounding_box_geometry, 
    new THREE.MeshLambertMaterial({ 
        opacity: 0.5, 
        transparent: true,
        alphaTest: 0.5
    })
);

Default view with bounding boxes

我使用THREE.Raycaster()跟踪摄像机中的矢量到当前鼠标位置的世界坐标:

var mouse_vector = new THREE.Vector3(mouse.x, mouse.y, 1).unproject(camera);
raycaster.set(camera.position, mouse_vector.sub(camera.position).normalize());
var bounding_box_intersections = raycaster.intersectObjects(bounding_boxes);

如果有bounding_box_intersections,我会检索相交的边界框的屏幕坐标并将其存储在screen_object_center中:

var width = window.innerWidth, height = window.innerHeight;
var widthHalf = width / 2, heightHalf = height / 2;
var screen_object_center = new THREE.Vector3();
var projector = new THREE.Projector();
projector.projectVector(screen_object_center.setFromMatrixPosition(INTERSECTED.matrixWorld), camera);
screen_object_center.x = (screen_object_center.x * widthHalf) + widthHalf;
screen_object_center.y = -(screen_object_center.y * heightHalf) + heightHalf;

一旦我有screen_object_center - 相交对象或边界框中心的屏幕坐标 - 我可以在鼠标悬停的任何地方放置偏移的文本标签。

作为一个例子,这里是一个快照,显示文本标签如何显示鼠标指针悬停在最中心粒子的边界框上:

Default view with label

我使用id_label边界框来调整标签的垂直偏移:

id_label.style.top = (screen_object_center.y - 0.85 * (id_label_rect.height / 2)) + 'px';

这没关系。

我的问题是如何设置标签的水平偏移量,相对于粒子的位置和深度。

复杂的是,更深的背景粒子比前景中的粒子小,所以我需要一个较小的水平偏移来使标签与边缘保持恒定的距离。

我失败的尝试涉及计算一个名为THREE.Vector3的{​​{1}},它试图获取粒子边界框({​​{1}}对象)的边缘,而不是其中心点。

通过检索与粒子边缘对应的屏幕坐标,我希望在粒子的边缘和标签之间设置一个恒定的水平间隙,而不管粒子的深度。

我通过复制screen_object_edge对象的矩阵,设置位于边界框角落的新位置,然后投射一个名为INTERSECTED的向量来复制矩阵相机的位置:

INTERSECTED

旋转场景后,事情就会中断:标签在垂直位置正确设置,但在水平位置设置不正确,因为有些标签现在与粒子的边界框重叠。

以下是在旋转粒子云之后突出显示的相同标签的示例,如上例所示:

Default view, rotated and showing label

如果操作正常,标签将与旋转场景中的右粒子边缘位于相同的水平距离,就像在原始的非旋转默认场景中一样。这里,标签与粒子重叠。

我的问题是如何计算screen_object_edge以便我可以获得粒子边界框边缘的正确屏幕坐标,然后相对于左边或右边正确偏移文本标签的水平位置它各自粒子的边缘。

修改

感谢vals的正确答案。以下是我修改后的var INTERSECTED_matrix_copy = new THREE.Matrix4().copy(INTERSECTED.matrixWorld); INTERSECTED_matrix_copy.setPosition(new THREE.Vector3(INTERSECTED.position.x + 0.0375, INTERSECTED.position.y + 0.0375, INTERSECTED.position.z + 0.0375)); var screen_object_edge = new THREE.Vector3(); projector.projectVector(screen_object_edge.setFromMatrixPosition(INTERSECTED_matrix_copy), camera); screen_object_edge.x = (screen_object_edge.x * widthHalf) + widthHalf; screen_object_edge.y = -(screen_object_edge.y * heightHalf) + heightHalf; 函数的片段:

screen_object_edge

当我旋转场景时,无论边界框的z深度如何,标签位置现在与边界框边缘保持恒定距离:

Revised edge vector, default position

Revised edge vector, rotated position

1 个答案:

答案 0 :(得分:1)

我认为解决方案应该是

  1. 您拥有边界框的中心
  2. 您可以计算相机中raycaster矢量和向上矢量的叉积。此向量应指向场景的右侧。
  3. 您将此向量长度设置为边界框大小的一半
  4. 将此向量添加到边界框的中心。