I have a bone-A that tracks to another armature’s bone-B, via a vector.
If bone B is below bone A, bone A is right side up, but if bone-B is above bone A, then bone A is upsidown.
I understand what’s happening, but have no idea how to limit bone A’s Y-rotation while tracking.
Here’s my code. Any help is appreciated.
import bge
import random
from bge import logic
from bge import render
from mathutils import Matrix, Vector, Quaternion
cont = logic.getCurrentController()
own = cont.owner
par = own.parent
### Position of the tracker Bone
if par['IK_head'] != 'null':
Look_Target = par.children[1]
boneloc = own.worldTransform * own.channels["head_root"].pose_matrix * own.channels["head_root"].location
own.channels["head_root"].rotation_mode = 0
## the Vector
myVect = Vector(Look_Target.worldPosition - boneloc).normalized()
#### display Global directional vector with a red Ray
render.drawLine(Look_Target.worldPosition, boneloc, [255,0,0] )
## apply on the Orientation Matrix, the tracking transformation as a Matrix
ownParent = own.channels["neck_01"]
# apply the armature and the parent's rotation to the direction vector
myVect = myVect * own.worldOrientation * ownParent.pose_matrix
own.channels["head_root"].rotation_quaternion = myVect.to_track_quat('Z','Y')
## useless option if an action is already playing ?
own.update()
just add to bone - constraint - limit rotation - and assign limit degress for axis XYZ and select type - global, local, local with parent - its very simple constraint for objects but this work - if you need off assign constraint - add armature actuator and add to actuator constraint and use influence
tbh, an ik rig should be setup in the armature, so all you need to do is position the ik target bone and let the builtin constraints system do the work it was designed to.
in fact, you can add an empty world<>world constraint on the target bone and specify the constraint .target to an object in the scene.
for limit rotation work - assign rotation diapazone XYZ plus and minus degress - if you not select diapazone constraint dont work, if diapazone equal zero bone not work. Check way bone you assign constraint - maybe bone children another bone and use forward link to parent, and use run armature for recalculation armature
Correct, but I am spawning in NPCs, and trying to make their heads track to invisible points, that jump smoothly to points of interest.
When I use the build in constraints, the track to bone will indeed track to the reference point, but as soon as I spawn in more NPCs, the track to function jumps randomly through the track to points, making the NPC’s head violently spasm back and fourth.
Since the obj.name is read-only, I can’t change it to make it unique for each spawn.
If you know a workaround, I’d love to hear it. This way is by far the simplest.
bones constrained to bones in the same armature seem to handle themselves in my experience, but you are right about pointing to objects.
this is why i mentioned setting the target in python. basically each npc has an empty object that is used to control the bone. then all you have to do is move the object around.
head_pos = owner.worldPosition+owner.getAxisVect((0, 0, 0.6)) # offset the track pivot point
target = player.worldPostion-owner.worldPosition # look at player object
obj.woldPosition = head_pos+target.normalized() # normalized to limit floating point errors
you add a constraint to the track bone and then toggle the “visibility” to disable it. then you can fill the target attribute with python, and then enable it.
I’ve stared at your reply for a while and I don’t get it…
I think we’re on the same page that you can’t track to spawned objects since they all share the same name, so I assume you’re saying the head tracks to a bone (We’ll call it Eyepoint) in the same armature, and that bone jumps to the empty’s location?
If we can’t track to a specific spawned-empty, how can we return the spawned-empty’s location to move the Eyepoint bone to?
I can say:
cont = logic.getCurrentController()
own = cont.owner
par = own.parent
Look_Target = par.children[1]
And now, “Look_Target” is the object we need to be tracking to, but we can’t move the bone to Look_Target, as it always returns that the bone Eyepoint, defined as own.channels["Eyepoint"] has no attribute worldOrientation.
Even if I wanted to skip the object the bone Eyepoint is jumping to, I would still have no way to move the bone Eyepoint, as I get the same error “has no attribute worldOrientation.”
i would recommend doing something like ct.target = own.children[ct.target.name]. what that does is gets the name of the object which you have picked in the blend file, but points it to the specific instance of that object relevant to the owner.
*(fun fact, you can also do own.children["Look_Target"] to get the object by name, in context of the owner)
in the image below, im using a constraint to have a bone in a suspension rig track to a wheel. for each wheel i add a new wheel object newobj = scene.addObject("Wheel.Buggy") and assign it to the constraint ct.target = newobj
I can change the target successfully, but it still gets confused when multiple NPCs spawn in and spasms looking at all points.
When I printed what par.children[1] was, it returned the same string for every single NPC, hence the issue.
When I used constraint.target == par.children[1].name it does the same.
I also tried constraint.target == par.children["IK_eye_point_NPC"] where IK_eye_point_NPC is the name of the object the head bone tracks to, and it did not return a unique identity as well.
If I can change this one, single line to get the objects unique identity, everything wold work perfectly. What am I missing?
I uploaded a blend if you want to see the issue live.
Assets are on layer 16 right below layer 1 FYI
Edit: Wait, if their tracking points are all on the same area, why are they still spasaming?
I’m starting to think the problem might not be what I thought it was…
Edit2: Update; I used a copy-location constraint on a bone, and made the head follow the bone instead of the object directly. Same exact glitch…
i think i know what your problem is. are you using upbge? vanilla bge has this issue and upbge fixed alot of constraint related issues. depending on the needs of the project, you might want to consider upbge 0.2.0 over the latest 0.2.5b. i find it to be much more stable.
WARNING: upbge files cant return to bge, make a BACKUP before testing in upbge. routinely backing up is always a good idea.
Can we at least find a way to limit a bone’s rotation via python on a single axis, so I can use the old, original code from the beginning? There’s no way it has to be this hard…
heres the fixed blend. the distance checker was broken (referencing owner, not parent) and i added the constraint target assign to the parent object (the code i posted earlier).
It seems a constraint, added to the bone must have a target pre-set when the game starts, else it returns an error.
However, that target cannot be fully scrubbed or re-set.
The error I’m experiencing is the tracker flipping between the new target and the old target, that cannot be removed.
This can be replicated by setting the starting target to something directly above the NPC, and setting a new target in python as soon as the game starts. It will flick between the new target and the old target above.
I was wrong to assume this was simply an issue of non specific object identities.