public static unsafe void Blend(CoreAnimationOperation blendOperation, float blendFactor, AnimationClipResult sourceLeft, AnimationClipResult sourceRight, AnimationClipResult result) { fixed(byte *sourceLeftDataStart = sourceLeft.Data) fixed(byte *sourceRightDataStart = sourceRight.Data) fixed(byte *resultDataStart = result.Data) { foreach (var channel in sourceLeft.Channels) { int offset = channel.Offset; var sourceLeftData = (float *)(sourceLeftDataStart + offset); var sourceRightData = (float *)(sourceRightDataStart + offset); var resultData = (float *)(resultDataStart + offset); float factorLeft = *sourceLeftData++; float factorRight = *sourceRightData++; // Ignore this channel if (factorLeft == 0.0f && factorRight == 0.0f) { *resultData++ = 0.0f; continue; } // Use left value if (factorLeft > 0.0f && factorRight == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); continue; } // Use right value if (factorRight > 0.0f && factorLeft == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceRightData, channel.Size); continue; } // Blending *resultData++ = 1.0f; switch (blendOperation) { case CoreAnimationOperation.Blend: // Perform linear blending // It will blend between left (0.0) and right (1.0) switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)(blendFactor < 0.5f ? sourceLeftData : sourceRightData), channel.Size); break; case BlendType.Float1: *resultData = MathUtil.Lerp(*sourceLeftData, *sourceRightData, blendFactor); break; case BlendType.Float2: Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref *(Quaternion *)sourceRightData, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case CoreAnimationOperation.Add: // Perform additive blending // It will blend between left (0.0) and left + right (1.0). switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Add(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Add(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; Quaternion.Multiply(ref *(Quaternion *)sourceLeftData, ref *(Quaternion *)sourceRightData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case CoreAnimationOperation.Subtract: // Perform subtractive blending // It will blend between left (0.0) and left - right (1.0). switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Subtract(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Subtract(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; // blend between left (0.0) and left * conjugate(right) (1.0) Quaternion.Invert(ref *(Quaternion *)sourceRightData, out rightValueQ); Quaternion.Multiply(ref rightValueQ, ref *(Quaternion *)sourceLeftData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); //throw new NotImplementedException(); Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; default: throw new ArgumentOutOfRangeException("blendOperation"); } } } }
/// <summary> /// Creates a new animation blend operation. /// </summary> /// <param name="operation">The blend operation.</param> /// <param name="blendFactor">The blend factor.</param> /// <returns></returns> public static AnimationOperation NewBlend(CoreAnimationOperation operation, float blendFactor) { return(new AnimationOperation { Type = AnimationOperationType.Blend, CoreBlendOperation = operation, BlendFactor = blendFactor }); }
public static unsafe void Blend(CoreAnimationOperation blendOperation, float blendFactor, AnimationClipResult sourceLeft, AnimationClipResult sourceRight, AnimationClipResult result) { fixed (byte* sourceLeftDataStart = sourceLeft.Data) fixed (byte* sourceRightDataStart = sourceRight.Data) fixed (byte* resultDataStart = result.Data) { foreach (var channel in sourceLeft.Channels) { int offset = channel.Offset; var sourceLeftData = (float*)(sourceLeftDataStart + offset); var sourceRightData = (float*)(sourceRightDataStart + offset); var resultData = (float*)(resultDataStart + offset); float factorLeft = *sourceLeftData++; float factorRight = *sourceRightData++; // Ignore this channel if (factorLeft == 0.0f && factorRight == 0.0f) { *resultData++ = 0.0f; continue; } // Use left value if (factorLeft > 0.0f && factorRight == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); continue; } // Use right value if (factorRight > 0.0f && factorLeft == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceRightData, channel.Size); continue; } // Blending *resultData++ = 1.0f; switch (blendOperation) { case CoreAnimationOperation.Blend: // Perform linear blending // It will blend between left (0.0) and right (1.0) switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)(blendFactor < 0.5f ? sourceLeftData : sourceRightData), channel.Size); break; case BlendType.Float2: Vector2.Lerp(ref *(Vector2*)sourceLeftData, ref *(Vector2*)sourceRightData, blendFactor, out *(Vector2*)resultData); break; case BlendType.Float3: Vector3.Lerp(ref *(Vector3*)sourceLeftData, ref *(Vector3*)sourceRightData, blendFactor, out *(Vector3*)resultData); break; case BlendType.Quaternion: Quaternion.Slerp(ref *(Quaternion*)sourceLeftData, ref *(Quaternion*)sourceRightData, blendFactor, out *(Quaternion*)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case CoreAnimationOperation.Add: // Perform additive blending // It will blend between left (0.0) and left + right (1.0). switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Add(ref *(Vector2*)sourceLeftData, ref *(Vector2*)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2*)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2*)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Add(ref *(Vector3*)sourceLeftData, ref *(Vector3*)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3*)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3*)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; Quaternion.Multiply(ref *(Quaternion*)sourceLeftData, ref *(Quaternion*)sourceRightData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); Quaternion.Slerp(ref *(Quaternion*)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion*)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case CoreAnimationOperation.Subtract: // Perform subtractive blending // It will blend between left (0.0) and left - right (1.0). switch (channel.BlendType) { case BlendType.Blit: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Subtract(ref *(Vector2*)sourceLeftData, ref *(Vector2*)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2*)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2*)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Subtract(ref *(Vector3*)sourceLeftData, ref *(Vector3*)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3*)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3*)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; // blend between left (0.0) and left * conjugate(right) (1.0) Quaternion.Invert(ref *(Quaternion*)sourceRightData, out rightValueQ); Quaternion.Multiply(ref rightValueQ, ref *(Quaternion*)sourceLeftData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); //throw new NotImplementedException(); Quaternion.Slerp(ref *(Quaternion*)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion*)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; default: throw new ArgumentOutOfRangeException("blendOperation"); } } } }
/// <summary> /// Creates a new animation blend operation. /// </summary> /// <param name="operation">The blend operation.</param> /// <param name="blendFactor">The blend factor.</param> /// <returns></returns> public static AnimationOperation NewBlend(CoreAnimationOperation operation, float blendFactor) { return new AnimationOperation { Type = AnimationOperationType.Blend, CoreBlendOperation = operation, BlendFactor = blendFactor }; }