The Palos Publishing Company

Follow Us On The X Platform @PalosPublishing
Categories We Write About

Implementing Bone Hierarchies with C++

Implementing bone hierarchies in C++ is a crucial step in creating character rigs for animation, especially in 3D games or graphics applications. A bone hierarchy represents the relationship between various bones that make up a skeleton, with each bone having a parent-child relationship. This is critical for skeletal animation, as transformations (translations, rotations, and scaling) applied to a parent bone affect its children.

Here’s a guide on how to implement a basic bone hierarchy in C++:

1. Define the Bone Class

A bone in a hierarchy typically needs several key properties:

  • A transformation matrix (or position, rotation, scale) to define its local transformation.

  • A reference to its parent bone.

  • A list of child bones.

Let’s start by defining a basic Bone class.

cpp
#include <iostream> #include <vector> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> class Bone { public: std::string name; // Name of the bone glm::vec3 position; // Position in 3D space glm::quat rotation; // Rotation using quaternion for better interpolation glm::vec3 scale; // Scale factor glm::mat4 localTransform; // Local transformation matrix Bone* parent; // Parent bone std::vector<Bone*> children; // Child bones Bone(std::string name) : name(name), position(0.0f), rotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), scale(1.0f), parent(nullptr) { updateLocalTransform(); } // Update the local transformation matrix from position, rotation, and scale void updateLocalTransform() { localTransform = glm::mat4(1.0f); // Identity matrix localTransform = glm::translate(localTransform, position); localTransform *= glm::mat4_cast(rotation); // Quaternion to matrix localTransform = glm::scale(localTransform, scale); } // Add a child bone void addChild(Bone* child) { children.push_back(child); child->parent = this; } // Get the global transformation by combining the parent's transformation glm::mat4 getGlobalTransform() { if (parent) { return parent->getGlobalTransform() * localTransform; } return localTransform; // Root bone has no parent } void printBoneHierarchy(int depth = 0) { std::string indent(depth * 2, ' '); std::cout << indent << name << "n"; for (Bone* child : children) { child->printBoneHierarchy(depth + 1); } } };

Explanation:

  1. Bone Attributes:

    • name: Identifies the bone.

    • position: The bone’s position in the local space.

    • rotation: The bone’s rotation, using a quaternion to avoid gimbal lock and for smooth interpolation.

    • scale: The scaling factor applied to the bone.

    • localTransform: A matrix that combines the bone’s position, rotation, and scale.

    • parent: A pointer to the bone’s parent, or nullptr if it’s the root.

    • children: A vector holding the bone’s children.

  2. Transformation Update:

    • The updateLocalTransform function recalculates the bone’s local transformation matrix whenever the position, rotation, or scale changes.

  3. Hierarchy Functions:

    • The addChild function adds a bone to the hierarchy, setting the child’s parent pointer.

    • The getGlobalTransform function calculates the global transformation by multiplying the parent’s global transform with the current bone’s local transform.

  4. Printing the Hierarchy:

    • The printBoneHierarchy function recursively prints the bone hierarchy. It uses indentation to show parent-child relationships visually.

2. Example Usage

Let’s create a simple hierarchy with a root bone, a child bone, and a grandchild bone.

cpp
int main() { // Create bones Bone* root = new Bone("Root"); Bone* upperArm = new Bone("UpperArm"); Bone* lowerArm = new Bone("LowerArm"); // Define positions and rotations (you can define them according to your needs) upperArm->position = glm::vec3(0.0f, 1.0f, 0.0f); upperArm->rotation = glm::quat(glm::vec3(0.0f, glm::radians(45.0f), 0.0f)); lowerArm->position = glm::vec3(0.0f, -1.0f, 0.0f); lowerArm->rotation = glm::quat(glm::vec3(0.0f, glm::radians(-45.0f), 0.0f)); // Build the hierarchy root->addChild(upperArm); upperArm->addChild(lowerArm); // Print the hierarchy root->printBoneHierarchy(); // Print the global transformation of the lower arm glm::mat4 lowerArmGlobal = lowerArm->getGlobalTransform(); std::cout << "Lower arm global transform: n"; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { std::cout << lowerArmGlobal[i][j] << " "; } std::cout << "n"; } // Clean up dynamically allocated memory delete root; delete upperArm; delete lowerArm; return 0; }

Explanation of the Example:

  1. Creating Bones:

    • Three bones are created: root, upperArm, and lowerArm.

    • Their positions and rotations are defined. You can modify these values to simulate different poses.

  2. Building the Hierarchy:

    • root->addChild(upperArm) establishes upperArm as a child of root.

    • upperArm->addChild(lowerArm) adds lowerArm as a child of upperArm.

  3. Print and Debug:

    • The printBoneHierarchy function prints the entire hierarchy.

    • The getGlobalTransform function calculates and prints the global transformation matrix of the lowerArm.

  4. Memory Management:

    • The dynamically allocated memory for the bones is cleaned up at the end using delete.

3. Further Enhancements

  • Animation: To implement skeletal animation, you can interpolate between different bone poses over time (keyframes) by adjusting the position, rotation, and scale of each bone.

  • Inverse Kinematics (IK): If you need to make the skeleton pose dynamically (e.g., for a character to reach for an object), inverse kinematics will help compute the appropriate joint angles.

  • Animation Blending: If you have multiple animations (walking, running, jumping), you can blend between them by linearly interpolating the transforms.

Conclusion

This basic implementation of bone hierarchies in C++ provides a good foundation for skeletal animation systems. By expanding upon this with more advanced features like inverse kinematics, animation blending, or advanced interpolation, you can build more sophisticated animation systems for games or 3D graphics applications.

Share this Page your favorite way: Click any app below to share.

Enter your email below to join The Palos Publishing Company Email List

We respect your email privacy

Categories We Write About