Приветствую, очень интересует возможно ли найти разницу между границами двух моделей.
Красной линией отмечена сочетание граней - черной модели, с белой, http://i.imgur.com/7qNojYS.png?2, это грудь модели http://i.imgur.com/8LN8hfG.png?1 , и изначально черная модель выходила за грани белой модели, http://i.imgur.com/Yyb8vOC.png?1, и мне пришлось вручную - при помощи манипуляций Кости(Груди)Передвинуть/подогнать(На глаз) ее на положение граней белой модели, т.к. общая форма черной модели должна соотвествовать белой.
Вопрос в том как - можно вычислить эту разницу(И через что), если она имеется, между 1 моделью и 2 моделью, и ввести полученное значение в XYZ Кости, по сути автоматизировать все те манипуляции которые делаются "на глаз".
Надеюсь более мене подробно описал ?Прошу сильно не закидывать ....
LighFusionПриветствую, очень интересует возможно ли найти разницу между границами двух моделей.
Вы можете попробовать это сделать с помощью MaxScript.
То есть, с помощью способа проб и ошибок, скрипт будет выполнять подгонку одной модели к другой.
Чем больше будет количество проб, тем больше потребуется времени и тем точнее будет результат.
мне пришлось вручную - при помощи манипуляций Кости(Груди)Передвинуть/подогнать(На глаз) ее на положение граней белой модели
Каким способом вы передвигали Кость (Груди)? Вы использовали инструмент Select and Move?
Кость-груди имеет родителя в виде кости?
Какие именно манипуляции вы совершали над кости-груди: передвигание, вращение, масштабирование?
по сути автоматизировать все те манипуляции которые делаются "на глаз".
Почему вы хотите автоматизировать эти манипуляции? Вы тратите много времени на эти манипуляции? Вас не устраивает полученный результат?
igorznagВы можете попробовать это сделать с помощью MaxScript.
То есть, с помощью способа проб и ошибок, скрипт будет выполнять подгонку одной модели к другой.
Чем больше будет количество проб, тем больше потребуется времени и тем точнее будет результат.
Каким способом вы передвигали Кость (Груди)? Вы использовали инструмент Select and Move?
Кость-груди имеет родителя в виде кости?
Какие именно манипуляции вы совершали над кости-груди: передвигание, вращение, масштабирование?
Почему вы хотите автоматизировать эти манипуляции? Вы тратите много времени на эти манипуляции? Вас не устраивает полученный результат?
Если через MaxScript то с чем именно ?
Кость Груди - я масштабировал по Y Координат.
Автоматизировать я хочу потому что другого варианта особо нету, поскольку моделей где-то около 100, и подогнать их надо к 1ой единственной, в ручную это очень долго может занять(+ не точность, может возникнуть).
Если через MaxScript то с чем именно ?
Кость Груди - я масштабировал по Y Координат.
Вы масштабировали Кость Груди в мировой или локальной системе координат?
Для вас обязательно масштабировать кость, а не саму модель?
Допустим, что у нас есть 2 модели без костей.
Объясните подробно ваш алгоритм подгонки одной модели к другой с помощью Scale.
Вас устраивает как работает скрипт RealSizeTB?
Попробуйте сначала объяснить алгоритм для простого примера.
В новой сцене в начале координат создаем одну сферу и один чайник.
Выравниваем центр Body чайника к Pivot-у чайника.
Устанавливаем для сферы и чайника одинаковый радиус, например 20.
Конвертируем сферу и чайник в Editable Poly.
Масштабируем сферу по оси X на 200%.
Теперь нужно подогнать Body чайника под размер "сферы" по оси X.
Запускаем скрипт RealSizeTB.
Выделяем полигоны Body чайника и прячем остальные полигоны.
Выделяем "сферу" и копируем её размер по оси X.
Выделяем чайник и вставляем размер сферы по оси X.
Показываем все полигоны чайника.
igorznagВы масштабировали Кость Груди в мировой или локальной системе координат?
Для вас обязательно масштабировать кость, а не саму модель?
Допустим, что у нас есть 2 модели без костей.
Объясните подробно ваш алгоритм подгонки одной модели к другой с помощью Scale.
Вас устраивает как работает скрипт RealSizeTB?
Попробуйте сначала объяснить алгоритм для простого примера.
В новой сцене в начале координат создаем одну сферу и один чайник.
Выравниваем центр Body чайника к Pivot-у чайника.
Устанавливаем для сферы и чайника одинаковый радиус, например 20.
Конвертируем сферу и чайник в Editable Poly.
Масштабируем сферу по оси X на 200%.
Теперь нужно подогнать Body чайника под размер "сферы" по оси X.
Запускаем скрипт RealSizeTB.
Выделяем полигоны Body чайника и прячем остальные полигоны.
Выделяем "сферу" и копируем её размер по оси X.
Выделяем чайник и вставляем размер сферы по оси X.
Показываем все полигоны чайника.
В вашем примере - в принципе так оно и нужно, только с поправкой на то что модель масштабировать необходимо через кость.
Я записал пример этого всего на видео
Сам метод работает через Bounding Box, возможно ли это решить как то иначе ? получив значение положения XYZ, самой дальней вершины(по ОСИ ХYZ) относительно центра, поскольку с bounding box, возникает проблема т.к. некоторые части второй модели(К примеру Ноги) не имеются у первой модели, и ввиду этого Bounding Box первой заходит за рамки - и дальнейшее вычисление становиться неправильным. Ну и на сколько я понял те значения - которые получаются при вычитании BBox1-BBox2=x, нужно приумножать на 10, т.е. 5.6*10=56, и масштабировать именно по оси X, а не по всем сторонам.
В вашем примере - в принципе так оно и нужно, только с поправкой на то что модель масштабировать необходимо через кость.
Вы можете мне предоставить пару ваших моделей с костями, чтобы я смог тестировать скрипт?
Если да, тогда сохраните для 3d max 2010.
Если нет, тогда я продолжу задавать вопросы:
Кость всегда находится в центре модели по оси X?
Я записал пример этого всего на видео
Спасибо что качество видео не 240p.
Сохраняйте видеo с качеством 720p, если есть возможность.
получив значение положения XYZ, самой дальней вершины(по ОСИ ХYZ) относительно центра
Значение дальней вершины вы получаете так: b.max
Значение центра можно получить так: b.center
Значение дальней вершины относительно центра будет так: b.max-b.center
Вас устраивает такое значение?
Ну и на сколько я понял те значения - которые получаются при вычитании BBox1-BBox2=x, нужно приумножать на 10,
Мне интересно узнать, как вы поняли, что нужно приумножать на 10.
Может быть нужно приумножать на 9 или 11?
Может быть нужно приумножать на 100/(BBox1/2)=100/(19,7802/2)=100/9,8901=10,1111?
LighFusionВ вашем примере - в принципе так оно и нужно, только с поправкой на то что модель масштабировать необходимо через кость.
Я записал пример этого всего на видео
Я написал скрипт для вашего простого примера с боксами и кости.
Проверьте если скрипт работает правильно.
Теперь объясните алгоритм для сложного примера.
try destroydialog igorznag_adjust_scale catch()
rollout igorznag_adjust_scale "Adjust Scale X"
(
fn gemetry_filt obj = superclassof obj == GeometryClass and classof obj != BoneGeometry
fn bone_filt obj = classof obj == BoneGeometry
pickbutton pb_master "Pick Master Object" filter:gemetry_filt width:100
pickbutton pb_slave "Pick Slave Object" filter:gemetry_filt width:100
pickbutton pb_bone "Pick Bone Object"filter:bone_filt width:100
button btn_apply "Apply";
on pb_master picked obj do pb_master.caption=obj.name
on pb_slave picked obj do pb_slave.caption=obj.name
on pb_bone picked obj do pb_bone.caption=obj.name
on btn_apply pressed do
(
master_obj=pb_master.object;slave_obj=pb_slave.object;bone_obj=pb_bone.object;
if isvalidnode master_obj and isvalidnode slave_obj and isvalidnode bone_obj then
(
if master_obj!=slave_obj then
(
bone_obj.scale=[1,1,1]
master_offset=master_obj.max.x-bone_obj.pos.x
slave_offset=slave_obj.max.x-bone_obj.pos.x
offset_x=1.0*master_offset/slave_offset
undo on (scale bone_obj [offset_x,1,1])
)--if master_obj!=slave_obj then
)--if isvalidnode master_obj a
)--on btn_apply pressed do
); createdialog igorznag_adjust_scale
igorznagЯ написал скрипт для вашего простого примера с боксами и кости.
Проверьте если скрипт работает правильно.
Теперь объясните алгоритм для сложного примера.
try destroydialog igorznag_adjust_scale catch()
rollout igorznag_adjust_scale "Adjust Scale X"
(
fn gemetry_filt obj = superclassof obj == GeometryClass and classof obj != BoneGeometry
fn bone_filt obj = classof obj == BoneGeometry
pickbutton pb_master "Pick Master Object" filter:gemetry_filt width:100
pickbutton pb_slave "Pick Slave Object" filter:gemetry_filt width:100
pickbutton pb_bone "Pick Bone Object"filter:bone_filt width:100
button btn_apply "Apply";
on pb_master picked obj do pb_master.caption=obj.name
on pb_slave picked obj do pb_slave.caption=obj.name
on pb_bone picked obj do pb_bone.caption=obj.name
on btn_apply pressed do
(
master_obj=pb_master.object;slave_obj=pb_slave.object;bone_obj=pb_bone.object;
if isvalidnode master_obj and isvalidnode slave_obj and isvalidnode bone_obj then
(
if master_obj!=slave_obj then
(
bone_obj.scale=[1,1,1]
master_offset=master_obj.max.x-bone_obj.pos.x
slave_offset=slave_obj.max.x-bone_obj.pos.x
offset_x=1.0*master_offset/slave_offset
undo on (scale bone_obj [offset_x,1,1])
)--if master_obj!=slave_obj then
)--if isvalidnode master_obj a
)--on btn_apply pressed do
); createdialog igorznag_adjust_scale
Спасибо огромное, будет с чего начать !
Пример сцены https://mega.co.nz/#!10Jk0byJ!Ef60M4LgYPuOP460jSL22dE36044tJOjkaM0sBa2jlw и внутри модели в FBX
Вся сложность, заключается в том что форма моделей, более специфична(ввиду того что это тело), ии загвоздка в том чтобы постепенно от первой кости - которая к примеру контролирует таз - Bip01Pelvis, производить манипуляции через скрипт(предварительно отключив иерархию, дочерних костей Bip01Pelvis), и после успешной манипуляции(подгонки модели 1 под модель 2), продолжить тот же процесс костью которая идет выше Bip01Pelvis, то есть Bip01Spine(В примере сцены это видно).
И еще один возможный нюанс, связан с те что кость возможно необходимо предварительно сдвинуть по одной из ОСИ XYZ, ввиду того что у сложных моделей(как в сцене- с телами) кости задействуют не половину модели(Как в примере с Боксом)а всю часть туловища/спины/шеи/живота и тд. По сему - возникает вопрос, возможно ли манипулировать таким образом чтобы вначале передвинуть По ОСИ XYZ модель 1, на грань модели 2 и далее сделать уже масштабирование по XYZ(Я думаю я смогу записать пример на видео, используя тот скрипт что вы мне дали, уже с более подобным примером), не ручаюсь что будет 720, не пойму точно почему видео портиться, но возможно исправлю.
Спасибо еще раз что дали такой обширный ответ, я уж думал подобное не кому не будет интересно =) .
Небольшой - Апдейт !
- несколько дней провозился( -- Off с этой погодой нереально настроиться...), но так и не смог решить основную загвоздку - более сложные модели - у которых вершины весов - образуют сложную модель, разница Bounding Box'ov, а точнее офсет - который между ними получается, как значение, не дает точного результата при массштабировании кости по оси X. Я записал весь процесс на видео.
Есть еще одна загвоздка(точнее это вся та же проблема) - опять же связанна с более сложной структурой скиннинга(у сложных моделей - типа тел) - скрипт массштабирует гораздо больше чем нужно, выходя за рамки, и опять же - непонятно какова идея этого кода
master_obj.max.x-bone_obj.pos.x
1.0*master_offset/slave_offset
так и не смог решить основную загвоздку - более сложные модели - у которых вершины весов - образуют сложную модель
Давайте я попробую решить эту загвозку.
Я понял, что вам нужно, но не понял полностью как вы вручную это делаете на глаз.
Больше не нужно объяснять алгоритм с помощью цифр.
Есть еще одна загвоздка- опять же связанна с более сложной структурой скиннинга(у сложных моделей - типа тел) - скрипт массштабирует гораздо больше чем нужно, выходя за рамки,
Давайте вы будете усложнять простой пример с боксами, а я попробую написать соответствующий скрипт.
Вы будете объяснять как вы делаете подгонку боксов вручную на глаз.
Может быть с 10 раза получиться написать подходящий скрипт.
Я написал скрипт для случая с боксами, который у вас на видео.
try destroydialog igorznag_adjust_scale catch()
rollout igorznag_adjust_scale "2 Adjust Scale X"
(
fn gemetry_filt obj = superclassof obj == GeometryClass and classof obj != BoneGeometry
fn bone_filt obj = classof obj == BoneGeometry
pickbutton pb_master "Pick Master Object" filter:gemetry_filt width:100
pickbutton pb_slave "Pick Slave Object" filter:gemetry_filt width:100
pickbutton pb_bone "Pick Bone Object" width:100 filter:bone_filt
button btn_apply "Apply";
on pb_master picked obj do pb_master.caption=obj.name
on pb_slave picked obj do pb_slave.caption=obj.name
on pb_bone picked obj do pb_bone.caption=obj.name
on btn_apply pressed do
(
master_obj=pb_master.object;slave_obj=pb_slave.object;bone_obj=pb_bone.object;
if isvalidnode master_obj and isvalidnode slave_obj and isvalidnode bone_obj then
(
if master_obj!=slave_obj then
(
master_length_x=master_obj.max.x-master_obj.min.x
slave_length_x=slave_obj.max.x-slave_obj.min.x
rescale_x=1.0*master_length_x/slave_length_x
undo on
(
scale bone_obj [rescale_x,1,1]
bone_obj.pos.x+=master_obj.center.x-slave_obj.center.x
)
)--if master_obj!=slave_obj then
)--if isvalidnode master_obj a
)--on btn_apply pressed do
); createdialog igorznag_adjust_scale
Попытался немного подробнее объяснить на боксах, в чем заключается проблема
Пробовал новый скрипт, толи я что-то не так делаю, толи он немного под другое настроен, но результат не тот, ввиду того что Master Object меньше чем Slave Object, а Scale( с примером от боксов) заточен наоборот, что Master Object больше а Slae Object Меньше.
LighFusionПопытался немного подробнее объяснить на боксах, в чем заключается проблема
Нет никакой проблемы. Я прекрасно понял, что вам нужно.
Я же просил, чтобы вы не объясняли мне эти цифры.
Вам не надоели эти цифры?
5,39 оригинальный размер белой брони
1,37 это длина - которой не достает до черной брони
если просто сложить 5,39+1,37=6,76 и это в принципе дает нужный результат
Чтобы это отразить в масштабировании через кость, нужно разделить длину черной брони на длину белой брони.
6,76/5,39=1,25
Это можно увидеть в коде последнего скрипта.
Если взять примерно такой же отрезок и прикрепить его к кости, значение 1,37 для масштабирования не будет давать нужного результата.
А правильным резултатом будет 6,76/5,39=1,25
Разница 1,37-1,25=0,12 не имеет никакого смысла и она никому не нужна.
LighFusionПробовал новый скрипт, толи я что-то не так делаю, толи он немного под другое настроен, но результат не тот, ввиду того что Master Object меньше чем Slave Object, а Scale( с примером от боксов) заточен наоборот, что Master Object больше а Slae Object Меньше.
То есть, если сделать Бокс-Master меньше чем Бокс-Slave, тогда последний скрипт работает неправильно?
Давайте сначала разберемся с боксами, а потом перейдем к брони.
igorznagНет никакой проблемы. Я прекрасно понял, что вам нужно.
Я же просил, чтобы вы не объясняли мне эти цифры.
Вам не надоели эти цифры?
5,39 оригинальный размер белой брони
1,37 это длина - которой не достает до черной брони
если просто сложить 5,39+1,37=6,76 и это в принципе дает нужный результат
Чтобы это отразить в масштабировании через кость, нужно разделить длину черной брони на длину белой брони.
6,76/5,39=1,25
Это можно увидеть в коде последнего скрипта.
Если взять примерно такой же отрезок и прикрепить его к кости, значение 1,37 для масштабирования не будет давать нужного результата.
А правильным резултатом будет 6,76/5,39=1,25
Разница 1,37-1,25=0,12 не имеет никакого смысла и она никому не нужна.
То есть, если сделать Бокс-Master меньше чем Бокс-Slave, тогда последний скрипт работает неправильно?
Давайте сначала разберемся с боксами, а потом перейдем к брони.
Так спасибо еще раз теперь я понял всю суть и зачем / Делить, в принципе скрипт работает на отлично, еще раз спасибо!
Но проблема основная проблема от этого не решается, подгонка брони через скрипт(автоматически) все еще далека от того что требуется.
В первую очередь остается загкозвдка с тем чтобы расположить на панели скрипта, своего рода иерархию скелета
примерно подобным образом
Upper | Body
Left Arm <= |Neck| =>Right Arm
|
Spine2
|
Spine1
|
Spine
|
<= Bip01Pelvis =>
Left Leg | Right Leg
|
|
|
Left Calf | Right Calf
|
|
|
Left Foot | Right Foot
Наверное примерно как в Motion Builder(там примерно такое же есть), но я не уверен стоит ли создавать кнопки Pick(выбора)(чтобы установить скелет из сцены), либо сделать обычные button и устанавливать кости по имени(как они есть, для каждой кнопки.
Ну и самое основное тут - ползунки/кнопки По Передвижению/Врашению - костей, в процентом соотношении, то есть 1-3% это 101-103, 10% это 110 для массштабирования, для scale -3% от начальной величины 90 - будет 87.
Я конечно возможно предлагаю не самый умный способ, может он и тупой(буду очень рад если получиться что-то сделать по серьезнее) не прибегая к таким способам, но этот способ - так сказать, напролом ! Он должен повторять то что я делаю в ручную(Подгонку), одной брони к другой.
Но вернусь я обратно к этой тулзе, необходимо чтобы весь этот процесс был более менее автоматичен, то есть к примеру сначало идет смешение bip01Pelvis, в зависимости от Lenght Obj1/Obj2, далее идет небольшое массштабирование Bip01Pelvis, и если нужно Врашение по Y, вот тут я не очень понимаю, задать это на глаз(то есть с CheckBox изначально) либо как это отмерять требуется ли наклон брони или нет., ну а далее примерно тоже самое но уже с теми костями которые идут выше, а потом уже руки и ноги.
Вообще основная загвоздка в том чтобы - скрывать нужные части тела(Брони), руки,ноги, чтоб к примеру был виден только пояс, как это возможно сделать через скрипт, чтобы уже потом можно было его применять.
LighFusionВообще основная загвоздка в том чтобы - скрывать нужные части тела(Брони), руки,ноги, чтоб к примеру был виден только пояс, как это возможно сделать через скрипт, чтобы уже потом можно было его применять.
Видео пример.
Для объекта Slave можно сделать так: Выделяем нужную кость.
Запускаем скрипт. В новом окне нажимаем кнопку "Show Selected Bone".
try destroydialog show_hide_by_bone catch()
rollout show_hide_by_bone "Bone Geometry"
(
button btn_show_selected_bone "Show Selected Bone"
button btn_hide_all "Hide All Geometry"
button btn_show_all "Show All Geometry"
on btn_show_selected_bone pressed do
(
undo on
(
if selection.count==1 then
(
bone_obj=selection[1]
if classof bone_obj==BoneGeometry then
(
bones_identic_name=getNodeByName bone_obj.name all:true
if bones_identic_name.count==1 then
(
old_selection=selection as array
for obj in objects do
(
skin_m=undefined
if obj.modifiers.count==1 then
(if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1])
if obj.modifiers.count==2 then
(
if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then
skin_m=obj.modifiers[2]
)--if obj.modifiers.count==2 then
if skin_m!=undefined then
(
select obj
if obj.modifiers.count==1 then
(
m=Edit_Poly(); m.name="igorznag_bone_show"
modPanel.addModToSelection m
)--if obj.modifiers.count==1 then
skin_m=obj.modifiers[2]
max modify mode
modPanel.setCurrentObject skin_m
nv = skinOps.GetNumberVertices skin_m
vert_a=#()
for i = 1 to nv do
(
nw = skinOps.GetVertexWeightCount skin_m i
for j=1 to nw do
(
BoneID = skinOps.GetVertexWeightBoneID skin_m i j
Weight = skinOps.GetVertexWeight skin_m i j
if Weight> 0 then
(
bsid=skinOps.GetVertexWeightBoneID skin_m i j
bn=skinOps.GetBoneName skin_m bsid 0
if bn==bone_obj.name then append vert_a i
)--if Weight> 0 then
)--for j=1 to nw do
)--for i = 1 to nv do
modPanel.setCurrentObject (obj.modifiers[1])
vert_a=vert_a as bitarray
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #UnhideAllFace
fs=obj.modifiers[1].GetSelection #Face
obj.modifiers[1].Select #face fs invert:true
obj.modifiers[1].SetEPolySelLevel #Vertex
obj.modifiers[1].ButtonOp #UnhideAllVertex
vs=obj.modifiers[1].GetSelection #Vertex
obj.modifiers[1].Select #Vertex vs invert:true
obj.modifiers[1].Select #Vertex vert_a
obj.modifiers[1].ConvertSelection #Vertex #Face requireAll:true
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #UnhideAllFace
obj.modifiers[1].ButtonOp #HideUnselectedFace
obj.modifiers[1].SetEPolySelLevel #Object
completeredraw()
)--if skin_m!=undefined then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--if bones_identic_name.count==1 then
)--if classof bone_obj==BoneGeometry then
)--if selection.count==1 then
)--undo on
)--on btn_show_selected_bone pressed do
on btn_hide_all pressed do
(
undo on
(
old_selection=selection as array
for obj in objects do
(
skin_m=undefined
if obj.modifiers.count==1 then
(if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1])
if obj.modifiers.count==2 then
(
if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then
skin_m=obj.modifiers[2]
)--if obj.modifiers.count==2 then
if skin_m!=undefined then
(
select obj; max modify mode
if obj.modifiers.count==1 then
(
m=Edit_Poly(); m.name="igorznag_bone_show"
modPanel.addModToSelection m
)--if obj.modifiers.count==1 then
modPanel.setCurrentObject (obj.modifiers[1])
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #HideUnselectedFace
obj.modifiers[1].ButtonOp #HideFace
obj.modifiers[1].SetEPolySelLevel #Object
)--if skin_m!=undefined then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--undo on
)--on btn_hide_all pressed do
on btn_show_all pressed do
(
undo on
(
old_selection=selection as array
for obj in objects do
(
if obj.modifiers.count==2 then
(
if obj.modifiers[1].name=="igorznag_bone_show" then deletemodifier obj 1
)--if obj.modifiers.count==2 then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--undo on
)--on btn_show_all pressed do
);createdialog show_hide_by_bone
igorznagВидео пример.
Для объекта Slave можно сделать так: Выделяем нужную кость.
Запускаем скрипт. В новом окне нажимаем кнопку "Show Selected Bone".
try destroydialog show_hide_by_bone catch()
rollout show_hide_by_bone "Bone Geometry"
(
button btn_show_selected_bone "Show Selected Bone"
button btn_hide_all "Hide All Geometry"
button btn_show_all "Show All Geometry"
on btn_show_selected_bone pressed do
(
undo on
(
if selection.count==1 then
(
bone_obj=selection[1]
if classof bone_obj==BoneGeometry then
(
bones_identic_name=getNodeByName bone_obj.name all:true
if bones_identic_name.count==1 then
(
old_selection=selection as array
for obj in objects do
(
skin_m=undefined
if obj.modifiers.count==1 then
(if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1])
if obj.modifiers.count==2 then
(
if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then
skin_m=obj.modifiers[2]
)--if obj.modifiers.count==2 then
if skin_m!=undefined then
(
select obj
if obj.modifiers.count==1 then
(
m=Edit_Poly(); m.name="igorznag_bone_show"
modPanel.addModToSelection m
)--if obj.modifiers.count==1 then
skin_m=obj.modifiers[2]
max modify mode
modPanel.setCurrentObject skin_m
nv = skinOps.GetNumberVertices skin_m
vert_a=#()
for i = 1 to nv do
(
nw = skinOps.GetVertexWeightCount skin_m i
for j=1 to nw do
(
BoneID = skinOps.GetVertexWeightBoneID skin_m i j
Weight = skinOps.GetVertexWeight skin_m i j
if Weight> 0 then
(
bsid=skinOps.GetVertexWeightBoneID skin_m i j
bn=skinOps.GetBoneName skin_m bsid 0
if bn==bone_obj.name then append vert_a i
)--if Weight> 0 then
)--for j=1 to nw do
)--for i = 1 to nv do
modPanel.setCurrentObject (obj.modifiers[1])
vert_a=vert_a as bitarray
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #UnhideAllFace
fs=obj.modifiers[1].GetSelection #Face
obj.modifiers[1].Select #face fs invert:true
obj.modifiers[1].SetEPolySelLevel #Vertex
obj.modifiers[1].ButtonOp #UnhideAllVertex
vs=obj.modifiers[1].GetSelection #Vertex
obj.modifiers[1].Select #Vertex vs invert:true
obj.modifiers[1].Select #Vertex vert_a
obj.modifiers[1].ConvertSelection #Vertex #Face requireAll:true
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #UnhideAllFace
obj.modifiers[1].ButtonOp #HideUnselectedFace
obj.modifiers[1].SetEPolySelLevel #Object
completeredraw()
)--if skin_m!=undefined then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--if bones_identic_name.count==1 then
)--if classof bone_obj==BoneGeometry then
)--if selection.count==1 then
)--undo on
)--on btn_show_selected_bone pressed do
on btn_hide_all pressed do
(
undo on
(
old_selection=selection as array
for obj in objects do
(
skin_m=undefined
if obj.modifiers.count==1 then
(if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1])
if obj.modifiers.count==2 then
(
if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then
skin_m=obj.modifiers[2]
)--if obj.modifiers.count==2 then
if skin_m!=undefined then
(
select obj; max modify mode
if obj.modifiers.count==1 then
(
m=Edit_Poly(); m.name="igorznag_bone_show"
modPanel.addModToSelection m
)--if obj.modifiers.count==1 then
modPanel.setCurrentObject (obj.modifiers[1])
obj.modifiers[1].SetEPolySelLevel #face
obj.modifiers[1].ButtonOp #HideUnselectedFace
obj.modifiers[1].ButtonOp #HideFace
obj.modifiers[1].SetEPolySelLevel #Object
)--if skin_m!=undefined then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--undo on
)--on btn_hide_all pressed do
on btn_show_all pressed do
(
undo on
(
old_selection=selection as array
for obj in objects do
(
if obj.modifiers.count==2 then
(
if obj.modifiers[1].name=="igorznag_bone_show" then deletemodifier obj 1
)--if obj.modifiers.count==2 then
)--for obj in objects do
clearSelection(); select old_selection;
completeredraw()
)--undo on
)--on btn_show_all pressed do
);createdialog show_hide_by_bone
Вот это просто афигенно, как будет $ на кошельке - обязательно скину немного - выручили капец просто !
Доступ к резюме доступен только по пакетному доступу HR менеджерам зарегистрированных компаний. Узнать о вариантах корпоративных пакетов можно по ссылке.
LighFusion
Красной линией отмечена сочетание граней - черной модели, с белой,
http://i.imgur.com/7qNojYS.png?2, это грудь модели http://i.imgur.com/8LN8hfG.png?1 , и изначально черная модель выходила за грани белой модели, http://i.imgur.com/Yyb8vOC.png?1, и мне пришлось вручную - при помощи манипуляций Кости(Груди)Передвинуть/подогнать(На глаз) ее на положение граней белой модели, т.к. общая форма черной модели должна соотвествовать белой.
Вопрос в том как - можно вычислить эту разницу(И через что), если она имеется, между 1 моделью и 2 моделью, и ввести полученное значение в XYZ Кости, по сути автоматизировать все те манипуляции которые делаются "на глаз".
Надеюсь более мене подробно описал ?Прошу сильно не закидывать ....
igorznag
То есть, с помощью способа проб и ошибок, скрипт будет выполнять подгонку одной модели к другой.
Чем больше будет количество проб, тем больше потребуется времени и тем точнее будет результат.
Каким способом вы передвигали Кость (Груди)? Вы использовали инструмент Select and Move?
Кость-груди имеет родителя в виде кости?
Какие именно манипуляции вы совершали над кости-груди: передвигание, вращение, масштабирование?
Почему вы хотите автоматизировать эти манипуляции? Вы тратите много времени на эти манипуляции? Вас не устраивает полученный результат?
LighFusion
Кость Груди - я масштабировал по Y Координат.
Автоматизировать я хочу потому что другого варианта особо нету, поскольку моделей где-то около 100, и подогнать их надо к 1ой единственной, в ручную это очень долго может занять(+ не точность, может возникнуть).
igorznag
Для вас обязательно масштабировать кость, а не саму модель?
Допустим, что у нас есть 2 модели без костей.
Объясните подробно ваш алгоритм подгонки одной модели к другой с помощью Scale.
Вас устраивает как работает скрипт RealSizeTB?
Попробуйте сначала объяснить алгоритм для простого примера.
В новой сцене в начале координат создаем одну сферу и один чайник.
Выравниваем центр Body чайника к Pivot-у чайника.
Устанавливаем для сферы и чайника одинаковый радиус, например 20.
Конвертируем сферу и чайник в Editable Poly.
Масштабируем сферу по оси X на 200%.
Теперь нужно подогнать Body чайника под размер "сферы" по оси X.
Запускаем скрипт RealSizeTB.
Выделяем полигоны Body чайника и прячем остальные полигоны.
Выделяем "сферу" и копируем её размер по оси X.
Выделяем чайник и вставляем размер сферы по оси X.
Показываем все полигоны чайника.
LighFusion
Я записал пример этого всего на видео
Сам метод работает через Bounding Box, возможно ли это решить как то иначе ? получив значение положения XYZ, самой дальней вершины(по ОСИ ХYZ) относительно центра, поскольку с bounding box, возникает проблема т.к. некоторые части второй модели(К примеру Ноги) не имеются у первой модели, и ввиду этого Bounding Box первой заходит за рамки - и дальнейшее вычисление становиться неправильным. Ну и на сколько я понял те значения - которые получаются при вычитании BBox1-BBox2=x, нужно приумножать на 10, т.е. 5.6*10=56, и масштабировать именно по оси X, а не по всем сторонам.
igorznag
Если да, тогда сохраните для 3d max 2010.
Если нет, тогда я продолжу задавать вопросы:
Кость всегда находится в центре модели по оси X?
Спасибо что качество видео не 240p.
Сохраняйте видеo с качеством 720p, если есть возможность.
Значение дальней вершины вы получаете так: b.max
Значение центра можно получить так: b.center
Значение дальней вершины относительно центра будет так: b.max-b.center
Вас устраивает такое значение?
Мне интересно узнать, как вы поняли, что нужно приумножать на 10.
Может быть нужно приумножать на 9 или 11?
Может быть нужно приумножать на 100/(BBox1/2)=100/(19,7802/2)=100/9,8901=10,1111?
igorznag
Проверьте если скрипт работает правильно.
Теперь объясните алгоритм для сложного примера.
try destroydialog igorznag_adjust_scale catch() rollout igorznag_adjust_scale "Adjust Scale X" ( fn gemetry_filt obj = superclassof obj == GeometryClass and classof obj != BoneGeometry fn bone_filt obj = classof obj == BoneGeometry pickbutton pb_master "Pick Master Object" filter:gemetry_filt width:100 pickbutton pb_slave "Pick Slave Object" filter:gemetry_filt width:100 pickbutton pb_bone "Pick Bone Object"filter:bone_filt width:100 button btn_apply "Apply"; on pb_master picked obj do pb_master.caption=obj.name on pb_slave picked obj do pb_slave.caption=obj.name on pb_bone picked obj do pb_bone.caption=obj.name on btn_apply pressed do ( master_obj=pb_master.object;slave_obj=pb_slave.object;bone_obj=pb_bone.object; if isvalidnode master_obj and isvalidnode slave_obj and isvalidnode bone_obj then ( if master_obj!=slave_obj then ( bone_obj.scale=[1,1,1] master_offset=master_obj.max.x-bone_obj.pos.x slave_offset=slave_obj.max.x-bone_obj.pos.x offset_x=1.0*master_offset/slave_offset undo on (scale bone_obj [offset_x,1,1]) )--if master_obj!=slave_obj then )--if isvalidnode master_obj a )--on btn_apply pressed do ); createdialog igorznag_adjust_scaleLighFusion
Пример сцены https://mega.co.nz/#!10Jk0byJ!Ef60M4LgYPuOP460jSL22dE36044tJOjkaM0sBa2jlw и внутри модели в FBX
Вся сложность, заключается в том что форма моделей, более специфична(ввиду того что это тело), ии загвоздка в том чтобы постепенно от первой кости - которая к примеру контролирует таз - Bip01Pelvis, производить манипуляции через скрипт(предварительно отключив иерархию, дочерних костей Bip01Pelvis), и после успешной манипуляции(подгонки модели 1 под модель 2), продолжить тот же процесс костью которая идет выше Bip01Pelvis, то есть Bip01Spine(В примере сцены это видно).
И еще один возможный нюанс, связан с те что кость возможно необходимо предварительно сдвинуть по одной из ОСИ XYZ, ввиду того что у сложных моделей(как в сцене- с телами) кости задействуют не половину модели(Как в примере с Боксом)а всю часть туловища/спины/шеи/живота и тд. По сему - возникает вопрос, возможно ли манипулировать таким образом чтобы вначале передвинуть По ОСИ XYZ модель 1, на грань модели 2 и далее сделать уже масштабирование по XYZ(Я думаю я смогу записать пример на видео, используя тот скрипт что вы мне дали, уже с более подобным примером), не ручаюсь что будет 720, не пойму точно почему видео портиться, но возможно исправлю.
Спасибо еще раз что дали такой обширный ответ, я уж думал подобное не кому не будет интересно =) .
LighFusion
- несколько дней провозился( -- Off с этой погодой нереально настроиться...), но так и не смог решить основную загвоздку - более сложные модели - у которых вершины весов - образуют сложную модель, разница Bounding Box'ov, а точнее офсет - который между ними получается, как значение, не дает точного результата при массштабировании кости по оси X. Я записал весь процесс на видео.
Есть еще одна загвоздка(точнее это вся та же проблема) - опять же связанна с более сложной структурой скиннинга(у сложных моделей - типа тел) - скрипт массштабирует гораздо больше чем нужно, выходя за рамки, и опять же - непонятно какова идея этого кода
master_obj.max.x-bone_obj.pos.x
1.0*master_offset/slave_offset
igorznag
Я понял, что вам нужно, но не понял полностью как вы вручную это делаете на глаз.
Больше не нужно объяснять алгоритм с помощью цифр.
Давайте вы будете усложнять простой пример с боксами, а я попробую написать соответствующий скрипт.
Вы будете объяснять как вы делаете подгонку боксов вручную на глаз.
Может быть с 10 раза получиться написать подходящий скрипт.
Я написал скрипт для случая с боксами, который у вас на видео.
try destroydialog igorznag_adjust_scale catch() rollout igorznag_adjust_scale "2 Adjust Scale X" ( fn gemetry_filt obj = superclassof obj == GeometryClass and classof obj != BoneGeometry fn bone_filt obj = classof obj == BoneGeometry pickbutton pb_master "Pick Master Object" filter:gemetry_filt width:100 pickbutton pb_slave "Pick Slave Object" filter:gemetry_filt width:100 pickbutton pb_bone "Pick Bone Object" width:100 filter:bone_filt button btn_apply "Apply"; on pb_master picked obj do pb_master.caption=obj.name on pb_slave picked obj do pb_slave.caption=obj.name on pb_bone picked obj do pb_bone.caption=obj.name on btn_apply pressed do ( master_obj=pb_master.object;slave_obj=pb_slave.object;bone_obj=pb_bone.object; if isvalidnode master_obj and isvalidnode slave_obj and isvalidnode bone_obj then ( if master_obj!=slave_obj then ( master_length_x=master_obj.max.x-master_obj.min.x slave_length_x=slave_obj.max.x-slave_obj.min.x rescale_x=1.0*master_length_x/slave_length_x undo on ( scale bone_obj [rescale_x,1,1] bone_obj.pos.x+=master_obj.center.x-slave_obj.center.x ) )--if master_obj!=slave_obj then )--if isvalidnode master_obj a )--on btn_apply pressed do ); createdialog igorznag_adjust_scaleLighFusion
Пробовал новый скрипт, толи я что-то не так делаю, толи он немного под другое настроен, но результат не тот, ввиду того что Master Object меньше чем Slave Object, а Scale( с примером от боксов) заточен наоборот, что Master Object больше а Slae Object Меньше.
igorznag
Я же просил, чтобы вы не объясняли мне эти цифры.
Вам не надоели эти цифры?
5,39 оригинальный размер белой брони
1,37 это длина - которой не достает до черной брони
если просто сложить 5,39+1,37=6,76 и это в принципе дает нужный результат
Чтобы это отразить в масштабировании через кость, нужно разделить длину черной брони на длину белой брони.
6,76/5,39=1,25
Это можно увидеть в коде последнего скрипта.
Если взять примерно такой же отрезок и прикрепить его к кости, значение 1,37 для масштабирования не будет давать нужного результата.
А правильным резултатом будет 6,76/5,39=1,25
Разница 1,37-1,25=0,12 не имеет никакого смысла и она никому не нужна.
То есть, если сделать Бокс-Master меньше чем Бокс-Slave, тогда последний скрипт работает неправильно?
Давайте сначала разберемся с боксами, а потом перейдем к брони.
LighFusion
Но проблема основная проблема от этого не решается, подгонка брони через скрипт(автоматически) все еще далека от того что требуется.
В первую очередь остается загкозвдка с тем чтобы расположить на панели скрипта, своего рода иерархию скелета
примерно подобным образом
Upper | Body Left Arm <= |Neck| =>Right Arm | Spine2 | Spine1 | Spine | <= Bip01Pelvis => Left Leg | Right Leg | | | Left Calf | Right Calf | | | Left Foot | Right FootНаверное примерно как в Motion Builder(там примерно такое же есть), но я не уверен стоит ли создавать кнопки Pick(выбора)(чтобы установить скелет из сцены), либо сделать обычные button и устанавливать кости по имени(как они есть, для каждой кнопки.Ну и самое основное тут - ползунки/кнопки По Передвижению/Врашению - костей, в процентом соотношении, то есть 1-3% это 101-103, 10% это 110 для массштабирования, для scale -3% от начальной величины 90 - будет 87.
Я конечно возможно предлагаю не самый умный способ, может он и тупой(буду очень рад если получиться что-то сделать по серьезнее) не прибегая к таким способам, но этот способ - так сказать, напролом ! Он должен повторять то что я делаю в ручную(Подгонку), одной брони к другой.
Но вернусь я обратно к этой тулзе, необходимо чтобы весь этот процесс был более менее автоматичен, то есть к примеру сначало идет смешение bip01Pelvis, в зависимости от Lenght Obj1/Obj2, далее идет небольшое массштабирование Bip01Pelvis, и если нужно Врашение по Y, вот тут я не очень понимаю, задать это на глаз(то есть с CheckBox изначально) либо как это отмерять требуется ли наклон брони или нет., ну а далее примерно тоже самое но уже с теми костями которые идут выше, а потом уже руки и ноги.
LighFusion
igorznag
Для объекта Slave можно сделать так: Выделяем нужную кость.
Запускаем скрипт. В новом окне нажимаем кнопку "Show Selected Bone".
try destroydialog show_hide_by_bone catch() rollout show_hide_by_bone "Bone Geometry" ( button btn_show_selected_bone "Show Selected Bone" button btn_hide_all "Hide All Geometry" button btn_show_all "Show All Geometry" on btn_show_selected_bone pressed do ( undo on ( if selection.count==1 then ( bone_obj=selection[1] if classof bone_obj==BoneGeometry then ( bones_identic_name=getNodeByName bone_obj.name all:true if bones_identic_name.count==1 then ( old_selection=selection as array for obj in objects do ( skin_m=undefined if obj.modifiers.count==1 then (if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1]) if obj.modifiers.count==2 then ( if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then skin_m=obj.modifiers[2] )--if obj.modifiers.count==2 then if skin_m!=undefined then ( select obj if obj.modifiers.count==1 then ( m=Edit_Poly(); m.name="igorznag_bone_show" modPanel.addModToSelection m )--if obj.modifiers.count==1 then skin_m=obj.modifiers[2] max modify mode modPanel.setCurrentObject skin_m nv = skinOps.GetNumberVertices skin_m vert_a=#() for i = 1 to nv do ( nw = skinOps.GetVertexWeightCount skin_m i for j=1 to nw do ( BoneID = skinOps.GetVertexWeightBoneID skin_m i j Weight = skinOps.GetVertexWeight skin_m i j if Weight> 0 then ( bsid=skinOps.GetVertexWeightBoneID skin_m i j bn=skinOps.GetBoneName skin_m bsid 0 if bn==bone_obj.name then append vert_a i )--if Weight> 0 then )--for j=1 to nw do )--for i = 1 to nv do modPanel.setCurrentObject (obj.modifiers[1]) vert_a=vert_a as bitarray obj.modifiers[1].SetEPolySelLevel #face obj.modifiers[1].ButtonOp #UnhideAllFace fs=obj.modifiers[1].GetSelection #Face obj.modifiers[1].Select #face fs invert:true obj.modifiers[1].SetEPolySelLevel #Vertex obj.modifiers[1].ButtonOp #UnhideAllVertex vs=obj.modifiers[1].GetSelection #Vertex obj.modifiers[1].Select #Vertex vs invert:true obj.modifiers[1].Select #Vertex vert_a obj.modifiers[1].ConvertSelection #Vertex #Face requireAll:true obj.modifiers[1].SetEPolySelLevel #face obj.modifiers[1].ButtonOp #UnhideAllFace obj.modifiers[1].ButtonOp #HideUnselectedFace obj.modifiers[1].SetEPolySelLevel #Object completeredraw() )--if skin_m!=undefined then )--for obj in objects do clearSelection(); select old_selection; completeredraw() )--if bones_identic_name.count==1 then )--if classof bone_obj==BoneGeometry then )--if selection.count==1 then )--undo on )--on btn_show_selected_bone pressed do on btn_hide_all pressed do ( undo on ( old_selection=selection as array for obj in objects do ( skin_m=undefined if obj.modifiers.count==1 then (if classof obj.modifiers[1]==skin then skin_m=obj.modifiers[1]) if obj.modifiers.count==2 then ( if classof obj.modifiers[2]==skin and obj.modifiers[1].name=="igorznag_bone_show" then skin_m=obj.modifiers[2] )--if obj.modifiers.count==2 then if skin_m!=undefined then ( select obj; max modify mode if obj.modifiers.count==1 then ( m=Edit_Poly(); m.name="igorznag_bone_show" modPanel.addModToSelection m )--if obj.modifiers.count==1 then modPanel.setCurrentObject (obj.modifiers[1]) obj.modifiers[1].SetEPolySelLevel #face obj.modifiers[1].ButtonOp #HideUnselectedFace obj.modifiers[1].ButtonOp #HideFace obj.modifiers[1].SetEPolySelLevel #Object )--if skin_m!=undefined then )--for obj in objects do clearSelection(); select old_selection; completeredraw() )--undo on )--on btn_hide_all pressed do on btn_show_all pressed do ( undo on ( old_selection=selection as array for obj in objects do ( if obj.modifiers.count==2 then ( if obj.modifiers[1].name=="igorznag_bone_show" then deletemodifier obj 1 )--if obj.modifiers.count==2 then )--for obj in objects do clearSelection(); select old_selection; completeredraw() )--undo on )--on btn_show_all pressed do );createdialog show_hide_by_boneLighFusion