Пробуем силы в MaxScript

Моим первым скриптом в 3DMax’е была стена по уроку Марины Бондаренко (можно найти в Вконтакте в их группе), но это не самостоятельная работа, а просто переписывание. С этим все понятно, но я хотел бы рассказать про собственный опыт.

Идею я почерпнул на сайте render.ru, из «откровений чайника»: создание петлей из сфер, но обо всем по-порядку. Я не буду разбирать здесь базовые знания из разряда «открыть редактор MaxScript», синтаксиса и прочего; а буду писать то, что, по моему мнению, может действительно вызвать вопросы или вызвало вопросы у меня, после чего пришлось «курить мануал».

Необязательное пояснение
Наконец-то запись, ради которой и создавался этот блог — для распространения своего опыта программирования в MaxScript. Информации на русском языке, которая удовлетворила бы меня полностью, я не нашел, поэтому решил сделать сам. Все полезные использованные ссылки будут приведены в конце статьи. Если вы знаете стоящие ресурсы по MaxScript на русском/английском языке кроме мануала, оставляйте их в комментариях с кратким описанием, что это (сборник примеров/учебник/так далее). Спасибо

Начальный этап

Идея есть, но ее надо разбить на составляющие. На старте необходимо научится хотя бы создавать сферы. Это делается довольно просто:

Код
Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
Разберем строку: слово Sphere здесь — это команда на создание примитива, все, что идет дальше — параметры создаваемого примитива. Радиус, сглаживание, количество сегментов и прочее (некоторые параметры я сам не знаю зачем, т.к. копипастил этот кусок кода, но все можно найти в мануале), а так же координаты, которые у меня указаны через переменные.

Хорошо, умеем создавать сферы, а дальше то что? Чтобы создать сфер нужное количество, следует запустить цикл. Выглядит это так:

Код
for i=1 to <Spheres_count> do ( —вместо <Spheres_count> ставим целочисленную переменную или констатну
 spheres[i] = Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
)

Данный код не будет работать, т.к. не определены переменные x,y,z. Нетрудно догадаться, что каждая переменная отвечает за свою ось. Раз мы хотим сделать замкнутые петли, то нас устроят тригонометрические функции. В данном случае я использовал синусы:

Код
for i=1 to <Spheres_count> do (
 x=sin (i-1) as float
 y=sin (i-1) as float
 z=sin (i-1) as float
 Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
)

Как видно, x=y=z, а, следовательно, это будут не петли, а прямая, причем очень плотная (сферы радиусом пять в прямой линии от [-1,-1,-1] до [1,1,1]). К тому же, функция sin в MaxScript принимает значения в градусах, и тогда при значении сфер больше 91 они начнут накладываться сами на себя. Попробуем немного модифицировать код и запустить:

Код
for i=1 to 20 do (
 x=sin (i-1)*50 as float
 y=sin (i-2)*50 as float
 z=sin (i-3)*50 as float
 Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
)

И вот результат:

ScriptFail

 

Второй этап

То есть особо-то ничего не поменялось. И вот тут пора что-то кардинально менять. А именно превращать прямую в кривую, да еще и замкнутую. То есть нужно сделать так, чтобы все шары были распределены на 360 (720/1080/и т.д.) градусов по каждой оси, да еще и с разными координатами! На помощь приходит математика (я пропускаю все свои выводы, не об этом пост) и я получаю следующий код:

Код
stepX = 360*spn8.value/(spn4.value-1) as float
stepY = 360*spn9.value/(spn4.value-1) as float
stepZ = 360*spn10.value/(spn4.value-1) as float
for i=1 to spn4.value do (
 x=sin ((i-1)*stepX)*spn5.value as float
 y=sin ((i-1)*stepY)*spn6.value as float
 z=sin ((i-1)*stepZ)*spn7.value as float
 Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
)

Чтобы было не страшно, поясняю: spnX.value — значения бегунков в окошке скрипта, о них позже. Сейчас разберемся с математикой:

Переменные с названием step — шаги в градусах для каждой создаваемой сферы по каждой оси, зависящие от количества петлей по этой и количества создаваемых шаров. Таким образом, они распределяются равномерно по всей длине наших петель. Чтобы было понятно, вот результат запуска скрипта с параметрами: 300 сфер, разбросы координат по осям по 100 в каждую сторону от нуля, 1 петля по X, 2 по Y и 3 по Z

ScriptAtWork

 

Создаем интерфейс

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

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

Статья получилась и так не маленькая, переходим к сути. Код интерфейса и его скриншот (функцию анимации рассматривать здесь я не буду, т.к. не до конца разобрался, как это работает):

Код
rollout TrigSpheres "TrigSpheres" width:162 height:342
 (
  button btn1 "Create Spheres" pos:[11,256] width:144 height:31
  spinner spn4 "N spher" pos:[19,5] width:140 height:16 range:[0,1000,300] type:#integer 
  spinner spn5 "Razbros X" pos:[17,102] width:140 height:16 range:[0,1000,100] type:#integer 
  spinner spn6 "Razbros Y" pos:[16,123] width:140 height:16 range:[0,1000,100] type:#integer 
  spinner spn7 "Razbros Z" pos:[17,146] width:140 height:16 range:[0,1000,100] type:#integer 
 
  spinner spn8 "2N voln po X" pos:[17,173] width:140 height:16 range:[0,10,2] type:#integer
  spinner spn9 "2N voln po Y" pos:[18,199] width:140 height:16 range:[0,10,2] type:#integer
  spinner spn10 "2N voln po Z" pos:[19,224] width:140 height:16 range:[0,10,2] type:#integer
  button btn3 "Animate" pos:[12,297] width:143 height:34
 
  on btn1 pressed do
   (
   global spheres = #()
   global sp4 = spn4.value
   global sp5 = spn5.value
   global sp6 = spn6.value
   global sp7 = spn7.value
   stepX = 360*spn8.value/(spn4.value-1) as float
   stepY = 360*spn9.value/(spn4.value-1) as float
   stepZ = 360*spn10.value/(spn4.value-1) as float
   print stepX
   print stepY
   print stepZ
   for i=1 to spn4.value do
    (
    x=sin ((i-1)*stepX)*spn5.value as float
    y=sin ((i-1)*stepY)*spn6.value as float
    z=sin ((i-1)*stepZ)*spn7.value as float
    spheres[i] = Sphere radius:5 smooth:on segs:8 chop:0 slice:off sliceFrom:0 sliceTo:0 mapCoords:off recenter:off pos:[x,y,z]
    select spheres
    )
  )
)
createDialog TrigSpheres

ScriptGui

Разберем код по составляющим. Ключевое слово rollout создает свиток интерфейса (окошко) со всем своим нутром, счетчиками, кнопками и прочим. Дальше идут строчки, отвечающие за создание счетчиков и кнопок, после чего идет описание функций, которые должны быть вызваны на то или иное событие (в данном случае — на нажатие первой кнопки). Код для нажатия третьей кнопки не привожу.

Почему я подписал «2N волн по оси»? Потому что 360 градусов в функции синуса дает две волны — в одну, и другую сторону относительно нуля. Разброс по осям — уже писал, от [-число] до [+число].

Нюанс, который вызвал затруднения у меня: массивы. В данном случае я объявляю глобальный массив сфер spheres, а потом каждому элементу массива ставлю в соответствие свежесозданную сферу. (Кстати, строчку select spheres стоит вынести за пределы цикла, пока писал статью, доперло)

Да, знаю, глобальные переменные использовать ай-ай-ай, но я не осилил, как здесь можно по-другому. Буду благодарен за советы.

Надеюсь, данная статья поможет чем-то и вам.

Использованные и полезные ссылки
Те самые «откровения чайника» на render.ru — ссылка

Теория MaxScript на русском — ссылка

Официальная справка по MaxScript — ссылка

Группа по MaxScript в ВК — ссылка

 

Обсуждение: есть 1 комментарий

  1. Shishlena:

    Шикарный пост, спасибо! А я лет 6 назад открыла 3dmax… и закрыла. К сожалению. Но благодаря тебе, возможно, начну все с начала

Добавить комментарий

© 2022 CAsperovskii BLOG.RU // Дизайн и поддержка: GoodwinPress.ru