2. Our Friend the SkelControl_CCD_IK
After reading up on Skeletal Controllers in the UDK and this post from the UDK Unrealscript forum, I decided to start with Inverse Kinematics using the CCD_IK controller. In short, this approach necessitates choosing a point in space known as the effector, towards which the chain of bones you dictate in the AnimTree will “reach”.
Within the Unreal AnimTree editor, we first needed to expose my 2 bones within the blue AnimTree box by right-clicking and clicking [Add]. Once added, we can then create 2 CCD_IK controllers, name them respectively ‘RightWing_CCD_IK’ and ‘LeftWing_CCD_IK’, and attach one to each of our bones. Rather than rehash all the specific details, again I’d point readers to this post on the forums which really does step through the basics.
We should take a look at the properties for each SkelController, as those can be a bit tricky. Zoom into this image of the AnimTree and the expanded properties list for one of the SkelControllers:
The most important fields in here for right now are:
- Effector Location Space: BCS_WorldSpace
- Num Bones: 4
- Angle Constraints: (a series of values, one per bone in the chain)
- Max Angle Steps: sum angle equal to sum of each angle constraint
- Control Name: LeftWing_CCD_IK (Name of our CCD_IK which we’ll use this in Unrealscript)
Taken in turn, the Effector Location Space can trip you up pretty easily as it can be set to refer to World Space, Local Space or a number of other spaces. If your effector is expecting Local Space and you’re feeding it World Space coordinates, things simply won’t work the way you think they should.
Depending on the limb you’re working with, you can set the Num Bones to determine how many bones in the chain you want to move with CCD. My setting of 4 encompasses my entire limb, from tip to shoulder socket. The individual Angle Constraints can be set to determine which bone gets moved how much, though for smooth movement, I set mine all equal. To create a subdued motion, i.e. not allow each bone to move it’s full capacity, I set these all to a low number (0.2) which seems to have worked, effectively constraining the ability for the arm to move beyond a limited range.
And while it’s pretty simple, its important to see that the name of the controller set in Control Name is the name which you will use later on to reference this controller in Unrealscript.
Now that my SkeletalMesh is all hooked up, back in UnrealScript, we can refer to these controllers pretty easily.
In our custom UDKOSC OSCPawn.uc class, we first declare vars for each controller:
var SkelControl_CCD_IK RightWing_CCD_IK; var SkelControl_CCD_IK LeftWing_CCD_IK;
Then in the PostInitAnimTree method we find our Bones by name, the SkelControl which is attached to each of them, and assign our 2 SkelControl_CCD_IK vars to point to each one.
RightWing_CCD_IK = SkelControl_CCD_IK( mesh.FindSkelControl('RightWing_CCD_IK') ); LeftWing_CCD_IK = SkelControl_CCD_IK( mesh.FindSkelControl('LeftWing_CCD_IK') );
With these references, we can access each SkelController in code from anywhere that holds a reference to our Pawn. We’ll do just that within our custom UDKOSC PlayerController class, the brilliantly named OSCPlayerControllerDLL.uc.
Now, as I mentioned at the start, the goal of all this was to rig our actor with manual control over it’s wings. When doing so, we’ll enter a custom state, in this case called “PlayerPosing” and modify our controller input primarily within the UpdateRotation() method there. So when entering this state (in the BeginState() method), we’ll flip from our standard Valkordia actor mesh (using the manual assignment of Mesh components I mentioned earlier) over to the custom OSCValkordia mesh package which contains our CCD_IK wing controllers.
Again, its within the UpdateRotation() method that the real magic happens. Here, we’ll assign an EffectorLocation to each of our CCD_IK controllers, which itself is just a point in space towards which the wing will reach. You can conceptualize the CCD_IK’s effector location as a ball, floating in front or off to the side of the Pawn. In fact, here’s a screen cap showing just that: effector locations are visualized as debug spheres (green for right wing, yellow for left wing).
The basic strategy here is to think of the EffectorLocation as a point in 3d space relative to the pawn’s location, that is in local space. If World Space can be thought of as the raw Unreal Unit X, Y and Z Cartesian coordinates and global rotation that describe the location and rotation of objects within the currently loaded map/environment, Local Space can be thought of as coordinates in a universe whose center and rotation is that of our Pawn. So if I want to offset a point 100 Unreal Units above and 200 UU to the right of our Pawn, regardless of its current rotation, I need to make sure that I translate that vector by the Pawn’s rotation. More info on vector rotators can be found on the UDN.
After the Break: Conditioning our Input data…