I am migrating from UnrealEngine 3, and I have a question about where in the asset pipeline additive animations used in Unity 2.6 are generated. (We are currently using Maya)
The workflow I am used to, is to create the additive animations inside the editor (UE3). By selecting an animation and choosing a pose (first frame of other animation) to subtract from it. This generates the difference into a new (additive) animation.
How is this done in Unity?
thanx in advance
/tax
There is no such thing in Unity
In Unity you can have multiple layers of animation as well as blending animations within the same animation layer if you want to.
All this is runtime code, import / editor / build side work.
Hmmm.
Do you mean there is no such thing as additive animations in unity? or do you mean that its done in the pipeline before entering unity?
Additive animations seems to be mentioned here
http://unity3d.com/support/documentation/Manual/Character-Animation.html
I continued looking at the problem, and decided to just insert some normal animations and learn from them. (Assuming that an animation is only offsets from a centerpose changing over time, and thus could be added to other animations.)
So this is what I did. I setup our rig with a looping idle animation, and attach the following script:
using UnityEngine;
using System.Collections;
public class
AdditiveAim: MonoBehaviour {
private AnimationState horizontal;
private AnimationState vertical;
void Start () {
horizontal = animation["horizontal"];
horizontal.layer = 10;
horizontal.blendMode = AnimationBlendMode.Additive;
horizontal.wrapMode = WrapMode.ClampForever;
horizontal.enabled = true;
horizontal.weight = 1.0f;
vertical = animation["vertical"];
vertical.layer = 10;
vertical.blendMode = AnimationBlendMode.Additive;
vertical.wrapMode = WrapMode.ClampForever;
vertical.enabled = true;
vertical.weight = 1.0f;
}
void Update () {
horizontal.normalizedTime = Input.GetAxis("Horizontal") * 0.5f + 0.5f;
vertical.normalizedTime = Input.GetAxis("Vertical") * 0.5f + 0.5f;
}
}
This works partly, but it has two problems. The pose looks a bit off, and it is shaking like a parkinson patient.
It seems to me that the additive animations are being played between the update() functioncalls, where they are being pushed to their location.
I found another thread touching the same symptoms, but it does not seem to be related to additive animations?
http://forum.unity3d.com/viewtopic.php?t=24054&highlight=additive+animation+normalizedtime
Thanx in advance.
/tax
P.S:
Just found out I could remove the jittering by setting the speed:
vertical.normalizedSpeed = 0.0f;
But my pose still looks a bit off. Do I need to bake additive animations in a special way?
This might just be a guess, but it seems to me that when I use the animations in additive mode the contribution is the difference from the first frame?
My sweep animations are aligned like this:
Frame Pose
----------------------------------------
0, Lower extreme (eg. aiming left)
25, Aiming straight
51, Higher extreme (eg. aiming left)
And this gives me zero contribution on frame 0. I would expect the zero contribution to be at frame 25.
If my assumption is correct, is there a way to set what frame to consider zero?
Thanx
/tax
There is a simple example of additive animation in the documentation here:
http://unity3d.com/support/documentation/Manual/Character-Animation.html#LayerExample
Additive animations in Unity are always relative to the first frame of the animation. This means that you will sometimes need to use more animations, or do a little more scripting than you would otherwise have done, but you should always be able to obtain the same results in the end as if you could have specified any frame as the reference.
For example, instead of one animation going from lower extreme through straight, to higher extreme, you could have two - one from straight to lower extreme and another from straight to higher extreme.
Another note:
Usually when animations are playing in Unity, they are advanced each frame according to their speed. If you want to set the frame/time manually without Unity interfering, just set the speed to 0. (Setting normalizedSpeed to 0 does the exact same thing.)
Hope that helps.
Rune
Spot on.
Thanx 
/tax
For other interested people:
I ended up with the following script.
using UnityEngine;
using System.Collections;
public class
AdditiveAim: MonoBehaviour {
private AnimationState left;
private AnimationState right;
private AnimationState up;
private AnimationState down;
public float sensitivity = 0.01F;
public float maxX = 0.5F;
public float maxY = 0.5F;
float rotationX = 0F;
float rotationY = 0F;
Quaternion originalRotation;
void Start () {
left = animation["left"];
left.layer = 10;
left.blendMode = AnimationBlendMode.Additive;
left.wrapMode = WrapMode.ClampForever;
left.enabled = true;
left.weight = 1.0f;
left.normalizedSpeed = 0.0f;
right = animation["right"];
right.layer = 10;
right.blendMode = AnimationBlendMode.Additive;
right.wrapMode = WrapMode.ClampForever;
right.enabled = true;
right.weight = 1.0f;
right.normalizedSpeed = 0.0f;
up = animation["up"];
up.layer = 10;
up.blendMode = AnimationBlendMode.Additive;
up.wrapMode = WrapMode.ClampForever;
up.enabled = true;
up.weight = 1.0f;
up.normalizedSpeed = 0.0f;
down = animation["down"];
down.layer = 10;
down.blendMode = AnimationBlendMode.Additive;
down.wrapMode = WrapMode.ClampForever;
down.enabled = true;
down.weight = 1.0f;
down.normalizedSpeed = 0.0f;
}
void Update () {
// Read the delta mouse input axis and accumulate
rotationX += Input.GetAxis("Mouse X") * sensitivity;
rotationY += Input.GetAxis("Mouse Y") * sensitivity;
//Clamp values
rotationX = ClampAngle (rotationX, -maxX, maxX);
rotationY = ClampAngle (rotationY, -maxY, maxY);
//Apply
if (rotationX != 0.0)
{
right.normalizedTime = 0.0f;
left.normalizedTime = 0.0f;
if (rotationX > 0.0f)
{
right.normalizedTime = rotationX;
left.normalizedTime = 0.0f;
}
else
{
right.normalizedTime = 0.0f;
left.normalizedTime = -rotationX;
}
}
if (rotationY != 0.0)
{
up.normalizedTime = 0.0f;
down.normalizedTime = 0.0f;
if (rotationY > 0.0f)
{
up.normalizedTime = rotationY;
down.normalizedTime = 0.0f;
}
else
{
up.normalizedTime = 0.0f;
down.normalizedTime = -rotationY;
}
}
}
public static float ClampAngle (float angle, float min, float max)
{
if (angle < -1.0F)
angle += 1.0F;
if (angle > 1.0F)
angle -= 1.0F;
return Mathf.Clamp (angle, min, max);
}
}
I have my code written exactly like this and it doesnt work.No Additive influence.