We have dozens of animations and every week we get more. Manually entering them all in the editor is time consuming and boring so we’ve been trying to automate it using an editor script (we like writing editor scripts). But we can’t figure out how to add new animations
Here’s part of the code:
ModelImporter modelImporter;
string path = AssetDatabase.GetAssetPath(3DSMaxFBXthingy);
modelImporter = AssetImporter.GetAtPath(path) as ModelImporter;
//--- This line goes boom
modelImporter.clipAnimations = new ModelImporterClipAnimation[numAnimations];
...code that reads a text file, builds ModelImporterClipAnimation, adds them to the array, calls AssetDatabase.ImportAsset, etc.
We have a character model already in the game. We get a reference to it. The model stores all the animations (name, start frame, end frame, wrap mode) in the property
ModelImporterClipAnimation[ ] clipAnimations
That’s a normal array, not a List<> or ArrayList so it can’t dynamically grow. Therefore, to add 10 animations, we create a new array of 10 items and try to set that. But it doesn’t like it when we do that
The error we get we don’t understand. The above line calls System.Reflection.MethodBase.Invoke which calls HostView.OnGUI, HostView.Invoke, another Reflection.MethodBase.Invoke which finally leads to the error:
TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke
Since that’s all Unity code, we can’t see what’s going on or the parameters involved but i’m guessing we don’t need to - i suspect the error is more our approach than any specific niggly detail in the Unity code
i realize not many people have probably tried this but anyone have any insight into how to make this import animation thing work?
Just to check, do you have splitAnimations set before you use this code?
Yup
Not sure if people want to see the full code but here’s what we wrote:
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public class AnimsImporter : ScriptableWizard {
public GameObject doll;
public TextAsset animFile;
private ModelImporter modelImporter;
[MenuItem("Editor/Models/Import Doll Anims")]
static void Import()
{
ScriptableWizard.DisplayWizard(
"Import anims", typeof(AnimsImporter),
"Apply Close");
}
void OnWizardCreate()
{
apply();
}
void apply()
{
string path = AssetDatabase.GetAssetPath(doll);
modelImporter = AssetImporter.GetAtPath(path) as ModelImporter;
loadAnimationsFromText(animFile.text);
AssetDatabase.ImportAsset(path);
}
public void loadAnimationsFromText(string animationsDescriptorFile)
{
char[] delimiters = ";".ToCharArray();
string[] lines = animationsDescriptorFile.Split(delimiters);
modelImporter.splitAnimations = true;
-!! THIS IS WHERE IT BLOWS UP !!-
modelImporter.clipAnimations = new ModelImporterClipAnimation[lines.Length];
for(int i=0;i<lines.Length;i++)
{
string line = lines[i];
modelImporter.clipAnimations[i] = parse(line);
}
}
public ModelImporterClipAnimation parse(string textEncoding)
{
ModelImporterClipAnimation newClip = new ModelImporterClipAnimation();
char[] delimiters = " =-".ToCharArray();
//--- Fix the tokens (two spaces makes a blank token, not what we want)
List<string> tokens = new List<string>();
string[] badTokens = textEncoding.Split(delimiters);
foreach (string token in badTokens)
{
if (!token.Equals(string.Empty))
tokens.Add(token.ToString());
}
newClip.name = tokens[0];
newClip.firstFrame = int.Parse(tokens[1]);
newClip.lastFrame = int.Parse(tokens[2]);
newClip.loop = false;
newClip.wrapMode = WrapMode.Once;
return newClip;
}
}
I’m not sure what’s happening, but I will try your script on Monday. Usually people modify ModelImporter in PreProcessModel, but your approach might be valid too (I don’t know if ModelImporter can be accessed during other phases). It might be something specific to clipAnimations.
Hi baylor,
Sorry for taking longer than promised - I had to fix some high-priority beta1 bugs yesterday.
There are several conclusions:
-
modelImporter.clipAnimations = new ModelImporterClipAnimation[1]; throws an exception. It shouldn’t. It caused by incoherent design on C# and C++ side in Unity (what happening is that members of new array are null, so that’s why you get an exception). I’ll raise a bug on it.
-
Even if the one above would work this:
modelImporter.clipAnimations[i] = parse(line);
wouldn’t do what you want, because in Unity arrays are always returned as copies, so you would be modifying your local copy and modelImporter.clipAnimations wouldn’t be affected.
3) The solution is to construct your array first and then assign it to modelImporter.clipAnimations. Something like this:
* *ModelImporterClipAnimation[] mica = new ModelImporterClipAnimation[1]; mica[0] = new ModelImporterClipAnimation(); // fill mica[0] modelImporter.clipAnimations = mica;* *
I hope this solves your problem.
Thanks Paulius. Finished testing it, that works, now our life is much, much happier 
This is going to save us tons of time - Thanks!
This method works on a 1:1 model to animation file ratio. In my case i have 4 distinct models and i want them all to share from a single animation file.
The problems is that if i split the clips i have to manually move over 1000clips into each model.
If i dont split the clips once i extract it from the source model(prefab) all the partitioning is lost.
Please help cos the only version that works run time takes 6+ minutes to partition the animation.
Nevermind i found a cheap trick. Loaded the prefab containing the animation into a game object then copied the animation states at runtime