2015-01-06 9 views
2

У меня есть страница three.js, которая отображает набор частиц (runnable demo и code at: https://dl.dropboxusercontent.com/u/31495717/cubemaker/index.html).Вычисление координаты экрана горизонтального края ограничивающей рамки в three.js

Вот снимок зрения по умолчанию, когда мы в основном смотрит в единичном кубе с центром в точке (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 под названием 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; 

Вещи ломаются, когда я поворачиваю сцену: эти метки правильно установлены в вертикальном положении, но они установлены неправильно в горизонтальном положении, так что некоторые теперь перекрывают ограничивающий прямоугольник частиц.

Ниже приведен пример того же этикетки выделены, как и в предыдущем примере, после того, как вращение облака частиц:

Default view, rotated and showing label

Если вещи работали правильно, метка будет располагаться на одной горизонтали на расстоянии от правого края частиц во вращающейся сцене, как в исходной, невращающейся по умолчанию сцене. Здесь метка перекрывает частицу.

Мой вопрос заключается в том, как рассчитать 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'; 
     } 
    } 
} 

Когда я повернуть сцену, положение этикетки теперь постоянное расстояние от ограничительной рамки края, независимо от г глубины ограничивающего параллелепипеда:

Revised edge vector, default position

Revised edge vector, rotated position

ответ

1

Я думаю, что решение должно быть

  1. У вас есть действующий объект?
  2. Вы вычислили кросс-произведение вектора raycaster и vector вверх в камере. Этот вектор должен указывать на право сцены.
  3. вы устанавливаете эту длину вектора в половину размера ограничивающей рамки
  4. вы добавляете этот вектор в центр рамки.
Смежные вопросы