Notifications
Clear all

[Closed] Skin Weight code optimization

 MZ1

This is an example of my code to rig a simple cloth to some bones. I’m looking for any tip-trick, update-upgrade to speed up or optimize my code:

delete objects
clearlistener()

(
	/*############################################*/
	/* Functions */
	/*############################################*/
	
	fn PrepareModifier TheModifier =
	(
		Obj = (refs.dependentNodes TheModifier)[1]
		if isvalidnode Obj do
		(
			setCommandPanelTaskMode mode:#modify
			classof Obj
			select Obj
			if modPanel.getCurrentObject() != TheModifier do modPanel.setCurrentObject TheModifier
		)
	)
	
	fn GetBoneIndex SkinModifier TheBone = 
	(
		if isvalidnode TheBone then
		(
			findItem (for i =1 to (skinOps.GetNumberBones SkinModifier) collect (skinOps.GetBoneName SkinModifier i 0)) TheBone.name
		)
		else 0
	)
	
	/*############################################*/
	/* Localizing SkinOps */
	/*############################################*/
	
	local GetNumberVertices = skinOps.GetNumberVertices
	local GetVertexWeightCount = skinOps.GetVertexWeightCount
	local GetVertexWeight = skinOps.GetVertexWeight
	local GetVertexWeightBoneID = skinOps.GetVertexWeightBoneID
	local SetVertexWeights = skinOps.SetVertexWeights
	local ReplaceVertexWeights = skinOps.ReplaceVertexWeights
	local SelectVertices = skinOps.SelectVertices
	local SelectBone = skinOps.SelectBone
	fn AddBone TheSkin TheBone UpdateInteger = (skinOps.addbone TheSkin TheBone 0 ; classof (refs.dependentnodes TheSkin)[1])
	local RemoveBone = skinOps.RemoveBone
	local BlendSelectedBone = skinOps.blendSelected
	local GetNumberBones = skinOps.GetNumberBones
	local GetBoneName = skinOps.GetBoneName
	
	/*############################################*/
	/* Default Variables */
	/*############################################*/
	
	Width = 100.0
	Height = 100.0
	WidthSegments = 4
	HeightSegments = 4
	WidthDistance = Width/WidthSegments
	HeightDistance = Height/HeightSegments

	/*############################################*/
	/* Skin Object */
	/*############################################*/
	
	Obj = Rectangle name:"Skin Object" length:Height width:Width transform:(matrix3 [1,0,0] [0,0,1] [0,-1,0] [Width/2,0,Height/2]) wirecolor:blue
	GarmentModifier = Garment_Maker autoMesh:true preserve:true relax:true outputType:0 figure:undefined stretchMapping:false showMesh:false showSeams:false
	addmodifier Obj GarmentModifier
	SkinModifier = skin()
	addmodifier Obj SkinModifier
	
	/*############################################*/
	/* Bones */
	/*############################################*/
	
	BoneArray = #()
	for i = 1 to WidthSegments + 1 do
	(
		for j = 1 to HeightSegments + 1 do
		(
			append BoneArray (sphere name:("Bone_"+(i as string)+"_"+(j as string)) radius:5 segments:6 pos:[(i-1)*WidthDistance,0,(j-1)*HeightDistance] wirecolor:yellow)
		)
	)
	
	/*############################################*/
	/* Skin */
	/*############################################*/
	
	PrepareModifier SkinModifier
	for TheBone in BoneArray do AddBone SkinModifier TheBone 0
	
	/*############################################*/
	/* Skin Weights */
	/*############################################*/
	
	WDis = WidthDistance/2
	HDis = HeightDistance/2
	NumberVertices = GetNumberVertices SkinModifier
	BonesTrueIndexes = for TheBone in BoneArray collect GetBoneIndex SkinModifier TheBone
	for i = 1 to NumberVertices do
	(
		VertexPos = getvert Obj.mesh i * Obj.objecttransform
		for BoneId = 1 to BoneArray.count do
		(
			TheBone = BoneArray[BoneId]
			BonePos = TheBone.pos
			if BonePos.x >= VertexPos.x - WDis and \
				BonePos.x < VertexPos.x + WDis and \
				BonePos.z >= VertexPos.z - HDis and \
				BonePos.z < VertexPos.z + HDis do ReplaceVertexWeights SkinModifier i BonesTrueIndexes[BoneId] 1
		)
	)
	
	/*############################################*/
	/* Blend Weights */
	/*############################################*/
	
	SelectVertices SkinModifier #{1..NumberVertices}
	for i = 1 to BoneArray.count do
	(
		SelectBone SkinModifier i
		BlendSelectedBone SkinModifier
	)
)
13 Replies

Dude. Make some explanations of what it does and how you don’t like it.
Or else…

 MZ1

It works too slow at hi-res meshes, I just want to optimize it as possible.

Added a few little optimizations

Time: 0.963sec. Mem: 281152L – unoptimized

  1. 0.025
  2. 0.116
  3. 0.075
  4. 0.036
    Time: 0.284sec. Mem: 167408L – optimized
delete objects
gc();t1=timestamp();hf = heapfree

(
	
	times = [0,0,0,0]
	t2 = timestamp()
	
	fn PrepareModifier TheModifier =
	(
		Obj = (refs.dependentNodes TheModifier)[1]
		if isvalidnode Obj do
		(
			setCommandPanelTaskMode mode:#modify
			select Obj
			if modPanel.getCurrentObject() != TheModifier do modPanel.setCurrentObject TheModifier
		)
	)
	
	fn GetBoneIndex SkinModifier TheBone = 
	(
		if isvalidnode TheBone then
		(
			findItem (for i=1 to (skinOps.GetNumberBones SkinModifier) collect (skinOps.GetBoneName SkinModifier i 0)) TheBone.name
		)
		else 0
	)
	

	/* Localizing SkinOps */
	
	local GetNumberVertices = skinOps.GetNumberVertices
	local GetVertexWeightCount = skinOps.GetVertexWeightCount
	local GetVertexWeight = skinOps.GetVertexWeight
	local GetVertexWeightBoneID = skinOps.GetVertexWeightBoneID
	local SetVertexWeights = skinOps.SetVertexWeights
	local ReplaceVertexWeights = skinOps.ReplaceVertexWeights
	local SelectVertices = skinOps.SelectVertices
	local SelectBone = skinOps.SelectBone
	local SkinOpsAddBone = skinOps.addbone	
	local RemoveBone = skinOps.RemoveBone
	local BlendSelectedBone = skinOps.blendSelected
	local GetNumberBones = skinOps.GetNumberBones
	local GetBoneName = skinOps.GetBoneName
	

	/* Default Variables */
	
	Width = 100.0
	Height = 100.0
	WidthSegments = 4
	HeightSegments = 4
	WidthDistance = Width/WidthSegments
	HeightDistance = Height/HeightSegments



	/* Skin Object */	
	t2 = timestamp()
	Obj = Rectangle name:"Skin Object" length:Height width:Width transform:(matrix3 [1,0,0] [0,0,1] [0,-1,0] [Width/2,0,Height/2]) wirecolor:blue
	GarmentModifier = Garment_Maker autoMesh:true preserve:true relax:true outputType:0 figure:undefined stretchMapping:false showMesh:false showSeams:false
	addmodifier Obj GarmentModifier
	SkinModifier = skin()
	addmodifier Obj SkinModifier
	times[1] += timeStamp() - t2

	/* Bones */	
	t2 = timestamp()
	BoneArray = #()
	for i = 1 to WidthSegments + 1 do
	(
		for j = 1 to HeightSegments + 1 do
		(
			append BoneArray (sphere name:("Bone_"+(i as string)+"_"+(j as string)) radius:5 segments:6 pos:[(i-1)*WidthDistance,0,(j-1)*HeightDistance] wirecolor:yellow)
		)
	)
	

	/* Skin */	
	PrepareModifier SkinModifier
	for TheBone in BoneArray do SkinOpsAddBone SkinModifier TheBone 0
	classof (refs.dependentnodes SkinModifier)[1] -- nice trick btw
	times[2] += timeStamp() - t2

	t2 = timestamp()

	/* Skin Weights */	
	WDis = WidthDistance/2
	HDis = HeightDistance/2
	NumberVertices = GetNumberVertices SkinModifier
	BonesTrueIndexes = for TheBone in BoneArray collect GetBoneIndex SkinModifier TheBone
		
	tri = Obj.mesh
	tm  = Obj.objecttransform	
		
	for i = 1 to NumberVertices do
	(
		VertexPos = getvert tri i * tm
		
		val = [ VertexPos.x - WDis, VertexPos.x + WDis, VertexPos.z - HDis, VertexPos.z + HDis ]
		
		for BoneId = 1 to BoneArray.count do
		(			
			BonePos = BoneArray[BoneId].pos
			
			if BonePos.x >= val[1] and BonePos.x < val[2] and BonePos.z >= val[3] and BonePos.z < val[4] do 
			(
				ReplaceVertexWeights SkinModifier i BonesTrueIndexes[BoneId] 1
			)
		)
		

	)
	free tri
	times[3] += timeStamp() - t2
	
	t2 = timestamp()
	/* Blend Weights */	
	SelectVertices SkinModifier #{1..NumberVertices}
	for i = 1 to BoneArray.count do
	(
		SelectBone SkinModifier i
		BlendSelectedBone SkinModifier
	)
	times[4] += timeStamp() - t2
	
	format "1. %\n2. %\n3. %\n4. %\n" (times[1]/1000 as float) (times[2]/1000 as float) (times[3]/1000 as float) (times[4]/1000 as float)
)


	

format "Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)

this new forum text formatting is just disgusting…

what does it do? update?

1 Reply
(@serejah)
Joined: 11 months ago

Posts: 0

Yes and seems like it is faster than redrawing.

you can collect bone ids first and replace vertex weights for array instead of one by one. it might be faster

for k=1 to BoneArray.count do SkinOpsAddBone SkinModifier BoneArray[k] (k/BoneArray.count)

you can put the count into variable of course

 MZ1

Nice! Thanks

 MZ1

It’s a bug I think and this should be called after AddBone , otherwise ReplaceVertexWeights doesn’t work correctly.

 MZ1

would you please show me that by changing the code please?

Page 1 / 2