-
Notifications
You must be signed in to change notification settings - Fork 71
Home
There are three parts to using this library.
- Creating and maintaining the tree structure.
- Setting up the solver and solving.
- Applying the solution back to your own tree structure.
The tree is essentially your interface to the solver. You must copy the positions and rotations that need solving into the tree, solve, and retrieve the solutions from the tree again.
The library provides a leightweight interface for building and maintaining a tree structure. Each node in the tree stores various information, such as the current transform or effector target information and chain length. The result data is also written to this tree and can be retrieved.
(see node.h for more info)
Creating a tree is quite straight forward. Every node requires a unique identifier within the tree structure. This is passed as an argument during creation and should not be changed thereafter.
struct ik_node_t* tree = ik_node_create(0);
struct ik_node_t* node = ik_node_create(1);
ik_node_add_child(tree, node);
You will need to mirror the same structure present in your project (assuming your project is using a scene graph or something similar). Whether you do this continuously or whether you rebuild the whole tree from scratch before solving when relevant parts of your scene graph become "dirty" is up to you. The former approach is recommended if your scene graph is expected to change a lot. The latter is of course easier to implement, but will be slower.
You can remove nodes with the function ik_node_destroy()
. You can
retrieve node objects by uid with ik_node_find_child()
In order to mark a node as an effector, you must create and attach an effector
object using ik_effector_create()
and ik_node_attach_effector()
.
/* create a tree with 8 nodes */
int i;
struct ik_node_t* node;
struct ik_node_t* tree = node = ik_node_create(0);
for (i = 1; i != 9; ++i)
{
struct ik_node_t* child = ik_node_create(i);
ik_node_add_child(node, child);
node = child;
}
/* the last node is an effector */
struct ik_effector_t* effector = ik_effector_create();
ik_node_attach_effector(node, effector);
The most important stuff to set for the effector are:
effector->chain_length = 3; /* how many parent segments should be affected */
effector->target_position = getMyTargetPosition();
effector->target_rotation = getMyTargetRotation();
A chain length of 1 means a single segment or "bone" is affected. Arms and legs typically use a value of 2. The default value is 0, which means all nodes right down to the root node are affected.
The target position and rotation is set in global space, where the target position is a 3-dimensional vector type and the rotation is a quaternion.
The first thing you should do is create your desired solver and set its tree.
ik_solver_t* solver = ik_solver_create(SOLVER_FABRIK);
ik_solver_set_tree(solver, tree); /* the tree we built earlier */
As of this writing, the only algorithm supported is FABRIK. Additional solvers may be added in the future.
WARNING: You must rebuild the tree at least once before solving to update internal data structures. Failing to do so will result in segaults. If you change the tree in any way (add nodes or remove nodes, add effectors or remove effectors) you must also rebuild the tree.
The solver exposes a host of different features which can be enabled and disabled according to your requirements.