Срабатывание кнопки скрипта в туллбаре в сочетании с Shift 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Срабатывание кнопки скрипта в туллбаре в сочетании с Shift



Содержание

Общие положения скриптинга

Срабатывание кнопки скрипта в туллбаре в сочетании с Shift

Нажмите радиокнопку с Maxscript в командной панели

Если ошибка сравнения чисел и получается false. Maxscript иногда возвращает округлённое значение, а у себя держит это за дробное число с плавающей точкой.

Нажимаем на любую кнопку панели Modify

Помещаем в буфер обмена имя файла и дату в обратном порядке и расширение для архиватора

Запуск внешнего скрипта как функции

Отправляем нажатие клавиш и хоткеев в активное окно (в сам 3dsMax)

Универсальные единые функции подсчёта вершин и полигонов для любого количества и типов объектов.

Как получить дескриптор любой кнопки чтобы нажать её скриптом

Перехват окна на примере STL Import и виртуальное нажатие в нём элементов UI

Функции-“синонимы”

Открытие роллаута на позиции прошлого закрытия

Нормализованные XYZ векторы камеры въюпорта

Функция проверки пуста ли папка

Русский (кириллица) в редакторе MaxScript

Фильтр по классу SplineShape, LinearShape, line

Применение структур.

Универсальные методы работы Edit_Poly и Editable_Poly

Тестовый пример для понимания работы со структурами

Структурой создана зависимость работы одного диалога от состояния другого

Value > MAXWrapper > Node

Viewport Redraw Callback Mechanism

Node Event событий System Коллбэк событий объекта

Сообщения windows.sendMessage, UIAccessor.sendMessage

Разбираемся. Пример. Ссылки

Управление элементами интерфейса 3dsMax.UIAccessor

Делаем окно роллаута “поверх определённого окна”

dialogMonitorOps.getWindowHandle()

radiobuttons

Конвертация текста в число и выполнение текста как кода

Заставим кнопку нажаться автоматически без использования функций

Интерактивность спиннера

Гиперссылка в роллауте

Быстро выделить объекты по имени

Подгрузка функции из файла.

Аббревиатуры

Сортировка массива пузырьком

Пример фильтра нескольких объектов по признаку.

Передаём функции переменную

Битовые массивы. Применение множеств

В битовом массиве проверка наличия элемента вместо finditem

Получение открытых вершн

Получение открытых рёбер

Способ формирования массива

Учимся Скрывать/открывать обновление командной панели Modify при выполнении скрипта

Использование функции полосы прогресса

Устанавливаем позицию вершины под модификатором Edit_Poly

Доступ к объектам и подобъектам под модификатором Edit_Poly

Работа с двумерными массивами.

Меняем местами значение двух переменных

Работа с интерфейсами (свойствами) функций.

Меняем местами подэлементы двумерного массива

Немножко логики и интересный способ присвоения значений переменным.

Работа с внешним текстовым файлом

1) Основные операции с файлом

2) Создание нового файла

3) Открытие файла:

Выполнение следующего кода если не выполнился или выполнился код

и доступ к геометрии

Выделение вершин функцией в Edit_Poly

В рамках улучшения понимания MaxScriptHelp, разбираемся с одним из методов.

А теперь рассмотрим ещё один грамм гранита науки касательно справки MaxScript и использования модификатора Edit_Poly

Организуем структуру

Организуем элемент интерфейса.

Выпадающий свиток dropDownList

PushPrompt. Messagebox. QueryBox

“%”в MaxScript

Рассадка одного объекта на вершины другого объекта

Рассчитывается угол между объектами (повёрнут ли один объект в сторону другого)

Поворачиваем объект с помощью кватерниона

Матрицы трансформаций

Сравнение элементов массивов

Циклы

Массивы

 

 

Общие положения скриптинга

_______________________________________________________________

1) Каждое выражение, которое добавляется в скрипт надо проверять в "песочнице", то-есть вводить выражение в Maxscript Editor с тестовыми параметрами и смотреть, что возвращает листенер.

Ещё раз:

 

ДЛЯ КАЖДОГО

СЛОВА

СТРОКИ кода

НАДО

ПРОВЕРЯТЬ

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

 

Это связано с тем, что очень легко пропустить какой то аргумент, или предположил, что функция максскрипта должна вернуть то что хочешь, а получаешь что то другое. Если каждое выражение в конструкции кода проходит проверку в эдиторе, то проблем не будет. Кроме того, код становится осмысленным, идёт полное понимание того, то происходит в процессе выполнения скрипта и никаких танцев с бубном!

 

2) Скрипт лучше всего писать конструируя его таким образом, что сначала перечисляются сложные функции как модули, из которых потом будет состоять более простенькая конструкция самого скрипта.

 

3) Переменные из тела самого скрипта не передаются функциям, поэтому переменные должны быть объявлены перед функцией, в которой присутствует эта переменная.

Пример:

macroScript...

(

---functions---

fn A_fn = (

aaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaa

)

 

fn B_fn= (

bbbbbbbbbbbbbbbbbbbbb

bbbbbbbbbbbbbbbbbbbbb

bbbbbbbbbbbbbbbbbbbbb

)

 

fn С_fn= (

ccccccccccccccccccccc

ccccccccccccccccccccc

ccccccccccccccccccccc

)

 

---script---

 

if A_fn() then B_fn() else C_fn()

)

 

4) Лишние скобки не нужны и всё следующее перечисленное в скобках не нуждается если:

- это единственная функция с несколькими параметрами, которые эта функция ожидает.

- если это конструкции

if()then()else()

if()then()

if()do()

case <expr> of ()

try()catch()

for () do|collect ()

while()do()

do()while()

5) В функциях можно использовать другие функции, эти другие функции должны располагаться в коде перед (выше) той функции, в которой они будут использоваться. По сути принцип схож с объявлением переменных.

Открытие роллаута на позиции прошлого закрытия

(
global PosRoll_testRoll
if PosRoll_testRoll==undefined do PosRoll_testRoll=[830,240]
try DestroyDialog test_roll catch()
rollout test_roll "test_roll" width:50 height:30
       (
       button OK_btn "ok" width:30 hight:22 align: #center
 
       on test_roll moved pos do PosRoll_testRoll=pos
       on OK_btn pressed do
                   (
                               DestroyDialog test_roll
                  )
      )
CreateDialog test_roll pos:PosRoll_testRoll
)

 

 

_______________________________________________________________

Применение структур.

Универсальные методы работы Edit_Poly и Editable_Poly

Суть в том, что организованы 2 структуры, содержащие одинаковые методы работы с объектами классов Edit_Poly и Editable_Poly, после проверки класса объекта, универсальный метод universal получает свою структуру, после чего синтаксис обращения к объекту получается одинаков и к объектам различных классов можно применять одинаковые строки кода. Это очень полезно с точки зрения организации UI скриптов, где необходимо единообразно увязать все методы в одном элементе.

 

 

obj

universal

edgeSel = #{}

 

struct polyFns -- структура для объекта класса Editable_Poly

       (

                   getVertPos = polyOp.getVert,

                   getEdgeVerts = polyOp.getEdgeVerts,

                   getEdgeSel = polyOp.getEdgeSelection,

                   setEdgeSel = polyOp.setEdgeSelection,

                   getVertsByEdges = polyOp.getVertsUsingEdge,

                   getEdgesByVerts = polyOp.getEdgesUsingVert

      )

 

 

struct polyModFns -- структура для модификатора Edit_Poly

       (

                   fn getListData list = case (classOf list) of (BitArray: list; Integer: #{list}; default: #{});,

                   fn getVertPos obj vert = obj.getVertex vert,

                   fn getEdgeVerts obj edge = #(obj.getEdgeVertex edge 1, obj.getEdgeVertex edge 2),

                   fn getEdgeSel obj = obj.getSelection #Edge,

                   fn setEdgeSel obj edgeList =

                   (

                               obj.setEPolySelLevel #Edge

                               obj.setSelection #Edge #{}

                               obj.select #Edge edgeList

                  ),

                   fn getVertsByEdges obj edgeList vertList:#{} =

                   (

                               edgeList = getListData edgeList

                               obj.getVertsUsingEdge &vertList &edgeList

                               vertList

                  ),

                   fn getEdgesByVerts obj vertList edgeList:#{} =

                   (

                               vertList = getListData vertList

                               obj.getEdgesUsingVert &edgeList &vertList

                               edgeList

                  )

      )          

       fn tryInit =

       (

                   if subObjectLevel == undefined then max modify mode

                   obj = Filters.GetModOrObj()

                   case (classOf obj) of

                   (

                   Editable_Poly: (universal = polyFns(); true)

                   Edit_Poly: (universal = polyModFns(); true)

                   default: (messageBox "This script only works with Edit/Editable_Poly objects."; false)

                  )

      )

tryInit() -- вызов функции проверки

universal.getEdgeSel obj

universal.getEdgesByVerts obj

universal.getVertsByEdges obj

universal.setEdgeSel obj

universal.getEdgeSel obj

universal.getEdgeVerts obj

universal.getVertPos obj

Источник: http://www.scriptspot.com/3ds-max/scripts/heuristic-edge-select

_______________________________________________________________

Тестовый пример для понимания работы со структурами

struct Counter (
       num=0,
       fn up_fn = (num+=1
       num),
       fn down_fn = (num-=1
       num)
)
test=Counter()
test.up_fn()
test.down_fn()
 
test2=Counter()
test2.up_fn()
test2.down_fn()
 
getPropNames test
getProperty test #num
getProperty test #down_fn

 

Источник: http://forums.cgsociety.org/archive/index.php?t-272425.html

_______________________________________________________________

Разбираемся. Пример. Ссылки

 

rollout accessTest "TestDialog"
(
       button one "press"
       checkbutton two "Check"
 
       on one pressed do print "One pressed!"
       on two changed state do
                   (
                   if state == true then
                   (print "check on")
                   else print "check off"
                  )
 
)
createDialog accessTest
-------------------------------------------------------------
-- Нажимаем
RollOutHandle = (windows.getChildHWND 0 "TestDialog")[1]
checkHandle =(windows.getChildHWND RollOutHandle "Check")[1]
VK_RETURN=0x000D -- Сообщение 13 (Enter)

 

-- Коды символов и клавиш http://jquery.page2page.ru/index.php5/Коды_символов_и_клавиш

WM_SETFOCUS=0x0007 -- wm_SetFocus Уведомляет окно о том, что оно получило фокус ввода. http://platonov-andrei.narod.ru/Delphi/WM_HELP/wm_SetFocus.htm

--http://www.opengl.org.ru/books/opengl4_22.html

WM_KEYDOWN=0x0100

--http://www.firststeps.ru/mfc/winapi/keyb/r.php?59

--https://msdn.microsoft.com/en-us/library/windows/desktop/ms646280(v=vs.85).aspx

--http://security-corp.org/programming/25399-chto-imenno-proishodit-kogda-polzovatel-nabiraet-v-adresnoy-stroke-googlecom-chast-1.html

WM_CHAR=0x0102 --Обрабатывалось нажатие клавиши http://www.info.oglib.ru/bgl/5000/137.html

-- Сообщение WM_CHAR содержит код символа клавиши, которая была нажата. http://www.vsokovikov.narod.ru/New_MSDN_API/Keyb_input/notify_wm_char.htm

--Коды виртуальных клавиш http://vsokovikov.narod.ru/New_MSDN_API/Other/virtual_key_code.htm

--код 0D работает и записывается как 0x0D

UIAccessor.sendMessage checkHandle WM_SETFOCUS 0 0
windows.sendMessage checkHandle WM_CHAR VK_RETURN 0

--или
--SendMessage(hWnd, WM_KEYDOWN, VK_RETURN, lParam)

windows.sendMessage checkHandle WM_KEYDOWN VK_RETURN 0

 

--Источник: http://www.scriptspot.com/forums/3ds-max/general-scripting/can-anyone-help-with-checking-a-checkbutton-via-uiaccessor

--http://forums.cgsociety.org/archive/index.php?t-1073040.html

 

http://www.tdoc.ru/c/programming/win32/windows-messages-book.html

http://ideafix.name/wp-content/uploads/stuff/book44.pdf

_______________________________________________________________

Radiobuttons

try DestroyDialog unnamedRollout catch() --пробовать закрыть Rollout, или ничего
rollout unnamedRollout "Untitled" width:160 height:70
(
button btn "Caption" width:40 hight:20 align: #center -- кнопка
radiobuttons ‘rBtn1’ “” labels:#("r1","r2","r3","r4") columns:2 default:1 -- radiobuttons с названием, массивом переключателей, количеством столбцов (columns) и значение по умолчанию
on btn pressed do (print rBtn1.state as string) -- Если нажать кнопку btn, то печатать значение счётчика радиокнопки rBtn1
fn updateButton_fn=(
btn.text=case rBtn1.state of
       (
                   1: "r1"
                   2: "r2"
                   3: "r3"
                   4: "r4"
      )
      ) -- функция обновления текста, в которой используется значение счётчика состояния радиокнопок. Если положение радиокнопок 1, то простой кнопке btn присваивается текст "r1" и т.п.
on rBtn1 changed state do updateButton_fn() -- вызов выше объявленной функции, если состояние (state) радиокнопок (rBtn1) меняется (changed), тогда делать: вызвать функцию updateButton_fn()
)
CreateDialog unnamedRollout -- создать диалог сформированного выше роллаута

 

_______________________________________________________________

Интерактивность спиннера

global tmp=0 -- декларируется временная переменная tmp
try DestroyDialog unnamedRollout catch() -- пробуем [try] закрыть диалоговое окно unnamedRollout (если оно есть), иначе ничего не делать [catch()]
rollout unnamedRollout "Untitled" width:160 height:70
(
CreateDialog unnamedRolloutspinner spn "Caption" range: [0,100,0] pos: [2,2]
on spn button up do print "hello world!" -- после отпускания кнопки спиннера spn делать…
on spn changed arg do tmp=arg - при каждом изменении значения спиннера делать переменную tmp равной значению спиннера.
)

_______________________________________________________________

Гиперссылка в роллауте

try DestroyDialog unnamedRollout catch()
rollout unnamedRollout "Untitled" width:80 height:20
(
HyperLink RolloutName_of_Link "Caption of Link" pos:[2,2] width:100 height:16 address:"http://www.scriptspot.com/" color:(color 0 255 0) hovercolor:(color 255 255 255) visitedcolor:(color 0 0 0)
)
CreateDialog unnamedRollout

 

Свойства:
color - цвет не посещённой ссылки
hovercolor - цвет ссылки при наведении
visitedcolor - цвет посещённой ссылки

 

_______________________________________________________________

 

Подгрузка функции из файла.

В файле C:\\Test.ms записано

fn PrintHello=format “Hello World!”

Вызов в скрипте:

global ExtF

ExtF=(include "C: \\ Test.ms")
PrintHello ()
--А для путей подальше чем c:\
global ExtF
ScriptsFolder=(GetDir #scripts)
ExtF=(include (ScriptsFolder+"Test.ms"))

 

_______________________________________________________________

Аббревиатуры

Открываем файл аббревиатур в MaxScript эдиторе

И записываем туда код по следующему образцу:

Образец оформления Аббревиатур.

Название сокращения = код с явно указанными табуляциями и знаками новой строки.

()=(\n|\n)
comment= /*CommentStart\n|\n*/
fn=fn fn_ arg=(\n|)
mess=messagebox\t"Category: \\ "Custom Scripts\\""
ms=macroScript\tmacroNAME\tcategory:"Custom Scripts"\ttoolTip:""\ticon:#("",1)\n(\n|\n)
roll=try DestroyDialog unnamedRollout catch()\nrollout unnamedRollout "Untitled" width:160 height:70\n(button btn "Caption" width:40 hight:20 align: #center\non btn pressed do (print "1")\n)\nCreateDialog unnamedRollout
for x=for x in ARRAY where ARG do\n(\n\tEXPR\n)
for i=for i = 1 to INTEGER where ARG do\n(\n\tEXPR\n)
if=if EXPR\nthen     EXPR\nelse EXPR
case=case EXPR of =\n(\n\tFACTOR: EXPR\n\tdefault: EXPR\n|)
 
spn=spinner spn "Caption" range: [0,100,0] type: #float fieldWidth:spnW1 align: #right
btn=button btn "Caption" width:wl align: #center
cbtn=checkbutton Cbt "Caption" align: #center
label=label Lbl "Caption" align:#center

 

Потом нажимаем Ctrl+S

и проверяем, вызывая аббревиатуру нажав Ctrl+Shift+R уже в другой вкладке с кодом.

Ещё моменты: на примере записи аббревиатур

fn=fn fn_ arg=(\n|)

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

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

А ещё аббревиатуру можно вызывать, напечатав её и затем нажать Ctrl+Shift+A

_______________________________________________________________

Пример фильтра нескольких объектов по признаку.

findItem (for i=1 to selection.count collect superClassOf selection[i] == shape) false == 0

-- За скобками: найти значение false в массиве, который получится циклом в скобках, сравнить результат поиска с нулём (то есть значение false ищем и не находим если результат поиска есть ноль.), тем самым удостоверяемся что внутри все значения true и проверку все прошли.
Теперь что происходит в скобках: Для каждого элемента i начиная с первого до числа выделенных объектов собрать в массив результаты сравнений каждого элемента по признаку суперкласса, который есть или не есть шэйп. Результатами сравнений получаются как раз булевые значения true/false, которые потом ищем файндитемом.

_______________________________________________________________

Передаём функции переменную

fn createSphere rad wc: (color 0 0 0) = (
Sphere radius:rad wirecolor:wc
)
createSphere 40
createSphere 40 wc: (color 0 200 200)
/*Здесь надо обратить внимание на параметр wc, передаваемый функции в строке объявления функции.*/

_______________________________________________________________

Получение открытых вершн

То есть таких вершин, которые находятся на краю по контуру

Метод для 2010 макса и выше

OpenE=#()
openEdges.Check currentTime selection[1] &OpenE
OpenVert=for e in OpenE collect selection[1].GetEdgeVertex e 1
OpenVert

Получение открытых рёбер

meshop.getOpenEdges <Mesh mesh>

polyop.getOpenEdges <Poly poly>

--------------------------------------------------------------

OpenE=#()

openEdges.Check currentTime selection[1] &OpenE

 

_______________________________________________________________

Способ формирования массива

Кусок выдернут из скрипта, поэтому переменные связаны с рёбрами и вершинами. Но уж пусть лучше с ними будет, чем a и b. Так лучше привыкаешь к синтаксису.

 

theVerts=#() -- создаём пустой массив
index = 1 -- первый индекс этого массива будет равен 1
for i in arVert do -- для каждого элемента i из набора вершин делать
if ($.GetVertexEdgeCount i == 2) do -- если вершине принадлежат 2 ребра то
       (
                   theVerts[index] = i -- первому индексу вначале созданного массива присваивается значение i
                   index += 1 -- индекс увеличиваем на единицу для дальнейшего присвоения ему следующих значений, удовлетворяющих условиям
      )

Внимание! Ещё проще конструкция делает то же самое вот так:

theVerts = for i in arVert where ($.GetVertexEdgeCount i == 2) collect i -- theVerts (новый массив) = для каждого элемента i в массиве arVert где выполняется условие (fnO.GetVertexEdgeCount i == 2), собрать в новый массив каждый i, удовлетворяющий условию

_______________________________________________________________

 

Интересный момент для BitArray массива

Poly объект Teapot при невыделенных рёбрах

Es=$.getselection #Edge -- #{} битовый массив
Es.numberset -- Количество выделенных рёбер 0
Es.count                         -- Всего ребер в объекте, возвращает число 1040
polyop.getNumEdges $ -- Всего ребер в объекте, возвращает число 1040
$.GetNumEdges()   -- Всего ребер в объекте, возвращает число 1040

_______________________________________________________________

И ещё один интересный момент

fn fEs =(Es=$.GetSelection #Edge) as array -- функция с переменной
fEs() -- Возвращает массив as Array

#(6)

Es -- Возвращает битовый массив

#{6}

_______________________________________________________________

Основные операции с файлом

--Создание текстового файла "test.txt" в корне диска "С"
f = createFile "C: \\ test.txt"
--Открытие текстового файла "test.txt" из корня диска "С"
f = createFile "C: \\ test.txt"
--Закрытие текстового файла "test.txt" используя переменную f
close f
--Запуск текстового файла "test.txt" из корня диска "С" сторонней программой, заданной по-умолчанию (Например: блокнот)
ShellLaunch "explorer.exe" "C: \\ test.txt"

 

Примечание: Файл обязательно нужно закрывать командой "close",

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

с редактированием и удалением файла (пока не будет закрыт 3ds Max)

 

Создание нового файла

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

--Запись текста в конце строки

format "Какой-то текст" to:f

Результат повторного выполнения:

"Какой-то текстКакой-то текст"

 

--Переход на следующую строку

"\n" (Например: format "Какой-то текст\n" to:f)

Результат повторного выполнения:

"Какой-то текст

Какой-то текст"

 

--Пример кода полностью:

f = createFile "C: \\ test.txt"
format "The first line \n " to:f
format "The second line \n " to:f
for i = 3 to 6 do
(
format ("Line #" + i as string + " \n ") to:f
)
close f
ShellLaunch "explorer.exe" "C: \\ test.txt"

 

Результат:
“The first line

The second line

Line #3

Line #4

Line #5

Line #6”

 

3) Открытие файла:

f = openFile "C: \\ test.txt" mode:"r+"

 

Есть множество режимов открытия файла (mode:) Основные:

r - чтение

rt - чтение текста

rb - чтение как бинарный код

r+ - чтение и запись (с сохранением содержимого)

w - запись

wt - запись текста (все содержимое удаляется)

wb - запись бинарного кода (все содержимое удаляется)

w+ - чтение/запись текста (все содержимое удаляется)

Внимание! эти атрибуты добавляются с кавычками, как строковые значения!

--Количество символов в файле:
filepos f
--Переход к десятому символу в строке:
seek f 10

 

Примеры кода полностью.

--Замена символов текстом "999999" в третьей позиции:
--(Допустим, в файле есть всего одна строка "The first line")
f = openFile "C: \\ test.txt" mode:"r+"
seek f 3
format "999999" to:f
close f
ShellLaunch "explorer.exe" "C: \\ test.txt"

 

Результат: "The999999 line"

 

--Вставка текста"999999" в третью позицию, без замены:

--(Допустим, в файле есть всего одна строка "The first line")

f = openFile "C: \\ test.txt" mode:"r+"
seek f #eof; maxlen=filepos f; seek f 3
res = readChars f maxlen errorAtEOF: false
seek f 3; format "999999" to:f; format res to:f
close f
ShellLaunch "explorer.exe" "C: \\ test.txt"

 

Результат: "The999999 first line"

 

-- Если файла по указанному пути не существует, то создать его

fPath=”c:\\tmp.txt”
if not doesFileExist fPath do (
       f = createFile fPath
       close f
)

 

Если файл существует, и надо добавлять в него данные, то:

f = openFile fPath mode:"a" -- файл открывается и готов к изменению, об этом говорит параметр “а”

format (“tmp” + \n) to:f -- печатать в файле строку “tmp” и перейти на следующую строку.

close f

 

Пример работы с файлами, скрипт выполняет чтение из файла вершин и выделяет их в объекте сцены 3dsMax

(
Arr = #()
try (s = openFile "c: \\ Vertex_ID_selector.txt") catch()
if (selection.count==1 and s!= undefined) then
       (
       while not eof s do -- пока не есть eof (конец файла s) делать
                   (
                   a = readValue s
                   append Arr a
                  )
       For i=1 to Arr.count do
       Arr[i] += 1
       try(PolyOp.SetVertSelection $ Arr) catch(messagebox("Some ID is not exist"))
       if getCommandPanelTaskMode()!= #modify then (max modify mode)
       subobjectlevel = 1
       redrawViews()
       close ssizeразмер
      )
)

 

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

_______________________________________________________________

Если скрипт выполняет то что нужно, но в каких-то ситуациях выдаёт ошибки, то можно их скрыть вот таким параметром, задаваемым в шапке макроскрипта.

macroScript UserScriptName category:"NewTools" tooltip:"toolName" silentErrors: true

Ну или можно локально сам код организовать с помощью конструкции перехвата ошибокtry () Catch (), по русски это можно понять как

try - пробовать выполнить ()

Catch если возникнет ошибка, тогда выполнять ()

Если при ошибке делать ничего не нужно, то Catch() так и остаётся с пустыми скобками.

_______________________________________________________________

И доступ к геометрии

Здесь рассмотрим такую проблему:

Как проверить изменения геометрии, если возвращаемый результат - есть бестолковое “OK”, причём в любом случае, хоть действия выполнились - хоть не выполнились. Ну и как заставить работать скрипт так, чтобы:

1) была выполнена команда или набор действий,

2) а затем в зависимости от результата выполнения этих действий, выполнялись бы другие задачи

Рассмотрим пример:

При написании скрипта для объекта под модификатором EditPoly была такая проблема, что я не мог получить доступ к геометрии средствами и методами этого самого модификатора EditPoly. Решением оказалось использование свойства.mesh выделенного объекта. Иначе говоря $.mesh даёт доступ к крайнему состоянию сетки после воздействия всех возможных модификаторов и с которым можно работать методами, предназначенными для <mesh> объекта

Код:

gco = modPanel.getCurrentObject()

(MeshCountF0 = getNumFaces $.mesh -- количество полигонов объекта первое состояние (засовываем это в переменную MeshCountF0)

gco.connectEdgeSegments = 1 -- какая то операция, ну в данном случае устанавливает количество рёбер коннекта между рёбрами.

gco.ButtonOp #ConnectEdges -- коннект

MeshCountF1 = getNumFaces $.mesh -- количество полигонов объекта второе состояние (засовываем это в переменную MeshCountF1)

MeshCountF0!= MeshCountF1 -- сравниваем значения переменных,

 РЕЗУЛЬТАТ СРАВНЕНИЯ В ПОСЛЕДНЕЙ СТРОКЕ БЛОКА КОДА - ЕСТЬ ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ ИЛИ РЕЗУЛЬТАТ ВЫПОЛНЕНИЯ ЭТОГО БЛОКА КОДА

) == <bool> и завершаем условный оператор if, сравнивая полученное значение выполняемого блока кода с тем вариантом, который нам необходим для дальнейших действий.

_______________________________________________________________

Выделение вершин функцией в Edit_Poly

Для модификатора Edit_Poly работает функция

setVertSelection <node> [<modifier_or_index>] (<sel_bitarray> | <sel_array>) [name:<name>] [keep:<boolean>]
 Пример
set_Vert=#{1..10}
gco = modPanel.getCurrentObject()
setVertSelection selection[1] gco set_Vert keep:on
)

Источник, как ни странно из методов Mesh Vertex Methods

http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012//index.html?url=files/GUID-90843EC5-AE3A-43EB-9406-A3631DAEADE-1092.htm,topicNumber=d28e386399,hash=WS3ED54CBA79FF2E3D-417FC02312B7835BF26-6B91

_______________________________________________________________

 

Организуем структуру

struct Menu -- в которой перечисляем параметры ЧЕРЕЗ ЗАПЯТУЮ
(
fName = "defscene", -- имя файла
fExt = ".txt", -- расширение файла
savePath = "d:\\", -- путь
 fn GetFullPath = savePath + fName + fExt -- функция, формирования пути
)
-- Используем созданную структуру
global ExporterMenu = Menu() -- присваиваем структуру глобальной переменной
s = ExporterMenu.GetFullPath() -- формирование пути, присвоение его переменной
file_var = createFile s -- создание файла

_______________________________________________________________

Матрицы трансформаций

t1 = $Teapot001

t2 = Teapot()

t2.pos = [0,0,50] -- t2 двигается на 50 по оси Z в глобальных координатах

t2.transform *= t1.transform -- устанавливаем положение и ориентацию t2 к t1

_______________________________________________________________

$.transform = rotateXmatrix <int (угол в градусах)> -- поворот матрицы на угол

$.transform = rotateYmatrix <int (угол в градусах)> -- поворот матрицы на угол

$.transform = rotateZmatrix <int (угол в градусах)> -- поворот матрицы на угол

$.dir -- вектор локальной оси z

$.transform = rotateY $.transform 45 -- поворачивает матрицу относительно начала коорд.

$.transform = rotateYmatrix 45 * $.transform -- локальный поворот

_______________________________________________________________

$.transform -- матрица трансформации

$.transform = matrix3 1 -- единичная матрица (начального положения объекта)

$.transform.scalepart -- только просмотр части масштаба от матрицы трансформации

$.transform.rotationpart -- только просмотр части поворота матрицы трансформации

$.transform.translationpart -- только просмотр части перемещения матрицы трансформации

_______________________________________________________________

$.transform.row4 = [0,0,0] -- на прямую Row4 (строка матрицы) не меняется (результата не будет)

-- отдельные трансфортмации матриц трансформации меняются через переменную

tmpTr = $.transform

tmpTr.Row4 = [110,0,0]

$.transform = tmpTr

_______________________________________________________________

SelEdge = polyop.getEdgeSelection $ as array -- массив выделенных рёбер

polyop.getVertsUsingEdge $ SelEdge as array -- Массив использованных рёбрами вершин

_______________________________________________________________

-- Проверка на принадлежность двух элементов массива элементам другого массива (код проверяте, принадлежит ли пара выделенных рёбер отверстию в геометрии)

compare = false

arrOpenEdges = (polyop.getOpenEdges $) as array -- массив рёбер, принадлежащих дыре в геометрии

SelEdges = (polyop.getEdgeSelection $) as array -- массив выделенных рёбер

 

for i=1 to arrOpenEdges.count do -- от 1 до конца рёбер из числа открытых делать

if SelEdges[1] == arrOpenEdges[i] then -- Если одно ребро из выделенных есть среди открытых рёбер (рёбер дыры) тогда

for j=1 to arrOpenEdges.count do -- от 1 до конца рёбер из числа открытых делать

if SelEdges[2] == arrOpenEdges[j] then (-- Если второе выделенное ребро есть среди рёбер из числа открытых тогда

compare = true -- переменная станет true

exit -- выход из цикла

)

compare -- возвращается результат после выполнения блока или функции для дальнейшей его обработки если это требуется. То есть вместо “OK”, после вычисления блока будет возвращено значение переменной.

_______________________________________________________________

Циклы

Прерываем выполнение нажатием Esc

for k=1 to 1000000 do if not keyboard.ESCpressed then (format "%\n" k)

_______________________________________________________________

-- Цикл Do-While (do выполняются, по крайней мере, один раз. При этом условие не проверяется до тех пор, пока не будет выполнено тело цикла)

(i = 0

do (

   t = teapot pos: [i*20, 0, i*20]

   i = i + 1

  ) while t.pos.x < 101

)

_______________________________________________________________

-- Цикл While-Do (сначала проверяется условие)

(i = 0   

testTrue = true

while testTrue do -- цил работает, получая значение true, поэтому после слова while стоит просто переменная, которая на начало цикла является true.

   (

   t = teapot pos: [i*20, 0, i*20]

   i = i+1

   testTrue = t.pos.x < 101

  )

)

_______________________________________________________________

Массивы

_______________________________________________________________

-- Создан пустой массив и к нему присоединён элемент - целое число 56

mуАrrау = #()

append mуАrrау 56

_______________________________________________________________

-- Сохраняем объекты в массиве и добавляем (append) в массив элемент

c = cylinder pos: [50,0,0]

b = box()

s = sphere pos: [-50,0,0]

objArray = #(c,b,s)

d = donut()

append objArray d

_______________________________________________________________

-- Ещё один способ создать массив из объектов, используя метасимвол "*"

coll = $teapot*

arr = coll as array

_______________________________________________________________

-- Обработка всех элементов массива в цикле

a = #("one", "word", "at", "a", "time")

for i = 1 to a.count do -- для каждого i от 1 до числа элементов массива делать

(print a[i]) -- печатать элемент массива

_______________________________________________________________

-- deleteItem

-- Удаляет элемент массива (в примере удалён элемент массива arr[2] и выведено сообщение с оставшимися элементами)

arr= #(1.0,.55,.3, 2.6)

deleteItem arr[2]

for i = 1 to arr.count do

messagebox (arr[i] as string)

_______________________________________________________________

-- join

-- Функция join объединяет два массива, а также совокупность и массив:

for i = 1 to 3 do

(

sphere()

box()

)

arr = $sphere* as array

join arr $box* -- то есть пишется join, а потом два параметра - два массива

for i = 1 to arr.count do

messagebox arr[i].name

_______________________________________________________________

-- sort

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

sort arr

_______________________________________________________________

arr = #(2.4, 4, 3.2, 1.1)

index = findItem arr 3.2 -- Найденный индекс будет равен 3

messagebox (index as string)

-- Значение 3.3 отсутствует в массиве, поэтому возвращаемый индекс равен 0

index = findItem arr 3.3

messagebox (index as string)

-- findItem

-- возвращает индекс искомого значения. Если искомое значение отсутствует в массиве, функция findItem возвращает 0:

_______________________________________________________________

amax <array> -- максимальное значение массива

amin <array> -- минимальное значение массива

$.max -- максимальное значение габаритного контейнера объекта

$.min -- минимальное значение габаритного контейнера объекта

; -- позволяет записать несколько команд кода в одну строку.

? -- возвращает последний вычисленный результат

_______________________________________________________________

Допустим создан и выделен какой то объект

v = $.pos -- вектор позиции объекта

length v -- длина этого вектора

Содержание

Общие положения скриптинга

Срабатывание кнопки скрипта в туллбаре в сочетании с Shift

Нажмите радиокнопку с Maxscript в командной панели

Если ошибка сравнения чисел и получается false. Maxscript иногда возвращает округлённое значение, а у себя держит это за дробное число с плавающей точкой.

Нажимаем на любую кнопку панели Modify

Помещаем в буфер обмена имя файла и дату в обратном порядке и расширение для архиватора

Запуск внешнего скрипта как функции

Отправляем нажатие клавиш и хоткеев в активное окно (в сам 3dsMax)

Универсальные единые функции подсчёта вершин и полигонов для любого количества и типов объектов.

Как получить дескриптор любой кнопки чтобы нажать её скриптом

Перехват окна на примере STL Import и виртуальное нажатие в нём элементов UI

Функции-“синонимы”

Открытие роллаута на позиции прошлого закрытия

Нормализованные XYZ векторы камеры въюпорта

Функция проверки пуста ли папка

Русский (кириллица) в редакторе MaxScript

Фильтр по классу SplineShape, LinearShape, line

Применение структур.

Универсальные методы работы Edit_Poly и Editable_Poly

Тестовый пример для понимания работы со структурами

Структурой создана зависимость работы одного диалога от состояния другого

Value > MAXWrapper > Node

Viewport Redraw Callback Mechanism

Node Event событий System Коллбэк событий объекта

Сообщения windows.sendMessage, UIAccessor.sendMessage

Разбираемся. Пример. Ссылки

Управление элементами интерфейса 3dsMax.UIAccessor

Делаем окно роллаута “поверх определённого окна”

dialogMonitorOps.getWindowHandle()

radiobuttons

Конвертация текста в число и выполнение текста как кода

Заставим кнопку нажаться автоматически без использования функций

Интерактивность спиннера

Гиперссылка в роллауте

Быстро выделить объекты по имени

Подгрузка функции из файла.

Аббревиатуры

Сортировка массива пузырьком

Пример фильтра нескольких объектов по признаку.

Передаём функции переменную

Битовые массивы. Применение множеств

В битовом массиве проверка наличия элемента вместо finditem

Получение открытых вершн

Получение открытых рёбер

Способ формирования массива

Учимся Скрывать/открывать обновление командной панели Modify при выполнении скрипта

Использование функции полосы прогресса

Устанавливаем позицию вершины под модификатором Edit_Poly

Доступ к объектам и подобъектам под модификатором Edit_Poly

Работа с двумерными массивами.

Меняем местами значение двух переменных

Работа с интерфейсами (свойствами) функций.

Меняем местами подэлементы двумерного массива

Немножко логики и интересный способ присвоения значений переменным.

Работа с внешним текстовым файлом

1) Основные операции с файлом

2) Создание нового файла

3) Открытие файла:

Выполнение следующего кода если не выполнился или выполнился код

и доступ к геометрии

Выделение вершин функцией в Edit_Poly

В рамках улучшения понимания MaxScriptHelp, разбираемся с одним из методов.

А теперь рассмотрим ещё один грамм гранита науки касательно справки MaxScript и использования модификатора Edit_Poly

Организуем структуру

Организуем элемент интерфейса.

Выпадающий свиток dropDownList

PushPrompt. Messagebox. QueryBox

“%”в MaxScript

Рассадка одного объекта на вершины другого объекта

Рассчитывается угол между объектами (повёрнут ли один объект в сторону другого)

Поворачиваем объект с помощью кватерниона

Матрицы трансформаций

Сравнение элементов массивов

Циклы

Массивы

 

 

Общие положения скриптинга

_______________________________________________________________

1) Каждое выражение, которое добавляется в скрипт надо проверять в "песочнице", то-есть вводить выражение в Maxscript Editor с тестовыми параметрами и смотреть, что возвращает листенер.

Ещё раз:

 

ДЛЯ КАЖДОГО

СЛОВА

СТРОКИ кода

НАДО

ПРОВЕРЯТЬ

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

 

Это связано с тем, что очень



Поделиться:


Последнее изменение этой страницы: 2021-04-13; просмотров: 124; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.12.36.30 (0.592 с.)