Keyframe
How do I use Keyframe
Below are practical examples compiled from projects for learning and reference purposes
Featured Snippets
File name: PhotonTransformViewPositionModel.cs
Copy
35 public AnimationCurve InterpolateSpeedCurve = new AnimationCurve( new Keyframe[] {
36 new Keyframe( -1, 0, 0, Mathf.Infinity ),
37 new Keyframe( 0, 1, 0, 0 ),
38 new Keyframe( 1, 1, 0, 1 ),
39 new Keyframe( 4, 4, 1, 0 ) } );
File name: AnimationBuilder.cs
Copy
91 public AnimationClip MakeAnimationClip(GameObject root, Animation animation, string baseFolderPath)
92 {
93 //Clear local caches
94 lastGameObjectCache.Clear();
95 animationEvents.Clear();
96 lastKeyframeCache.Clear();
97 spriteChangeKeys.Clear();
98 spriteBaseFolder = baseFolderPath;
99
100 var animClip = new AnimationClip();
101 animClip.name = animation.Name;
102
103 //Set clip to Generic type
104 //AnimationUtility.SetAnimationType(animClip, ModelImporterAnimationType.Generic);
105
106 //Populate the animation curves & events
107 MakeAnimationCurves(root, animClip, animation);
108
109 return animClip;
110 }
File name: AnimationBuilder.cs
Copy
222 private void SetGameObjectForRef(GameObject root, Ref childRef, float time)
223 {
224 TimelineKey key = childRef.Referenced;
225 if (time < 0) time = key.Time;
226
227 TimelineKey lastKey;
228 lastKeyframeCache.TryGetValue(key.Timeline, out lastKey);
229
230 //Get the relative path based on the current hierarchy
231 var relativePath = childRef.RelativePath;
232
233 //If this is the root, skip it
234 if (string.IsNullOrEmpty(relativePath))
235 {
236 Debug.Log("Skipping root node in SetGameObjectForRef (SHOULD NEVER HAPPEN)");
237 return;
238 }
239
240
241 //Find the gameObject based on relative path
242 var transform = root.transform.Find(relativePath);
243 if (transform == null)
244 {
245 Debug.LogError("ERROR: Unable to find GameObject at relative path " + relativePath);
246 return;
247 }
248
249 var gameObject = transform.gameObject;
250 gameObject.SetActive(true);
251
252 //Get transform data from ref
253 Vector3 localPosition;
254 Vector3 localScale;
255 Vector3 localEulerAngles;
256
257 childRef.BakeTransforms(out localPosition, out localEulerAngles, out localScale);
258
259 //Set the current GameObject's transform data
260 transform.localPosition = localPosition;
261 transform.localScale = localScale;
262
263 //Spin the object in the correct direction
264 var oldEulerAngles = transform.localEulerAngles;
265
266 if (oldEulerAngles.z - localEulerAngles.z > 180) localEulerAngles.z += 360;
267 else if (localEulerAngles.z - oldEulerAngles.z > 180) localEulerAngles.z -= 360;
268 /*
269 switch(childRef.Unmapped.Spin)
270 {
271 case SpinDirection.Clockwise:
272 while (oldEulerAngles.z > localEulerAngles.z) localEulerAngles.z += 360;
273 break;
274 case SpinDirection.CounterClockwise:
275 while (oldEulerAngles.z < localEulerAngles.z) localEulerAngles.z -= 360;
276 break;
277 }*/
278 transform.localEulerAngles = localEulerAngles;
279
280 int zIndex = -1;
281 var spriteKey = key as SpriteTimelineKey;
282 if (spriteKey != null)
283 {
284 zIndex = ((ObjectRef)childRef).ZIndex;
285 //transform.GetComponent
286 }
287
288 acb.SetCurve(root.transform, transform, time, lastKey, zIndex);
289
290
291 //Get last-used game object for this Timeline - needed to clean up reparenting
292 GameObject lastGameObject;
293 if (lastGameObjectCache.TryGetValue(key.Timeline, out lastGameObject) && gameObject != lastGameObject)
294 {
295 //Let Unity handle the global->local position cruft for us
296 lastGameObject.transform.position = transform.position;
297 lastGameObject.transform.eulerAngles = transform.eulerAngles;
298
299 //TODO: Also need to do something about scale - this is a little more tricky
300 lastGameObject.transform.localScale = localScale;
301
302 //Deactivate the old object
303 lastGameObject.SetActive(false);
304
305 acb.SetCurve(root.transform, lastGameObject.transform, time, lastKey);
306 }
307
308 //Set cached value for last keyframe
309 lastKeyframeCache[key.Timeline] = key;
310 }
File name: AnimationBuilder.cs
Copy
312 private void BuildSpriteChangeCurve(ref AnimationClip clip, KeyValuePair313 {
314 // First you need to create Editor Curve Binding
315 EditorCurveBinding curveBinding = new EditorCurveBinding();
316
317 // I want to change the sprites of the sprite renderer, so I put the typeof(SpriteRenderer) as the binding type.
318 curveBinding.type = typeof(SpriteRenderer);
319
320 // Regular path to the GameObject that will be changed
321 curveBinding.path = timeline.Key;
322
323 // This is the property name to change the sprite of a sprite renderer
324 curveBinding.propertyName = "m_Sprite";
325
326 // An array to hold the object keyframes
327 ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[timeline.Value.Count];
328
329 int i = 0;
330 foreach (var key in timeline.Value)
331 {
332 keyFrames[i] = new ObjectReferenceKeyframe();
333 // set the time
334 keyFrames[i].time = key.Time;
335 // set reference for the sprite you want
336 keyFrames[i].value = key.Sprite;
337 i++;
338
339 }
340
341 AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames);
342 }
File name: AnimationCurveBuilder.cs
Copy
110 public void SetCurveActiveOnly(Transform root, Transform current, float time)
111 {
112 var path = AnimationUtility.CalculateTransformPath(current, root);
113 var obj = GetOrCreateAnimationCurves(path);
114
115 //IsActive curve
116 float val = (current.gameObject.activeInHierarchy) ? 1.0f : 0.0f;
117 obj.Curves[(int)AnimationCurveIndex.IsActive].AddKey(new Keyframe(time, val, float.PositiveInfinity, float.PositiveInfinity) { tangentMode = 0 });
118 }
File name: AnimationCurveBuilder.cs
Copy
128 private void UpdateTransformCurve(ObjectCurves obj, Transform current, float time, TimelineKey lastTimelineKey, int zIndex = -1)
129 {
130 float val;
131 //IsActive curve
132 val = (current.gameObject.activeSelf) ? 1.0f : 0.0f;
133 obj.Curves[(int)AnimationCurveIndex.IsActive].AddKey(new Keyframe(time, val, float.PositiveInfinity, float.PositiveInfinity) { tangentMode = 0 });
134
135 //Position curves
136 obj.Curves[(int)AnimationCurveIndex.LocalPositionX].AddKey(new Keyframe(time, current.localPosition.x) { tangentMode = 0 }, lastTimelineKey);
137 obj.Curves[(int)AnimationCurveIndex.LocalPositionY].AddKey(new Keyframe(time, current.localPosition.y) { tangentMode = 0 }, lastTimelineKey);
138 obj.Curves[(int)AnimationCurveIndex.LocalPositionZ].AddKey(new Keyframe(time, current.localPosition.z, float.PositiveInfinity, float.PositiveInfinity)); //Z value always has instant transition
139
140 //Rotation curves
141 var quat = Quaternion.Euler(current.localEulerAngles);
142 obj.Curves[(int)AnimationCurveIndex.LocalRotationX].AddKey(new Keyframe(time, quat.x) { tangentMode = 0 }, lastTimelineKey);
143 obj.Curves[(int)AnimationCurveIndex.LocalRotationY].AddKey(new Keyframe(time, quat.y) { tangentMode = 0 }, lastTimelineKey);
144 obj.Curves[(int)AnimationCurveIndex.LocalRotationZ].AddKey(new Keyframe(time, quat.z) { tangentMode = 0 }, lastTimelineKey);
145 obj.Curves[(int)AnimationCurveIndex.LocalRotationW].AddKey(new Keyframe(time, quat.w) { tangentMode = 0 }, lastTimelineKey);
146
147 //Scale curves
148 obj.Curves[(int)AnimationCurveIndex.LocalScaleX].AddKey(new Keyframe(time, current.localScale.x) { tangentMode = 0 }, lastTimelineKey);
149 obj.Curves[(int)AnimationCurveIndex.LocalScaleY].AddKey(new Keyframe(time, current.localScale.y) { tangentMode = 0 }, lastTimelineKey);
150 obj.Curves[(int)AnimationCurveIndex.LocalScaleZ].AddKey(new Keyframe(time, current.localScale.z) { tangentMode = 0 }, lastTimelineKey);
151
152 //Sprite Curves
153 var spriteTimelineKey = lastTimelineKey as SpriteTimelineKey;
154 if (spriteTimelineKey != null)
155 {
156 obj.IsSpriteKey = true;
157 obj.Curves[(int)AnimationCurveIndex.ColorR].AddKey(new Keyframe(time, spriteTimelineKey.Tint.r) { tangentMode = 0 }, lastTimelineKey);
158 obj.Curves[(int)AnimationCurveIndex.ColorG].AddKey(new Keyframe(time, spriteTimelineKey.Tint.g) { tangentMode = 0 }, lastTimelineKey);
159 obj.Curves[(int)AnimationCurveIndex.ColorB].AddKey(new Keyframe(time, spriteTimelineKey.Tint.b) { tangentMode = 0 }, lastTimelineKey);
160 obj.Curves[(int)AnimationCurveIndex.ColorA].AddKey(new Keyframe(time, spriteTimelineKey.Tint.a) { tangentMode = 0 }, lastTimelineKey);
161 obj.Curves[(int)AnimationCurveIndex.ZIndex].AddKey(new Keyframe(time, zIndex, float.PositiveInfinity, float.PositiveInfinity));
162 }
163 }
File name: AnimationCurveUtils.cs
Copy
36 public static void AddKey(this AnimationCurve curve, Keyframe keyframe, TimelineKey lastKey)
37 {
38 var keys = curve.keys;
39
40 //Early out - if this is the first key on this curve just add it
41 if (keys.Length == 0)
42 {
43 curve.AddKey(keyframe);
44 return;
45 }
46
47 if (lastKey == null)
48 {
49 Debug.Log(string.Format("ERROR: NULL lastkey passed to AddKey when curve contains {0} keys", keys.Length));
50 return;
51 }
52
53 //Get the last keyframe
54 Keyframe lastKeyframe = keys[keys.Length - 1];
55
56 //If no TimelineKey is supplied, default to Linear curve
57 CurveType curveType = lastKey.CurveType;
58
59 switch (curveType)
60 {
61 case CurveType.Instant:
62 lastKeyframe.outTangent = 0;
63 curve.MoveKey(keys.Length - 1, lastKeyframe);
64
65 keyframe.inTangent = float.PositiveInfinity;
66 curve.AddKey(keyframe);
67 break;
68
69 case CurveType.Linear:
70 var val = (keyframe.value - lastKeyframe.value) / (keyframe.time - lastKeyframe.time);
71 lastKeyframe.outTangent = val;
72 curve.MoveKey(keys.Length - 1, lastKeyframe);
73
74 keyframe.inTangent = val;
75 curve.AddKey(keyframe);
76 break;
77
78 case CurveType.Quadratic:
79 {
80 //Increase to cubic
81 var c1 = (2 * lastKey.CurveParams[0]) / 3;
82 var c2 = 1 - (2 * lastKey.CurveParams[0] + 1) / 3;
83
84 //Convert [0,1] into unity-acceptable tangents
85 c1 *= 3 * (keyframe.value - lastKeyframe.value) / (keyframe.time - lastKeyframe.time);
86 c2 *= 3 * (keyframe.value - lastKeyframe.value) / (keyframe.time - lastKeyframe.time);
87
88 //Set the out tangent for the previous frame and update
89 lastKeyframe.outTangent = c1;
90 curve.MoveKey(keys.Length - 1, lastKeyframe);
91
92 //Set the in tangent for the current frame and add
93 keyframe.inTangent = c2;
94 curve.AddKey(keyframe);
95 break;
96 }
97
98 case CurveType.Cubic:
99 {
100 //Get curve parameters
101 var c1 = lastKey.CurveParams[0];
102 var c2 = 1 - lastKey.CurveParams[1];
103
104 //Convert [0,1] into unity-acceptable tangents
105 c1 *= 3 * (keyframe.value - lastKeyframe.value) / (keyframe.time - lastKeyframe.time);
106 c2 *= 3 * (keyframe.value - lastKeyframe.value) / (keyframe.time - lastKeyframe.time);
107
108 //Set the out tangent for the previous frame and update
109 lastKeyframe.outTangent = c1;
110 curve.MoveKey(keys.Length - 1, lastKeyframe);
111
112 //Set the in tangent for the current frame and add
113 keyframe.inTangent = c2;
114 curve.AddKey(keyframe);
115 break;
116 }
117
118 default:
119 Debug.LogWarning("CurveType " + curveType.ToString() + " not yet supported!");
120 break;
121 }
122 }
File name: AnimationCurveUtils.cs
Copy
127 public static void AddLinearKey(this AnimationCurve curve, Keyframe keyframe)
128 {
129 var keys = curve.keys;
130 //Second or later keyframe - make the slopes linear
131 if (keys.Length > 0)
132 {
133 var lastFrame = keys[keys.Length - 1];
134 float slope = (keyframe.value - lastFrame.value) / (keyframe.time - lastFrame.time);
135 lastFrame.outTangent = keyframe.inTangent = slope;
136
137 //Update the last keyframe
138 curve.MoveKey(keys.Length - 1, lastFrame);
139 }
140
141 //Add the new frame
142 curve.AddKey(keyframe);
143 }
File name: AnimationCurveUtils.cs
Copy
145 public static void AddKeyIfChanged(this AnimationCurve curve, Keyframe keyframe)
146 {
147 var keys = curve.keys;
148 //If this is the first key on this curve, always add
149 //NOTE: Add TWO copies of the first frame, then we adjust the last frame as we move along
150 //This guarantees a minimum of two keys in each curve
151 if (keys.Length == 0 || !ENABLE_KEYFRAME_REDUCATION)
152 {
153 curve.AddKey(keyframe);
154 keyframe.time += float.Epsilon;
155 curve.AddKey(keyframe);
156 }
157 else
158 {
159 //TODO: This method of keyframe reduction causes artifacts in animations that are supposed to deliberately pause
160 //Find the last keyframe
161 Keyframe lastKey = keys[keys.Length - 1];
162 if (lastKey.time >= keyframe.time)
163 Debug.LogError("Keyframes not supplied in consecutive order!!!");
164
165 //Grab 2 frames ago
166 var last2Key = keys[keys.Length - 2];
167
168 //If the previous 2 frames were different, add a new frame
169 if (lastKey.value != last2Key.value)
170 {
171 curve.AddKey(keyframe);
172 }
173 //The previous frame is redundant - just move it
174 else
175 {
176 curve.MoveKey(keys.Length - 1, keyframe);
177 }
178 }
179 }
Keyframe 113 lượt xem
Gõ tìm kiếm nhanh...