ПрограммированиеПодсказкиФизика

Создание собственного материала для геометрии коллизии с помощью MAX Script

Автор:

Немного предистории. Поскольку наша команда писала свой игровой движок, постепенно развивая его, у нас появилась необходимость создать геометрию коллизии игрового мира. Но создать её — это одно дело, другое дело было наложить на неё соответсвующий материал и экспортировать саму геометрию с привязанными материалами и их флагами.

В этой части статьи мы рассмотрим, как при помощи MAX Script и 3DS Max 2016 мы можем создать простой материал, который можно было бы применить к геометрии коллизии.

Для начала ознакомимся с базовой документацией, которая нам понадобится для создания подобного скрипта.

В MAX Script Help в поиске, забив Scripted Plug-ins, вы сможете найти саму базу, которая относится к разным плагинам и более детальное описание. Элементы, например как:
  plugin <superclass> <varname>,
  name:<string>, classID:#(<int>,<int>)

и другие подробно описаны, что и для чего они предназначены в данном документе.

Далее также необходимо ознакомиться с частью документации Scripted Plug-in Clauses, где есть полезная информация о вставных положениях в скрипте.

На основе полученной информации из документации по MAX Script приступим к написанию самого скрипта — материала.

Начало скрипта начинается с “plugin <superclass> <varname>”, которая по сути является общей формой для любого скриптового плагина.
Где:
<superclass> является одним из поддерживаемых модулей 3DS Max.
<varname> имя, которое будет присвоено к глобальной переменной, которая содержит в себе данный плагин класс.

Поскольку наш скрипт относится к материалам, то наш «супер класс» логично будет materials.

Название переменной мы выберем “TUT_COL_MAT”, из этого выходит следующее:
plugin material TUT_COL_MAT

Следуйщий элемент, который нам понадобится, это само название “name:<string>”, которое будет представлять наш материал в интерфейсе 3DS Max:
name:”Engine Collision Materials”

Следующий элемент classID, который очень важен для правильной работы плагина, чтобы он мог быть создан и сохранён в сцене. Также ID, присвоенный к плагину, будет постоянной его ID и будет использован 3DS Max для идентификации объектов, которые были сохранены и загружены в сцену с данным ID. Для генерации подобного ID можно воспользоваться встроенной функцией в 3D Studio MAX genClassID(), прописав её в Listener (примените горячую клавишу F11 для вызова или пройдите по адресу Scripting и нажмите на MAXScript Listener …), будет сгенерирован случайный ID, который мы можем использовать в нашем скрипте.

genClassID()
#(0x19cabdb1, 0x6be0eed3)
OK

В нашем скрипте мы добавляем следующую строку:
classID:#(0x19cabdb1, 0x6be0eed3)

Следующий параметр – блок с последующими параметрами, которые нам понадобятся в разработке:
extents:<maxClass> replaceUI:<boolean> version:<integer>.

extents:<maxClass> нужен в том случае, если необходимо базировать плагин на уже существующем плагине. Мы будем базировать плагин на Standard Material классе.

replaceUI:<boolean> понадобится для того, чтобы заменить оригинальный интерфейс класса Standard Material на наш, который нам предстоит создать.

version<integer> нужен для обозначения версии плагина, оно же используется для обновления определений скрипта.

То есть в нашем случае строка будет выглядеть следующим образом:
extends:Standard replaceUI:true version:1

Весь скрипт в сборе, который на данный момент имеется:

plugin material TUT_COL_MAT
name:"Engine Collision Materials"
classID:#(0x19cabdb1, 0x6be0eed3)
extends:Standard replaceUI:true version:1
(
)

В блок скобок будет занесён наш основной код материала. Начинка будет состоять из нескольких компонентов, в начале мы определим все локальные переменные и методы, дальше будет компонент с параметрами плагина, за которым будет следовать компонент “rollout”, ну и в конце скрипта у нас будут размещены обработчики сообщений.

Продолжаем, из локальных переменных и методов нам потребуется пока что только один, который будет возвращать лист элементов-типов материала, который будет необходим для графического элемента dropDownList.

fn getColMaterialTypes =
(
return #("M_ASPHALT", "M_GRASS", "M_CONCRETE", "M_WOOD") 
)

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

parameters <name> [rollout:<name>] 
( 
{ <param_defs> }+ 
{ <event_handler> } 
)

Немного подробностей о значении данных элементов.
<name> название, которое будет ассоциировано с блоком параметров, в MAX Script используется для того, чтобы подключиться к параметру в объекте плагина, который загружается из сцены.
[rollout:<name>] указывает на определение графического интерфейса в другом месте в плагине, чтобы графический интерфейс мог бы быть использован, в связи с параметрами блока.

Мы из этого сформируем следующую часть скрипта:
parameters main rollout:mainRollout

Дальше необходимо заполнить блок параметров параметрами материала.

В данном случае нам понадобятся 3 главные вещи: цвет, который будет накладываться на геометрию коллизии, чтобы было проще различать разные материалы, сам тип материала — индекс его <integer>, а также мы добавим еще один параметр.

И получаем мы вот такую структуру параметров:

parameters main rollout:mainRollout
(
  M_COLOUR  type:#color default:[64,64,64] ui:cp_colour
  M_MAT_TYPE type:#integer ui:cb_dropDL
  M_FLAG_PROPS type:#boolean ui:cb_props
  color type:#color ui:cp_colour
  on color set val do
  (
    delegate.diffuse_color = val
  )
)

Теперь предстоит создать сам rollout, другими словами графическую часть данного плагина.

rollout mainRollout "Collision Parameters"
(
  Group "Surface Material:" 
  (
    colorPicker cp_colour "Material Color" pos:[15,25] width:120 height:20 enabled:true
    dropDownList cb_dropDL "Material List" pos:[15,50] width:141 height:40 items:([i]getColMaterialTypes()[/i])
  )
  
  Group "Surface Material Properties:" 
  (
    checkbox cb_props "Generate Props" pos:[15,120] width:107 height:15 enabled:true tooltop:"Generates props on this surface."
  )
  
  on mainRollout open do
  (
    if cb_dropDL.items.count > 1 and cb_dropDL.selection == 0 do
    (
      cb_dropDL.selection = 1
    )    
  )
)

Пару слов о том, что выше представлено. Элементы настроек разделены на группы “Surface Material” и “Surface Material Properties”, это сделано для удобства в работе с материалом, конечно, в больших проектах будет больше настроек, в данном материале представлен только один дополнительный флаг (checkbox cb_props) в целях демонстрации.

Для каждой локальной переменной ui:<variable name> есть свой графический элемент.

Насчёт функции getColMaterialTypes() — возможно она и не нужна была бы, но она была добавлена для того, чтобы показать, как можно использовать отдельный метод для возврата массива элементов.

Последние, что остаётся добавить, это обработчики событий и их только два в нашем случае:

on create do 
 ( 
  this.name = delegate.name; 
  this.color = [64,64,64]
)
  
on load do 
(
  this.name = delegate.name;
)

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

Конечно, это довольно простой скрипт материала, я надеюсь, что он даёт общее представление о создании подобного плагина.

Есть еще две полезных команды, которые могут пригодиться:
getFilenamePath(<string – full file path>) возвращает путь к файлу, но без его названия и расширения.
getThisScriptFilename() возвращает полный путь скрипта.

Объединив эти функции, можно получить путь папки, где лежит сам скрипт. Таким образом, если некий файл, который содержит настройки материалов, лежит около скрипта, можно запросто получить его полный путь, и дальше его загрузить с помощью нашей функции: “getColMaterialTypes()”.
getFilenamePath(getThisScriptFilename()) + “materials.txt”

Полный код:

plugin material TUT_COL_MAT
name:"Engine Collision Materials"
classID:#(0x19cabdb1, 0x6be0eed3)

extends:Standard replaceUI:true version:1
(
  fn getColMaterialTypes =
  (
    return #("M_ASPHALT", "M_GRASS", "M_CONCRETE", "M_WOOD") 
  )
  
  parameters main rollout:mainRollout
  (
    M_COLOUR       type:#color default:[64,64,64]   ui:cp_colour
    M_MAT_TYPE    type:#integer              ui:cb_dropDL
    M_FLAG_PROPS  type:#boolean              ui:cb_props
    
    color      type:#color                  ui:cp_colour
    on color set val do
    (
      delegate.diffuse_color = val
    )
  )

  rollout mainRollout "Collision Parameters"
  (
    Group "Surface Material:" 
    (
      colorPicker cp_colour "Material Color" pos:[15,25] width:120 height:20 enabled:true
      dropDownList cb_dropDL "Material List" pos:[15,50] width:141 height:40 items:(getColMaterialTypes())
    )
    
    Group "Surface Material Properties:" 
    (
      checkbox cb_props "Generate Props" pos:[15,120] width:107 height:15 enabled:true tooltop:"Generates props on this surface."
    )
    
    on mainRollout open do
    (
      if cb_dropDL.items.count > 1 and cb_dropDL.selection == 0 do
      (
        cb_dropDL.selection = 1
      )    
    )
  )
  on create do 
  ( 
    this.name = delegate.name; 
    this.color = [64,64,64]
  )
    
  on load do 
  (
    this.name = delegate.name;
  )
)
+ Показать

#3D Studio MAX, #bullet physics, #collision, #MAX Script, #физика, #скрипты

17 января 2017

Комментарии [3]