How could I get hold of individual armature bones with mouse over?

Hi all,

I would like to be able to select individual armature bones in realtime with a right click of the mouse. At the moment Im getting hold of the relevant armature by just adding 'Arm' to the appropriate mesh name which Ive acquired with the mouse over sensor. (After Ive re-instantiated the physics after the rigged mesh has been moved.) I could cycle through the names of the bones until I get to the one I want, but Id like for the process to be more free flowing.

I`m not sure which is the best/possible avenue to explore?

  • I could get the hit position of the mouse over and check all verticies within the mesh for distancing to see which bone is the closest?

  • I could get the nearest vert to the hit position then find (somehow) its bone group and go this way?

If anyone has any ideas itd be great. The whole selection process doesnt have to be efficient at all. It`ll only be called once every now and again.

Cheers for your time,
Daz

An armature does not have a mesh. Therefore it is not possible to have a mouse over.

But you can have mouse over on mesh objects which are parented to a bone.

Yeh, thats as far as Ive got at the moment. Getting the mesh, then the armature by using the meshes name. (Im not sure if theres a better way for this?)

I was hoping I could get a vert from the getPolygon option and then look at that verts bone groups? Im not sure how/if thats possible at the moment? Im experimenting/learning the layout of the data for getVertex and getPolygon still.

Cheers Monster.

Unforunately, I forsee that determining the bones in that fashion would be slow.
Instead, you could create hitboxes per armature that denote their parent bones.

I would like to be able to just drop in, potentially complex (30 or more bones), rigged models. So the hitbox idea is a none starter really, it breaks up the whole free flowing thing Id like to have going on. I like the idea though. Thinking outside the box, or hitbox in this case. ;) ... Ill get my coat.

It doesn`t need to be efficient. Its just a single user defined choice from within a selection screen.

Cheers agoose77.

Ill be researching some more and if I come up with anything Ill post my findings.

You can access the head and tail positions of the bones (in armature space).
Thus you could get the hitposition on an armature, and (I believe) do the following:

  • For each bone: Get the bone channel, and store all head and tail pose positions in a dictionary (multiplied by armature transformation matrix). Map this dictionary to the relevant bones.
  • Get the closest bone component position to the mouse hit position.
  • Find the bones which share the joint (bone component aforementioned)
  • Access the opposite component to each bone (if joint is head, take tail)
  • Get the dot product between the vector from joint to bone component and joint to point, and the same product for the other bone (which shares that nearest point).
  • Whichever dot product is smaller is the closer bone.

Or just using the angle method of each vector instance in the same way (although dot is less resource intensive)

Eeek, armature space?!
Thanks for the ideas. Im assuming Ill need to normalise the head to tail and head to point vectors? (Assuming head is the nearest component.)… Just asking, Ill see how I get on and figure it out. I havent done dots and crosses for a while now. (They make my brain hurt. :slight_smile: ), and it`s gonna be your fault agoose.

Ive been thinking, and can think of a few scenarios where the nearest poly may not be linked/grouped with that bone. However, Ive also realised there may be times I need to select a bone which is off screen. So I`ve put in a keyboard selection ability.

I think these two, for now, will work nicely.
Id still like to be sure that the bone Im acquiring is the one the poly/vert is grouped to. So, I`ll post my progress of this, and if another route comes to mind of that to.

Cheers.
Daz

Here is a working example (I hope).
It simply gets the closest head or tail position. Determines which bones own that position (within a margin, as bone head and tail can differ very slightly for the same visual position). Gets the angle between the joint (shared head OR tail) to opposite point (tail if joint is head, else head) and the point for each bone, and determines whichever angle is smallest is the closer bone.

You’ll need to reinstance the physics mesh for the armature deformed mesh every time it deforms, so make sure the visible mesh is triangle-mesh physics bounds, then use object.reinstancePhysicsMesh() to show the armature deformation update.


import bge
import mathutils

def getObject(scene, name):
    
    try:
        return [o for o in scene.objects if o.name==name][0]
    except:
        return []

def BoneChannel(armature, *args, **kwargs):
    class CustomBone(bge.types.BL_ArmatureChannel):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            armature_transform = armature.worldTransform
            self.positions = [armature_transform * self.pose_head, armature_transform * self.pose_tail]
        
        def is_close(self, a, b):
            return (a - b).magnitude <= 0.1
        
        def __contains__(self, point):
            for pos in self.positions:
                if self.is_close(point, pos):
                    return True
                
        def opposite(self, point):
            for pos in self.positions:
                if not self.is_close(pos, point):
                    return pos
                 
    return CustomBone(*args, **kwargs)

def closest_bone(point, armature):
    
    bone_map = [BoneChannel(armature, channel) for channel in armature.channels]
    bone_positions = [position for bone in bone_map for position in bone.positions]                   
    closest_point = min(bone_positions, key=lambda n:(point - n).magnitude)
    shared_bones = [bone for bone in bone_map if closest_point in bone]
    
    # Simple test
    if len(shared_bones) < 2:
        return shared_bones[0]
    
    # Complex test
    shared_positions = [p.opposite(closest_point) for p in shared_bones]
    
    bone_vectors = {p[:]:p - closest_point  for p in shared_positions}
    point_vector = point - closest_point
    
    angle_to_position = {point_vector.angle(b): mathutils.Vector(a) for a, b in bone_vectors.items()}
    
    closest_bone = [b for b in shared_bones if closest_point in b and angle_to_position[min(angle_to_position)] in b][0]
    
    return closest_bone


def find(cont):
    own = cont.owner
    scene = bge.logic.getCurrentScene()
    
    armature = getObject(scene, "Armature")
    point = own.worldPosition
    
    closest = closest_bone(point, armature)
    
    print("Closest bone = {}".format(closest))

Holy **kwargs batman!?.. What is **kwargs?

Its gonna take me a day, ie tomorrow, to get my head around your code. Hope you dont mind but I may need a few pointers.

Like, why…

… I was going to ask some stuff here, but its late for me now. So I`ll just leave it at why and hopefully sort this out tomorrow.

Thanks for your time agoose77.

Daz

Python can use the asterisk operator for multliple things. For example, when used within function parenthesis, it unpacks an iterable into individual arguments. It unpacks at key level:

iterable = [1, 2, 3]
def myfunc(a, b, c):
pass

myfunc(*iterable)

It can also be used on the receiving end to pack to from an iterable:

def myfunc(*catch):
a, b, c = catch

myfunc(1, 2, 3)

You can also have a two depth unpack and pack - uses keyword arguments.

def myfunc(one=1, two=2):
pass

args = {“one” : 3, “two” : 5}

myfunc(args)

or packing

def myfunc(**args):
print(args)

myfunc(one=2, three=4)

Agoose: That would have been really useful to know yesterday, I had to find it out with google…

Thanks for the example explanations for the *args and **kwargs. Seems nifty and perhaps a little over my head at the moment.

Im having to find out how win() and .magnitude are used. Just getting used to the syntax. The lambda operation within the string comprehension seems very good. Ive just got to make it all stick now. :slight_smile: It`s been a long time since I pythoned this intensely. Thanks for that.

A probably daft question which I just cant seem to grasp on a slightly defferent matter. On start up/initialise, I cycle through all the objects in the scene. Whats a good way to test if the object is an armature? At the moment Im doing a crude ‘try’ and read the objects channel name and if it fails its not an armature.


            try:
                ObName = c.sensors['Over'].hitObject.name
                ObChanName = l.getCurrentScene().objects[ObName + 'Arm'].channels[ObChanNum].name
            except:
                ObHasArm = False
                print ('Does not have Armature')
            
            else:
                ObHasArm = True
                print ('Has Armature')

Also, at the moment, when I get hold of just the armature by getting the name of the mesh the mouse over has hit and adding ‘Arm’ to it, to get the, so named, armature object. How can I find out what index number that object is in the scene from its name?

I think my brain is over complicating these two things and I can`t seem to get a better solution.

Thanks for your time Agoose, I`ll be picking over and learning from your code.

Do you mean min()?
Well, firstly, most Blender Python Math types (vectors, eulers, matrices etc…) Derive from mathutils classes.
Vectors have an attribute “magnitude” that calculates the length of a vector.

min() is a function in python to extract the smallest element in an iterable. If can accept a key argument which should be a function accepting an item from a list, and returning an object which can be compared against the other objects returned by the key function. You could just return the item passed to the key argument, but that would make little sense. The same goes for the max() function, but it takes the largest item.

Testing for armatures:
As I think I said before, all Python objects derive from bge.types classes. Thus, you can test whether a gameobject derives from the armature class, in order to determine if it an armature:


import bge

def is_armature(obj):
    '''Returns True if object is an Armature derivative
    @param obj: object to test for armature'''
    return isinstance(obj, bge.types.BL_ArmatureObject)


Some important footnotes
I would be very wary of using try statements without catching specific errors
For example, take this code block:


my_list = [1, 2, 3, None]

try:
    item = my_list[3]
    a = item + 2
except:
    print("The list is too short")


This would fail, and the except would be called. You’d think form the print statement that it was the fact that the list has no item at index 3, however, it would actually be caused by the addition of a None object to an integer.

Yes, I did mean min(). I get the magnitude attribute now, thanks. I`m coming from a long while of heavily managed c# so things are a little different.

I`m gonna chance my arm with one more… :smiley:


    for obj in l.getCurrentScene().objects:
        if (isinstance(obj, bge.types.BL_ArmatureObject)):
            print (obj, ' : IsArmature')  

I`m used to obj being a numerical value, not an actual object. (I think)
How do I turn obj into a numerical value?

Thanks again for all your help and Ive taken on board your footnotes from previous post. I should have enough here to keep me going for a week or three and Ill update here to try and close/solve the thread if I manage it.

Daz

Carrying on!
Firstly, you use a lot of condensed statements and acronyms for variables.
It is common knowledge that the majority of the time a developer spends with his / her code is lost in reading the previous work.
Thus, using full length names, and creating variables where necessary is preferable for both the initial developer and later revisers. Additionally, it means that if you revisit your scripts in later life, there would be a good chance that the use of comments and self-explanatory variable names would enable you to make sense of it, long since your memory has forgotten its inner workings.

obj is typically used as a reference to a GameObject in Blender Game scripts. It’s an informal convention.
you shouldn’t use numerical references, because objects are stored in a sort of list/dictionary (it’s a special type for Blender).
Use the object names OR ids.

Why / how ids?
The game engine object list allows you to access its contents via their runtime ID. This changes every time the interpreter is run (but exists within the duration of the game engine), and is unique per object.

For example:


cont = bge.logic.getCurrentController()
own = cont.owner

own_id = id(own)

scene = bge.logic.getCurrentScene()
own_from_id = scene.objects.from_id(own_id)

Thanks for


own_id = id(own)

The id() is exactly what I was after.

Even though, for me personally, it`s horrid looking code. Takes me a while to read an _ , dunno why.

Cheers again for ya time.