How to animate a model – ArmA: Armed Assault

From Bohemia Interactive Community
Revision as of 12:50, 8 April 2007 by TeRp (talk | contribs) (→‎Animations: added offset description by Sgt. Flyer)
Jump to navigation Jump to search

Introduction

Attention: This article is a tutorial on how to animate parts of your model (e.g. wheels, rotors, etc.). Take all information of this article with a pinch of salt: everything is based on experiments and hasn't been confirmed nor documented by BIS, yet.

To animate a model, you have to make use of both, the cfgModels and cfgSkeletons class.

The cfgSkeletons class defines the bones of a vehicle. Bones are, more or less, the animated selections of a model.

The cfgModels class is an extended version of the OFP cfgModels class. It defines the selections of a model which you want to animate or use with the setObjectTexture command, but since ArmA, you have to put everything related to animate your model in here.

model.cfg

According to the article about Model Config, the cfgSkeletons and cfgModels class should be part of a model.cfg file which is located in the addon pbo file. However, this does not seems to work (I assume the model.cfg files will be put into the model p3d file during binarization). For now, you can add the cfgSkeletons and cfgModels class to your config.cpp which works like a charm.

cfgSkeletons

The cfgSkeletons class defines, as mentioned before, the bones (= animated selections) of a vehicle.

Each skeleton is a subclass within the cfgSkeletons class, consisting of three parameters:

Parameter Description
isDiscrete currently unknown, set to 1.
skeletonInherit inherit bones from given class.
skeletonBones[] define your own bones here.

Defining a bone

Bones are defined in the skeletonBones[]-array which is made of a list of unsorted bones. Each bone is the name of a selection you want to animate.

A single bone

A bone is defined by using two strings:

"bone",""

You may define multiple bones by strining them togeter.

Attention: Do not leave out the second string as this will lead to errors! (see linked bones for more information on the second string argument)

Example
skeletonBones[]=
{
	"bone1","", //defines bone1
	"bone2",""  //defines bone2
};

Linked bones

The second argument (empty in the example above) is used for linking two bones:

"bone1","bone2"

Linking is used to make the animation of "bone1" depending on the movement of "bone2". If you e.g. have a turret, you have to make use of linking here, because the up and down movement of the turrets weapon is typically influenced by left and right movement of the turret:

Example
skeletonBones[]=
{
	"turret_x","",         //defines bone turret_x
	"turret_y","turret_x"  //defines bone turret_y and makes it linked to bone turret_x
};

Attention:
You can not link more than two bones in a row!
If you do something like

	"bone1","bone2","bone3"

this will result in an error, as Armed Assault interprets this as

  • defining "bone1" which is linked to "bone2"
  • defining "bone3", which misses the second argument.

However, it should be possible to use a syntax like this (not tested yet):

skeletonBones[]=
{
	"bone1","bone2", //defines bone "bone1" and makes it linked to "bone2"
	"bone2","bone3", //defines bone "bone2" and makes it linked to "bone3"
	"bone3",""       //defines bone "bone3".
};

In conclusion, "bone1" is linked to "bone2", which is linked to "bone3".
So "bone1" should be depending on the movement of both, "bone2" and "bone3".

cfgSkeletons Example

class cfgSkeletons
{
	class BWMod_Tiger_Skeleton
	{
		isDiscrete=1;

		skeletonInherit="";
		skeletonBones[]=
		{
			"wheelL","",
			"wheelR","",

			"turret_RMK_x","",
			"turret_RMK_y","turret_RMK_x",

			"turret_OSIRIS_y","",
			"turret_OSIRIS_x","turret_OSIRIS_y"
		};
	};
};

cfgModels

The cfgModels class is used to declare the selections of a model you want to animate or access via the setObjectTexture command. Since ArmA, the cfgModels class has been extended an is now used to define all animations of a model.

Each of your model is a subclass inside of the cfgModels class and the models filename is used as the name of your class (without .p3d). E.g. your model p3d is named "myVehicle.p3d" your class is "class myvehicle {}". We will call them "modelclasses" in this article for the sake of simplicity.

Each modelclass consists of three parameters and an additional subclass which defines the animations of your models:

Parameter Description
sectionsInherits inherit sections (= selections) from given glass.
sections[] define your sections here.
skeletonName class name of skeleton used by this model.
class Animations {} subclass which defines the animations of your model.

Sections

A section is the same as a selection: a part of the model which may be animated or changed via the setObjectTexture command. To define selections in your modelclass make use of the section[]-array. This array is an unordered list of all selections you want to use in the ways described above.

Example

sections[]=
{
	"mainRotor","mainRotor_static","mainRotor_blur","mainRotor_dive",
	"tailRotor","tailRotor_static","tailRotor_blur","tailRotor_dive",

	"turret_RMK_x","turret_RMK_y"
};

Animations

To define animations for your model, you have to make use of the class animations in your modelclass. Each animation is a subclass in the class animations with a userdefinable name and consists of the following parameters:

Parameter Description
type the type of the animation, e.g. rotating or translation. Refer to Model Config for a list of all animation types.
source The source used to animate the selection. Refer to Model Config for a list of all sources.
selection The name of the bone (= selection) you want to animate. Has to be defined in the cfgSkeletons class.
axis The name of the axis you want to use (only necessary for types rotation and translation).
memory If using an own axis (by the axis-parameter) use value 1 if axis is located in the memory lod of your model or 0 if the axis is located in the lod (or better: every lod) where your animated selection is used.
sourceAdress Use "loop" if you want your animation to "loop" (e.g. on wheels) or "clamp" if you want your animation to stop at a specific angle (e.g. on the steering wheel of a car).
minValue If source returns a value <= minValue, the animation is animated with angle0 (see below)
maxValue If source returns a value >= maxValue, the animation is animated with angle1 (see below)
angle0 The angle the selection is animated when minValue is reached.
angle1 The angle the selection is animated when maxValue is reached.
offset0 The distance the bone is moved when using type="rotation" and minValue is returned. Distance is calculated by the distance of axis' vertices. If the have a distance of 1m and you are using offset0 = 1, the bone will be moved by 1m. If using offset0=0.5, the bone will be moved by 0.5m, etc.
offset1 Same as offset0, but when maxValue is returned.

Attention

I am assuming that each source is returning a value between 0 and 1 (the animationPhase) which is used to animate your selection. Some may even return a value from -1 to 1:

  • If using source="speed", the source is returning 0 when the vehicle is not moving and 1 when the vehicle is moving at maximum speed.
  • If using source="drivingWheel", the source is returning -1 when the vehicle is turning left, 0 when the vehicle is not turning and 1 when the vehicle is turning right.

On turrets, it is necessary that the classnames of the animations match the according turret selection names.
So if you're mainTurret selection is named "turret_RMK_x" you have to name your class "turret_RMK_y", too. The same goes for the mainGun selection.

Example

class mainRotor
{
	type="rotationY"; //rotation around the Y axis
	source="rotorH";
	selection="mainRotor";
	axis=""; //no own axis, use centre of selection
	memory=1;
	sourceAddress="loop";
	minValue=0;
	maxValue=1;
	angle0=0;
	angle1="rad -360";
};

Axes

Since the axes seem a bit messed up when using rotationX, rotationY, rotationZ, translationX, translationY, translationZ, here is a small image of how the axes are arranged.

Keep in mind that this image shows only the direction of these axes and not their position. The position is always defined by the center of your animated selection.

As a short examle, the wheels would need "rotationX" as animation type.

Howtoanimmodel axes.jpg

cfgModels example

class cfgModels
{
	class bwmod_tiger
	{
		sectionsInherit="";
		sections[]=
		{
			"mainRotor","mainRotor_static","mainRotor_blur","mainRotor_dive",
			"tailRotor","tailRotor_static","tailRotor_blur","tailRotor_dive",

			"turret_RMK_x","turret_RMK_y"
		};

		skeletonName="BWMod_Tiger_Skeleton";

		class Animations
		{
			class mainRotor
			{
				type="rotationY";
				source="rotorH";
				selection="mainRotor";
				axis="";
				memory=1;
				sourceAddress="loop";
				minValue=0;
				maxValue=1;
				angle0=0;
				angle1="rad -360";
			};

			class tailRotor
			{
				type="rotationX";
				source="rotorV";
				selection="tailRotor";
				axis="";
				memory=1;
				sourceAddress="loop";
				minValue=0;
				maxValue=1;
				angle0=0;
				angle1="rad -360";
			};

			class wheelL
			{
				type="translation";
				source="altRadar";
				selection="wheelL";
				axis="axis_damper"; //vertical axis, vertex distance 1 m
				memory=0;
				animPeriod=0;
				minValue=0;
				maxValue=0.05;      //max value 0.05m above ground
				offset0=0;
				offset1=-0.05;      //animate wheels downwards for 0.05m when maxValue is reached.
			};

			class wheelR
			{
				type="translation";
				source="altRadar";
				selection="wheelR";
				axis="axis_damper";
				memory=0;
				animPeriod=0;
				minValue=0;
				maxValue=0.05;
				offset0=0;
				offset1=-0.05;
			};

			class turret_RMK_x //the horizontal moving part of the turret
			{
				type="rotationY";
				source="mainTurret";
				selection="turret_RMK_x";
				axis="axis_turret_RMK_x";
				animPeriod=0;
				memory=1;
				minValue="rad -360";
				maxValue="rad +360";
				angle0="rad -360";
				angle1="rad +360";
			};

			class turret_RMK_y //the vertical moving part of the turret
			{
				type="rotationX";
				source="mainGun";
				selection="turret_RMK_y";
				axis="axis_turret_RMK_y";
				animPeriod=0;
				memory=1;
				minValue="rad -360";
				maxValue="rad +360";
				angle0="rad -360";
				angle1="rad +360";
			};
		};
	};
};