1. Пользоваться форумом на планшетах и телефонах стало удобнее благодаря Tapatalk

Два skin modifier в один.

Тема в разделе "Анимация", создана пользователем firsak, 10 янв 2010.

Модераторы: Артер
  1. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Есть несколько mesh'ев. У каждого свой модификатор skin. Вроде бы простая задача: объединить все объекты в один и сохранить при этом skin и все bone weights. Но у присоединяемых объектов всегда сбрасываются все данные в модификаторе skin. Как быть?
     
  2. Vertalet

    Vertalet Активный участник

    С нами с:
    08.05.2009
    Сообщения:
    44
    Симпатии:
    0
    Баллы:
    5
    ниче неполучитса.... смотря какой обьект ... может с помощью хелперов как нить обьедени
     
  3. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Тогда это полный идиотизм. Элементарная вроде фича. Должна быть по сути дела.
     
  4. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    Писал скрипт для объединения двух объектов с модификатором скин в один.

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

    код:

    Код:
    macroscript mergeSkinObjects
    category:"AndreyK"
    (
    	fn fnMergeSkinObjects objectsList refFrame = 
    	(
    		ObjSkinVertices = #()
    		bonesList = #()
    			
    		struct sSkinVertex (bonesCount,bonesID,bonesWeight)
    			
    		--1
    		setCommandPanelTaskMode #modify
    
    		bonesOffset = 0
    		for obj in objectsList do
    		(
    			select obj
    			
    			skinMod = undefined
    			for i=1 to obj.modifiers.count do
    			(
    				if (classof obj.modifiers[i] == Skin) do skinMod = obj.modifiers[i]
    			)				
    			
    			if(skinMod != undefined) then
    			(
    				--modPanel.setCurrentObject skinMod
    				vertices_count = skinOps.GetNumberVertices skinMod 
    				
    				for i = 1 to vertices_count do
    				(
    					newSkinVertex = sSkinVertex 0 #() #()
    					newSkinVertex.bonesCount =  skinOps.getVertexWeightCount skinMod i
    					for j = 1 to newSkinVertex.bonesCount do
    					(
    						Append newSkinVertex.bonesID ((skinOps.getVertexWeightBoneID skinMod i j)+bonesOffset)
    						Append newSkinVertex.bonesWeight ( skinOps.getVertexWeight skinMod i j )
    					)
    					append ObjSkinVertices newSkinVertex
    				)
    				
    				bones_count = skinOps.GetNumberBones skinMod
    				bonesOffset += bones_count
    				
    				for i = 1 to bones_count do
    				(
    					appendifunique bonesList (skinOps.GetBoneName skinMod i 0)
    				)
    			)--	if(skinMod != undefined)
    			else deleteItem objectsList (findItem objectsList obj)
    		)--for obj in objectsList
    
    		--2
    		at time refFrame 
    		(
    			skinobj = box prefix:"skinobj_"
    			convertto skinobj editable_poly
    			polyop.deleteVerts skinobj #{1..8}
    
    			for newElement in objectsList do
    			(
    				polyop.attach skinobj newElement
    			)
    
    		--3
    			skinMod = skin()
    			addModifier skinobj skinMod
    			skinMod.bone_limit = 4 --todo - find maximum bone_limit in all objects
    			skinMod.weightAllVertices = false
    
    			select skinobj
    			setCommandPanelTaskMode #modify
    			--modPanel.setCurrentObject skinMod
    
    
    			for BoneName in BonesList do
    			(
    				skinOps.addbone skinMod (GetNodeByName(BoneName)) 1
    			)
    			
    			skinOps.Invalidate skinMod 0
    			
    			skinOps.SelectBone skinMod 1
    			
    			--4
    			vertices_count = skinOps.GetNumberVertices skinMod
    				
    			for i = 1 to vertices_count do
    			(
    					skinOps.SetVertexWeights skinMod i ObjSkinVertices[i].bonesID[1] 1
    					skinOps.SetVertexWeights skinMod i ObjSkinVertices[i].bonesID ObjSkinVertices[i].bonesWeight
    			)
    		)--at time refFrame 
    	)--fn fnMergeSkinObjects
    	
    	on execute do
    	(
    		objectsList = selection as array
    		
    		if(objectsList.count>0) do
    		try
    		(
    			fnMergeSkinObjects objectsList 0
    		)
    		catch()
    	)
    )--macroscript
    
    
     
  5. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    О. Практически оно. Спасибо, работает! Но блин, у меня как раз объекты с одинаковыми костями... У вертексов с одинаковыми костями веса пропадают. Реально ли доработать скрипт?
     
  6. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    у вас в обоих мешах присутствуют одни и те же кости, или это разные кости с одинаковыми именами?
     
  7. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Chebu,

    Одни и те же кости. Разных костей с одинаковыми именами нет.



    Допустим, имеем: 3 объекта. верхняя губа, нижняя губа, голова.
    [​IMG]
    Поставил keyframe на 50-м кадре (открыл рот).



    Выделяю губы, жму на кнопку mergeSkinObjects (голову не трогаю), получаю:
    [​IMG]
    У нижней губы исчезают почти все bone weights. Undo.



    Теперь уже выделяю все три объекта, жму mergeSkinObjects, результат:
    [​IMG]


    Все объекты - editable poly, с одним модификатором (skin).


    Юзаю 3ds max 2008 x64. Куда копать?
     
  8. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    firsak,

    ок, понял, допилю.
     
  9. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    firsak, пробуйте:

    Код:
    macroscript mergeSkinObjects
    category:"AndreyK"
    (
    	fn fnMergeSkinObjects objectsList refFrame = 
    	(
    		ObjSkinVertices = #()
    		bonesList = #()
    			
    		struct sSkinVertex (bonesCount,bonesID,bonesWeight)
    			
    		--1
    		setCommandPanelTaskMode #modify
    
    		bonesOffset = 0
    		for obj in objectsList do
    		(
    			select obj
    			
    			skinMod = undefined
    			for i=1 to obj.modifiers.count do
    			(
    				if (classof obj.modifiers[i] == Skin) do skinMod = obj.modifiers[i]
    			)				
    			
    			if(skinMod != undefined) then
    			(
    				--modPanel.setCurrentObject skinMod
    				vertices_count = skinOps.GetNumberVertices skinMod 
    				
    				for i = 1 to vertices_count do
    				(
    					newSkinVertex = sSkinVertex 0 #() #()
    					newSkinVertex.bonesCount =  skinOps.getVertexWeightCount skinMod i
    					for j = 1 to newSkinVertex.bonesCount do
    					(
    						Append newSkinVertex.bonesID ((skinOps.getVertexWeightBoneID skinMod i j)+bonesOffset)
    						Append newSkinVertex.bonesWeight ( skinOps.getVertexWeight skinMod i j )
    					)
    					append ObjSkinVertices newSkinVertex
    				)
    				
    				bones_count = skinOps.GetNumberBones skinMod
    				bonesOffset += bones_count
    				
    				for i = 1 to bones_count do
    				(
    					append bonesList (skinOps.GetBoneName skinMod i 0)
    				)
    			)--	if(skinMod != undefined)
    			else deleteItem objectsList (findItem objectsList obj)
    		)--for obj in objectsList
    
    		--2
    		at time refFrame 
    		(
    			skinobj = box prefix:"skinobj_"
    			convertto skinobj editable_poly
    			polyop.deleteVerts skinobj #{1..8}
    
    			for newElement in objectsList do
    			(
    				polyop.attach skinobj newElement
    			)
    
    		--3
    			skinMod = skin()
    			addModifier skinobj skinMod
    			skinMod.bone_limit = 4 --todo - find maximum bone_limit in all objects
    			skinMod.weightAllVertices = false
    
    			select skinobj
    			setCommandPanelTaskMode #modify
    			--modPanel.setCurrentObject skinMod
    
    
    			for BoneName in BonesList do
    			(
    				skinOps.addbone skinMod (GetNodeByName(BoneName)) 1
    			)
    			
    			skinOps.Invalidate skinMod 0
    			
    			skinOps.SelectBone skinMod 1
    			
    			--4
    			vertices_count = skinOps.GetNumberVertices skinMod
    				
    			for i = 1 to vertices_count do
    			(
    					skinOps.SetVertexWeights skinMod i ObjSkinVertices[i].bonesID[1] 1
    					skinOps.SetVertexWeights skinMod i ObjSkinVertices[i].bonesID ObjSkinVertices[i].bonesWeight
    			)
    		)--at time refFrame 
    	)--fn fnMergeSkinObjects
    	
    	on execute do
    	(
    		objectsList = for obj in selection where (superclassof obj ==GeometryClass) collect obj
    		
    		if(objectsList.count>0) do
    		try
    		(
    			fnMergeSkinObjects objectsList 0
    		)
    		catch()
    	)
    )--macroscript
    
    
     
  10. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Едрён батон.
    Работает ведь!
    Большое спасибо, Chebu.

    Только почему то старый скрипт присосался к Максу, несмотря на то, что я старый *.mcr удалил и заменил на новый. Так и висит под категорией AndreyK. Поэтому сначала запускался старый скрипт. Думал, опять не повезло. Пришлось в доработанном скрипте категорию переименовать в AndreyK2. Странно.


    Еще проблема.
    Если объединенном с помощью скрипта меше опуститься уровнем ниже и сделать WELD вертексов, а затем вернуться обратно к skin, то веса у соединенных вертексов портятся. К примеру, у двух смежных вертексов такие веса:
    Код:
    0,400 Bone01
    0,200 Bone02
    0,200 Bone03
    0,200 Bone04
    А если их объединить, то получается бред:
    Код:
    0,308 Bone01
    0,281 Bone01
    0,206 Bone03
    0,205 Bone02

    Или:

    было
    Код:
    0,700 Bone01
    0,300 Bone02
    стало
    Код:
    0,418 Bone01
    0,275 Bone01
    0,183 Bone02
    0,124 Bone02
    Насколько я понимаю, Max пытается усреднить значения. Но зачем их усреднять, если они идентичные? Все равно, что взять две единицы и попытаться их "усреднить". Идиотизм, короче.
    Выход из проблемы нашел в использовании SkinUtilities.
    То бишь, сначала соединяю все, что нужно с помощью скрипта от Chebu. Затем юзаю комманду Extract Skin Data To Mesh на полученном объекте. Потом делаю WELD всех вертексов (веса у смежных вертексов портятся). И в конце концов восстанавляваю правильные веса с помощью Import Skin Data From Mesh.
     
  11. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    на здоровье.

    теоретически, можно попробовать перед велдом снять в скине галку always deform, а после велда поставить обратно. save-load весов тоже может помочь.
     
  12. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Chebu, только что заметил кое-что еще.
    При соединении нескольких объектов, дублируются envelope'ы. Допустим, три объекта, у каждого общая кость bone01. Соединяешь их - получаешь сразу три bone01 в списке модификатора skin. Одна из них нормальная, две остальные с нулевыми influences. Можете сделать, чтобы скрипт автоматом сносил лишние envelope'ы? Или может на что-то нажать можно? Кнопку remove zero weights вижу. Кнопку, типа, remove envelopes with zero influences не вижу. :(

    Постоянно приходится отсоединять/присоединять объекты (ввиду особенности модели). Пустые envelope'ы плодятся в бешенном темпе.
     
  13. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    firsak, поправлю в понедельник, когда до рабочего компьютера доберусь.
     
  14. firsak

    firsak Активный участник

    С нами с:
    06.06.2009
    Сообщения:
    65
    Симпатии:
    0
    Баллы:
    5
    Нет ли каких-нибудь сподвижек в шлифовании скрипта? :) В принципе, и так уже хорош (не знаю, что бы я без него делал), но все же один баг присутствует (дублируются envelopes с разных объектов).
     
  15. Chebu

    Chebu Знаток

    С нами с:
    23.10.2005
    Сообщения:
    141
    Симпатии:
    0
    Баллы:
    60
    Прошу прощения, сейчас совсем не до этого. Когда будет время - отпишусь.
     
  16. 3dlub

    3dlub Пользователь сайта

    С нами с:
    19.01.2010
    Сообщения:
    21
    Симпатии:
    0
    Баллы:
    2
    Есть немного странный способ, но работает на 100%
    Скачиваете ActorX importer (скрипт для 3DMAX), и ActoX exporter (Плагин для 3D Max)
    Устанавливате плагин, он появляется в утилитах.
    Експортите сцену со всеми мешами и скинами. В файл формата PSK.
    Далее очищаете сцену и импортите этот PSK с помощью скрипта ActorX importer.
    Все! Сцена из одного меша. Все скины сохранены. Удачи.
     
  17. Flashpavel

    Flashpavel Знаток

    С нами с:
    05.05.2009
    Сообщения:
    18
    Симпатии:
    0
    Баллы:
    27
    К чему столько сложностей, разве стандартные Skin Utilities не работают?
     
  18. INCUS

    INCUS Знаток

    С нами с:
    03.08.2010
    Сообщения:
    857
    Симпатии:
    30
    Баллы:
    29
    А у меня, вроде, и без утилит получилось.
    Weight Tool может скопировать в буфер веса выделенных вершин присоединяемого скина.
    Так что, потом можно эту геометрию приаттачить к главной геометрии с главным скином и кости, ему же те добавить.
    Отрыть уже этот главный Weight Tool, выделить те же вершины и, - paste.
    Энвелопы, правда не сохраняются...наверное, из-за того, что у них свой копипаст.
     
  19. Евгения Ремезова

    Евгения Ремезова Пользователь сайта

    С нами с:
    01.11.2012
    Сообщения:
    1
    Симпатии:
    0
    Баллы:
    2
    А можно поподробнее о ActorX importer? А то у меня не получается импортить, вываливается окно с ошибкой. Skin Utilities хорош для объединения двух мешей, но он не всегда корректно переносит веса.
     
Модераторы: Артер

Поделиться этой страницей