/// <summary> /// Filters the animation to the specified sub-trees given by <see cref="roots"/>. /// </summary> /// <param name="nodes">The node hierarchy.</param> /// <param name="roots">The node roots of sub-trees that should be active (others will be filtered out).</param> public void FilterNodes(ModelNodeDefinition[] nodes, params string[] roots) { // Initialize list of factors (matching nodes list) var nodeFactors = new float[nodes.Length]; for (int index = 0; index < nodes.Length; index++) { var node = nodes[index]; if (roots.Contains(node.Name) || (node.ParentIndex != -1 && nodeFactors[node.ParentIndex] == 1.0f)) { nodeFactors[index] = 1.0f; } } //Make sure Evaluator is populated //TODO this is not optimal, but since evaluators are being pooled there is no other safe way if (Evaluator == null) { Evaluator = AnimationComponent.Blender.CreateEvaluator(Clip); } // Update animation channel factors var blenderChannels = Evaluator.BlenderChannels; var channels = Evaluator.Channels.Items; for (int index = 0; index < blenderChannels.Count; index++) { var blenderChannel = blenderChannels[index]; // Find node index var nodeName = MeshAnimationUpdater.GetNodeName(blenderChannel.PropertyName); var nodeIndex = nodes.IndexOf(x => x.Name == nodeName); if (nodeIndex != -1) { // Update factor channels[index].Factor *= nodeFactors[nodeIndex]; } } }
/// <summary> /// Creates a new animation pop operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <param name="time">The time.</param> /// <returns></returns> public static AnimationOperation NewPop(AnimationClipEvaluator evaluator, TimeSpan time) { return new AnimationOperation { Type = AnimationOperationType.Pop, Evaluator = evaluator, Time = time }; }
/// <summary> /// Creates a new animation push operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <returns></returns> public static AnimationOperation NewPush(AnimationClipEvaluator evaluator) { return new AnimationOperation { Type = AnimationOperationType.Push, Evaluator = evaluator, Time = TimeSpan.Zero }; }
public AnimationClipEvaluator CreateEvaluator(AnimationClip clip) { // Check if this clip has already been used if (clips.Add(clip)) { // If new clip, let's scan its channel to add new ones. foreach (var curve in clip.Channels) { Channel channel; if (channelsByName.TryGetValue(curve.Key, out channel)) { // TODO: Check if channel matches } else { // New channel, add it to every evaluator // Find blend type var blendType = BlendType.None; var elementType = curve.Value.ElementType; if (elementType == typeof(Quaternion)) { blendType = BlendType.Quaternion; } else if (elementType == typeof(float)) { blendType = BlendType.Float1; } else if (elementType == typeof(Vector2)) { blendType = BlendType.Float2; } else if (elementType == typeof(Vector3)) { blendType = BlendType.Float3; } else if (elementType == typeof(Vector4)) { blendType = BlendType.Float4; } // Create channel structure channel.BlendType = blendType; channel.Offset = structureSize; channel.PropertyName = curve.Key; // TODO: Remove this totally hardcoded property name parsing! channel.NodeName = curve.Value.NodeName; channel.Type = curve.Value.Type; channel.Size = curve.Value.ElementSize; // Add channel channelsByName.Add(channel.PropertyName, channel); channels.Add(channel); // Update new structure size // We also reserve space for a float that will specify channel existence and factor in case of subtree blending structureSize += sizeof(float) + channel.Size; // Add new channel update info to every evaluator // TODO: Maybe it's better lazily done? (avoid need to store list of all evaluators) foreach (var currentEvaluator in evaluators) { currentEvaluator.AddChannel(ref channel); } } } } // Update results to fit the new data size lock (availableResultsPool) { foreach (var result in availableResultsPool) { if (result.DataSize < structureSize) { result.DataSize = structureSize; result.Data = new byte[structureSize]; } } } // Create evaluator and store it in list of instantiated evaluators AnimationClipEvaluator evaluator; lock (evaluatorPool) { if (evaluatorPool.Count > 0) { evaluator = evaluatorPool.Pop(); } else { evaluator = new AnimationClipEvaluator(); } } evaluator.Initialize(clip, channels); evaluators.Add(evaluator); return(evaluator); }
public AnimationClipEvaluator CreateEvaluator(AnimationClip clip) { // Check if this clip has already been used if (clips.Add(clip)) { // If new clip, let's scan its channel to add new ones. foreach (var curve in clip.Channels) { Channel channel; if (channelsByName.TryGetValue(curve.Key, out channel)) { // TODO: Check if channel matches } else { // New channel, add it to every evaluator // Find blend type var blendType = BlendType.None; var elementType = curve.Value.ElementType; if (elementType == typeof(Quaternion)) { blendType = BlendType.Quaternion; } else if (elementType == typeof(float)) { blendType = BlendType.Float1; } else if (elementType == typeof(Vector2)) { blendType = BlendType.Float2; } else if (elementType == typeof(Vector3)) { blendType = BlendType.Float3; } else if (elementType == typeof(Vector4)) { blendType = BlendType.Float4; } // Create channel structure channel.BlendType = blendType; channel.Offset = structureSize; channel.PropertyName = curve.Key; // TODO: Remove this totally hardcoded property name parsing! channel.NodeName = curve.Value.NodeName; channel.Type = curve.Value.Type; channel.Size = curve.Value.ElementSize; // Add channel channelsByName.Add(channel.PropertyName, channel); channels.Add(channel); // Update new structure size // We also reserve space for a float that will specify channel existence and factor in case of subtree blending structureSize += sizeof(float) + channel.Size; // Add new channel update info to every evaluator // TODO: Maybe it's better lazily done? (avoid need to store list of all evaluators) foreach (var currentEvaluator in evaluators) { currentEvaluator.AddChannel(ref channel); } } } } // Update results to fit the new data size lock (availableResultsPool) { foreach (var result in availableResultsPool) { if (result.DataSize < structureSize) { result.DataSize = structureSize; result.Data = new byte[structureSize]; } } } // Create evaluator and store it in list of instantiated evaluators AnimationClipEvaluator evaluator; lock (evaluatorPool) { if (evaluatorPool.Count > 0) { evaluator = evaluatorPool.Pop(); } else { evaluator = new AnimationClipEvaluator(); } } evaluator.Initialize(clip, channels); evaluators.Add(evaluator); return evaluator; }
public void ReleaseEvaluator(AnimationClipEvaluator evaluator) { lock (evaluatorPool) { evaluators.Remove(evaluator); evaluator.Cleanup(); evaluatorPool.Push(evaluator); } }
/// <summary> /// Creates a new animation pop operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <param name="time">The time.</param> /// <returns></returns> public static AnimationOperation NewPop(AnimationClipEvaluator evaluator, TimeSpan time) { return(new AnimationOperation { Type = AnimationOperationType.Pop, Evaluator = evaluator, Time = time }); }
/// <summary> /// Creates a new animation push operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <returns></returns> public static AnimationOperation NewPush(AnimationClipEvaluator evaluator) { return(new AnimationOperation { Type = AnimationOperationType.Push, Evaluator = evaluator, Time = TimeSpan.Zero }); }