All Kitted Up

Published October 07, 2016
Advertisement

weapons.jpg

Decided to take a break from player/world interactions and look at something I've never tried before, namely attaching objects like weapons to the player skeleton.

The implementation took a bit of messing around and educated guesswork to get it right. Because my game has my own hand-rolled implementation of a skeleton animation system, I was able to extend the [font='courier new']Skeleton[/font] interface to support this.

class Skeleton{public: // snip void setKeyFrame(const KeyFrame &key); const MatrixPalette &palette() const; Vec3 bindPosition(uint index, const Matrix &world) const; Matrix placementTransform(uint index, const Matrix &offset, const Matrix &world) const; // snip};With the new [font='courier new']placementTransform()[/font] method, you pass in the index of the bone (which can be first looked-up by name), an initial offset matrix to apply to the weapon mesh in its local space and the current world matrix of the player. The result is the matrix you need to set as the transform on the weapon.


So, for example, inside the player character's code, we create the bow mesh on startup and add a scene node linking the bow mesh to the scene. You can have as many scene nodes linked to the same mesh as you wish in my system, each with its own transform and visibility status and so on.

We can then use the above [font='courier new']Skeleton::placementTransform()[/font] method to assign the bow's scene node the correct transform inside of the player's [font='courier new']prepareScene()[/font] method.

void Pc::prepareScene(SceneParams &params, float blend){ KeyFrame key = data.animation.controller.keyFrame(blend, data.animation.map); data.animation.skeleton.setKeyFrame(key); Matrix world = rotationMatrixFromQuaternion(data.rot.value(blend)) * translationMatrix(pos.value(blend) + data.settings.positionOffset); mesh->setTransform(world); mesh->setPalette(data.animation.skeleton.palette()); uint leftHand = data.animation.skeleton.index("Left Hand"); Matrix initialLeft = translationMatrix(Vec3(-0.1f, 0.05f, 0)); bow->setVisible(true); bow->setTransform(data.animation.skeleton.placementTransform(leftHand, initialLeft, world));}So we take the current interpolated [font='courier new']KeyFrame[/font] from the animation controller and apply this to the player's [font='courier new']Skeleton[/font] which then generates a matrix palette for the shader skinning. But we can also now query the [font='courier new']Skeleton[/font] for the placement matrix for the left hand, for example, and apply this to the scene node representing the bow.


The [font='courier new']placementTransform()[/font] method is implemented quite simply.

Matrix Skeleton::placementTransform(uint index, const Matrix &offset, const Matrix &world) const{ return offset * translationMatrix(bindPosition(index, identityMatrix())) * palette()[index] * world;}First we do the local offset transform on the object in local space. The [font='courier new']bindPosition()[/font] method returns the position of the bone in the bind pose, which is multipled by the relevant matrix from the skinning palette to move it to the current [font='courier new']KeyFrame[/font] position. Then finally we multiply the result by the overall world matrix of the character.


For simplicity, the weapon meshes are defined with their local origin being the middle of the point at which they are held and rotated so that they match the player in bind pose. We can then tweak this transform with a hardcoded offset matrix to get the position looking visually correct, moving them slightly depending on which hand is holding them for example.

The big challenge, of course, is coming up with animations for attacking, drawing the bow and so on that look good. My 3D model editor, Charm, has a pretty comprehensive animation system for creating these, but my lack of artistic talent is working against me here. Still, we'll see how it goes. Need to decide on how the combat system is going to work before I can do this anyway.

Hope this was of interest to someone. This project is almost entirely hand-rolled due to my coding masochism so if there are any specific aspects of this project that people would like to know more about, please just let me know.

Thanks, as always, for stopping by.

Previous Entry Quick Video
3 likes 4 comments

Comments

MagForceSeven

Working with sockets like those is something that I've had to spend a lot of time with. Have you considered yet how you could include them directly in your skeleton data? There are a lot of interesting things that I've seen animators do with them when they're in the data like that and can be directly animated separately from the bones.

Very cool work!

October 08, 2016 07:46 PM
Aardvajk

Working with sockets like those is something that I've had to spend a lot of time with. Have you considered yet how you could include them directly in your skeleton data? There are a lot of interesting things that I've seen animators do with them when they're in the data like that and can be directly animated separately from the bones.

Very cool work!


Hey, thanks for the interest.

I'd not really thought much about that. At the moment it will be nice to just create an animation of, say, swinging a melee weapon that would work equally well regardless of what the actual current weapon mesh was, so a sword, axe etc could all be handled with the same melee attack animations, just based on the orientation of the hand.

I was thinking, for the bow and arrow stuff, I might want to build a rigged mesh (skeleton mesh) for the bow, so it can animate being drawn back and so on. My inclination would be to add a skeleton to the bow mesh and have the animation be handled by the bow itself here, synchronised with the player animation by the firing of my animation events. No reason the weapons can't have skeleton-based meshes with their own animations as well, although the current bow and sword are just what I call static meshes.

I guess if you wanted to hold your hand still, but have the weapon spin in your palm, say, I could add an extra hidden bone to the player skeleton, attach the weapon to this hidden bone then make the spinning be part of the player animation. Interesting idea.
October 09, 2016 08:53 AM
MagForceSeven

I guess if you wanted to hold your hand still, but have the weapon spin in your palm, say, I could add an extra hidden bone to the player skeleton, attach the weapon to this hidden bone then make the spinning be part of the player animation. Interesting idea.

Exactly, that's the kind of thing that would do for idle animations or other flourish type animations. The other thing that it bought them (I'm trying to recall as animation is not my specialty) was that you could get a position of a bone, but that it never had an orientation. The sockets were things that had both position and orientation. At least in our system that was why they were talked about separately. Maybe with your skeletal system this isn't an important distinction and everything is a bone.

I was thinking, for the bow and arrow stuff, I might want to build a rigged mesh (skeleton mesh) for the bow, so it can animate being drawn back and so on.

A skeletal mesh for the bow sounds like a good idea. Are you planning any IK support down the road? A simpler solution would be to only need a single animation (for the character) and then the bow's skeleton just reacts to where it's pulled by the fact that it's attached at two points (one on the bow and one on the string). Maybe that's more complicated code-wise, but during the runtime it's really nice to not have to be sure that two animated objects are staying synchronized with each other.

October 09, 2016 01:43 PM
Aardvajk
Some interesting ideas there, thanks. I'm probably going to keep this system fairly simple to be honest but some food for thought.
October 13, 2016 06:12 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement