Вращение векторов и объектов в MaxScript


Вращение в MaxScript - пожалуй одно из самых загадочных преобразований. Использование кватернионов только усиливает впечатление (для любознательных - см. статью в Википедии). В справке по MaxScript сначала написано достаточно просто: кватернион состоит из угла поворота (скалярная часть) и направления оси поворота (векторная часть) - вроде все понятно. Следующее предложение интереснее: если кватернион нормализован, то скалярная часть равна косинусу половины угла поворота, а векторная часть - есть ось вращения, а длина вектора оси равна синусу половины угла поворота. Т.е. когда смотришь в окне консоли (Listener) на значение нормализованного кватерниона, то сии циферки, кроме тривиальных случаев, не вызывают никаких ассоциаций. Например, (quat 0 0 0.258819 0.965926) означает всего навсего поворот на 30° вокруг оси Z. Не буду спорить, что алгебра кватернионов - штука мощная и полезная как в вычислительном плане, так и для получения "сглаженного и естественного движения", но для человеческого разума - совершенно неудобоваримая.

Дополнительной пикантности придает путаница с положительным направлением поворота относительно оси: везде в Максе используется правая система, а при работе с матрицей трансформации - левая. (Для запоминания: сожмите руку в кулак и вытяните большой палец - большой палец указывает направление оси, а остальные - положительное направление поворота.)

 

 

Далее представлены плоды моих изысканий в данной области. Целью было понять, как в MaxScript выполнить поворот вектора или объекта на заданный угол относительно заданной точки. Поэтому некоторые моменты, связанные с наследованием трансформаций, координатными системами и т.п. просто не учитывались.

Скрипт состоит из трех функциональных частей:

  1. вращение вектора (значение типа point3) вокруг указанного центра и визуализация его конечного положения в виде объектов Point (помечено красным цветом);
  2. вращение объекта Point при помощи конструкции about ... rotate (помечено синим цветом);
  3. вращение объекта, аналогичное использованию конструкции about ... rotate, посредством присваивания свойствам pos и rotation соответствующих значений (помечено зеленым цветом).

В каждой части имеется цикл, в котором переменная a принимает значения от 0° до 150° с шагом 30°. Использование конечного значения 150° позволяет лучше видеть начальное и конечное положение, а также направление поворота.

Остальные комментарии - в теле скрипта. Если редакторе MaxScript кириллица отображается некорректно, то в файле <maxroot>/MXS_Editor.properties необходимо заменить значение code.page на 0 (вместо -1) и перезапустить 3ds Max.

В результате работы скрипта должна появиться вот такая картинка:


-- Проверка вращения вектора относительно произвольной точки

undo "rotationTest" on (

pt = [50, 0, 0]         -- вектор
center = [50, 50, 0]    -- центр вращения
axis = [0, 0, 1]        -- ось вращения (Z)

-- при использовании матрицы вращения
-- происходит левый поворот (против часовой стрелки)

for a = 0 to 150 by 30 do (                 -- угол вращения
	q = quat a axis                          -- кватернион: поворот на угол a относительно положительного направления оси Z
	rm = q as matrix3                        -- преобразуем кватернион в матрицу вращения
--	rm = inverse rm                          -- инвертировать матрицу поворота для правого поворота (по часовой стрелке)
											 -- этот оператор должен стоять ДО задания цетра поворота
	rm.row4 = center                         -- четвертая строка матрицы - задаем центр вращения
	rotpt = pt * rm                          -- поворачиваем вектор
	point pos:rotpt box:true wirecolor:red   -- создаем объект Point в текущем положении повернутого вектора
                                            -- здесь вращаем только вектор, объект создается без поворота
	format "a = % rotpt = %\n" a rotpt       -- выводим лог в Listener
)


-- при использовании конструкции about ... rotate
-- происходит правый поворот (по часовой стрелке)

pobj = point pos:(pt + center) box:true wirecolor:blue name:"rotPoint00" size:15
for a = 0 to 150 by 30 do (                 -- угол вращения
	npobj = instance pobj                    -- создаем инстанс объекта Point
	npobj.wirecolor = blue
	q = quat a axis                          -- кватернион: поворот на угол a относительно положительного направления оси Z
	about center rotate npobj q              -- поворачиваем объект вокруг заданного центра на текущий угол
)
delete pobj                                 -- удаляем исходный объект


-- поворот объекта, аналогичный использованию конструкции about ... rotate,
-- посредством присваивания свойствам pos и rotation соответствующих значений

pobj = point pos:pt box:true wirecolor:green name:"rotmatrixPoint00" size:10
for a = 0 to 150 by 30 do (                 -- угол вращения
	npobj = instance pobj                    -- создаем инстанс объекта Point
	npobj.wirecolor = green
	q = quat a axis                          -- кватернион: поворот на угол a относительно положительного направления оси Z
	rm = q as matrix3                        -- преобразуем кватернион в матрицу вращения
	rm = inverse rm
	rm.row4 = center                         -- четвертая строка матрицы - задаем центр вращения
	npobj.pos *= rm                          -- поворачиваем объект вокруг заданного центра на текущий угол (без вращения самого объекта!)
	in coordsys (transmatrix npobj.pos) npobj.rotation = q -- поворачиваем сам объект вокруг пивота на текущий угол
)
delete pobj                                 -- удаляем исходный объект

) -- undo

© Black Sphinx, 2009. All rights reserved. Counter
Хостинг от uCoz