3D Engineering

...Лучшее из общего.

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Экономичная и экологическая оценка танкера двойного действия


Нажмите что бы увеличить

OKHOTSK SEA & SEA ICE, MOMBETSU, JAPAN, 24-28.2.2002

Подробнее...
 

3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 3: Анатомия человека

Леонардо да Винчи сказал, "Высшая неудача - это когда теория опережает выполнение." Хотя эта книга стремится быть практическим руководством, есть некоторые предположения о человеческой анатомии, которые должны быть обсуждены в более аналитической манере. Хотя в этой главе и рассматривается анатомия, она не претендует быть полным исследованием по этой теме. Целые книги написаны об этом предмете. Они должны служить более подходящими руководствами для серьезного студента отделения гуманитарных наук, желающего глубокого изучать анатомию.

Подробнее...
 

Peter Ratner 3-D HUMAN MODELING AND ANIMATION 2nd Edition 3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 1: Основы техники моделирования

Точно так же как ребенок, каждый должен сначала научиться ползать, прежде чем сможет ходить. Это же относится и к трехмерному моделированию.

Подробнее...
 

3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 2: Техника моделирования среднего уровня

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

Подробнее...
 

PДДSTESEADMETE- JA VAHENDITEGA SEOTUD LEPPEMДRGID


mida kasutatakse kooskхlas Rahvusvahelise konventsiooni

inimelude ohutusest merel (SOLAS 1974/1978) reegliga III/9.2.3

Подробнее...
 


Страница 1 из 31

Архив статей

 Янв   Февраль 2012   Мар

ВПВСЧПС
   1  2  3  4
  5  6  7  8  91011
12131415161718
19202122232425
26272829 
Julianna Willis Technology

Случайная новость

vladirr

Привет всем! Вот и решился я снова потревожить ваш покой. Пойдем мы, как говорится - ab ovo, то бишь от постановки яйц... тьфу, задачи. :)

Те, кто занимался низкополигональным моделированием, особенно если занимались не только в качестве хобби, знают две очень полезные утилиты - Summary Info (вызывается последовательным нажатием ALT+F+U, дает полную информацию о составе и объектах сцены) и PoligonCounter (по умолчанию - клавиша Q/(в пятой версии - клавиша 7), показывает количество вершин и фейсов для выделенного объекта). В принципе - этого вполне достаточно, чтобы контролировать процесс моделирования... но лично мне неудобно с ними работать - а потому приступим...

Сегодняшний урок достаточно прост, поскольку несет нагрузку не учебную, а абсолютно практическую - мы попытаемся сделать так, чтобы нужная нам при работе информация всегда находилась перед глазами, а не где-то там, куда добираться 15 вест, зимой и в гору :) На кого расчитан данный урок? Я подразумеваю, что вы в состоянии самостоятельно открыть окно MaxScriptListener, не задавая вопросов что это такое (ну в крайнем случае - подсмотрев в справке :)), создать объект, выделить его и снять выделение, обнулить/перезапустить 3dsmax (да простят меня разработчики, но в дальнейшем я буду называть его просто "максом" )... ну и еще умение печатать без ошибок :)... вроде все, поскольку теорией мучить сегодня я не буду, кто хочет - сам найдет, а кто не хочет... думаю все понятно.

Для начала определимся, что же мы хотим видеть?
Нас интересуют в общем-то только два параметра - количество фейсов в сцене вообще, и количесво их же, но у редактируемого в данный момент объекта. Но поскольку при работе с конкретным объектом некоторые особо продвинутые товарищи предпочитают видеть еще и количество вершин в нем, то, что же делать - дадим им такую возможность :). Итак, мы должны получить в конечном итоге три следующие строки:

SelectObj Vertex= ###
SelectObj Face =###
Scene Face = ###

Задача поставлена, соответственно - половина дела сделана.

Переходим к решению.

Во первых, у нас сразу же есть проблема - тот же PolygonCounter имеет небольшой недочет - при выделении сплайнового объекта он начинает показывать количество вершин и полигонов для этого объекта, исходя из преобразования данного сплайна в mesh - объект. Не знаю, какой логикой пользовались создатели данного скрипта, но для нужд низкополигонального моделирования она не подходит - даже если в процессе создания модели и используются сплайны, то только как вспомогательные объекты, ну а при переводе данного объекта в вид редактируемого mesh-а любой нормальный моделлер сократит количество полигонов получаемого объекта до минимума. Эрго - данная информация нам просто не нужна, а в некоторых случаях даже вредна, поскольку дает искаженное представление о состоянии сцены. Ввиду вышесказанного все сплайновые объекты мы с вами должны будем просто проигнорировать в нашем алгоритме, для чего ввести соответствующее условие выбора. А поможет нам в этом метод Category, возвращающий категорию выбранного объекта.

Обнулите макс, создайте в нем бокс как представителя класса геометрических объектов, и окружность, как представителя класса спрайновых объектов. Нажмите клавишу Q/7 (либо другим способом запустите PolygonCounter) и выделите сначала бокс, а потом окружность. Наблюдая за значениями количества фейсов убедитесь в наличии ошибки алгоритма. Для полной уверенности можно так же взглянуть на Summary Info - этот алгоритм не учитывает полигоны для сплайнов - и правильно делает :)
Убедились? Будем лечить... Открываем окно MaxScriptListener и в нижнем поле вводим:

$Circle01.category (Circle01 - имя нашей окружности, если у Вас не совпадает, подставьте свое)

Жмем Enter (на цифровой панели!) и получаем в том же окне ответ:

#Splines

Все верно, это у нас сплайн :)
Однако сейчас мы указали объект напрямую, через его имя, но делать это постоянно мы не можем, потому воспользуемся тем фактом, что данный объект выделен, следовательно - может быть вызван с помощью метода $selection
выделен у нас при работе один объект, следовательно он будет первым и единственным элементом массива, представляющего выделение. Для проверки введем:

$selection.count - мы запрашивает количество элементов массива

после ввода получаем ответ

1 - мы получили число элементов выделения, как ни удивительно, но оно и правда равно еденице :) Вводим:

$selection[1] - доступ к первому элементу массива, жмем enter, получаем ответ:
-----------------
$Circle:Circle01 @ [-11.532874,-35.139202,0.000000] - в квадратных скобках - положение опорной точки в пространстве, у Вас, естественно - другие значения...

Убедились, что первый элемент выделения при условии, что выделен один объект - сам этот объект, теперь можем смело требовать доступа к его свойствам, в частности - узнавать его категорию:

$selection[1].category
----------------
#Splines

выделим бокс, и повторим ввод, для чего мышкой установим курсор в окне MaxScriptListener на ту же строку и снова нажмем enter (для выполнения операции, вводимой с клавиатуры нажимать enter нужно именно на цифровой панели).

$selection[1].category
----------------------------------
#Standard_Primitives

как видно, данный способ позволяет определить категорию выделенного объекта.

теперь определимся с фейсами-вершинами... для получения такой информации воспользуемся методом getPolygoncount, возвращаюшим массив из двух элементов - количество фейсов, и количество вершин:

getPolygoncount $selection[1]
----------------------------------------------
#(12, 8)

Ну это уже практически все :)

наша задача теперь выглядит следующим образом - убедиться, что выбранный объект не является сплайном, и если это условие истинно, то показать количество фейсов и вершин. Отмечу только, что в максе сплайновый объект может быть представлен в виде собственно сплайна - $Splines и в виде шейпа - редактируемой плоской формы... поскольку для нас в данном случае это едино, то условие придется делать двойное:

if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
)
else
(
getPolygoncount $selection[1]
)

Мы указали, что если выделенный объект является плоской формой, то ничего делать не надо, в противном случае - вывести значения количества фейсов и вершин. В окно проекции выделите бокс, введите указанный выше текст в окне MaxScriptListener, выделите его целиком мышью и нажмите ввод, если все сделано правильно - должен появиться ответ:

#(12, 8)

теперь выделите окружность, снова выделите весь текст и нажмите ввод - ответ должен быть:

undefined - то есть не определено... что и требовалось.

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

if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
)
else
(
(getPolygoncount $)[1]
)
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
)
else
(
(getPolygoncount $)[2]
)

повторите операции с проверкой работы алгоритма, поочередно выделяя бокс и окружность, и выполняя написанный выше код

С общими параметрами разобрались, теперь полезем в "святая святых" :) - займемся интерфейсом. Для начала в окне MaxScriptListener выполните File->New Script (нажмите CTRL+N) и создайте пустой файл сценария.
--------------
macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
)
----------------
Сохраните файл как

\\root_max\UI\Macroscripts\Macro_ScenePolyCounter.ms

где root_max - корневая директория макса. Таким образом мы разместили наш скрипт в разделе пользовательского интерфейса. С помошью проводника найдите этот файл и измените ему разрешение на *.mcr - чтобы макс воспринимал его как макроскрипт. У меня получилось следующим образом:

D:\WORK\3D_PROG\3DSMAX5\UI\Macroscripts\Macro_ScenePolyCounter.mcr

Теперь надо закрыть макс и снова стартовать его... Идем в меню Customize->Customize User Interface, вкладка Toolbars,
группа - main UI, категория, как и указали - MAX Script Tools. Если все сделано правильно, то в окне Action должен находиться наш макрос. Берем его, и ташим на панель закладок, например - на вкладку объекты. В принципе это не важно, поскольку в последствии мы все равно удалим эту кнопку, но поскольку работать мы будем с объектами, то так несколько удобнее. У нас появилась новая кнопка с надписью ScenePolyCounter. Закрываем окно редактирования интерфейса и пытаемся нажать на нашу кнопку. Ничего не происходит, и это правильно, ведь мы не указали - что именно должно происходить... Сейчас мы запишем туда код обработчика, и все начнет работать :)

Правый клик мыши по нашей кнопке, выбираем пункт Edit Macro Script. Вводим обработчик нажатия, конечный текст выглядит следующим образом:

-----------------------
macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
local ScenePolyCounterOn = false

on ischecked return ScenePolyCounterOn

on execute do
(
ScenePolyCounterOn = not ScenePolyCounterOn
completeredraw ()
updateToolbarButtons()
)

)
-----------------------

мы добавили:
-обработчик нажатия кнопки ischecked, возвращающий значение переменной ScenePolyCounterOn , в которой хранится состояние нашего макроса - активирована или не активирована. По умолчанию, естественно, неактивна (false).
- обработчик события execute - исполнение, то есть собственно последовательность выпоняемых действий. Первым делом мы в нем меняем значение активности макроса на противоположное, поскольку с каждым вызавом макроса он последовательно активируется и дезактивируется. Для описания этого мы воспользовались оператором NOT, меняющим значение булевской переменной (тип ДА НЕТ) на противоположное. Оставшиеся две строки - перерисовка рабочего экрана и кнопки вызова скрипта.
Нажимаем комбинацию клавиш CTRL+E - так называемое событие Evaluate - аналог компиляции програмного кода. не закрывая окна с телом скрипта пробуем нажать на нашу кнопку. Как мы видим, она изменяет свое состояние, но больше ничего не происходит. Ну что ж, "продолжаем разговор" (С)... Введем следующий код:
-----------------------------
macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
local ScenePolyCounterOn = false
local TextFaceObj, TextVertexObj, TextFaceAll
local lastViewport
fn printtext =
(
TextFaceObj = "SelObjFace : "
TextVertexObj = "SelObjVertex :"
TextFaceAll = "SceneFace : "
gw.wtext [5, 40, 0] TextFaceObj color:(color 255 234 0)
gw.wtext [5, 60, 0] TextVertexObj color:(color 255 234 0)
gw.wtext [5, 80, 0] TextFaceAll color:(color 255 234 0)
gw.enlargeUpdateRect #whole
gw.updateScreen()
if viewport.activeViewport != lastViewport then
(
completeredraw()
lastViewport = viewport.activeViewport
)
)

on ischecked return ScenePolyCounterOn

on execute do
(
if ScenePolyCounterOn then
unregisterRedrawViewsCallback printtext
else
(
registerRedrawViewsCallback printtext
)
ScenePolyCounterOn = not ScenePolyCounterOn
completeredraw ()
updateToolbarButtons()
)
)
---------------------------
нажимаем комбинацию CTRL+E (компилируем код) и нажимаем на кнопку нашего макроса. В активном видовом окне появились три надписи, соответствующие установленным нами. Убеждаемся, что при переключении окон проекции надписи следуют за переключением, а по выключении макроса - исчезают, и идем дальше. Давайте разберемся, что же мы написали.

Во-первых, мы добавили переменную lastViewport, в которой хранится значение текущего окна проекции, и добавили действие - при смене окна проекции перерисовать все видовые окна - completeredraw().

if viewport.activeViewport != lastViewport then
(
completeredraw()
lastViewport = viewport.activeViewport
)

В качестве условия мы поставили выражение viewport.activeViewport != lastViewport . Таким образом, в случае если хранящееся в переменной lastViewport значение текущего окна проекции не совпадает с реальным, получаемым с помощью вызова viewport.activeViewport, мы перерисовываем все окна проекций и меняем значение переменной lastViewport на актуальное. Закомментируйте или удалите строки с данным условием, и попробуйте попереключать окна проекций при активном макросе, чтобы стала понятна необходимость данного условия...
Так же мы добавили вывод наших надписей на экран:

gw.wtext [5, 40, 0] TextFaceObj color:(color 255 234 0)
gw.wtext [5, 60, 0] TextVertexObj color:(color 255 234 0)
gw.wtext [5, 80, 0] TextFaceAll color:(color 255 234 0)
gw.enlargeUpdateRect #whole
gw.updateScreen()
первые три строки - собственно вывод, то есть команда gw.wtext - написать текст, далее координаты вывода в текущем окне, далее - что, собственно писать, ну и в последнем разделе - цвет надписей.
последние две строки -
gw.enlargeUpdateRect #whole - задаем прямоугольник, впределах которого необходимо произвести перерисовку экрана (в данном случае - весь экран)
gw.updateScreen() - собственно перерисовка, то есть вывод на экран заданных значений.

Начинаем собирать кусочки мозаики, то есть создавать конечный код. Дописываем следующее:
-------------------------------
macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
local ScenePolyCounterOn = false
local TextFaceObj, TextVertexObj, TextFaceAll
local lastViewport
fn printtext =
(
TextFaceObj = "SelObjFace : "
TextVertexObj = "SelObjVertex :"
TextFaceAll = "SceneFace : "
if selection.count == 1 do
(
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextFaceObj= "SelObjFace :0"
)
else
(
TextFaceObj= "SelObjFace : " + (getPolygoncount $)[1] as string
)
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextVertexObj = "SelObjVertex :0"
)
else
(
TextVertexObj = "SelObjVertex :" + (getPolygoncount $)[2] as string
)
)
gw.wtext [5, 40, 0] TextFaceObj color:(color 255 234 0)
gw.wtext [5, 60, 0] TextVertexObj color:(color 255 234 0)
gw.wtext [5, 80, 0] TextFaceAll color:(color 255 234 0)
gw.enlargeUpdateRect #whole
gw.updateScreen()
if viewport.activeViewport != lastViewport then
(
completeredraw()
lastViewport = viewport.activeViewport
)
)
on ischecked return ScenePolyCounterOn
on execute do
(
if ScenePolyCounterOn then
unregisterRedrawViewsCallback printtext
else
(
registerRedrawViewsCallback printtext
)
ScenePolyCounterOn = not ScenePolyCounterOn
completeredraw ()
updateToolbarButtons()
)
)
-------------------------

Что мы добавили? Во-первых, мы определили выделение:
if selection.count == 1 do ,
то есть в случае, если у нас выделен один объект, то мы в соответствии с алгоритмом, выработанным в начале урока, проверяем - является ли он плоской формой, и если не является, то фиксируем количество принадлежащих ему фейсов и вершин.
Так же несколько изменилась строка

TextVertexObj = "SelObjVertex :" + (getPolygoncount $)[2] as string,

здесь мы добавили к нашей записи SetObj... значение, получаемое с помощью метода getPolygonCounter, приписанное в конец записи как строковая переменная: as string для совпадения форматов.
Сохраните макрос и перезапустите макс. Создайте в сцене несколько объектов, включая камеры, вспомогательные объекты, сплайны и, собственно, геометрические объекты. Активируйте наш макрос и попереключайте выделение с одного объекта на другой.

Убедитесь, что все работает как надо...
Небольшое примечание - мы вводили условия только для сплайнов, поскольку во-первых, все остальные объекты, не являющиеся геометрическими - итак не имеют ни вершин, ни фейсов, следовательно - нам жить не мешают :) а во-вторых - как сказано в самом начале - мы делаем инструмент для низкополигонального моделирования, соответственно - остальные объекты нас вообще в данной ситуации не интересуют.
Итак, нам осталось немного - получить информацию о всей сцене. Для этого нам придется воспользоваться во-первых, методом rootnode, а заодно вспомнить, что все объекты сцены являются потомками корневого узла сцены. Следовательно, задав обращение rootnode.children мы должны получить список всех объектов сцены.
Если вы успели обнулить макс - создайте в сцене небольшой хаос из объектов различных категорий :) и открывайте окно MaxScriptListener. Вводим:
rootnode.children
-------------------------------
#children($Box01, $Cylinder01, $Pyramid01, $L-Ext01, $Plane01, $Arc01, $NGon01, $Fspot01, $Camera01, $BoxGizmo01)

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

getPolygonCount rootnode.children[1]
rootnode.children[1].category
-----------------------------
#(12, 8)
#Standard_Primitives

как мы видим, все правильно и аналогично тем действиям, что мы делали с выделением одного объекта. Разница лишь в том, что в данном случае мы вынуждены будем организовать цикл и последовательно суммировать фейсы всех объектов сцены. Для этого нам понадобится оператор while ... do и значение количества объектов в сцене, которое мы получим с помощью метода count.

В общем виде алгоритм будет выглядеть следующим образом:

facecount = 0 - - задаем стартовое значение количества фейсов
iter=1 - - задаем начальное количество итераций цикла
countObjScene = rootnode.children.count - - получаем информацию о количестве объектов в сцене
while iter < (countObjScene+1) do - - задаем цикл
(
if (rootnode.children[iter].category == #shape) or (rootnode.children[iter].category == #Splines) then
(
TextFaceAll= "SceneFace :0"
)
else
(
facecount = facecount + (getPolygoncount rootnode.children[iter])[1]
)
TextFaceAll= "SceneFace : " + facecount as string
iter = iter+1
)



дописываем это выражение в наш макрос и проверяем:
-----------------------------------
macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
local ScenePolyCounterOn = false
local TextFaceObj, TextVertexObj, TextFaceAll
local lastViewport
fn printtext =
(
TextFaceObj = "SelObjFace : "
TextVertexObj = "SelObjVertex :"
TextFaceAll = "SceneFace : "
if selection.count == 1 do
(
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextFaceObj= "SelObjFace : 0"
)
else
(
TextFaceObj= "SelObjFace : " + (getPolygoncount $)[1] as string
)
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextVertexObj = "SelObjVertex : 0"
)
else
(
TextVertexObj = "SelObjVertex :" + (getPolygoncount $)[2] as string
)
)
facecount=0
countObjScene = rootnode.children.count
iter=1
while iter < (countObjScene+1) do
(
if (rootnode.children[iter].category == #shape) or (rootnode.children[iter].category == #Splines) then
(
TextFaceAll= "SceneFace :0"
)
else
(
facecount = facecount + (getPolygoncount rootnode.children[iter])[1]
)
TextFaceAll= "SceneFace : " + facecount as string
iter = iter+1
)
gw.wtext [5, 40, 0] TextFaceObj color:(color 255 234 0)
gw.wtext [5, 60, 0] TextVertexObj color:(color 255 234 0)
gw.wtext [5, 80, 0] TextFaceAll color:(color 255 234 0)
gw.enlargeUpdateRect #whole
gw.updateScreen()
if viewport.activeViewport != lastViewport then
(
completeredraw()
lastViewport = viewport.activeViewport
)
)
on ischecked return ScenePolyCounterOn
on execute do
(
if ScenePolyCounterOn then
unregisterRedrawViewsCallback printtext
else
(
registerRedrawViewsCallback printtext
)
ScenePolyCounterOn = not ScenePolyCounterOn
completeredraw ()
updateToolbarButtons()
)
)
--------------------------------------------------

Должно все работать. Мы неплохо потрудились, напоследок вкусности :)

О чем хотелось бы сказать в заключение?
Во первых, о том, что не доделано... можно было задать условие, при котором перерисовывался бы не весь экран, а только та часть его, в которой мы пишем... если кому интересен этот вариант - отправляю разбираться с алгоритмом, реализованным в макросе PoligonCounter, по крайней мере в пятой версии макса этот способ реализован.
Можно было обойтись и без цикла для определения количества полигонов в сцене, однако исходя из того, что макрос писался под задачи низкополигонального моделирования и, соответственно, небольшого количества объектов в сцене и небольшого числа полигонов - данный способ скорее предпочтителен. Причина проста - быстрота написания, легкость доступа к коду и возможность редактирования "на лету", а главное - не требуется дополнительных компиляторов кода, фактически работа ведется в текстовом редакторе.
Ну и главное - как всегда - учите скрипты, они строить и жить помогают :) Два способа изучения мы рассмотрели в данном уроке. Первый - с использованием MaxScriptListener - это хороший инструмент для отладки черновых кусков кода, наблюдения за результатами своих действий. Второй - загрузка своего сценария как макроса и интерактивная его отладка. Лично мне второй способ наиболее симпатичен хотя бы потому, что позволяет сохранить в текстовом файле результаты своих попыток, даже если эти искания приводят к зависанию компьютера (ну бывает, бывает :)) - главное чаще использовать волшебную комбинациюCTRL+S... В качестве источников информации можно использовать справку (она достаточно тупа, не говоря уже про то, что на буржуйском) и волшебную кнопку - правую на мышке. Кликаешь на любую (ну или почти любую) кнопку на панели закладок, выбираешь Edit Macro Script и получаешь неограниченный доступ к информации о строении, методах и процедурах макса. Главное при этом - научиться разбираться в коде и не бояться экспериментировать...

Ну что ж - вот и конечный текст нашего макроса с небольшим добавлением как в заголовке, так и в самом теле макроса. Заодно и задачка - найти 10 отличий и понять, зачем они нужны :)

--------------start macros--------------------------------
-- MacroScript File

-- Created: Sept 12 2003
-- Author: VladiRR
-- MacroScript for Turning On a Polygon counter in the viewpot.
--***********************************************************************************************
-- MODIFY THIS AT YOUR OWN RISK


macroScript ScenePolyCounter
category:"MAX Script Tools"
internalcategory:"MAX Script Tools"
buttontext:"ScenePolyCounter"
toolTip:"ScenePolyCounter"
(
local ScenePolyCounterOn = false
local TextFaceObj, TextVertexObj, TextFaceAll
local lastViewport
fn printtext =
(
try
(
TextFaceObj = "SelObjFace : "
TextVertexObj = "SelObjVertex :"
TextFaceAll = "SceneFace : "
if selection.count == 1 do
(
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextFaceObj= "SelObjFace : 0"
)
else
(
TextFaceObj= "SelObjFace : " + (getPolygoncount $)[1] as string
)
if ($selection[1].category == #shape) or ($selection[1].category == #Splines) then
(
TextVertexObj = "SelObjVertex : 0"
)
else
(
TextVertexObj = "SelObjVertex :" + (getPolygoncount $)[2] as string
)
)
facecount=0
countObjScene = rootnode.children.count
iter=1
while iter < (countObjScene+1) do
(
if (rootnode.children[iter].category == #shape) or (rootnode.children[iter].category == #Splines) then
(
TextFaceAll= "SceneFace :0"
)
else
(
facecount = facecount + (getPolygoncount rootnode.children[iter])[1]
)
TextFaceAll= "SceneFace : " + facecount as string
iter = iter+1
)
gw.wtext [5, 40, 0] TextFaceObj color:(color 255 234 0)
gw.wtext [5, 60, 0] TextVertexObj color:(color 255 234 0)
gw.wtext [5, 80, 0] TextFaceAll color:(color 255 234 0)
gw.enlargeUpdateRect #whole
gw.updateScreen()
if viewport.activeViewport != lastViewport then
(
completeredraw()
lastViewport = viewport.activeViewport
)
)
catch ()


)
on ischecked return ScenePolyCounterOn
on execute do
(
if ScenePolyCounterOn then
unregisterRedrawViewsCallback printtext
else
(
registerRedrawViewsCallback printtext
)
ScenePolyCounterOn = not ScenePolyCounterOn
completeredraw ()
updateToolbarButtons()
)

)
--------------end macros----------------------


Нам осталось только удалить созданную вначале урока кнопку (с помощью правого клика мышки и выбора меню Delete Button), и назначить нашему макросу горячую клавишу для вызова. Лично у меня сейчас настроен на клавишу Q вызов макроса PoligonCounter, а на комбинацию CTRL+Q - свежесозданный. Используются по очереди и по ситуации оба.

Да, и самое главное - основная задача все-таки не макросы писать (по крайней мере у большинства, я надеюсь) - а потому всем творить, моделировать, анимировать etc. Ну и если не хватает инструментов - создавать их самим :)

Успехов всем! Если есть вопросы - пишите Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript , по возможности постараюсь ответить.

Титры:
Создание макроса - 2 часа
Написание урока - 3.5 часа
выпито: кофе - 2 литра
пива - не помню
при написании урока ни один компьютер не пострадал.

Скачать макрос урока

Всегда Ваш - VladiRR

далее