armature bone rotation

If your topic doesn't fit anywhere else, put it here.

Moderator: joepal

armature bone rotation

Postby jujube » Sun Apr 22, 2018 12:48 am

Makehuman-utils (https://bitbucket.org/MakeHuman/makehuman-utils/) has an unfinished blender addon that exports makehuman skeletons. In an .mhskel file, bones have a property called "rotation_plane". The blender addon does not create rotation planes, which have to be set manually by opening the file in a text editor.

I wanted to understand the logic behind the rotation planes, having no idea what to manually set them to, so I drilled deep into makehuman\shared\skeleton.py in the source code.
Internally, the rotation_plane is used to set the Bone.roll property. But from my reading of the code, it looks like none of the functions that use Bone.roll are used anywhere.
(and even if they were, the default value for roll is 0, so it shouldn't hurt anything to leave it empty, anyway. )
Or at least not in skeleton.py; one of those functions may still be used somewhere else in the code.

Some of the notes I made for myself while studying skeleton.py:
Code: Select all
Class Bone:
One of the arguments for the Bone constructor is roll, where the default argument is also 0.

Some places where the Bone.roll property is used:

Skeleton.addReferencePlanes._remap_plane_strategy_[numbers 1-3]
These strategies use the Bone.roll property.
The Skeleton.plane_map_strategy property is used to determine the strategy here.
But addReferencePlanes() is not called anywhere.

Skeleton.scaled
This method is only used in Skeleton.clone
   This method is only used in Skeleton.createFromPose
      This method is not used anywhere.

Bone.get_normal
   Used in Bone.build
      this function passes get_normal() to a variable which is only used to pass into getMatrix (which may also perform an action) and assign a value to matRestGlobal
      matRestGlobal determines matRestRelative, and the other way around.
         matPoseGlobal and matRestGlobal determine matPoseVerts
            matPoseVerts is used in Bone.skinMesh
               skinMesh is not used anywhere


edit: the list of planes is also loaded from the mhskel, but planes are also only used in addReferencePlanes()
edit2: From plugs\3_libraries_skeleton\skeletonlibrary.py, which creates/uses a skeleton object:
Code: Select all
            # Remap bone orientation planes from reference rig
            skel.addReferencePlanes(self.referenceRig)  # Not strictly needed for the new way in which we determine bone normals

edit3: addReferencePlanes is definitely used, as it can display its warning, "No normal found for bone %s: no reference bones and could not map implicitly by name", in makehuman.
edit4: wait, crap, that's wrong, that error message is from _get_normal.
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Re: armature bone rotation

Postby jujube » Sun Apr 22, 2018 3:00 am

secrets of skeleton.py part 2
basically ignore my last post.

Skeleton.build:
Code: Select all
        if ref_skel:
            # Direct or reference bone-mapped copy of ref_skel's normals
            normal = copy_normal(self, ref_skel)
        else:
            # Calculate normal from bone's plane definition
            normal = self.get_normal()


The copy_normal method is what throws the error message "No normal found for bone %s: no reference bones and could not map implicitly by name" sometimes seen when attempting custom rigs.
The get_normal method is the one that uses the "planes"/"reference_plane" in an mhskel file (known as "roll" in the code).
It would seem that one of the requirements for a custom armature to work is to set ref_skel to false/none/whatever, somehow.

but, the only thing I can find that sets ref_skel to something other than none is updateJoints()
UpdateJoints is only used in scaled()
scaled is only used in clone()
clone() is not used in skeleton.py. But it is used in skeletonlibrary.py, in def onShow().

Code: Select all
        self.oldHumanMat = self.human.material.clone()
        self.oldPxyMats = dict()
        self.human.material = self.xray_mat
        for pxy in self.human.getProxies(includeHumanProxy=False):
            obj = pxy.object
            self.oldPxyMats[pxy.uuid] = obj.material.clone()
            obj.material = self.xray_mat

Code: Select all
    def clone(self):
        return self.scaled(self.scale)

Code: Select all
    def scaled(self, scale):
        """
        Create a scaled clone of this skeleton
        """
        from core import G

        result = type(self)(self.name)
        result.joint_pos_idxs = dict(self.joint_pos_idxs)
        result.vertexWeights = self.vertexWeights
        result.scale = scale
        result.version = self.version
        result.license = self.license.copy()
        result.description = self.description
        result.planes = dict(self.planes)

        for bone in self.getBones():
            parentName = bone.parent.name if bone.parent else None
            rbone = result.addBone(bone.name, parentName, bone.headJoint, bone.tailJoint, bone.roll, bone.reference_bones, bone._weight_reference_bones)
            rbone.matPose = bone.matPose.copy()
            rbone.matPose[:3,3] *= scale

        # Fit joint positions to that of original skeleton
        human = G.app.selectedHuman
        result.updateJoints(human.meshData, ref_skel=self)  # copy bone normals from self

        return result


So there is no way to not have it use the default joints?? I am confused :?
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Re: armature bone rotation

Postby jujube » Sun Apr 22, 2018 9:50 pm

Part 3 of my "What the heck are rotation planes even for, anyway?" adventure.
I used pyan (https://github.com/davidfraser/pyan) and the GraphViz GUI to view function call graphs of some of the makehuman python 3 source code.
Arrow pointing from foo() to -> bar() indicates that foo() calls bar(). I spent all day looking at them, and then cobbled some bits together in MSPaint, with obvious additions:
planes.png


This is what getBones and __cacheGetBones do:
Code: Select all
    def getBones(self):
        """
        Returns linear list of all bones in breadth-first order.
        """
        if self.boneslist is None:
            self.__cacheGetBones()
        return self.boneslist

    def __cacheGetBones(self):
        from collections import deque

        result = []
        queue = deque(self.roots)
        while len(queue) > 0:
            bone = queue.popleft()
            bone.index = len(result)
            result.append(bone)
            queue.extend(bone.children)
        self.boneslist = result


A lot of stuff uses getBones:
getbones.png


But I haven't actually run any of this, and I don't know if boneslist contains any information about rotation planes. I also haven't found where addReferencePlanes is used. So I still don't know yet if rotation planes do anything useful.
Some possible scenarios:
1. Rotation planes do something absolutely vital, and somebody has to figure out the logic of what to put in them
2. Rotation planes only do something in makehuman, but not in exported files, so we can find a workaround
3. Rotation planes' functionality isn't even fully implemented yet, so we can ignore them
4. Rotation planes do something, but it's optional; you can set them to 0 and it doesn't hurt anything
5. Something else I didn't think of yet

Bonus: Motivations for why I want to figure out how to add custom rigs:
-So makehuman can be more functional and well documented
-So we can add more realistic rigs to makehuman (eg bkurt's stuff)
-So I can have crazy stuff in makehuman like wings or hair rigs or kitsune tails
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Re: armature bone rotation

Postby Elvaerwyn » Sun Apr 22, 2018 11:48 pm

Not sure if this helps at all, but bone rotation is enforced in opensim/Second life and similar worlds to help in bvh creation for fluid character movement.(broken joints-extened armature, clothing seperation etc.) As such some tables have been worked out in relation to this. This chart is an example http://wiki.secondlife.com/wiki/Suggest ... ion_Limits. I have noticed a lack of adherence to proper bone rotation in poses and actions since the launch of bento patch, in many places especially where the legacy avatars meet the new mesh ones with bento skeletons. This is vital for quadraped, tiny, fantasy body type, and winged/tailed avatars. Just food for thought in your process I hope.
She who knows in repose with prose...
User avatar
Elvaerwyn
 
Posts: 375
Joined: Tue Aug 22, 2017 11:28 pm
Location: Canada

Re: armature bone rotation

Postby jujube » Tue Apr 24, 2018 8:54 pm

...hey, that would be pretty cool to have, actually! MHX2 only locks the position of the joint. I thought I remembered it also restricted some of the joints from being moved on certain axes but I just checked and no, they do not.

What I'm really interested in is making MakeHuman more realistic. Well, having the freedom to change the basemesh radically enough to make it realistic, as well as fantasy-based. Whatever the heart desires. (anatomy is really cool though.) blindsaypatten used to post here a lot making threads pointing out anatomical errors, and discovered that the default human apparently has inconsistent weight painting.
viewtopic.php?f=3&t=14183
Lindsay and bkurt were/are perfectly capable of making improved armatures, but the problem was that no one really knows how to put new rigs into makehuman. Only that it's possible in theory because of the extra rigs that are included with makehuman.

One of them was that in the rig file listing the bones, each bone has a property called a "rotation plane", where a rotation plane is apparently defined by two joint tails and one joint head, in a seemingly random manner, and the only tool for making those files doesn't do that automatically.

(I forget which stuff I explained already in this thread, and which was from the other thread(s), so sorry if I'm repeating myself...)

Examples of planes:
Code: Select all
        "breast.L____plane": [
            "special01____tail",
            "spine01____head",
            "spine01____tail"
        ],

The breasts are connected to the base of spine01, but special01 is located somewhere completely different and controls the upper lip.

Code: Select all
        "clavicle.R____plane": [
            "lowerarm01.R____tail",
            "lowerarm01.R____head",
            "upperarm02.R____head"

The clavicle isn't connected to any of these bones. :?

Code: Select all
        "eye.L____plane": [
            "orbicularis03.L____tail",
            "orbicularis04.L____tail",
            "eye.L____head"

The eye bone use its own head to define its reference plane.
All three bones in the finger have their planes defined by the middle bone, last bone, and wrist bone. The feet, head, and jaw bones use their own head and tail to define their reference planes. etc etc etc.

I was digging in the code to understand the inner workings of the MH skeleton, in order to figure out the logic of the rotation planes, or hopefully find out that they aren't needed at all and we can just get rid of them. My next plan might be to get makehuman running from source on my (windows) computer, so that I can start learning more about debugging.
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Re: armature bone rotation

Postby joepal » Tue Apr 24, 2018 9:32 pm

Honestly, I never really understood the rig process, despite several attempts at it. It is unfortunate that there is no good documentation for it.

Getting MH up and running from source I can help with though. I've updated the FAQ item at http://www.makehumancommunity.org/wiki/ ... on_windows with up-to-date instructions for running the current development code on windows.
Joel Palmius (LinkedIn)
MakeHuman Infrastructure Manager
http://www.palmius.com/joel
joepal
 
Posts: 4474
Joined: Wed Jun 04, 2008 11:20 am

Re: armature bone rotation

Postby jujube » Tue Apr 24, 2018 11:10 pm

Oh!! Thanks! I was wondering why it wasn't running. The github page said to install numpy twice, but it turns out I need opengl too. (I'm trying to run the python 3 version of makehuman.)
edit: It didn't fix my errors.
Running download_assets_git.py: "TypeError: stat: can't specify None for path argument"
Trying to run the compile models/etc scripts, I get a numpy ImportError.
And running makehuman.py doesn't give me an error, it prints a nice message to the console, but the window doens't appear.
edit2: There was an old version of numpy in python35/lib that pip didn't uninstall, makehuman runs now, but with broken opengl. the screen is white, the error points to my pyopengl installation
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Re: armature bone rotation

Postby joepal » Wed Apr 25, 2018 10:01 am

Sometimes the order in which you install the packages can confuse things a bit, as pyopengl seems to pull in a specific version of numpy if no numpy was installed before.

A hint if you're interested in experimenting with multiple different python versions/enviroments is to use Anaconda: https://www.anaconda.com/download. This helps you maintain and switch between python profiles and package collections. I have recently switched all my development to anaconda precisely in order to avoid messy python installs when experimenting with different python versions.

I can't really say what causes your opengl issue though. But there are many good reasons for why we've started to basically rewrite the opengl code from scratch.

It would be interesting to know if you get something that works if running the refactor gl branch (https://github.com/makehumancommunity/m ... tor_opengl). Master still runs the old opengl code. Note that the refactor branch isn't even close to functional. Currently you'll see a Qt logo instead of a human when starting it, if it works at all.

Also, if you're interested in further testing exactly where GL breaks (if it breaks with Qt too on your machine), there is a repo with test cases that gradually lifts in more GL stuff: https://github.com/makehumancommunity/gl-test-cases. This is where we're experimenting with what setup to use in MH when having replaced the GL code.
Joel Palmius (LinkedIn)
MakeHuman Infrastructure Manager
http://www.palmius.com/joel
joepal
 
Posts: 4474
Joined: Wed Jun 04, 2008 11:20 am

Re: armature bone rotation

Postby Aranuvir » Wed Apr 25, 2018 8:23 pm

And just another hint. When you're really going to work on the code it might make sense to use a good IDE. I can recommend PyCharm Community Edition. It's free, has some nice tools for code inspection and lets you install python dependencies and manage virtual environments ...
Aranuvir
 
Posts: 1314
Joined: Sun Oct 12, 2014 2:12 pm

Re: armature bone rotation

Postby jujube » Fri Apr 27, 2018 8:47 pm

Update: I installed pycharm, and I'm trying to use it to run the openGL test cases scripts. They don't produce error messages*, but they don't launch any canvases either.
*or I think they don't... I'm not sure what the exit codes mean.
They all print this:
Code: Select all
EFFECTIVE QT VERSION : 5.10.1
REQUESTED GL VERSION : (2, 0)


The one error message I get is when running the genericgl init
Code: Select all
Traceback (most recent call last):
  File "C:/gl-test-cases-master/genericgl/__init__.py", line 5, in <module>
    from .testapplication import TestApplication
SystemError: Parent module '' not loaded, cannot perform relative import


The virtual environment is running python 3.5, with these things in it:
mhvenv.PNG
mhvenv.PNG (6.42 KiB) Viewed 7417 times


I am using Windows 7.

edit: The makehuman master does run, but the main window is still blank white, and there's a lot of errors with glmodule.py
edit2: The refactor branch runs, with no human in the startup, same as it was for me in the last branch. It loaded quicke4r, and the graphics window works but there is a cube instead of a human.
edit3: I see that the refactor branch is incomplete.
jujube
 
Posts: 404
Joined: Fri Aug 14, 2015 10:46 pm

Next

Return to General discussions about makehuman

Who is online

Users browsing this forum: No registered users and 1 guest