Notifications
Clear all

[Closed] changing existing keyframes: moving objects up

Hello there

I’m doing a practise for a company and they have the problem that sometimes their animated characters go through the ground. So they asked me to make a script that detects such behaviour and corrects it.

So detecting works fine: I am using the min-property of the objects and if the z-value of min is under the ground, i search for the smallest z-value of all vertices. At the end i get the distance i need to “push up” the object to position it on the ground.

Put this “pushing up” doesn’t really work. The characters normally have a lot of object parts and i try to lift all that have no parents, so the character stays the same.

I have two correction modes:
1. I correct every keyframe. (e.g. for a walking character)

local allObjectsWithName = execute ( "$" + objToMove.objectName + "*" )
			with animate on
			(
				for ob in allObjectsWithName where ob.parent == undefined do
				(
					local keyarray = ob.transform.controller.keys
					if ( keyarray.count <= 0) then
					(
						--try the other way
						local temp = ob[3][1].keys -- keys for position
						keyarray = for asdf in temp collect ( asdf.time )
						
						temp = ob[3][2].keys -- keys for rotation
						join keyarray (for asdf in temp collect ( asdf.time ))
						
						temp = ob[3][3].keys -- keys for scale
						join keyarray (for asdf in temp collect ( asdf.time ))
					)					
					keyarray = uniqueItemsInArray keyarray
					for keyTime in keyarray do
					(
						at time ( keyTime )
						(						
							local newTransform = ob.transform
							local oldPosition = newTransform.row4
							newTransform.row4 = oldPosition + [ 0.0 , 0.0 , objToMove.calcDistanceForObject ]
							ob.transform = newTransform
							--move ob [ 0 , 0 , objToMove.calcDistanceForObject ]
						)
					)
				) -- end for object without parent
			) -- end with animate on

objToMove is a struct i made, which contains the character name and the distance to the ground i calculated before.

2. I correct only the keyframes in which the object goes through the ground. (e.g. for a jumping character)

local allObjectsWithName = execute ( "$" + objToMove.objectName + "*" )
			with animate on
			(
				for ob in allObjectsWithName where ob.parent == undefined do
				(
					local keyarray = ob.transform.controller.keys
					if ( keyarray.count <= 0) then
					(
						--try the other way
						local temp = ob[3][1].keys -- keys for position
						keyarray = for asdf in temp collect ( asdf.time )
						
						temp = ob[3][2].keys -- keys for rotation
						join keyarray (for asdf in temp collect ( asdf.time ))
						
						temp = ob[3][3].keys -- keys for scale
						join keyarray (for asdf in temp collect ( asdf.time ))
					)					
					keyarray = uniqueItemsInArray keyarray
					local itemIndex = findItem keyarray objToMove.problematicFrame
					
					if ( itemIndex > 0 ) then
					(
						local keyFrameTime = keyarray [ itemIndex ] 
						at time ( keyFrameTime )
						(						
							local newTransform = ob.transform
							local oldPosition = newTransform.row4
							newTransform.row4 = oldPosition + [ 0.0 , 0.0 , objToMove.calcDistanceForObject ]
							ob.transform = newTransform
						)
					)			
				) -- end for object without parent
			) -- end with animate on

Here i use objToMove.problematicFrame where i detected the object going into the ground.

Here is my problem:
I made some mini-examples with an animated cube that goes up and down and rotates and so passes the ground. My script works fine as expected.
I used a character from my company and moved that around, and the script works fine.
But when i use a character from my company that just walks, the character isn’t pushed up correctly, that means that the correct distance is detected, and it is added to the transform at the specified keys, but in the end, the character is only lifted like a 60% of the calculated distance. If i run the script again, it lifts the character another 80% or so. It seems that it approximates it. But the distance is calculated correctly, I am sure. The correction pushes the character to the right position after running it like 3 or 4 times in a batch.
I use coordsys world for all calculations, but the result is the same if i remove the coordsys-command.

Do you have any ideas what am i missing? Maybe I got a wrong idea or maybe some weird (weird for me) maxscript-transform-secrets are trolling with me or i don’t know.

Any help is appreciated! Let me know if you want some code. But i can’t give you the characters…
Regards!

1 Reply

I found a way to make the first correction mode work.

-- Get biped root node
local bip = getNodeByName (( objToMove.objectName + "_Bip01" ) as string )

--Turn on Move All Mode
bip.controller.moveAllMode = true

move bip [ 0 , 0 , objToMove.calcDistanceForObject ]
biped.collapseMoveAllMode bip.controller
bip.controller.moveAllMode = false

But that only works with Biped and only if it is called “Name_Bip01”. And one more condition: The character already moves around. It doesn’t work when the character stands still and only its hand moves into the ground.

I would really appreciate it if the second correction mode could work, too.
If someone has any ideas, please share!

Thanks in advance!