Я пишу простую компьютерную анимацию, которая представляет собой линию, которая вращается вокруг фиксированной точки в центре этой линии. Величина вращения основана на алгоритме градиентного шума (шум OpenSimplex). Строка имеет начало [x, y] и номер кадра анимации. Эти три значения, включенные в шум OpenSimplex, дают значение поворота. Эта часть работает отлично.
Проблема в том, что я хочу, чтобы линия выглядела как курсор мыши, в зависимости от того, насколько далеко курсор мыши находится от линии. Курсор имеет координаты [mx, my] (которые меняются для каждого кадра анимации). Я могу легко повернуть линию и указать прямо на курсор. Но я испытываю трудности с учетом расстояния. Уточнить;линия - это вращение градиентного шума, и курсор мыши изменяет это вращение, чтобы линия (в [x, y]) указывала в [mx, my].
Кроме того, линия имеет 180-градусную идентичностьпоэтому ближайший конец должен указывать на мышь.
В основном то, что я делаю сейчас, - это "линия вращения" плюс "мышь вращения". Если он находится между 90 и 270 градусами, задняя часть линии является ближайшей к курсору, в противном случае - передней (для простоты это не включено в приведенный ниже пример кода). Затем я беру разность, множитель расстояния и вычитаю или добавляю ее к повороту линии. И это работает довольно хорошо, за исключением некоторых артефактов.
let r = OpenSimplexNoise(x, y, frame); // gives current original rotation
let frame = 68; // whichever frame
let x = 60; // some fixed coordinate of line
let y = 60; // some fixed coordinate of line
let mouseX = 10; // changes when the mouse moves
let mouseY = 10; // changes when the mouse moves
let mouseRadius = 200;
let width = 100;
let height = 1;
function distance (x, y, cx, cy) {
return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
}
function angle (x1, y1, x2, y2) {
let dx = x1 - x2;
let dy = y1 - y2;
return 360 + (Math.atan2(dy, dx) * 180 / Math.PI);
}
if (distance(x, y, mouseX, mouseY) <= mouseRadius) {
let dist = distance(x, y, mouseX, mouseY);
let mouseR = angle(x, y, mouseX, mouseY) % 360;
let near = (mouseRadius - dist) / mouseRadius;
let far = 1 - near;
r = (r * far + near * mouseR) % 360;
}
// r now includes mouse
Живая версия: https://jsfiddle.net/Ruudt/56pk2wd1/1/
Проблема заключается в случаях, когда мышь проходит слева направо от перпендикуляра клиния (оригинальное вращение). Здесь вычисление назначит другой конец как "замыкания", затем вычислит расстояние и применяет это к вращению. Это приводит к тому, что линия переходит от направления немного влево от курсора вправо от курсора (или наоборот).
Есть ли способ исправить это?
Я сделал изображение, чтобы проиллюстрировать ситуацию.
- Красная линия представляет линию, использующую только вращение градиентного шума
- Черная линия - это линия, которая также включает в себя мышьположение
- синяя дуга - значение поворота мыши (правый конец - начало координат)
поворот строки: