Atom Posted May 2, 2018 Share Posted May 2, 2018 (edited) I am trying to use python to create a series of CHOP expressions to link a mocap/.bclip driven bone structure to a NULL based FBX rig. While this CHOP technique works fine for translation (hips track mocap good), it does not seem to work for rotation. I have tried all kinds of offsets and axis re-mappings but none of them produce a tracked result that I need to continue with this work. Is there some kind of math that needs to happen to rotation values to transfer them from one node to another? Here is my basic working expression, with 90 being an manual offset I tried. (90+chop("/obj/crowd_mocap_SOURCE/mocap/data/calf_L:rx")) The attached scene contains my entire working setup so far, including the fixup scripts I used to prepare the BVH data from mocapdata.com for .bclip conversion. As you can see in the animated image I do get some tracking on the thigh, but it does not fully match the range of movement found in the mocap. mocap_retarget_issue.zip Edited May 2, 2018 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted May 2, 2018 Author Share Posted May 2, 2018 (edited) Had a small break through. I am using a Limit CHOP with Normalize enabled to force the MIN/MAX of each channel in to the known -1,1 range. This allows me to construct a fit from the CHOP to remap into the target range for the NULL rotations. The new CHOP expression looks like this for the lower leg. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/foot_L:rx"),-1,1, 10,(10-90)) The new CHOP expression looks like this for the upper leg. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/calf_L:ry"),-1,1, 25,(25-45)) I guess I have to determine each bone range by trial and error..? Edited May 2, 2018 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted May 2, 2018 Author Share Posted May 2, 2018 (edited) It looks like the upper leg, on the right side, needs it's fit range reversed, while the lower leg does not...hmmm. A jumble of special cases. Upper RIGHT leg expression. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/calf_R:ry"),-1,1, (25-45),25) Lower RIGHT leg expression. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/foot_R:rx"),-1,1, 10,(10-90)) Edited May 2, 2018 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted May 4, 2018 Author Share Posted May 4, 2018 (edited) I managed to get the upper arms socket mapped to two axis from the mocap data. So on this particular joint, RZ is driven by RX data and RX is driven by RY. RZ gets these expression. // Left Side. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_L:rx"),-1,1, -70,(-70+90)) // Right Side. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_R:rx"),-1,1, 70,(70-90)) RX gets these expressions. // Left Side. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_L:ry"),-1,1, 45,(45-90)) // Right Side. fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_R:ry"),-1,1, (45-90),45) Edited May 4, 2018 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted May 4, 2018 Author Share Posted May 4, 2018 (edited) I created a def to link offset values to the expression. The slider callback is linked to the def.This makes it easier to dial in a specific bone section on the target rig. exec(kwargs['node'].parm('python').eval());updateUpperArm() node_self = hou.pwd() bone_target = node_self.parm("rig_target").eval() def updateUpperArm(): value_X = hou.Node.evalParm(node_self, "rot_upper_arm_X") value_Z = hou.Node.evalParm(node_self, "rot_upper_arm_Z") # Right. target_candidate = "%s/%s" % (bone_target, "upperarm_R") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_R:ry"),-1,1, (%s-90),%s)' % (value_X,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_R:rx"),-1,1, %s,(%s-90))' % (value_Z,value_Z) t.parm('rz').setExpression(expr) # Left. target_candidate = "%s/%s" % (bone_target, "upperarm_L") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_L:ry"),-1,1, %s, (%s-90))' % (value_X,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/lowerarm_L:rx"),-1,1, -%s,(-%s+90))' % (value_Z,value_Z) t.parm('rz').setExpression(expr) Edited May 4, 2018 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted May 4, 2018 Author Share Posted May 4, 2018 I have spine neck and head installed. It looks like each expression set requires it's own def to update the expressions when the sliders change. def updateSpine(): value_X = hou.Node.evalParm(node_self, "rot_spine_X") value_X_range = hou.Node.evalParm(node_self, "rot_spine_X_range") #45 value_Y = hou.Node.evalParm(node_self, "rot_spine_Y") value_Y_range = hou.Node.evalParm(node_self, "rot_spine_Y_range") #45 value_Z = hou.Node.evalParm(node_self, "rot_spine_Z") value_Z_range = hou.Node.evalParm(node_self, "rot_spine_Z_range") #45 # Spine from pelvis up to head. target_candidate = "%s/%s" % (bone_target, "spine01") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/spine02:rx"),-1,1, %s,(%s+%s))' % (value_X,value_X_range,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/spine02:ry"),-1,1, (%s+%s),%s)' % (value_Y,value_Y_range,value_Y) t.parm('ry').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/spine02:rz"),-1,1, (%s-%s),%s)' % (value_Z,value_Z_range,value_Z) t.parm('rz').setExpression(expr) target_candidate = "%s/%s" % (bone_target, "spine02") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/neck:rx"),-1,1, %s,(%s+%s))' % (value_X,value_X_range,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/neck:ry"),-1,1, (%s+%s),%s)' % (value_Y,value_Y_range,value_Y) t.parm('ry').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/neck:rz"),-1,1, (%s-%s),%s)' % (value_Z,value_Z_range,value_Z) t.parm('rz').setExpression(expr) target_candidate = "%s/%s" % (bone_target, "spine03") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/head:rx"),-1,1, %s,(%s+%s))' % (value_X,value_X_range,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/head:ry"),-1,1, (%s+%s),%s)' % (value_Y,value_Y_range,value_Y) t.parm('ry').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/head:rz"),-1,1, (%s-%s),%s)' % (value_Z,value_Z_range,value_Z) t.parm('rz').setExpression(expr) target_candidate = "%s/%s" % (bone_target, "neck") t = hou.node(target_candidate) if t != None: expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/headEnd:rx"),-1,1, %s,(%s+%s))' % (value_X,value_X_range,value_X) t.parm('rx').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/headEnd:ry"),-1,1, (%s+%s),%s)' % (value_Y,value_Y_range,value_Y) t.parm('ry').setExpression(expr) expr = 'fit(chop("/obj/crowd_mocap_SOURCE/mocap/OUT/headEnd:rz"),-1,1, (%s-%s),%s)' % (value_Z,value_Z_range,value_Z) t.parm('rz').setExpression(expr) Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.