Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
AnimationAssetCompiler.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Threading.Tasks;
5 
6 using SiliconStudio.Assets.Compiler;
7 using SiliconStudio.BuildEngine;
8 using SiliconStudio.Core;
9 using SiliconStudio.Core.Collections;
10 using SiliconStudio.Core.IO;
11 using SiliconStudio.Core.Mathematics;
12 using SiliconStudio.Core.Serialization.Assets;
13 using SiliconStudio.Paradox.DataModel;
14 using SiliconStudio.Paradox.Engine;
15 
16 namespace SiliconStudio.Paradox.Assets.Model
17 {
18  public class AnimationAssetCompiler : AssetCompilerBase<AnimationAsset>
19  {
20  protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, AnimationAsset asset, AssetCompilerResult result)
21  {
22  // Get absolute path of asset source on disk
23  var assetDirectory = assetAbsolutePath.GetParent();
24  var assetSource = UPath.Combine(assetDirectory, asset.Source);
25  var extension = assetSource.GetFileExtension();
26  var buildStep = new ListBuildStep();
27 
28  var additiveAnimationAsset = asset as AdditiveAnimationAsset;
29  if (additiveAnimationAsset != null)
30  {
31  var baseUrlInStorage = urlInStorage + "_animation_base";
32  var sourceUrlInStorage = urlInStorage + "_animation_source";
33 
34  var baseAssetSource = UPath.Combine(assetDirectory, additiveAnimationAsset.BaseSource);
35 
36  // Import base and main animation
38  {
39  buildStep.Add(new ImportFbxCommand { SourcePath = assetSource, Location = sourceUrlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
40  buildStep.Add(new ImportFbxCommand { SourcePath = baseAssetSource, Location = baseUrlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
41  }
42  else if (ImportAssimpCommand.IsSupportingExtensions(extension))
43  {
44  buildStep.Add(new ImportAssimpCommand { SourcePath = assetSource, Location = sourceUrlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
45  buildStep.Add(new ImportAssimpCommand { SourcePath = baseAssetSource, Location = baseUrlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
46  }
47  // Wait for both import fbx commands to be completed
48  buildStep.Add(new WaitBuildStep());
49 
50  // Generate the diff of those two animations
51  buildStep.Add(new AdditiveAnimationCommand(urlInStorage, new AdditiveAnimationParameters(baseUrlInStorage, sourceUrlInStorage, additiveAnimationAsset.Mode)));
52  }
53  else
54  {
55  // Import the main animation
57  buildStep.Add(new ImportFbxCommand { SourcePath = assetSource, Location = urlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
58  else if (ImportAssimpCommand.IsSupportingExtensions(extension))
59  buildStep.Add(new ImportAssimpCommand { SourcePath = assetSource, Location = urlInStorage, ExportType = "animation", AnimationRepeatMode = asset.RepeatMode });
60  }
61 
62  result.BuildSteps = buildStep;
63  }
64 
65  internal class AdditiveAnimationCommand : AssetCommand<AdditiveAnimationParameters>
66  {
67  public AdditiveAnimationCommand(string url, AdditiveAnimationParameters asset) : base(url, asset)
68  {
69  }
70 
71  protected override Task<ResultStatus> DoCommandOverride(ICommandContext commandContext)
72  {
73  var assetManager = new AssetManager();
74 
75  // Load source and base animations
76  var baseAnimation = assetManager.Load<AnimationClip>(asset.BaseUrl);
77  var sourceAnimation = assetManager.Load<AnimationClip>(asset.SourceUrl);
78 
79  // Generate diff animation
80  var animation = SubtractAnimations(baseAnimation, sourceAnimation);
81 
82  // Save diff animation
83  assetManager.Save(Url, animation);
84 
85  return Task.FromResult(ResultStatus.Successful);
86  }
87 
88  private AnimationClip SubtractAnimations(AnimationClip baseAnimation, AnimationClip sourceAnimation)
89  {
90  if (baseAnimation == null) throw new ArgumentNullException("baseAnimation");
91  if (sourceAnimation == null) throw new ArgumentNullException("sourceAnimation");
92 
93  var animationBlender = new AnimationBlender();
94 
95  var baseEvaluator = animationBlender.CreateEvaluator(baseAnimation);
96  var sourceEvaluator = animationBlender.CreateEvaluator(sourceAnimation);
97 
98  // Create a result animation with same channels
99  var resultAnimation = new AnimationClip();
100  foreach (var channel in sourceAnimation.Channels)
101  {
102  // Create new instance of curve
103  var newCurve = (AnimationCurve)Activator.CreateInstance(typeof(AnimationCurve<>).MakeGenericType(channel.Value.ElementType));
104 
105  // Quaternion curve are linear, others are cubic
106  if (newCurve.ElementType != typeof(Quaternion))
107  newCurve.InterpolationType = AnimationCurveInterpolationType.Cubic;
108 
109  resultAnimation.AddCurve(channel.Key, newCurve);
110  }
111 
112  var resultEvaluator = animationBlender.CreateEvaluator(resultAnimation);
113 
114  var animationOperations = new FastList<AnimationOperation>();
115 
116  // Perform animation blending for each frame and upload results in a new animation
117  // Note that it does a simple per-frame sampling, so animation discontinuities will be lost.
118  // TODO: Framerate is hardcoded at 30 FPS.
119  var frameTime = TimeSpan.FromSeconds(1.0f / 30.0f);
120  for (var time = TimeSpan.Zero; time < sourceAnimation.Duration + frameTime; time += frameTime)
121  {
122  // Last frame, round it to end of animation
123  if (time > sourceAnimation.Duration)
124  time = sourceAnimation.Duration;
125 
126  TimeSpan baseTime;
127  switch (asset.Mode)
128  {
129  case AdditiveAnimationBaseMode.FirstFrame:
130  baseTime = TimeSpan.Zero;
131  break;
132  case AdditiveAnimationBaseMode.Animation:
133  baseTime = TimeSpan.FromTicks(time.Ticks % baseAnimation.Duration.Ticks);
134  break;
135  default:
136  throw new ArgumentOutOfRangeException();
137  }
138 
139  // Generates result = source - base
140  animationOperations.Clear();
141  animationOperations.Add(AnimationOperation.NewPush(sourceEvaluator, time));
142  animationOperations.Add(AnimationOperation.NewPush(baseEvaluator, baseTime));
143  animationOperations.Add(AnimationOperation.NewBlend(AnimationBlendOperation.Subtract, 1.0f));
144  animationOperations.Add(AnimationOperation.NewPop(resultEvaluator, time));
145 
146  // Compute
147  AnimationClipResult animationClipResult = null;
148  animationBlender.Compute(animationOperations, ref animationClipResult);
149  }
150 
151  resultAnimation.Duration = sourceAnimation.Duration;
152  resultAnimation.RepeatMode = sourceAnimation.RepeatMode;
153 
154  return resultAnimation;
155  }
156  }
157 
158  [DataContract]
160  {
161  public string BaseUrl;
162  public string SourceUrl;
164  public int BaseStartFrame;
165 
167  {
168  }
169 
170  public AdditiveAnimationParameters(string baseUrl, string sourceUrl, AdditiveAnimationBaseMode mode)
171  {
172  BaseUrl = baseUrl;
173  SourceUrl = sourceUrl;
174  Mode = mode;
175  }
176  }
177  }
178 }
TimeSpan Duration
Gets or sets the duration of this clip.
Dictionary< string, Channel > Channels
Gets the channels of this clip.
Result of a compilation of assets when using IAssetCompiler.Compile
A command processing an Asset.
Definition: AssetCommand.cs:11
AdditiveAnimationParameters(string baseUrl, string sourceUrl, AdditiveAnimationBaseMode mode)
The context used when compiling an asset in a Package.
When embedded in a EnumerableBuildStep, this build step will force all previous computations to be fi...
An aggregation of AnimationCurve with their channel names.
AnimationRepeatMode
Enumeration describing how an animation should be repeated.
override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, AnimationAsset asset, AssetCompilerResult result)
Represents a four dimensional mathematical quaternion.
Definition: Quaternion.cs:45
Untyped base class for animation curves.
Performs animation blending. For now, all AnimationClip must target the same skeleton.
static bool IsSupportingExtensions(string ext)
Defines a normalized file path. See UPath for details. This class cannot be inherited.
Definition: UFile.cs:13