Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
8
Question by ZioFede87 · May 29, 2017 at 08:51 PM · animation3dsmaxkeyframeread-only

How to add keyframes on imported, read-only, animation?

I have multiple animation imported from 3ds max 8.

they are several animation of the same object divided in multiple .max files (ex fire, walk etc) so I've ended up importing them with the @ workaround. Now I need to add an event on them (for ex in the fire animation I have to wake up a fire emitter right in the moment that the weapons fires) unfortunately all the animations are read-only, so no editing is possible.

I know that this question had been posted several times on this forum, but none of the previous answers seems to work for me.

  • I've try to copy the entire animation (ctrl+d), and the copy remains read-only

  • I've try the script for copy the animation keyframes to a new anim file (I'm unable to find that script now, but if someone need it I can search better..) but the problem was that this script copy only the animation, I have a whole object with multiple mesh and materials that was lost...

So please someone help me... If you need I can provide the .max file or the demo or the entire project as well.....I need to fix this thing very badly.

Thanks

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

6 Replies

· Add your reply
  • Sort: 
avatar image
40
Best Answer

Answer by Bunny83 · Nov 21, 2011 at 05:09 PM

You have to duplicate the animationclip-asset. Select the animation clip in your imported model and press ctrl+d. Now you should have a seperate AnimationClip file. This animation clip have to be added to an instance of your model. Just drag your model asset into the scene and replace the referenced AnimationClip in the animation array. After you added the AnimationClip to your model you can open the animation editor window and select your model in the hierarchy. Select the right animation on top (if there are multiple) and you can edit anything in this animation. All changes will be saved to the .anim file since that's the animation you're using now.

You can't replace the AnimationClip on the imported model itself but you can create a new prefab out of the instanciated model in your scene. This prefab will used the assigned AnimationClip.

I have created a special AssetPostProcessor which automatically extracts the .anim files and add them automatically to the model prefab since we have 90+ animations ;)

edit

I've created a small test scene with your model:

AnimationEventsTest.unitypackage

All I've done is:

  1. Draged the model into the scene
  2. Created a new prefab ("Unit_Prefab")
  3. Draged the model onto the prefab to store the model in the prefab
  4. Assigned the seperate AnimationClips("moverun1.anim", "idlefiring1.anim") to the animation array on the new prefab.
  5. Added my test script to provide a function for the AnimationEvent.
  6. Select the model in the scene and open the animation window.
  7. Added two AnimationEvents for the run animation.

Your idle_firing animation seems to be empty, but the run animation works. Oh and i cleaned up unnecessary/duplicated textures. All the animation-fbx files doesn't need to have a material / texture. Unity just need the AnimationClip. Actually after you duplicated the AnimationClip you could completely remove the animation-fbx files. Only when you want to update your animation you have to reimport the animation and duplicate the Clip again.

Because of that procedure we created a specialized AssetPostProcessor which does this steps automatically. If you need to do this 90+ times it's no fun ;)

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image ZioFede87 · Nov 24, 2011 at 09:39 AM 0
Share

Thank you for the answer, unfortunately I can't manage to solve the problem that way... I've duplicated the animation script and then added it to the new prefab instance, and this way the script become editable, by the way the animation are not in the animation script (nor in the original neither..), they are stored in several sub-object child of the $$anonymous$$aster object, so when I use the Animation tool to inspect the animation script file I found it empty, but if I navigate trough the sub object to the one named $$anonymous$$aster, I can see the animation...

I have put my animation here: http://www.federicolaggiard.altervista.org/forumExample/Animations.rar

Please try to edit them yourself if you have time (you can find the .max files, the fbm files and the materials also)

Thank you!

avatar image Bunny83 · Nov 25, 2011 at 01:19 PM 0
Share

@ZioFede87: I've updated my answer with an example ;)

avatar image ZioFede87 · Nov 28, 2011 at 01:17 PM 0
Share

$$anonymous$$an you did the magic! That's work like a charm! thank you so much for your patience

avatar image JasonM · Dec 21, 2011 at 05:39 PM 0
Share

You mentioned a postProcessor to do this, can you link to it?

avatar image Bunny83 · Dec 21, 2011 at 06:01 PM 0
Share

@Jason$$anonymous$$: As i said we used a specialised postprocessor. It only reacts to some special filenames, so it won't help much i guess. If you need information on the AssetPostprocessor just search.

Show more comments
avatar image
4

Answer by WILEz1975 · Jun 26, 2017 at 01:37 PM

The clip duplication technique is very cumbersome. With dozens of clips and the need to edit them from the program (Maya, Max, Blender etc ...) becomes some problems...

The best solution is to insert the events in the animations at runtime, in the start function with this function:

 void AddEvent(int Clip,float time, string functionName,float floatParameter)
 {
     anim = GetComponent<Animator>();
     AnimationEvent animationEvent = new AnimationEvent();
     animationEvent.functionName = functionName;
      animationEvent.floatParameter = floatParameter;
     animationEvent.time = time;
     AnimationClip clip = anim.runtimeAnimatorController.animationClips[Clip];
     clip.AddEvent(animationEvent);
 }


For example:

 Animator anim;


 void Start () {
     anim = GetComponent<Animator>();
     AddEvent(1, 0.2f, "EmitProjectile", 0);
 }

 void AddEvent(int Clip, float time, string functionName, float floatParameter)
 {
     anim = GetComponent<Animator>();
     AnimationEvent animationEvent = new AnimationEvent();
     animationEvent.functionName = functionName;
      animationEvent.floatParameter = floatParameter;
     animationEvent.time = time;
     AnimationClip clip = anim.runtimeAnimatorController.animationClips[Clip];
     clip.AddEvent(animationEvent);
 }



Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Barrrettt · Sep 18, 2017 at 03:30 PM 0
Share

in my opinion, best way! thx

avatar image minearjade · Mar 11, 2018 at 11:02 AM 0
Share

$$anonymous$$gest an edit to use the initializer with new AnimationEvent()

 AnimationEvent animationEvent = new AnimationEvent
         {
             functionName = functionName,
             floatParameter = floatParameter,
             time = time
         };
avatar image Bunny83 minearjade · Mar 11, 2018 at 11:18 AM 0
Share

Uhm, why? The Object initializer syntax is just a "shorthand" for the exact same code that is in the answer. Actually your code has 6 lines of code while the original has only 4. So it's just a matter of subjective preferences.


Of course adding animation events procedurally at runtime does work, however note that if the animationclip is shared between multiple objects you only have to add the event once. If every object adds the event each of the N objects will receive the event N times. (at least that's what it used to be several years ago)

avatar image ecv80 · Jun 20, 2020 at 03:47 PM 0
Share

Thank you for this. Upvoted. $$anonymous$$ine is longer ;)

The pretty version is here: https://pastebin.com/f0ZneTtx . Sorry I couldn't be bothered to adjust the CODE tags forever. $$anonymous$$y code is overflowing no matter what and it just doesn't work.

bool AddEvent(string clipName, float time, string functionName) { return AddEvent(clipName, time, functionName, null); } bool AddEvent(string clipName, float time, string functionName, T parameter) { bool found=false; AnimationClip animationClip=null; foreach (AnimationClip aniclip in ani.runtimeAnimatorController.animationClips) if (aniclip.name.Equals(clipName)) { animationClip=aniclip; found=true; break; } if (found==false) return false;

 AnimationEvent animationEvent = new AnimationEvent();
 animationEvent.functionName = functionName;
 animationEvent.time = time;
 if (!(parameter is Object && parameter==null))
     switch (parameter)
     {
         case int p: animationEvent.intParameter=p; break;
         case float p: animationEvent.floatParameter=p; break;
         case string p: animationEvent.stringParameter=p; break;
         case Object p: animationEvent.objectReferenceParameter=p; break;
         default:
         break;
     }
 animationClip.AddEvent(animationEvent);

 return true;

}

Note 1: ani is the Animator, implied elsewhere in the Class

Note 2: Switch-Case for types only works on C# 7+. Other options I found are checking for type names, and using lambdas (which I didn't like).

avatar image
2

Answer by lesiry · Jul 30, 2014 at 07:35 AM

using UnityEditor; using UnityEngine; using System.IO; using System.Collections;

public class MultipleCurvesTransferer { const string duplicatePostfix = "_copy"; const string animationFolder = "Animations";

 static void CopyClip(string importedPath, string copyPath)
 {
     AnimationClip src = AssetDatabase.LoadAssetAtPath(importedPath, typeof(AnimationClip)) as AnimationClip;
     AnimationClip newClip = new AnimationClip();
     newClip.name = src.name + duplicatePostfix;
     AssetDatabase.CreateAsset(newClip, copyPath);
     AssetDatabase.Refresh();
 }

 [MenuItem("Assets/Transfer Multiple Clips Curves to Copy")]
 static void CopyCurvesToDuplicate()
 {
     // Get selected AnimationClip
     Object[] imported = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Unfiltered);
     if (imported.Length == 0)
     {
         Debug.LogWarning("Either no objects were selected or the objects selected were not AnimationClips.");
         return;
     }

     //If necessary, create the animations folder.
     if (Directory.Exists("Assets/" + animationFolder) == false)
     {
         AssetDatabase.CreateFolder("Assets", animationFolder);
     }

     foreach (AnimationClip clip in imported)
     {
         string importedPath = AssetDatabase.GetAssetPath(clip);

         Debug.Log("OriginalPath: " + importedPath);

         //If the animation came from an FBX, then use the FBX name as a subfolder to contain the animations.
         string copyPath;
         if (importedPath.Contains(".fbx") || importedPath.Contains(".FBX"))
         {
             //With subfolder.
             string folder = importedPath.Substring(importedPath.LastIndexOf("/") + 1, importedPath.LastIndexOf(".") - importedPath.LastIndexOf("/") - 1);
             if (!Directory.Exists("Assets/Animations/" + folder))
             {
                 AssetDatabase.CreateFolder("Assets/Animations", folder);
             }
             copyPath = "Assets/Animations/" + folder + "/" + clip.name + duplicatePostfix + ".anim";
         }
         else
         {
             //No Subfolder
             copyPath = "Assets/Animations/" + clip.name + duplicatePostfix + ".anim";
         }

         Debug.Log("CopyPath: " + copyPath);

         CopyClip(importedPath, copyPath);

         AnimationClip copy = AssetDatabase.LoadAssetAtPath(copyPath, typeof(AnimationClip)) as AnimationClip;
         if (copy == null)
         {
             Debug.Log("No copy found at " + copyPath);
             return;
         }
         // Copy curves from imported to copy
         AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(clip, true);
         for (int i = 0; i < curveDatas.Length; i++)
         {
             AnimationUtility.SetEditorCurve(
                 clip, 
                 EditorCurveBinding.FloatCurve(curveDatas[i].path, curveDatas[i].type, curveDatas[i].propertyName), 
                 curveDatas[i].curve
                 );
         }
         Debug.Log("Copying curves into " + copy.name + " is done");
     }
 }

}

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

Answer by Crook108 · May 29, 2017 at 08:31 PM

I remember figuring out a way to unlock the read-only status on anim files on a previous project but it escapes me now. The best alternative I can think of if you just want to add events to your animations you can do it in the animation import options.

Just double click your animation file and expand the Events menu. Sadly the precision isn't perfect, its kind of hard to pick an exact key frame. Once you add an event you can name a function it calls and specify and input argument (float, int or string). You will need to link it to an object with a public function with the same name you specified earlier. I will try and update this if I find a better solution.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image KarlKarl2000 · Feb 08, 2019 at 08:58 AM 0
Share

This one is the true answer. Don't duplicate your animation clips thats just a poor workflow. Doing it via script might work, but not as visually simple. I$$anonymous$$O.

Just as @ Crook108 stated.

  1. Create a script with a public void calling your function (Let's name it public void DOGBAR$$anonymous$$). In my case its a sound effect.

  2. Locate the specific animation and find the "Events" drop down way at the bottom. Then add a "ADD EVENTS" key. Inside the FUNCTION box, type in DOGBAR$$anonymous$$. Do that for as many keyframes that need this function to be called.

  3. $$anonymous$$ake sure the script with the DOGBAR$$anonymous$$ function, is on the same game object as the animator that needs to find the function.

Done. Then at run time whenever that animation is called, it'll auto look for the script containing that function.

  • note*

  • It's possible to get the precise keyframe, just scrub the GREY BOX beside the big black play button.. Not sure why Unity colored it that way.. but scrubbing the timeline lets u find the preceise keyframe to add the event keyframe

avatar image
1

Answer by refardeon · Mar 25, 2021 at 02:58 AM

Just stumbled over this - there is another way of dealing with this issue: In the import settings, under the 'Animation' tab, scroll down to the 'Events' tab to edit events - see attached image, I'm using it to emit footstep events. You can even use the little preview window on the bottom to find the correct spot in the animation. Same for the 'Curves' etc. Once you're done, apply your changes and you're done.

alt text


snip2.png (80.4 kB)
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image melsov · Feb 11 at 07:12 PM 0
Share

Logged in to upvote this answer.

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

17 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Importing Keyframe Animation (not Bone-based Animation) 0 Answers

How do I create a climb/clambering animation for Unity, in 3DS Max? 0 Answers

Unity Animation - Loop around a closed loop trajectory 1 Answer

How to add keyframe animation to an imported FBX. 0 Answers

3ds Max assets importing - missing materials 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges