Thanks again Cairyn. It sounds like 'op' is similar to 'this' in c#.
BTW - I was able to join your Patreon.
This posting is now closed.
Thanks again Cairyn. It sounds like 'op' is similar to 'this' in c#.
BTW - I was able to join your Patreon.
This posting is now closed.
Hi Cairyn,
Your suggested changed fixed my issue! How do I access the user data for parameters from the tag?
My old method was to first find the null object, then the user data within it:
# Find this controller
contlr = doc.SearchObject("Re-Target_Controller")
if not contlr:
c4d.gui.MessageDialog("ERROR Motion Retarget Controller not found!")
return
baseSource = contlr[c4d.ID_USERDATA, 2]
if not baseSource:
c4d.gui.MessageDialog("ERROR Source object joint root not provided!")
return
Hi Cairyn,
Thanks for the VERY detailed reply and sample project! I'll try re-doing my project.
BTW - I'm trying to join your Patreon (if I get the web site to send me an email to reset my password). I have another Python joint animation re-targeting project I'm having challenges with matrixes and changing joint rotation orientation.
Bruce Kingsley
Hi Cairyn,
Thanks for the reply. Much of your insight is correct, here is the breakdown.
I created a null and added user data for parameters, object links and a button. This is the only way I know how to create an interface.
I attached a Python tag to the null. The Python tag has a AddEventNotification and a message function to capture when the button is pressed, which in turn calls the Python code that does the re-targeting.
When the re-targeting code starts, it first obtains all the user data (interface) attached to the null, then performs the re-targeting.
I'm guessing the AddEventNotification is stealing Cinema 4D performance because it's being called anytime anything happens in Cinema 4D.
Reading between the lines of your last reply, I should be calling a Python script? Does this mean a standalone Python file? If so, do you know of any examples of that demonstrate how to create a user interface that is displayed that the Python code can obtain the parameters and run specific code when buttons is pressed?
Hi Cairyn,
I already tried doc.ExecutePasses(None,True,True,True, c4d.BUILDFLAGS_NONE) after the SetTime() function, but it doesn't make a difference. Are there different parameters I should be using?
I've created two Python scripts (tag based) that transfer animation from one character to another. The first one simply copies the source character joint rotation keyframes to the target character joints. This script works fine.
The second script is a bit different. Here the source character is setup with IK chains and goals. I first perform my animation using the goals plus some xPresso that also moves the joints. In this case, the joints don't have any keyframes to copy because the joints are being rotates by external means. I wrote my script to read the source joints rotation values, then copy them to the target character joints creating keyframe. I'm using the doc.SetTime() function to move to the next frame in the timeline. The problem is, it looks like doc.SetTime() doesn't actually change the current frame while the script is running. My target character does get new keyframes for each frame, but it's only of the first frame. It's like time line (and source character) isn't getting updated every time doc.SetTime() is called. Is there a Python function that tells Cinema 4D to update everything when the current frame is changed by the script?
I'm using Cinema 4D R21.
Is the version of Python used within Cinema 4D R21 "built-in" to Cinema 4D, or can it be updated to a new version?
If it can, how is it done, and is there backwards compatibility risks with exiting plugins, scripts, etc?
@m_magalhaes
Hi Manuel,
Sorry for not making my last post clear, I wasn't requesting you to test my code as is it seems to work from my tests. I just wanted to see if I was combining the matrixes together correctly. Thanks for the help, consider this issue "Solved".
@m_magalhaes
Hi Manuel,
It looks like the code does what I need, though I'm still working to understand why it works. Below is a code snip of how I combined all of the joints three rotation values from the source joint and transferred it to the target joint as well as obtaining the new target rotation vector to set animation keyframes. Does this look correct?
# Rotation values from source joint (for code testing only).
sourceYValue = 90
sourceXValue = -90
sourceZValue = 0
# Define a matrix rotation around the axis of the source joint rotation values
mX = c4d.utils.MatrixRotX(c4d.utils.DegToRad(sourceXValue))
mY = c4d.utils.MatrixRotY(c4d.utils.DegToRad(sourceYValue))
mZ = c4d.utils.MatrixRotZ(c4d.utils.DegToRad(sourceZValue))
# Combine all source joint rotation maxtrixs into one.
mTotalTargetRelitiveTransforms = mX * mY * mZ
# We just want the rotation so we can reset the offset
mTotalTargetRelitiveTransforms.off = c4d.Vector(0, 0, 0)
# Get the target joint orginal matrix rotations.
mTargetOrginalTransforms = targetJoint.GetMg()
# Combine target joint orginal matrix with new relitive rotation matrix.
newTargetMatrix = mTotalTargetRelitiveTransforms * mTargetOrginalTransforms
# As we just want to keep the rotation, we "reset" the position with the
# previous one.
newTargetMatrix.off = mTargetOrginalTransforms.off
# To be sure the scale remain to 1 we normalize the matrix
newTargetMatrix.Normalize()
# Set the target joint new rotations.
doc.AddUndo(c4d.UNDOTYPE_CHANGE, targetJoint)
targetJoint.SetMg(newTargetMatrix)
# Use this vector to set animation keyframes.
vNewAnimationValues = targetJoint.GetRelRot()
@m_magalhaes
Hi Manuel,
Thanks for the same code, I try it this weekend.
I've spent the last couple of days studying Matrixes and playing with code. During my tests, I noticed the GetMg() function returned the rotation created by the parent shoulder joint being changed to 45 deg, where I can see why the order of operation is important. I found a bunch of sample code rotating objects with points, but noting on a joint that has no points.
Thanks again. Bruce.
@m_magalhaes
Hi Manuel,
Attached is two characters, a source character rigged in a T-Pose and target character rigged in a A-Pose.
I animated the joints to show the challenge. I first rotate the shoulder of the target character shoulder so it's in the T-Pose like the source character. Then I rotate both characters forearm 66 deg in the H axis. You can see the poses don't match due to target orientation of the axis when rigged being different.
As far as my code, I'm doing pretty much the same as the Retarget tag except I'm reading the animation tracks of the source character and reading the vector values, and creating new animation track for the target character, which works fine if the both characters were originally rig using the same pose. But in this case, I'm adding 45 degs to the target character shoulder values which makes all child joints orientation of the axis different. So using the vector values are no longer correct.
I’ve run into a math challenge working on an animation re-targeting script. This Python script copies the bone rotational properties from one character rig to another (like the retarget tag) but also performs additional modifications and clean-up.
I'm using Cinema 4D R21.
Up to now, both characters were always rigged based on an “A-Pose”, but now the source characters can be based on a “T-Pose”. Simply adding 45 deg to the shoulder works fine, but every bone to the fingers center of rotation is now off by 45 deg. I’m struggling to find the math or hopefully a Cinema 4D Python functions that will enables me to calculate from the single axis rotation from the source rig, to the “multiple axis” rotations required for the target. This would be similar math used by Cinema 4D when rotation an object in “World Space”.
Example, if I have the source character in the T-Pose position and rotate the forearm “forward” 45 deg in the “H” axis only, the target character I first add 45 deg to the shoulder to the “B” axis making it in the T-Pose, then I need to apply multiple axis values close to (H = 35.264, P = -30, B = 9.736) to get the same orientation of the source character.
Source Character
Target Character
Any ideas? Bruce Kingsley
Does anyone know of Python code to both remove keyframe noise and also perform keyframe reduction somewhat like the timeline keyframe reduce function? I'm importing face capture FBX files produced by the Apple ARKit which contains multiple morphs with keyframes on every frame. Some keys have very small changes that produces a "vibration" look, or sudden changes "spikes" that I manually delete. Then I perform the keyframe reduce function on each morph not only to remove keys, but to create a nice smooth curve giving the animation a more fluid, natural look.
Another option is if anyone knows how (and if) the Cinema 4D keyframe reduce function can be called from Python.
I'm using Cinema 4D R21.