Вращение 3D с осью и углом
Я знаю, что 3D-ротация хорошо документирована на SO и многих других сайтах, но, несмотря на чтение бесчисленных объяснений, я до сих пор не понял, где я ошибаюсь. Мой опыт в искусстве и дизайне, а не в математике и программировании, и я никогда не уверен, что мой угол атаки (не каламбур) является правильным. Вместо того, чтобы вставлять пэдворк моего мрачного кода, я включаю изображение, описывающее мою проблему. Мне бы очень хотелось, это поэтапное разбиение на то, как его решить. Псевдокод полезен, но я узнаю больше, если кто-то просто нацелит меня в правильном направлении или укажет на общие подводные камни.
![alt text]()
Красный = ось X, зеленый = ось Y, синий = ось Z
Пурпурные векторы = начало → некоторые X, Y, Z точка
Magenta cube = среднее значение конечных точек двух пурпурных векторов (есть ли лучшее название для этого?)
Белый вектор = перекрестное произведение двух пурпурных векторов (расширенное для отображения, фактический вектор нормализуется)
Объект Cyan cube = сбой вращения
Ранее я использовал Away3D и Papervision; в этих библиотеках, применяя углы Эйлера к объекту rotationX, rotationY или rotationZ свойства будут вращать объект локально, как если бы он в начале координат, независимо от его фактического положения. С Three.js это не так. Изменение свойств объекта rotation.x и rotation.y приводит к причудливому эффекту, когда объект, по-видимому, немного наклоняет ось Z. Еще более запутанным является то, что это происходит, когда объект находится в начале координат. Я думал, что, возможно, использование функций Quaternion → Matrix или Axis/Angle → Matrix решит мою проблему, но не кубики. Кажется, есть основная концепция, которую я не получаю.
Во всяком случае, то, что я хотел бы сделать, это ориентировать куб на вектор перекрестного продукта (белый), так что вершина куба обращена к направлению этого вектора. Затем я хотел бы повернуть куб вдоль той же оси. Изображение, которое я добавил, показывает результат больше часов, чем я хотел бы признать, пытаясь достичь этого результата. Мой код выглядит следующим образом:
axis = Vector3.cross(a, b)
axis.normalize()
angle = 45 * TO_RADIANS;
quat = AxisAngle2Quaternion(axis, angle)
rot = Quaternion2Matrix(quat)
cube.matrix = rot
Спасибо заранее,
Кейси
Изменить: запуск баунти
Возможно, я не понимаю, как это должно работать. Вот еще одно изображение:
![alt text]()
Я неправильно понял, что этот пурпурный вектор является осью, а оранжевые стрелки показывают вращение вокруг этой оси на основе угла? Так или иначе, я хочу сориентировать голубой куб на основе какого-то направленного вектора и открутить его. Что я делаю неправильно??
Ответы
Ответ 1
Ваш подход звучит правильно, но вы не показываете, какие векторы a, b и постоянный угол, я предполагаю, просто для тестирования. Я сделал это раньше, поэтому я выкопал свой код, и это математика, которую я нашел...
Дано:
originalVec = единичный вектор, направленный вверх по оси Y (направление вершины куба/норма)
targetVec = белый вектор
Теперь вам нужна ось и угол, которые будут вращать originalVec для выравнивания с targetVec. Самая прямая ось вращения перпендикулярна обоим входным векторам, поэтому возьмите их поперечное произведение. Эта ось не является единичным вектором, а также нормализует ее. Угол поворота (в радианах) является обратным косинусом точечного произведения.
axis = Vector3.cross(originalVec, targetVec)
axis.normalise
angle = inversecos(Vector3.dot(originalVec, targetVec))
quat = AxisAngle2Quaternion(axis, angle)
rot = Quaternion2Matrix(quat)
cube.matrix = rot
Вместо замены матрицы куба, я думаю, вы хотите скомпоновать его с новым преобразованием...
cube.matrix.multiplyBy(rot)
... но я не уверен на 100%. Кроме того, я видел реализации, где AxisAngle2Quaternion принимает угол в градусах. Когда входные векторы параллельны или противоположны оси, она равна < 0,0,0 > , поэтому ее необходимо проверить. Если куб вращается неправильным образом, то параметры вектора кросс-продукта находятся в неправильном порядке, я никогда не помню, что и просто попробовать их обоих. НТН.
Edit
У меня была возможность сыграть с Three.js и взломать один из примеров, чтобы сориентировать куб. Комментарии показывают, где я добавил материал, и вся ориентировочная математика происходит в alignCube().
Пример выравнивания и поворота
Смещение вверх/вниз перемещает целевую линию. Мышцы левого/правого вращения на линии.
Объекты сцены в Three.js, кажется, все наследуются от Object3D, у которого свойство autoUpdateMatrix по умолчанию установлено true. Это нужно установить false, иначе будет вызвана функция updateMatrix, которая пересчитывает матрицу из свойств объекта, масштаба и вращения. В качестве альтернативы вы можете назначить другую функцию updateMatrix.
Было бы неплохо, если бы у Three.js была документация:)
Ответ 2
Из примера Trochoid, здесь функция, которую я использую для достижения выравнивания и вращения со второго изображения:
//object, normalized direction vector, rotation in radians
function align(target, dir, rot) {
//Three.js uses a Y up coordinate system, so the cube inits with this vector
var up = new THREE.Vector3(0, 1, 0);
//euler angle between direction vector and up vector
var angle = Math.acos(up.dot(dir));
//cross product of the up vector and direction vector
var axis = new THREE.Vector3();
axis.cross(up, dir);
axis.normalize();
//rotation to aligns the target with the direction vector
var rotate = THREE.Matrix4.rotationAxisAngleMatrix(axis, angle);
//rotation around direction vector
var revolve = THREE.Matrix4.rotationAxisAngleMatrix(dir, rot);
//compose the rotations (order matters, can be done other ways)
revolve.multiplySelf(rotate);
//assign matrix (autoUpdateMatrix = false)
target.matrix = revolve;
}
Ответ 3
Поскольку у нас нет действительно хорошего решения, я могу хотя бы советовать вам, как приблизиться.
Есть 3 возможные проблемы, и у вас есть один из них:
- Математика неверна, или вы ее не понимаете. (Здесь не должно быть такой проблемы)
- Арифметика с плавающей запятой всегда является проблемой для компьютеров (также не должно быть проблемой, потому что она довольно простая. Если ваша инфраструктура не может предоставить решение, тогда фреймворк не имеет никакого значения для 3d-программирования)
- Вы не используете фреймворк справа
Потому что довольно вероятно, что № 3 в этом случае, попробуйте найти список рассылки или форум поддержки или что-то еще для рамки и поговорить с людьми там. Они должны быть в состоянии объяснить вам, что вы делаете неправильно с их рамками. Затем вернитесь и отправьте решение здесь!