Atom Posted August 3, 2016 Share Posted August 3, 2016 (edited) Hi All, I am trying to make a python script that will read the Acclaim .asf file and generate a skeleton from the file. I have the basics of bone creations and parsing done but I just can't figure out the bone rotations. What I end up with is a skeleton that curves in on itself. The code can be placed in a shelf tool button to run. The rotation calculation occur around line # 120. import os file_asf = r"C:\Users\Admin\Documents\Mocap\amc_original_data\61.asf" lst_source_axis = ["rx","ry","rz"] lst_target_axis = ["rx","ry","rz"] def returnIndexForAxis(passedAxis): for (i,axis) in enumerate(lst_source_axis): if axis == passedAxis: return i return None def returnASFBoneRecord(passedBoneName): # Read the .asf skeleton file looking for DOF information. lst_record = [] if os.path.isfile(file_asf): lines = [line.rstrip('\n') for line in open(file_asf)] gather_data = False found_section = False last_name = "" for raw_line in lines: line = raw_line.lstrip() if found_section: if gather_data: if line == "end": if last_name == passedBoneName: # This is the record, we are done. return lst_record else: # Blank record and wait for next begin. lst_record = [] # Stop gathering we have encountered an end. gather_data = False else: # Split this line an review. ary = line.split(" ") if ary[0] == "name": last_name = ary[1] #print "last_name:%s" % last_name lst_record.append(line) else: if line == "begin": gather_data = True else: if line == ":bonedata": found_section = True else: print "File [%s] not found." % file_asf return lst_record def returnASFHierarchy(): # Read the .asf skeleton file looking for bone hierarchy. lst_record = [] if os.path.isfile(file_asf): lines = [line.rstrip('\n') for line in open(file_asf)] gather_data = False found_section = False last_name = "" for raw_line in lines: line = raw_line.lstrip() if found_section: if gather_data: if line == "end": return lst_record else: lst_record.append(line) else: if line == "begin": gather_data = True else: if line == ":hierarchy": found_section = True else: print "File [%s] not found." % file_asf return lst_record # Button click handlers. # ---------------------- def generateSkeleton(): bone_length_mult = 0.45 #global scale from .asf files (they all seem to be the same). skeleton_root_name = 'ap_skeleton_asf' lst_hierarchy_record = returnASFHierarchy() if len(lst_hierarchy_record) > 0: node_subnet = hou.node('/obj').createNode('subnet',skeleton_root_name) #print "" for parent_child_bone_chain in lst_hierarchy_record: ary = parent_child_bone_chain.split(' ') l = len(ary) if l > 1: # Create each bone in this bone chain. for index in range(l): bone_name = ary[index] bone_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, bone_name) bone_node = hou.node(bone_candidate) if bone_node == None: # Time to create this bone node. if index == 0: bone_node = hou.node('/obj/%s' % skeleton_root_name).createNode('null',bone_name) else: bone_node = hou.node('/obj/%s' % skeleton_root_name).createNode('bone',bone_name) # The first name is the parent of all children in this bone chain. parent_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, ary[0]) parent_node = hou.node(parent_candidate) if parent_node != None: for index in range(1,l): #print l, index bone_name = ary[index] bone_candidate = "%s/%s" % ('/obj/%s' % skeleton_root_name, bone_name) bone_node = hou.node(bone_candidate) if bone_node != None: print "connecting [%s] to [%s]." % (parent_node.name(), bone_node.name()) bone_node.setInput(0,parent_node) lst_bone_record = returnASFBoneRecord(bone_name) lst_items = lst_bone_record[3].split(' ') # bone length. bone_length = float(lst_items[1]) * bone_length_mult bone_node.parm("length").set(bone_length) lst_items = lst_bone_record[4].split(' ') # axis offset in degrees. lst_degrees_offset = [float(lst_items[1]),float(lst_items[2]),float(lst_items[3])] lst_items = lst_bone_record[2].split(' ') # direction vec_target = hou.Vector3(float(lst_items[1]),float(lst_items[2]),float(lst_items[3])) vec_source = hou.Vector3(0,0,-1) * parent_node.worldTransform() #Bones in Houdini are oriented down the -Z axis by default rot_result = vec_source.matrixToRotateTo(vec_target) eulerAngles = rot_result.extractRotates() for (i,value) in enumerate(lst_degrees_offset): bone_degrees = eulerAngles[i] #+ value bone_node.parm(lst_target_axis[i]).set(bone_degrees) else: print "unable to locate [%s]." % parent_candidate generateSkeleton() Does anyone know how to fix such rotation issues? The above script and an example .asf file to test with are attached in the ZIP file. asf_file_reader.zip Edited August 3, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
michael Posted August 3, 2016 Share Posted August 3, 2016 is there a reason you're not using the mcacclaim command line tool? Help > Stand-alone Utilities > mcacclaim Quote Link to comment Share on other sites More sharing options...
Atom Posted August 3, 2016 Author Share Posted August 3, 2016 (edited) I am trying to leverage motion capture but no matter what software I use the end result is a bound up junky looking character. I remember the first time I applied a motion capture to a poser figure over ten years ago. I thought wow, look, I animated that. But I was, of course, looking past the fact that the shoulders were all jacked up and the feet slid all over the place. Ten years have gone by and I am still looking into how to leverage mocap. I only have access to the free mocap data posted on the web. While this data does have some issues, the main issue I have is with the binding of the mesh to mocap skeleton. If I use Poser, Blender, Houdini it does not matter, in the end I get a mesh that bends wrong and interpenetrates with itself. In Houdini, I have carefully set weights and event sculpted and smoothed them but there is no volume preserving in the deform node AFAIK. My recent approach was to try to adjust bone chain lengths via scripting to better fit the target mesh but I still cant get a decent looking mesh after weeks of coding. After reading a bit on the Carnegie Mellon University page I noticed that the original acclaim mocap data was converted to BVH and other formats using a tool that no longer exists. I wanted to return to the original data and try to import it to see if something was lost during the conversion. I have used mcbiovision but not mcacclaim. I as I poke around with command line parameters I can not get the mcacclaim.exe to work. Here is my line from the Windows BATch file which produces no results. "C:\Program Files\Side Effects Software\Houdini 15.5.480\bin\mcacclaim.exe" "C:\Users\Admin\Documents\Mocap\amc_original_data\61_11.acm" "C:\Users\Admin\Documents\Mocap\amc_original_data\61.asf" Edited August 3, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
MrScienceOfficer Posted August 3, 2016 Share Posted August 3, 2016 (edited) vec_source = hou.Vector3(0,0,-1) * parent_bone_world_matrix #Bones in Houdini are oriented down the -Z axis of the parent transform rot_result = vec_source.matrixToRotateTo(vec_target) eulerAngles = rot_result.extractRotates() I said on your other thread "#Bones in Houdini are oriented down the -Z axis by default". My phrasing probably should have been more clear (see above). However this won't solve your problem with poor deformation, it's not that it is wrong it's simply that an anatomical being of bone and flesh is always interpenetrating itself, it's just that flesh will move out of the way of the other flesh. You need to simulate the flesh and bones. I highly recommend diving into PBD(rather then FEM, but that's just my opinion though) for this, a good way to do this is convert the entire character mesh into a grain object then capture and drive the particles using the bone skeleton. However this solution is not simple and will likely require months of work to get appealing(rather then just non-interpenetrating) results. Edited August 3, 2016 by MrScienceOfficer Quote Link to comment Share on other sites More sharing options...
Atom Posted August 3, 2016 Author Share Posted August 3, 2016 (edited) Thank you Tom, I am just getting back to this task and I was implementing your suggestion from the other thread in this stand alone shelf button. Now I see your addition of the parent matrix for the source. The addition of the parent matrix to the source vector does help! Now I mainly have to deal with arms fixup which might require applying those axis offsets from the .asf file. vec_source = hou.Vector3(0,0,-1) * parent_node.worldTransform() #Bones in Houdini are oriented down the -Z axis by default rot_result = vec_source.matrixToRotateTo(vec_target) eulerAngles = rot_result.extractRotates() for (i,value) in enumerate(lst_degrees_offset): bone_degrees = eulerAngles[i] bone_node.parm(lst_target_axis[i]).set(bone_degrees) Edited August 3, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted August 3, 2016 Author Share Posted August 3, 2016 (edited) @Michael: I have copied my .asf and .acm files into the bin folder where the mcaaclaim.exe resides. When I specify the files the tool can not read the .acm file? I have tried other paths as well (not residing under Program Files) but the tool can not read the .acm file. It looks like a valid .amc file... Have you tried the tool recently? #!OML:ASF I:\salsa\salsa 7_09\Patient 1\Session 1\dancerfemale.ASF :FULLY-SPECIFIED :DEGREES 1 root 20.2295 16.0545 -0.871178 -179.638 -87.324 -175.278 lowerback -2.21309 1.89048 -0.205027 upperback -4.94698 2.37668 -1.31581 thorax -3.8039 1.12054 -1.26386 lowerneck -2.9433 -3.43647 -6.60136 upperneck 9.01638 -5.03474 7.89536 . . . acclaim_example_set_acm+asf.zip Edited August 3, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
Atom Posted August 3, 2016 Author Share Posted August 3, 2016 (edited) I have included a .acm reading portion in this tool. I think I am applying the .acm rotations right but I still don't have a valid rig structure. asf_amc_file_reader.zip Edited August 3, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
michael Posted August 3, 2016 Share Posted August 3, 2016 running Houdini 15.5.557 Linux Mint extracted your acclaim_example_set_acm+asf.zip file into a directory in a shell: > mcacclaim 61_11.amc 61.asf 61_11_test I get these two warnings Quote Warning 14: Ignoring unsupported 'axis' tag for :root (assuming 'xyz') Warning 16: Ignoring unsupported 'orientation' tag for :root (assuming 0,0,0) but I do get the following files: 61_11_test.cmd 61_11_test.bclip and I can run the cmd file in Houdini 61_11_test.zip I'll find someone to test this on Windows to see if that might be where the problem is... Quote Link to comment Share on other sites More sharing options...
Atom Posted August 3, 2016 Author Share Posted August 3, 2016 (edited) Thanks for testing Michael, the resulting file does work, however the FPS seems OFF compared to the .bclip generated by mcbiovision for the same mocap clip. I still can't get any mcacclaim conversion to work at all on windows 7. I have tried backwards and forwards slashes, putting the path in quotes and not putting the path in quotes. This is the same exact batch file that does work with mcbiovision. Your resulting skeleton is the same as the one generated by the BVH version generated by mcbiovision.exe. The hierarchy is the same as my script code except for a slight naming convention. I guess there is no point in re-inventing the wheel if the skeleton is the same. Edited August 3, 2016 by Atom 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.