Bone Info for geometry nodes

Hello everyone!

At the moment I am trying to write new nodes for GeometryNodes.

My tasks are to write a node that will accept only the Armature Type. (I think this is not a problem, I have already written some node that checks whether it is armature).

But I ran into a problem, and I do not really see any documentation about it.

Let’s imagine that there is armature - it has bones.

I want to create dynamic outputs from the node with the name of each bone from the armature.

Here is some concept:


Please help me!

I`m not good at geometry nodes, but I think such node will help to some ppl.

If you can, share some example of C++ code. Would be great.

You have to choose, or armature input socket or dynamic output sockets. And still quite hard to implement for beginner and not sure this is mean to be commited into blender so this is right place to discuse this.

For a node that dynamically adds sockets you could check out the Index Switch node:

However, the design as described doesn’t work very well, because the Object is itself a runtime value. At the time when the node sockets are defined the actual object is unknown, so you can’t actually tell what (if any) bones it has and which sockets would need to be added. The node can be evaluated in different context with a different armature.

If you make the armature object a fixed property of the node itself you could get the actual pointer in the node_declare function - but then it cannot be a socket and the node is not a re-usable building block any more. It gets tied to one specific object and users would have to change the setting inside the node tree.

The above aside, I’m also not sure its a usable/workable design option. I mean the Armature could easily have 100’s of bones. Remember, not only are the deform bones actual bones, but so are all the animation control bones, so average human character, 1000+ bones, easy.

Just the fingers/thumb would be 15 deform bones, likely double for FK/IK/Tweak control bones, then add the rest of the hand, then double again for other hand, I think you get the picture.

A massive long Armature node.
What you’d need is some sort of method/nodes to select/extract the bones or bone chain that you then want the rest of the node tree to work on.
But now of course we are starting to talk about a whole rigging nodes system and the dev’s aren’t up to that stage yet.

2 Likes

Why not? Probably there is some documentation of API blender (not python).

I trying to get it :frowning:

You`re right 100%.

Maybe it’s worth making a pointer on the armature, adjusting the socket directly in the n-panel.

So yeah, we will not show all bones dynamically. We can create by hand.

Thanks for the suggestion and idea!

Since I have a rather small understanding of writing nodes, by default I will output the vector-position of the bone (To begin with). I think I will somehow select the bone in the menu.

image

No Problem, best of luck.

1 Like

A Bone Info node seems like a better fit, that takes an armature object and bone name as input, and outputs various bone properties.

2 Likes

Yeah. Probably good idea. I trying to understand how to get pointer of Armature. In python it was pretty easy. In C++ there almost no documentation about it. If you can send some link - would be great.

Right now the code doesnt looks good. But Im trying my best. Thanks to everyone who help me.

Zakmen150/blender_fork: The official Blender project repository. - blender_fork - Blender Projects

Right now Its working (Bad). But working only if something update to node. Like the Function execute working only if we did something with node.

The search is done by bone name, which will probably be quite difficult in terms of speed and memory for larger rigs.

But I hope you like the idea and you will not remain indifferent.

So the main question is: How to get realtime changing of bone? Somehow need to getting bone position by desgraph (MAYBE!).

Can you help with it? Code below.

Maybe I need to look at something. But for now cant find it.

Video:

1 Like

You will likely need to make changes in source/blender/nodes/intern/geometry_nodes_dependencies.cc and source/blender/modifiers/intern/MOD_nodes.cc.

Basically you need to add a dependency graph relation, so that Blender knows to update the geometry nodes when the armature is modified. update_depsgraph in MOD_armature.cc shows how to add such relations.

Simplest would be to start with adding a DEG_OB_COMP_EVAL_POSE relation for the whole pose, and then maybe later refine it so it’s only for the individual bones.

Hell yeah! Its working. Im not sure if its optimized (probably not, need to code review).

But! yeah! I did changes with source/blender/nodes/intern/geometry_nodes_dependencies.cc

and source/blender/modifiers/intern/MOD_nodes.cc.

Basically what I did:

I added few function to dependecies.cc

static void add_object_socket_pose_dependency(const bNodeSocket &socket,
                                             GeometryNodesEvalDependencies &deps)
{
  if (socket.is_input()) {
    if (socket.is_logically_linked()) {
      return;
    }
  }
  
  if (socket.type == SOCK_OBJECT) {
    if (Object *object = static_cast<bNodeSocketValueObject *>(socket.default_value)->value) {
      if (object->type == OB_ARMATURE) {
        
        deps.add_object(object);
        
        int session_uid = object->id.session_uid;
        if (deps.objects_info.contains(session_uid)) {
          auto &info = deps.objects_info.lookup(session_uid);
          info.armature_pose = true;
        }
      }
    }
  }
}

static void add_armature_pose_dependencies(const bNodeTree &tree,
                                           GeometryNodesEvalDependencies &deps)
{
  for (const bNode *node : tree.nodes_by_type("GeometryNodeArmatureInfo")) {
    if (node->is_muted()) {
      continue;
    }
    
    for (const bNodeSocket *socket : node->input_sockets()) {
      if (STREQ(socket->name, "Object")) {
        add_object_socket_pose_dependency(*socket, deps);
        break;
      }
    }
  }
}

and some changes to MOD_nodes.cc


if (object.type == OB_ARMATURE) {
    if (info.armature_pose) {
      DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_EVAL_POSE, "Nodes Modifier");
    }
  }
}

Thank you very much! Also, the code on half done with ChatGPT (Yeah im suck in C++, but started to understand how it works) now i can add more nodes, and make more optimized stuff.

Also, here is example:

The main good thing - I understand how it works finally.

Thank you for your help!! :heart_eyes:

6 Likes

Well I did some rework.

Node named as Bone Info. Now It has:

Inputs:

  • Armature Object
  • Bone Name
  • Use Parent
  • Local Axis

Outputs:

  • Location of Bone
  • Rotation of Bone
  • Scale of Bone

Use Parent - bool value. When the parameter is enabled, the position of the bone is taken taking into account the parent. When disabled, the position is taken without taking into account the parent, if the bone as a whole would not have a parent.

Local Axis - bool value. If disabled, the world orientation of the bone is taken. If enabled, the local orientation of the bone is taken.

3 Likes


Small rig test.

Its already parented to the bone with default solution. But rotation made with geonodes.

This is how node and properties of node are work.

4 Likes

I reworked the node again and learned a lot of new things.

Use Child (Default ON):

  • ON = takes into account all bone constraints (Copy Location, Child Of, IK, etc. but not with parent AK ctrl + p)
  • OFF = only basic bone transformation without constraints

Uses the same logic as drivers - BKE_constraint_mat_convertspace

  • When Use Child = ON - gets pose_mat (with constraints) and converts to local space
  • When Use Child = OFF - uses BKE_pchan_to_mat4 for pure transformation
  • Properly handles all rotation modes (Euler XYZ/XZY/etc, Quaternion, Axis-Angle)

Shows an error if the bone is not found

Yeah! Now it works with constraints just like Drivers do.

Here is my video:

The whole rig done with geonodes. And bones.

For those who are interested: Shape keys are also made through geonodes.


4 Likes

Added new outputs:

  • Head
  • Tail
  • Length
  • Roll

Inputs:

  • Swap Z/Y - renamed from Local Axis
  • Eval Constraints - renamed from Use Child (Idk why I named this use child)
  • Rest Pose - Rest Position of bone

Planning for future:

  • Add Use Parent option, to include transformation with parent.
1 Like

Some tests


8 Likes

This looks super cool !
Do you think a transform matrix could be outputed to be alligned with the object info ? I’m guessing that a lot of easy operations would be done only using the transform information.

Hi! Thank you and yes. I just talked with devs.

We could use Rest Transform, and just Transform.

I removed some outputs…

You can watch process: #141062 - WIP: Geometry nodes - Bone Info node - blender - Blender Projects


1 Like