Joints from a text file

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

Thread Tools Search this Thread Display Modes
  11 November 2017
Joints from a text file

Has anyone ever written code (COFFEE, C++, Python) that creates joints from a text file?
Parsing the text data and using it to create the joints is pretty simple.
But I'm having trouble figuring out how to handle the nested tree branches when adding the joints to the OM. And I'd like to see how other people would approach this problem.

Searching the internet on this turned up nothing helpful at all.

My Gallery
  11 November 2017
Shouldn't the text file already define the hierarchy? If not, how do you determine how the joint tree is supposed to look like? And if yes, isn't that already the answer to your question?
  11 November 2017
I'm having a hard time with joints that are on the same level as other joints. But in different branches.

Suppose I've parsed my text file into a list of tuples where each tuple has the joint's name & the joint's level like this:
*To keep this short. I've only shown the arm joints for the right side.
joints = [ ('Hips', 0), ('spine', 1) , (chest, 2), ('RightCollar', 3), ('RightShldr', 4) ('RightHand', 5), ('RightThumb1', 6), (RightThumb2, 7), ('RightIndex1', 6), ('RightIndex2', 7), ('RightMid1, 6 ), ('RightMid2, 7) ]

Notice how once we get to the fingers. Some of the joints are on the same level...But not in the same branch.
I keep getting twisted around trying to figure out how to describe to the computer which joints to add to which branch.
It's not enough to know their levels. I also need to somehow incorporate the branches they belong to. But I can't get it working properly.

My Gallery
  11 November 2017
You just need to keep an array of pointers to the last element in each level. Then any element you encounter will be appended as next sibling in the hierarchy behind that last element on the level. You just need to set the conditions right, and of course the file source must never do funny stuff like skipping a level.

Like this:
Initialize your array with nulls.
You start with hips, will become the first element in the array because the array is null everywhere [null, null, null, null, null, ...] and the hips are on level 0.
Array is now [hips, null, null, null, ...]
Then the spine, is on the next level, where the array is still null, so the spine will be appended as first child of the previous array element, and the spine will become the second array element.
Array is now [hips, spine, null, null, ...]
Then the chest, is on the next level again, same procedure. chest becomes a child of spine.
Array is now [hips, spine, chest, null, null, ...]
And so on down to the RightThumb2, this is boring.
Array is now [hips, spine, chest, rightcollar, rightshoulder, righthand, rightthumb1, rightthumb2, null, null, ...]
Now things become interesting as the next element has an index that was used before: rightindex1. This is on level 6. We already have an element on level 6 in the array, which is rightthumb1. Thus, rightindex1 becomes the next sibling of rightthumb1 (as child of righthand), will become the level 6 pointer in the array, and the array after level 6 is nulled.
Array is now [hips, spine, chest, rightcollar, rightshoulder, righthand, rightindex1, null, null, ...]
Next element is rightindex2, which goes to level 7 which is now nulled, so it becomes the first child of rightindex1 again.
The game continues until all elements of the file are added. When the OM tree is built, you can throw away the array.
The array needs to be big enough to hold a pointer for all levels of the prospective hierarchy, but that is not difficult.
  11 November 2017
Thanks for trying to the help Robert. But I'm not having troubles parsing the data into arrays.
The problem I'm having is trying to re-create those joints in C4D from the array elements.
Once I have the entire rig listed in an array in the correct order. I can't just simply use doc.InsertObject(curArrItem, prevArrItem) on them. Because in some cases where there are multiple branches per level that puts them under the wrong parent.
I need to know the code to determine if a joint being inserted is the child of an existing branch. And where that parent is. Or if it's the start of a brand new branch. And where that new branch is.
It's not as simple as it sounds. It's easy to get all twisted around trying to set up the rules to solve this.
I keep getting close..but not quite there.

Another approach I've tried is to read the joints from the text file. And create them in C4D as a flat tree (no parent/child branches) in the same order they are in the text file. Then iterate over them and set up the parent/child relationships.
Doing it this way. The joint names have empty spaces in front of them. Which I can count , and use to determine what level each joint should be moved to.
I can successfully create the flat tree with all the joints in the proper order. But once again. When I go to try to set up the parent/child relationships. I have the same problem where multiple joints have the same level (in this case. The same number of empty spaces in the names). And I can't figure out how to determine which branch to put them in.
Then I start pulling my hair out again.

My Gallery
  11 November 2017
Quote: Thanks for trying to the help Robert. But I'm not having troubles parsing the data into arrays.
The problem I'm having is trying to re-create those joints in C4D from the array elements.

You misunderstand what I'm using the array for.

Please read the algorithm again TO THE END when I get to the fingers (the hip/spine/chest part is trivial), and you will see how the array serves as a marker for the last element in a level. This array is not the stuff you read from the file, but a dynamic structure that is used for delimiting the floating "border" of the generated OM tree.
  11 November 2017
Sorry about that Robert.
I have a problem with sentence based coding explanations. If it's not written in code form I have a very hard time understanding what the person is saying most of the time.
If the answer is there. I'm not seeing it.

My Gallery
  11 November 2017
Originally Posted by Scott Ayers: Sorry about that Robert.
I have a problem with sentence based coding explanations. If it's not written in code form I have a very hard time understanding what the person is saying most of the time.
If the answer is there. I'm not seeing it.

maxlevels = 25
edgeoftree = new Array [0..maxlevels] # this is the mysterious array
def clear_edge (start):
    # just for nulling the array
    for i in [start..maxlevels]:
        edgeoftree[i] = None

def insert_joint(rootobj, currentjoint):
    # naturally, you need to check the parameters for None here,
    # also the level in the currentjoint for > maxlevels
    currentjoint_obj = make_obj_from_joint(currentjoint) # create your C4D BaseObject from your own data type
    if currentjoint.level = 0:
        currentjoint_obj.InsertUnderLast(rootobj) # joint is inserted into OM tree on the top level
        edgeoftree[0] = currentjoint_obj # remember this object as last inserted for the level 0
        currentjoint_obj.InsertUnderLast(edgeoftree[currentjoint.level - 1]) # joint is inserted under the last created parent
        edgeoftree[currentjoint.level] = currentjoint_obj # remember this object for adding future children
        clear_edge(currentjoint.level + 1)
        # clearing the rest of the array is actually needed to perform validity test that I'm skipping here,
        # so it looks unnecessary, but you will appreciate it when you handle the error cases

def load_joints(obj):
    # parameter is the root of the constructed joint tree, for example a null in the hierarchy
    while there are joints in the file:
        currentjoint = read_from_file() # currentjoint is your own data type containing all the data from the file, including the level and the name

No guarantees, as this is just pseudocode and obviously not tested in any way.
  11 November 2017
For me there is two of doing it.
Implemting your own BaseList2D with serialization (I mean at least, each object get an Unique ID, each Object know parent uuid and his next / pred uuid), cool things about that it allow you to manage the file async or in parallel.

The other way is by register the order you foud an object. For Exemple to get the 4th object you have done. RootObj.GetNext().GetDown().GetNext() so you know the actual structure, since the order is the same and if in the the writting of the file you do it from top to bottom, you are sure if you insert from top to bottom to have the exact same thing. Cool things about this is way more easy to implement, since you don't have to rewrite your kind of BaseList2D class.

Hope it's help !
  11 November 2017
Thanks Robert.
That pseudo code was just enough information for me to figure it out.
Have a nice Thanksgiving.

Here is a working Python version of it in case anyone else needs it:
import c4d

#Load and parse your text data into a list from a text file however you want
#Here I just hard code it manually
textData = [('Hips', 0),

#This list is used to store the parent joints
#So we can go back and find the right parent joint later on as needed
parents = []

#This is a list of the current joints
joints = []

def main():

 #First create all of the joints from the names listed in the textData list
 #Then store them in a list
 #Then create a null element in the parents list for each joint
 for i in xrange(len(textData)):
 jnt = c4d.BaseObject(1019362)

 #Add the first joint (hips) to the OM
 #Then set this joint as the first parent element in the parents list
 root = joints[0]
 parents[0] = root
 Now that we have the hips as the root of the hierarchy
 Lets create the children in the OM
 for i in xrange(len(textData)-1): 
 currentjoint = joints[i+1] #NOTE: i+1 skips processing the root joint
 level = textData[i+1][1] #NOTE: i+1 skips processing the root joint
 currentjoint.InsertUnderLast(parents[level - 1])
 parents[level] = currentjoint
 parents[level + 1] = None


if __name__=='__main__':

My Gallery
  11 November 2017
From artist perspective a question : in which cases do you get a text file with joints? Fbx multi app pipeline ? Custom rig builder?
  11 November 2017
In my case it's for 3 reasons.
1- To know how to do it in case I need it
2- For use in my own plugins
3 -The exporters/importers in my version of C4D (R13) have some limitations and bugs in them. So sometimes I want to do things myself with my own code

My Gallery
  11 November 2017
I see, thanks!
  11 November 2017
Why are you storing an int for the level rather than an array of joint and parent object? That way branching and such would be a non-issue, no?
"We do not - not wag our genitals at one another to make a point!"
  11 November 2017
Hi Bret,
I'm using integers for the levels because it's more application agnostic that way.
There will be times when I do this task inside of Qt, or Maya, or some other app. Not just in C4D.
There's probably lots of other ways to skin this cat.
For example. I'll bet it can also be done using recursion rather using arrays.

My Gallery
reply share thread

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Society of Digital Artists

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump

All times are GMT. The time now is 08:31 AM.

Powered by vBulletin
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.