У меня есть страница three.js, которая отображает набор частиц (runnable demo и code at: https://dl.dropboxusercontent.com/u/31495717/cubemaker/index.html).Вычисление координаты экрана горизонтального края ограничивающей рамки в three.js
Вот снимок зрения по умолчанию, когда мы в основном смотрит в единичном кубе с центром в точке (0, 0, 0):
У меня есть прозрачные ограничивающие рамки, сосредоточенные на каждой частице внутри этого куба блока. Если я изменить непрозрачность, мы можем увидеть коробки окружающих каждую частицу:
var bounding_box = new THREE.Mesh(
bounding_box_geometry,
new THREE.MeshLambertMaterial({
opacity: 0.5,
transparent: true,
alphaTest: 0.5
})
);
я использую 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
- экранные координаты центра пересекаемого объекта или ограничивающего прямоугольника - я могу поместить смещенную текстовую метку везде, где будет курсировать мышь.
В качестве примера, вот снимок того, как текст метка появляется с указателем мыши парил над ограничительной рамкой Центральных частиц:
я использую коробку id_label
ограничительной для регулировки вертикального смещения на этикетке:
id_label.style.top = (screen_object_center.y - 0.85 * (id_label_rect.height/2)) + 'px';
Это работает нормально.
Мой вопрос в том, как установить горизонтальный смещение метки относительно положения и глубины частицы.
Усложнение заключается в том, что более глубокие частицы фона меньше, чем частицы на переднем плане, и поэтому мне нужно меньшее горизонтальное смещение, чтобы держать метку на постоянном расстоянии от ее края.
Моя неудачная попытка включает вычисление THREE.Vector3
под названием screen_object_edge
, которое пытается получить границу ограничивающего прямоугольника частицы (объект INTERSECTED
) вместо его центральной точки.
Получив координаты экрана, соответствующие краю частицы, я надеюсь установить постоянный горизонтальный зазор между краем частицы и меткой, независимо от глубины частицы.
Я стараюсь, скопировав матрицу INTERSECTED
объекта, установив новую позицию, которая лежит в углу прямоугольника, а затем проектирование вектор называется screen_object_edge
, который лежит в этой скопированной позиции матрицы для камеры:
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
, чтобы я мог получить правильные координаты экрана края ограничивающей рамки частицы, а затем правильно смещать горизонтальное положение текстовой метки относительно левого или правого края ее соответствующей частице.
EDIT
Благодаря вальса для правильного ответа. Вот отрывок из моей модифицированной render()
функции:
function render() {
// ...
var scene_right = new THREE.Vector3().crossVectors(raycaster.ray.origin, camera.up).setLength(0.0375);
var bounding_box_intersections = raycaster.intersectObjects(bounding_boxes);
if (bounding_box_intersections.length > 0) {
// ...
var INTERSECTED_matrix_copy = new THREE.Matrix4().copy(INTERSECTED.matrixWorld);
INTERSECTED_matrix_copy.setPosition(new THREE.Vector3(INTERSECTED.position.x + scene_right.x, INTERSECTED.position.y + scene_right.y, INTERSECTED.position.z + scene_right.z));
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;
// ...
if (mouse.x < 0)
id_label.style.left = (screen_object_center.x - (screen_object_edge.x - screen_object_center.x)) + 'px';
else {
id_label.style.left = (screen_object_center.x + (screen_object_edge.x - screen_object_center.x) - id_label_rect.width) + 'px';
id_label.style.textAlign = 'right';
}
}
}
Когда я повернуть сцену, положение этикетки теперь постоянное расстояние от ограничительной рамки края, независимо от г глубины ограничивающего параллелепипеда: