فهرست منبع

updated nugets
WIP with samplers

Vicente Penades 6 سال پیش
والد
کامیت
1037136560

+ 2 - 2
build/SharpGLTF.CodeGen/SharpGLTF.CodeGen.csproj

@@ -8,8 +8,8 @@
 
   <ItemGroup>
     <PackageReference Include="LibGit2Sharp" Version="0.26.0" />
-    <PackageReference Include="NJsonSchema.CodeGeneration" Version="9.13.37" />
-    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="9.13.37" />
+    <PackageReference Include="NJsonSchema.CodeGeneration" Version="9.14.1" />
+    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="9.14.1" />
   </ItemGroup>
 
 </Project>

+ 70 - 25
src/SharpGLTF.Core/Schema2/gltf.Animations.cs

@@ -76,7 +76,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(linear ? AnimationInterpolationMode.LINEAR : AnimationInterpolationMode.STEP);
 
-            sampler.SetVector3Keys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.scale)
                 .SetSampler(sampler);
@@ -86,7 +86,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(AnimationInterpolationMode.CUBICSPLINE);
 
-            sampler.SetVector3Keys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.scale)
                 .SetSampler(sampler);
@@ -96,7 +96,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(linear ? AnimationInterpolationMode.LINEAR : AnimationInterpolationMode.STEP);
 
-            sampler.SetQuaternionKeys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.rotation)
                 .SetSampler(sampler);
@@ -106,7 +106,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(AnimationInterpolationMode.CUBICSPLINE);
 
-            sampler.SetQuaternionKeys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.rotation)
                 .SetSampler(sampler);
@@ -116,7 +116,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(linear ? AnimationInterpolationMode.LINEAR : AnimationInterpolationMode.STEP);
 
-            sampler.SetVector3Keys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.translation)
                 .SetSampler(sampler);
@@ -126,7 +126,7 @@ namespace SharpGLTF.Schema2
         {
             var sampler = this._CreateSampler(AnimationInterpolationMode.CUBICSPLINE);
 
-            sampler.SetVector3Keys(keyframes);
+            sampler.SetKeys(keyframes);
 
             this._UseChannel(node, PropertyPath.translation)
                 .SetSampler(sampler);
@@ -137,9 +137,14 @@ namespace SharpGLTF.Schema2
             throw new NotImplementedException();
         }
 
+        private AnimationChannel FindChannel(Node node, PropertyPath path)
+        {
+            return _channels.FirstOrDefault(item => item.TargetNode == node && item.TargetNodePath == path);
+        }
+
         public IEnumerable<(Single, Vector3)> FindScaleChannel(Node node)
         {
-            var channel = _channels.FirstOrDefault(item => item.TargetNode == node && item.TargetNodePath == PropertyPath.scale);
+            var channel = FindChannel(node, PropertyPath.scale);
             if (channel == null) return null;
 
             return channel.Sampler.AsLinearVector3KeyFrames();
@@ -147,7 +152,7 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, Quaternion)> FindRotationChannel(Node node)
         {
-            var channel = _channels.FirstOrDefault(item => item.TargetNode == node && item.TargetNodePath == PropertyPath.rotation);
+            var channel = FindChannel(node, PropertyPath.rotation);
             if (channel == null) return null;
 
             return channel.Sampler.AsLinearQuaternionKeyFrames();
@@ -155,7 +160,7 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, Vector3)> FindTranslationChannel(Node node)
         {
-            var channel = _channels.FirstOrDefault(item => item.TargetNode == node && item.TargetNodePath == PropertyPath.translation);
+            var channel = FindChannel(node, PropertyPath.translation);
             if (channel == null) return null;
 
             return channel.Sampler.AsLinearVector3KeyFrames();
@@ -167,9 +172,33 @@ namespace SharpGLTF.Schema2
 
             var xform = node.LocalTransform;
 
-            var sfunc = this.FindScaleChannel(node).CreateLinearSamplerFunc();
-            var rfunc = this.FindRotationChannel(node).CreateLinearSamplerFunc();
-            var tfunc = this.FindTranslationChannel(node).CreateLinearSamplerFunc();
+            Func<float, Vector3> sfunc = null;
+            Func<float, Quaternion> rfunc = null;
+            Func<float, Vector3> tfunc = null;
+
+            var schannel = FindChannel(node, PropertyPath.scale);
+            if (schannel != null)
+            {
+                if (schannel.Sampler.InterpolationMode == AnimationInterpolationMode.STEP) sfunc = schannel.Sampler.AsLinearVector3KeyFrames().CreateStepSamplerFunc();
+                if (schannel.Sampler.InterpolationMode == AnimationInterpolationMode.LINEAR) sfunc = schannel.Sampler.AsLinearVector3KeyFrames().CreateLinearSamplerFunc();
+                if (schannel.Sampler.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE) sfunc = schannel.Sampler.AsCubicVector3KeyFrames().CreateCubicSamplerFunc();
+            }
+
+            var rchannel = FindChannel(node, PropertyPath.rotation);
+            if (rchannel != null)
+            {
+                if (rchannel.Sampler.InterpolationMode == AnimationInterpolationMode.STEP) rfunc = rchannel.Sampler.AsLinearQuaternionKeyFrames().CreateStepSamplerFunc();
+                if (rchannel.Sampler.InterpolationMode == AnimationInterpolationMode.LINEAR) rfunc = rchannel.Sampler.AsLinearQuaternionKeyFrames().CreateLinearSamplerFunc();
+                if (rchannel.Sampler.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE) rfunc = rchannel.Sampler.AsCubicQuaternionKeyFrames().CreateCubicSamplerFunc();
+            }
+
+            var tchannel = FindChannel(node, PropertyPath.translation);
+            if (tchannel != null)
+            {
+                if (tchannel.Sampler.InterpolationMode == AnimationInterpolationMode.STEP) tfunc = tchannel.Sampler.AsLinearVector3KeyFrames().CreateStepSamplerFunc();
+                if (tchannel.Sampler.InterpolationMode == AnimationInterpolationMode.LINEAR) tfunc = tchannel.Sampler.AsLinearVector3KeyFrames().CreateLinearSamplerFunc();
+                if (tchannel.Sampler.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE) tfunc = tchannel.Sampler.AsCubicVector3KeyFrames().CreateCubicSamplerFunc();
+            }
 
             if (sfunc != null) xform.Scale = sfunc(time);
             if (rfunc != null) xform.Rotation = rfunc(time);
@@ -185,12 +214,14 @@ namespace SharpGLTF.Schema2
 
             Guard.MustShareLogicalParent(this, node, nameof(node));
 
-            var channel = _channels.FirstOrDefault(item => item.TargetNode == node && item.TargetNodePath == PropertyPath.weights);
-            if (channel == null) return morphWeights;
+            var mchannel = FindChannel(node, PropertyPath.weights);
+            if (mchannel == null) return morphWeights;
+
+            Func<float, float[]> mfunc = null;
 
-            var mfunc = channel.Sampler
-                .AsLinearArrayKeyFrames(morphWeights.Count)
-                .CreateLinearSamplerFunc();
+            if (mchannel.Sampler.InterpolationMode == AnimationInterpolationMode.STEP) mfunc = mchannel.Sampler.AsLinearArrayKeyFrames().CreateStepSamplerFunc();
+            if (mchannel.Sampler.InterpolationMode == AnimationInterpolationMode.LINEAR) mfunc = mchannel.Sampler.AsLinearArrayKeyFrames().CreateLinearSamplerFunc();
+            if (mchannel.Sampler.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE) mfunc = mchannel.Sampler.AsCubicArrayKeyFrames().CreateCubicSamplerFunc();
 
             return mfunc(time);
         }
@@ -324,7 +355,7 @@ namespace SharpGLTF.Schema2
 
         public Accessor Output => this.LogicalParent.LogicalParent.LogicalAccessors[this._output];
 
-        public float Duration { get { var keys = Input.AsScalarArray(); return keys[keys.Count - 1]; } }
+        public float Duration { get { var keys = Input.AsScalarArray(); return keys.Count == 0 ? 0 : keys[keys.Count - 1]; } }
 
         #endregion
 
@@ -419,14 +450,14 @@ namespace SharpGLTF.Schema2
             return (keys, vals);
         }
 
-        public void SetVector3Keys(IReadOnlyDictionary<Single, Vector3> keyframes)
+        internal void SetKeys(IReadOnlyDictionary<Single, Vector3> keyframes)
         {
             var kv = _Split(keyframes);
             _input = this._CreateInputAccessor(kv.Item1).LogicalIndex;
             _output = this._CreateOutputAccessor(kv.Item2).LogicalIndex;
         }
 
-        public void SetVector3Keys(IReadOnlyDictionary<Single, (Vector3, Vector3, Vector3)> keyframes)
+        internal void SetKeys(IReadOnlyDictionary<Single, (Vector3, Vector3, Vector3)> keyframes)
         {
             var kv = _Split(keyframes);
 
@@ -437,14 +468,14 @@ namespace SharpGLTF.Schema2
             _output = this._CreateOutputAccessor(kv.Item2).LogicalIndex;
         }
 
-        public void SetQuaternionKeys(IReadOnlyDictionary<Single, Quaternion> keyframes)
+        internal void SetKeys(IReadOnlyDictionary<Single, Quaternion> keyframes)
         {
             var kv = _Split(keyframes);
             _input = this._CreateInputAccessor(kv.Item1).LogicalIndex;
             _output = this._CreateOutputAccessor(kv.Item2).LogicalIndex;
         }
 
-        public void SetQuaternionKeys(IReadOnlyDictionary<Single, (Quaternion, Quaternion, Quaternion)> keyframes)
+        internal void SetKeys(IReadOnlyDictionary<Single, (Quaternion, Quaternion, Quaternion)> keyframes)
         {
             var kv = _Split(keyframes);
 
@@ -457,7 +488,7 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, Vector3)> AsLinearVector3KeyFrames()
         {
-            if (this.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE) throw new ArgumentException();
+            Guard.IsFalse(this.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
 
             var keys = this.Input.AsScalarArray();
             var frames = this.Output.AsVector3Array();
@@ -467,14 +498,20 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, Quaternion)> AsLinearQuaternionKeyFrames()
         {
+            Guard.IsFalse(this.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
+
             var keys = this.Input.AsScalarArray();
             var frames = this.Output.AsQuaternionArray();
 
             return keys.Zip(frames, (key, val) => (key, val));
         }
 
-        public IEnumerable<(Single, Single[])> AsLinearArrayKeyFrames(int dimensions)
+        public IEnumerable<(Single, Single[])> AsLinearArrayKeyFrames()
         {
+            Guard.IsFalse(this.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
+
+            var dimensions = this.Output.Count / this.Input.Count;
+
             var keys = this.Input.AsScalarArray();
             var frames = this.Output.AsMultiArray(dimensions);
 
@@ -483,6 +520,8 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, (Vector3, Vector3, Vector3))> AsCubicVector3KeyFrames()
         {
+            Guard.IsFalse(this.InterpolationMode != AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
+
             var keys = this.Input.AsScalarArray();
             var frames = GroupThree(this.Output.AsVector3Array());
 
@@ -491,14 +530,20 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<(Single, (Quaternion, Quaternion, Quaternion))> AsCubicQuaternionKeyFrames()
         {
+            Guard.IsFalse(this.InterpolationMode != AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
+
             var keys = this.Input.AsScalarArray();
             var frames = GroupThree(this.Output.AsQuaternionArray());
 
             return keys.Zip(frames, (key, val) => (key, val));
         }
 
-        public IEnumerable<(Single, (Single[], Single[], Single[]))> AsCubicArrayKeyFrames(int dimensions)
+        public IEnumerable<(Single, (Single[], Single[], Single[]))> AsCubicArrayKeyFrames()
         {
+            Guard.IsFalse(this.InterpolationMode != AnimationInterpolationMode.CUBICSPLINE, nameof(InterpolationMode));
+
+            var dimensions = this.Output.Count / (this.Input.Count * 3);
+
             var keys = this.Input.AsScalarArray();
             var frames = GroupThree(this.Output.AsMultiArray(dimensions));
 

+ 1 - 1
src/SharpGLTF.Core/SharpGLTF.Core.csproj

@@ -41,7 +41,7 @@
   
   <ItemGroup>    
     <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
-    <PackageReference Include="System.Memory" Version="4.5.2" />
+    <PackageReference Include="System.Memory" Version="4.5.3" />
     <PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

+ 40 - 0
src/SharpGLTF.Core/Transforms/AnimationSamplerFactory.cs

@@ -47,6 +47,19 @@ namespace SharpGLTF.Transforms
             return (left.Value.Item2, right.Value.Item2, amount);
         }
 
+        internal static Func<float, T> CreateStepSamplerFunc<T>(this IEnumerable<(float, T)> collection)
+        {
+            if (collection == null) return null;
+
+            T _sampler(float offset)
+            {
+                var sample = collection._GetSample(offset);
+                return sample.Item1;
+            }
+
+            return _sampler;
+        }
+
         internal static Func<float, Vector3> CreateLinearSamplerFunc(this IEnumerable<(float, Vector3)> collection)
         {
             if (collection == null) return null;
@@ -103,6 +116,11 @@ namespace SharpGLTF.Transforms
             return CreateCubicSamplerFunc<Quaternion>(collection, Hermite);
         }
 
+        internal static Func<float, float[]> CreateCubicSamplerFunc(this IEnumerable<(float, (float[], float[], float[]))> collection)
+        {
+            return CreateCubicSamplerFunc<float[]>(collection, Hermite);
+        }
+
         internal static Func<float, T> CreateCubicSamplerFunc<T>(this IEnumerable<(float, (T, T, T))> collection, Func<T, T, T, T, float, T> hermiteFunc)
         {
             if (collection == null) return null;
@@ -146,5 +164,27 @@ namespace SharpGLTF.Transforms
 
             return Quaternion.Normalize((value1 * part1) + (value2 * part2) + (tangent1 * part3) + (tangent2 * part4));
         }
+
+        internal static float[] Hermite(float[] value1, float[] tangent1, float[] value2, float[] tangent2, float amount)
+        {
+            // http://mathworld.wolfram.com/HermitePolynomial.html
+
+            var squared = amount * amount;
+            var cubed = amount * squared;
+
+            var part1 = (2.0f * cubed) - (3.0f * squared) + 1.0f;
+            var part2 = (-2.0f * cubed) + (3.0f * squared);
+            var part3 = (cubed - (2.0f * squared)) + amount;
+            var part4 = cubed - squared;
+
+            var result = new float[value1.Length];
+
+            for (int i = 0; i < result.Length; ++i)
+            {
+                result[i] = (value1[i] * part1) + (value2[i] * part2) + (tangent1[i] * part3) + (tangent2[i] * part4);
+            }
+
+            return result;
+        }
     }
 }

+ 1 - 1
tests/SharpGLTF.Tests/SharpGLTF.Tests.csproj

@@ -11,7 +11,7 @@
   <ItemGroup>
     <PackageReference Include="LibGit2Sharp" Version="0.26.0" />
     <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0" />
-    <PackageReference Include="nunit" Version="3.11.0" />
+    <PackageReference Include="nunit" Version="3.12.0" />
     <PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />    
   </ItemGroup>