Notifications
Clear all

[Closed] Helper bones in conjunction with lookat

I’ve got a selection of helper/twist/roll bones in my model, all of which work.

I’m now attempting to add a LookAt constraint to my two upper shoulder bones so that they act like the top part of the Trapezium – they pivot from the same place as the upper arms, they take 50% of the arm rotation, but they always look at the root point of my second neck bone.

I can do either part on its own, but can’t get them to work together.

For example, the lookat:

NeckLook = LookAt_Constraint relative:false
NeckLook.appendTarget $‘Char NeckU’ 100
$‘R ShoulderRoll’.rotation.controller = NeckLook

This works, and when I move the arms/clavicle/neck, the Shoulder bone always looks where I expect. However, this doesn’t take on 50% of the arm roll which I can accomplish like this (I’m using expose transform nodes):

paramWire.connect $eTm_RArm.baseObject[#Local_Euler_X] $‘R ShoulderRoll’.rotation.controller[#X_Rotation] “Local_Euler_X*0.5”
paramWire.connect $eTm_RArm.baseObject[#Local_Euler_Y] $‘R ShoulderRoll’.rotation.controller[#Y_Rotation] “Local_Euler_Y”
paramWire.connect $eTm_RArm.baseObject[#Local_Euler_Z] $‘R ShoulderRoll’.rotation.controller[#Z_Rotation] “Local_Euler_Z”

When I use this code, the bone rotates like I want, but doesn’t look where I want it to.

Can anyone point me in the correct direction to get both parts working together?

9 Replies

I’ve been thinking about this further, and now I think I have a slightly different idea on how this will work.

Rather than assigning my shoulder roll to look at the neck, and then attempting to override it’s X rotation, I’ll position a dummy for each shoulder roll at the neck position, and have the dummy rotate. Then I’ll make the the shoulder roll look at that dummy object instead.

However, I don’t want the dummies to be part of the skeleton hierarchy, this rig will be going into a game engine. I plan to make the two dummy objects be the children of another Neck_Target helper, and someone make it follow the neck around.

I just need get a little bit of syntax sorted out – trying to link the position of my neck target to the neck bone using paramwire. The neck target should always be in the same worldspace position as the second neck bone, so I’ve got an expose transform helper exposing the neck bone values.

Copying from the listener (know I’m using the $ in here instead of the target name, I’ll update them whenit works):

$eTm_Neck.exposenode = $‘Char NeckU’
PH_Neck_Target = Point pos:ned isSelected:on name:“PH_Neck_Target” wirecolor:(color 8 8 136) size: 0.1
select $PH_Neck_Target
paramWire.connect $eTM_Neck.baseObject[#Expose][#World_Position_X] $.pos.controller[#X_Position] “World_Position_X”
paramWire.connect $eTM_Neck.baseObject[#Expose][#World_Position_Z] $.pos.controller[#Z_Position] “World_Position_Z”
paramWire.connect $eTM_Neck.baseObject[#Expose][#World_Position_Y] $.pos.controller[#Y_Position] “World_Position_Y”

But running that as a script fails, I get – No ““get”” function for undefined for each of the three wiring commands. I’m now going to have to figure out why positional wiring is breaking.

Well, that was simple – remove the [#Expose]

paramWire.connect $eTM_Neck.baseObject[#World_Position_X] $‘PH_Neck_Target’.pos.controller[#X_Position] “World_Position_X”
paramWire.connect $eTM_Neck.baseObject[#World_Position_Z] $‘PH_Neck_Target’.pos.controller[#Z_Position] “World_Position_Z”
paramWire.connect $eTM_Neck.baseObject[#World_Position_Y] $‘PH_Neck_Target’.pos.controller[#Y_Position] “World_Position_Y”

I still can’t get my roll bone to roll – it’s moving around when the arms do, the rolls start at the shoulder joint, their end points are set to look at a point helper that takes on 50% of the X rotation of the arm, but even though the lookat object rotates, they do not.

So, back to the original question – can I make an object in max Look At one object, but rotate along it’s X axis from another driver?

1 Reply
 eek
(@eek)
Joined: 1 year ago

Posts: 0

Ofcourse, its called the upNode. Do this put a look at controller on an object and look at it’s parameters – you can define the axis of direction and the axis of twist. By default the axis of twist is world but you can pick anything to be the upNode.

Target is the node it looks at, upNode is the node it’s twist uses. You can either have a lookAt method or an axis alignment method. The later actually uses the target upNodes rotation to define the twist, where as the lookAt method uses the upNodes position in space.

Cheers! I’ll have a look at that in the morning. I had some success with adding an Orientation constraint as well as the Lookat, but one constraint is a lot cleaner.

Eek, you are a genius, cheers!

I have to tell max not to use the world upnode as well as specifying the upnode to use. Simply specifying an upnode and not setting world_upnode to false doesn’t work.

The working code:

– Make the shoulders look at the shoulder helpers
NeckLookL = LookAt_Constraint relative:true upnode_world: false pickUpNode: $‘PH_LShoulder’
NeckLookL.appendTarget $‘PH_LShoulder’ 100
$‘L ShoulderRoll’.rotation.controller = NeckLookL

NeckLookR = LookAt_Constraint relative:true upnode_world: false pickUpNode: $‘PH_RShoulder’
NeckLookR.appendTarget $‘PH_RShoulder’ 100
$‘R ShoulderRoll’.rotation.controller = NeckLookR

1 Reply
 eek
(@eek)
Joined: 1 year ago

Posts: 0

You still need to specify an upnode if you declare the world:false because it still needs a vector to build its internal matrix. Because essentially your building a constant matrix, firstly by using the target as the direction and the upnode as the twist, i.e an L shape – from this you can determine the other axis using standard math internal to max.

Glad to help,

Yea, I was kinda hoping that setting the upnode would override the world:true, but hey, max likes to be explicit at times.