Notifications
Clear all

[Closed] my copy/paste poses in skinmorph tool

Hello!

Thanks to Rivendale i could finish this script With it you can quickly copy/paste “poses” between skinmorphtargets. For example if you work on a shoulder and want the base to stay the same unregarding the skintransformation (and not using an external morph). Especially if there are lots of targets its easier to get a coherent result.

how to use:

save it into macroscripts folder and it should appear in a sebstools section
after its run, select the object to work on and in the dropdown the bone.
now just select source and target and it will copy the vertexselection between those.
If just the object is selected (and no verts) it will copy the whole morph the the target.

this is my first i think is good enough to show so take it easy on me


-- skin morph tools V1.0

/*
Script to copy a "pose" from one morph to another. This is useful when working on for 
example on several shoulder corrective morphs where the base should stay the same - basically
getting rid of the inital skintransformation. 
*/



--there are dead morphs that i cant delete for some reason so i need to get them by name
fn FindSkinMorphByName smorph boneId name = 
(
	local numMorphs = smorph.boneGetNumberOfMorphs smorph.bones[boneId]
	for i = 1 to numMorphs do (	
		if (smorph.boneGetMorphIsDead smorph.bones[boneID] i) do continue --dead morph! 
		mname = smorph.boneGetMorphName smorph.bones[boneID] i
		if name == mname do return i
	)
	return undefined
)
		
--find the "local" vertex ids for a mesh vertex ids - they are different across morphs
fn FindSkinMorphId smorph morphID boneID vertexIDs = 
(
	local returnIds = #()
	local vertexIds = makeobjarray vertexIds

	for v in vertexIds do (
		local numVerts = smorph.boneGetMorphNumPoints smorph.bones[boneID] morphId
		found = false 
		for i = 1 to numVerts do (
			if (smorph.boneGetMorphVertID smorph.bones[boneID] morphId i) == v do
			(
				append returnIds i --found
				found = true
				break;
			)
		)
		if not found do append returnIds -1 --bad!
	)
	
	if returnIds.count > 1 then return returnIds else return returnIds[1]
)


fn PasteSkinMorphVertices smorph mSource mTarget boneID vertices:undefined = 
(
	
	--need the targets transform also (to get the right vector)
	local mTargetMatrix = smorph.boneGetMorphTM smorph.bones[boneID] mTarget
	
	format "Source Morph: %
"(smorph.boneGetMorphName smorph.bones[boneID] mSource )
	format "Target Morph: %
"(smorph.boneGetMorphName smorph.bones[boneID] mTarget)
	
	if (smorph.boneGetMorphIsDead smorph.bones[boneID] mTarget) do (
			print "This morph is dead"
			return false			
		)
	
	--to get the vertex selection we need to get the object
	local obj 
	deps = refs.dependents  smorph
	for d in deps do if (superclassof d == geometryclass ) do (
		obj = d
		break
	)
	if obj == undefined do (
		format "Couldnt get %'s baseobject.." smorph
		return false
	)
	
	local numVerts = smorph.boneGetMorphNumPoints smorph.bones[boneID] mSource 
	local skinobj = modpanel.getcurrentobject()
	local copyAll = false -- instead of the current vertselection
	
	if classof skinobj != skin_morph do (
		copyAll = Querybox "No vertices in skinmorph selected. Copy whole morph?"
		if copyAll == false then return false
		else modpanel.setCurrentObject smorph --getting an exception otherwise
	)
		

	for i = 1 to numVerts do (
		local id = smorph.boneGetMorphVertID smorph.bones[boneID] mSource i
		
		local doit = false
		if copyAll then doit = true else if skinobj.isSelectedVertex obj id do doit = true
		
		if doit do (
		
			local vecSource = smorph.boneGetMorphVecInParentSpace smorph.bones[boneID] mSource i
				
			local baseSource = smorph.boneGetMorphBasePoint smorph.bones[boneID] mSource i
			-- ok so the index is per morph. i need to find the matching id on the other morph
			idTarget = FindSkinMorphId smorph mTarget boneID id
			if idTarget == -1 do ( --the vert is actually not in the other morph (or not moved)
				print "Couldnt find vertex in targetmorph. skipping."
				continue
			)
			
			local baseTarget = smorph.boneGetMorphBasePoint smorph.bones[boneID] mTarget idTarget
			local posSource = (baseSource+vecSource) --position in parentspace
			local vecTargetBefore = smorph.boneGetMorphVecInParentSpace smorph.bones[boneID] mTarget idTarget

			local vecTarget = posSource - baseTarget -- that should be the new vector
			format "i:% iTarget:% Vec target:% Before:%
" i idTarget vecTarget vecTargetBefore
				
			smorph.boneSetMorphVecInParentSpace smorph.bones[boneID] mTarget idTarget vecTarget
		)
	)
	
	smorph.update()
)

--for making the dropdown entries. get all morphnames that are not dead
fn GetValidSkinmorphs smorph boneId=
(
	local names = #()	
	local numMorphs = smorph.boneGetNumberOfMorphs smorph.bones[boneId]
	for i = 1 to numMorphs do (	
		if (smorph.boneGetMorphIsDead smorph.bones[boneID] i) do continue --dead morph! 
		append names (smorph.boneGetMorphName smorph.bones[boneID] i)
	)
	return names
)

	 	

rollout uiCopyMorph "Copy Morph from ..." width:128 height:296
(
	listbox lbxMorphs "copy morph from.." pos:[8,56] width:112 height:10
	button btnUpdate "update" pos:[8,264] width:48 height:24
	button btnFetchMorph "copy" pos:[56,264] width:64 height:24
	
	local smorph = undefined
	
	dropdownList ddlBones "Bones" pos:[8,8] width:112 height:40
	
	dropdownList ddlTargetMorph "copy morph to..." pos:[8,216] width:112 height:40
	
	fn clearUI = (
		lbxMorphs.items = #()
		ddlTargetMorph.items =#()
		ddlBones.items = #()
		smorph = undefined
	)
	
	fn updateUI = 
	(
		local obj = selection[1]
		try (smorph = obj.modifiers[#skin_morph]; if smorph == undefined do (ClearUI();return false))
		catch (
			ClearUI()
			return false
		)
		--get bones in skinmod
		
		local names = for b in smorph.bones collect b.name
		ddlBones.items = names
				
		
		--get morphs for that bone
		local morphs =  GetValidSkinmorphs smorph ddlBones.selection
		if morphs != undefined do (
			lbxMorphs.items = morphs
			ddlTargetMorph.items = morphs
		)
	)
	on uiCopyMorph open do
	(
		--make some callbacks to update the ui
		callbacks.addScript  #selectionSetChanged  "uiCopyMorph.updateUi()" id:#SkinMorphToolsCallbacks
		callbacks.addScript #modPanelObjPostChange "uiCopyMorph.updateUi()" id:#SkinMorphToolsCallbacks
			updateUI()
	)
	
	on uiCopyMorph close do 
	(
		--remove callbacks
		callbacks.removeScripts id:#SkinMorphToolsCallbacks
	)

	on btnUpdate pressed do
	(
		updateUI()
	)
	
	on btnFetchMorph pressed do
	(
		if smorph == undefined do (
			MessageBox "Skin morph invalid"
			return false
		)
		--get the selections from dropdowns
		if lbxMorphs.selection == ddlTargetMorph.selection then (
			MessageBox "Cant copy onto itself. blast!"
		)
		else (
						
			local boneID = ddlBones.selection
			source = FindSkinMorphByName smorph boneID lbxMorphs.items[lbxMorphs.selection]
			target = FindSkinMorphByName smorph boneID ddlTargetMorph.items[ddlTargetMorph.selection]
			with undo on
			PasteSkinMorphVertices smorph source target boneID
			
		)

	)
	
	on ddlBones selected sel do
	(
		local morphs =  GetValidSkinmorphs smorph ddlBones.selection
		if morphs != undefined do
			lbxMorphs.items = morphs

	)
	
)


macroscript msCopyMorph category:"Sebstools"
(
	CreateDialog uiCopyMorph
)



please let me know if there are “style errors” and if you think its useful! Next thing im going to is something to copy a skinmorph properly to another object!

thanks, seb
:wip: