I am trying to add a head aim ctrl. However I keep getting cycle errors since the head and neck have space switches.
If you were to use the biped template, what postBuild script would you run to set something like this up?
I am trying to add a head aim ctrl. However I keep getting cycle errors since the head and neck have space switches.
If you were to use the biped template, what postBuild script would you run to set something like this up?
This is basically how I do it:
Add a control_01 control under the neck. This is the node that will aim towards the aimer. The head should not be parented under it, or it will cycle. (I use basic control_01 nodes for my neck and head, so the head/neck guide that is combined might be harder to setup.)
Add an aimer control for the head, forward near the eye aim. At the same translateY as the aim node.
And then add an upvector control too, above the head. Also not parented under the head. Parent it under the chest or neck. Basically set it all up so that node would aim like you want your head to aim.
And then I guess this is the trick to avoiding the cycle: In the guide, add that aim control_01 as an additional space switch for the head.
In a post script:
I started experimenting with a similar chest aim too, for certain types of characters.
Downside. Since this is a choice between spaces, this won’t work if you want an aim for every one of your space switches. If you want aim plus rotation isolation. But maybe it would work if you add a space switch to the upvector object too…? And then link the two space switches.
Thank you Chris
these post scripts * add the aim constraint.
"
The solution I devised. I didn’t connect the on/off to visibility but did give the aimCtl an on/off switch.
def rig_head_aim(self):
bodyUi = pm.PyNode('bodyUI_C0_ctl')
aimCtrl = pm.PyNode('headAim_C0_ctl')
aimedCtrl = pm.PyNode('neck_C0_head_cns')
aimedGrp = rigbits.addNPO(aimedCtrl)[0]
aimedGrp = pm.rename(aimedGrp, 'headAim_npo')
attribute.unlockAttribute(aimedGrp, ["tx", "ty", "tz", "rx", "ry", "rz"])
# aim constrain the cns to the aimCtrl
aimConst = pm.aimConstraint(aimCtrl,
aimedGrp,
worldUpType='vector',
worldUpVector=[0, 1, 0],
maintainOffset=True)
# orient constrain the aim ctrl to the head
applyop.oriCns(aimedCtrl, aimCtrl, maintainOffset=True)
# add aim constraint on/off attr to itself
aimOnOff_attr = attribute.addAttribute(aimCtrl, 'headAim', 'bool',
channelBox=True,
keyable=True,
value=True)
weight_attr = aimConst.getWeightAliasList()[0]
pm.connectAttr(aimOnOff_attr, weight_attr)
# set attrs
pm.addAttr(f'{aimCtrl}.control_control', edit=True, en='aim:')
pm.setAttr(aimOnOff_attr, 0)
attribute.lockAttribute(aimCtrl, attributes=["rx", "ry", "rz", "sx", "sy", "sz", "ro"])
I don’t suggest using a “vector” for an upVector. If you rotate your character in world space, it might not follow.
Instead make an upVector object. And place it above your aimedGrp, in the direction of “upVector” in your aimConstraint.
And also define your aimVector and upVector. In a forward-facing biped, default X and Y should be fine by coincidence. But if you keep this snippet as a template, you’ll be able to quickly change it for other situations.
Example:
worldUpObj = pm.PyNode('Some node you make')
aimConst = pm.aimConstraint(
aimCtrl,
aimedGrp,
name='{}_aimconstraint'.format(aimedGrp.name()),
aimVector=(1,0,0),
upVector=(0,1,0),
worldUpType='object',
worldUpObject=worldUpObj,
mo=True,
)
Thanks @chrislesage ! I’ll implement that.
Question: the upVector object, does it need to follow the body or be in the world?
@actoratwork , the bodyUI control is indeed an attribute host control that I added. I think I was going to put the on/off switch attr on it, but just put it on the aimCtrl in the end, and forgot to remove that first declaration in the method.
In general, it has to follow the space you want your upVector to be.
Specifically here, you want it to follow the same space the head would follow. So I make it follow the closest control under the head or neck that won’t cycle. For example the chest, or top of the spine.