three.js - вращать прямоугольный спрайт вокруг сферы, сохраняя минимальную близость - PullRequest
0 голосов
/ 06 сентября 2018

С учетом three.js сцены с статической камерой , сферой в 0,0,0 и прямоугольным спрайтом (например, текстовая метка) произвольных размеров, я ищу «метод Threejs» (или формулу), который позволяет вращать спрайт вокруг сферы без срезания, на минимально возможном радиусе.

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

const xPolar = Math.sin(phi) * Math.sin(theta);
const yPolar = Math.cos(phi);
const zPolar = Math.sin(phi) * Math.cos(theta);
const x = xPolar + sprite.radius * xPolar;
const y = yPolar + sprite.radius * yPolar;
const z = zPolar + (theta < 0 ? -sprite.radius : sprite.radius) * xPolar // ahem;

Рабочий пример здесь: https://codepen.io/theprojectsomething/full/xadQvK/

Обратите внимание на отсечение, когда phi приближается к полюсам. Неплохо в этом примере, но надеемся, что найдется более изящное решение и от кого-то, кто лучше понимает действующие силы!

Примечания:

  • Хорошо осведомлен о классе three.js Spherical; ручные расчеты для наглядности.
  • В этом примере используется координатное пространство по умолчанию three.js, будет принято любое адаптируемое решение!

1 Ответ

0 голосов
/ 06 сентября 2018

Давайте попробуем формализовать то, что имеем. Во-первых, мы предполагаем, что мы находимся в системе координат, где сфера находится в начале координат, а направление взгляда - это ось z. Если мы не находимся в этой системе координат, легко преобразовать входные данные в эту систему координат, затем выполнить расчет и, наконец, преобразовать обратно в исходную систему координат.

У нас есть вектор направления d, который указывает направление, в котором мы хотим, чтобы центр спрайта появился (это то, что вы называете xyzPolar в своем фрагменте кода). Кроме того, у нас есть ширина спрайта w и высота h, и мы знаем, что ширина увеличивается вдоль оси x, а высота расширяется вдоль оси y (так как у нас есть система координат с выравниванием вида).

Теперь для произвольного скалярного смещения t мы можем указать центр нашего спрайта как t * d. Точки на нашем спрайте затем описываются следующим набором:

{ t * d + x * (w/2, 0, 0) + y * (0, h/2, 0) | -1 <= x <= 1, -1 <= y <= 1 }

x и y - это параметрические позиции на спрайте, где (-1, -1) определяет левый нижний угол, а (0, 0) определяет центр. Нас особенно интересует точка, которая находится ближе всего к центру сферы, и мы хотим, чтобы эта точка находилась на расстоянии r (радиус сферы) от нее. Следовательно:

     min          (t * dx + x * w/2)^2 + (t * dy + y * h/2)^2 + (t * dz)^2 = r^2
x, y in [-1, 1]

Если мы знаем параметры x и y этой ближайшей точки, мы можем легко найти значение для t, что дает нам окончательную центральную позицию спрайта.

Однако мы не знаем этих параметров. Давайте разделим эту формулу на части:

(    min     (t * dx + x * w/2)^2 ) + (    min     (t * dy + y * h/2)^2 ) + (t * dz)^2 = r^2
 x in [-1, 1]                          y in [-1, 1]

Первые два условия минимизируются, если мы можем установить

x = -2 dx t / w
y = -2 dy t / h

В этом случае оба условия будут равны нулю, и мы можем решить для t = r / abs(dz). По сути, это поместит спрайт в плоскость, выровненную по xy, где z = +- r. И это верно, если у нас есть бесконечный спрайт, где мы не ограничиваем x и y.

Однако у нас нет бесконечного спрайта. Мы должны ограничить x и y в пределах допустимого диапазона. Таким образом, если у нас есть кандидат t, мы также можем проверить, является ли оно верным решением, просто рассчитав x и y с помощью приведенных выше формул и проверив, находятся ли они в допустимом диапазоне. Это будет верно, если ближайшая точка находится где-то посередине спрайта (а не на ребре или в углу).

К счастью, есть только несколько возможных значений для x и y, которые нам нужно проверить. Таким образом, алгоритм вычислит t для всех возможных значений, затем проверит, является ли решение допустимым, и сохранит только одно действительное решение. Теперь, какие значения возможны для x и y?

Мы уже знаем случай, когда -1 <= x <= 1 и -1 <= y <= 1. Все значения в этом диапазоне эквивалентны, потому что они делают первые два слагаемых нулевыми (не влияющими на конечный результат). И затем есть еще два случая для каждой переменной. Либо x = -1, либо x = 1 (то же самое для y). Это дает в общей сложности 9 комбинаций, которые нам нужно решить. Но мы можем сделать лучше. Мы знаем, что t, w и h являются положительными. Следовательно, x и y будут иметь противоположные знаки dx и dy соответственно. Например, если dx положительно, нам нужно только проверить случаи, когда x = -1 или первый член исчезает (по сути, это означает, что правый край спрайта никогда не может быть ближайшей точкой, если вектор направления указывает на право). Эквивалентно, если dx или dy равны нулю, мы сразу знаем, что соответствующий термин исчезает, и нам не нужно принимать во внимание другой случай. Кроме того, если dz = 0, не оценивайте случай, когда первые два члена исчезают

Итак, у нас до четырех дел. Для справки, вот термины для трех разных случаев для каждой переменной:

            first term
-1 = x      dx^2 * t^2 - dx * t * w + w^2 / 4
-1 < x < 1  0
     x = 1  dx^2 * t^2 + dx * t * w + w^2 / 4

            second term
-1 = y      dy^2 * t^2 - dy * t * h + h^2 / 4
-1 < y < 1  0
     y = 1  dy^2 * t^2 + dy * t * h + h^2 / 4

Для четырех случаев, которые вам нужно оценить, соберите квадратные уравнения и решите для t. Наконец, вычислите x и y и проверьте, соответствуют ли они регистру (если у вас есть регистр x = 1, проверьте x >= 1 и т. Д.) Наконец, вычислите центр спрайта как t * d.

Так что, к сожалению, это не более элегантно, чем у вас, но более точно.

...