AnimatedModel - Fish-In-A-Suit/Conquest GitHub Wiki

package animatedModel;

import org.lwjgl.util.vector.Matrix4f;

import animation.Animation;
import animation.Animator;
import openglObjects.Vao;
import textures.Texture;

public class AnimatedModel {
	// skin
	private final Vao model;
	private final Texture texture;

	// skeleton
	private final Joint rootJoint;
	private final int jointCount;

	private final Animator animator;

	public AnimatedModel(Vao model, Texture texture, Joint rootJoint, int jointCount) {
		this.model = model;
		this.texture = texture;
		this.rootJoint = rootJoint;
		this.jointCount = jointCount;
		this.animator = new Animator(this);
		rootJoint.calcInverseBindTransform(new Matrix4f());
	}

	public Vao getModel() {
		return model;
	}

	public Texture getTexture() {
		return texture;
	}

	public Joint getRootJoint() {
		return rootJoint;
	}

	public void delete() {
		model.delete();
		texture.delete();
	}

	public void doAnimation(Animation animation) {
		animator.doAnimation(animation);
	}

	public void update() {
		animator.update();
	}

	public Matrix4f[] getJointTransforms() {
		Matrix4f[] jointMatrices = new Matrix4f[jointCount];
		addJointsToArray(rootJoint, jointMatrices);
		return jointMatrices;
	}

	private void addJointsToArray(Joint headJoint, Matrix4f[] jointMatrices) {
		jointMatrices[headJoint.index] = headJoint.getAnimatedTransform();
		for (Joint childJoint : headJoint.children) {
			addJointsToArray(childJoint, jointMatrices);
		}
	}

}

Each AnimatedModel comprises of two things: the skin (mesh data and texture) and skeleton (root joint and number of joints). VAO model holds mesh information. texture holds a Texture instance. rootJoint refers to the joint that is at the top of the hierarchy (ie, the parentless joint). jointCount refers to the total number of joints in the skeleton, just so that when the array of joint transforms (to be loaded to the shader) is created, we know how big it should be (its size is the same as number of joints, since one joint is associated with one and only one joint transform). Each AnimatedModel instance also has its Animator instance (which has the job of keeping track of the current animation and calculating/setting the joint transforms accordingly).

The constructor AnimatedModel(Vao model, Texture texture, Joint rootJoint, int jointCount), takes in the skin and skeleton information. Note that the joint hierarchy should already be deterrmined by this stage. It stores input parameters to corresponding fields and at the end it calculates the inverse bind tranform for each joint: rootJoint.calcInverseBindTransform(new Matrix4f());. Note that since the root joint has no parent, it just takes in an identity matrix.

getModel(), getTexture() and getRootJoint() just normal getter methods.

delete() method deletes the VAO and texture object when the game is closed.

doAnimation(Animation animation) Instructs this entity to carry out a given animation. To do this it sets the chosen animation as the current animation in the Animator object.

update() updates the Animator for this entity, basically updating the animated pose of the entity. Must be called every frame.

getJointTransforms() gets the array of model-space transforms of all joints (with the current animation pose applied). The joints are ordered in the array based on their joint index. The position of each joint's transform in the array is equal to the joint's index. It creates an array of matrices, the size of which being equal to jointCount. Then, recursive method addJointsToArray(Joint headJoint, Matrix4f[] jointMatrices) is used to add the transform for each joint into the array.