Explorar el Código

fixed issue with vertex types not copying properties.

Vicente Penades hace 6 años
padre
commit
20ac3471bf

+ 1 - 1
src/SharpGLTF.Core/Transforms/MeshTransforms.cs

@@ -71,7 +71,7 @@ namespace SharpGLTF.Transforms
         {
         {
             _AbsoluteMorphTargets = useAbsoluteMorphTargets;
             _AbsoluteMorphTargets = useAbsoluteMorphTargets;
 
 
-            if (morphWeights.IsZero)
+            if (morphWeights.IsWeightless)
             {
             {
                 _Weights = new SparseWeight8((0, 1));
                 _Weights = new SparseWeight8((0, 1));
                 return;
                 return;

+ 64 - 30
src/SharpGLTF.Core/Transforms/SparseWeight8.cs

@@ -10,7 +10,7 @@ namespace SharpGLTF.Transforms
     /// Represents a sparse collection of non zero weight values, with a maximum of 8 weights.
     /// Represents a sparse collection of non zero weight values, with a maximum of 8 weights.
     /// </summary>
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("[{Index0}]={Weight0}  [{Index1}]={Weight1}  [{Index2}]={Weight2}  [{Index3}]={Weight3}  [{Index4}]={Weight4}  [{Index5}]={Weight5}  [{Index6}]={Weight6}  [{Index7}]={Weight7}")]
     [System.Diagnostics.DebuggerDisplay("[{Index0}]={Weight0}  [{Index1}]={Weight1}  [{Index2}]={Weight2}  [{Index3}]={Weight3}  [{Index4}]={Weight4}  [{Index5}]={Weight5}  [{Index6}]={Weight6}  [{Index7}]={Weight7}")]
-    public struct SparseWeight8 : IReadOnlyList<float>, IReadOnlyDictionary<int, float>
+    public struct SparseWeight8 : IReadOnlyList<float>
     {
     {
         #region lifecycle
         #region lifecycle
 
 
@@ -36,6 +36,7 @@ namespace SharpGLTF.Transforms
         public SparseWeight8(params (int, float)[] items)
         public SparseWeight8(params (int, float)[] items)
         {
         {
             Guard.NotNull(items, nameof(items));
             Guard.NotNull(items, nameof(items));
+            Guard.MustBeLessThanOrEqualTo(items.Length, 8, nameof(items));
 
 
             this.Index0 = items.Length > 0 ? items[0].Item1 : 0;
             this.Index0 = items.Length > 0 ? items[0].Item1 : 0;
             this.Index1 = items.Length > 1 ? items[1].Item1 : 0;
             this.Index1 = items.Length > 1 ? items[1].Item1 : 0;
@@ -58,7 +59,8 @@ namespace SharpGLTF.Transforms
 
 
         private SparseWeight8(ReadOnlySpan<int> indices, ReadOnlySpan<float> weights)
         private SparseWeight8(ReadOnlySpan<int> indices, ReadOnlySpan<float> weights)
         {
         {
-            System.Diagnostics.Debug.Assert(indices.Length == weights.Length);
+            System.Diagnostics.Debug.Assert(indices.Length <= 8, nameof(indices));
+            System.Diagnostics.Debug.Assert(indices.Length == weights.Length, nameof(weights));
 
 
             this.Index0 = indices.Length > 0 ? indices[0] : 0;
             this.Index0 = indices.Length > 0 ? indices[0] : 0;
             this.Index1 = indices.Length > 1 ? indices[1] : 0;
             this.Index1 = indices.Length > 1 ? indices[1] : 0;
@@ -146,17 +148,44 @@ namespace SharpGLTF.Transforms
 
 
         public float this[int index] => GetExpandedAt(index);
         public float this[int index] => GetExpandedAt(index);
 
 
+        /// <summary>
+        /// Gets a value indicating whether all the weights in this <see cref="SparseWeight8"/> are zero.
+        /// </summary>
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        public bool IsZero => Weight0 == 0 & Weight1 == 0 & Weight2 == 0 & Weight3 == 0 & Weight4 == 0 & Weight5 == 0 & Weight6 == 0 & Weight7 == 0;
-
-        public IEnumerable<int> Keys => GetPairs().Select(item => item.Item1);
-
-        public IEnumerable<float> Values => GetPairs().Select(item => item.Item2);
+        public bool IsWeightless => Weight0 == 0 & Weight1 == 0 & Weight2 == 0 & Weight3 == 0 & Weight4 == 0 & Weight5 == 0 & Weight6 == 0 & Weight7 == 0;
 
 
         #endregion
         #endregion
 
 
         #region API
         #region API
 
 
+        public static SparseWeight8 OrderedByWeight(in SparseWeight8 sparse)
+        {
+            Span<int> indices = stackalloc int[8];
+            Span<float> weights = stackalloc float[8];
+
+            var c = CopyTo(sparse, indices, weights, 0);
+            BubbleSortByWeight(indices, weights, c);
+
+            indices = indices.Slice(0, c);
+            weights = weights.Slice(0, c);
+
+            return new SparseWeight8(indices, weights);
+        }
+
+        public static SparseWeight8 OrderedByIndex(in SparseWeight8 sparse)
+        {
+            Span<int> indices = stackalloc int[8];
+            Span<float> weights = stackalloc float[8];
+
+            var c = CopyTo(sparse, indices, weights, 0);
+            BubbleSortByIndex(indices, weights, c);
+
+            indices = indices.Slice(0, c);
+            weights = weights.Slice(0, c);
+
+            return new SparseWeight8(indices, weights);
+        }
+
         public static SparseWeight8 Add(in SparseWeight8 x, in SparseWeight8 y)
         public static SparseWeight8 Add(in SparseWeight8 x, in SparseWeight8 y)
         {
         {
             return _OperateLinear(x, y, (xx, yy) => xx + yy);
             return _OperateLinear(x, y, (xx, yy) => xx + yy);
@@ -177,7 +206,7 @@ namespace SharpGLTF.Transforms
             return _OperateLinear(x, y, (xx, yy) => xx / yy);
             return _OperateLinear(x, y, (xx, yy) => xx / yy);
         }
         }
 
 
-        public static SparseWeight8 InterpolateLinear(SparseWeight8 x, SparseWeight8 y, float amount)
+        public static SparseWeight8 InterpolateLinear(in SparseWeight8 x, in SparseWeight8 y, float amount)
         {
         {
             var xAmount = 1.0f - amount;
             var xAmount = 1.0f - amount;
             var yAmount = amount;
             var yAmount = amount;
@@ -185,7 +214,7 @@ namespace SharpGLTF.Transforms
             return _OperateLinear(x, y, (xx, yy) => (xx * xAmount) + (yy * yAmount));
             return _OperateLinear(x, y, (xx, yy) => (xx * xAmount) + (yy * yAmount));
         }
         }
 
 
-        public static SparseWeight8 InterpolateCubic(SparseWeight8 x, SparseWeight8 xt, SparseWeight8 y, SparseWeight8 yt, float amount)
+        public static SparseWeight8 InterpolateCubic(in SparseWeight8 x, in SparseWeight8 xt, in SparseWeight8 y, in SparseWeight8 yt, float amount)
         {
         {
             var basis = Animations.SamplerFactory.CreateHermitePointWeights(amount);
             var basis = Animations.SamplerFactory.CreateHermitePointWeights(amount);
 
 
@@ -223,11 +252,6 @@ namespace SharpGLTF.Transforms
             return false;
             return false;
         }
         }
 
 
-        IEnumerator<KeyValuePair<int, float>> IEnumerable<KeyValuePair<int, float>>.GetEnumerator()
-        {
-            return GetPairs().Select(item => new KeyValuePair<int, float>(item.Item1, item.Item2)).GetEnumerator();
-        }
-
         public override string ToString()
         public override string ToString()
         {
         {
             var sb = new StringBuilder();
             var sb = new StringBuilder();
@@ -247,31 +271,41 @@ namespace SharpGLTF.Transforms
 
 
         #region code
         #region code
 
 
-        private static int CopyTo(SparseWeight8 p, Span<int> indices, Span<float> weights, int offset)
+        /// <summary>
+        /// Copies the current index-weight pairs to available slots in destination <paramref name="dstIndices"/> and <paramref name="dstWeights"/>
+        /// </summary>
+        /// <param name="src">The source <see cref="SparseWeight8"/>.</param>
+        /// <param name="dstIndices">The destination index array.</param>
+        /// <param name="dstWeights">The destination weight array.</param>
+        /// <param name="dstLength">The explicit length of both <paramref name="dstIndices"/> and <paramref name="dstWeights"/></param>
+        /// <returns>The new length of the destination arrays.</returns>
+        private static int CopyTo(SparseWeight8 src, Span<int> dstIndices, Span<float> dstWeights, int dstLength)
         {
         {
-            System.Diagnostics.Debug.Assert(indices.Length == weights.Length);
+            System.Diagnostics.Debug.Assert(dstIndices.Length == dstWeights.Length);
+            System.Diagnostics.Debug.Assert(dstIndices.Length >= dstLength, $"{nameof(dstIndices)}.Length must be at least {nameof(dstLength)}");
+            System.Diagnostics.Debug.Assert(dstWeights.Length >= dstLength, $"{nameof(dstWeights)}.Length must be at least {nameof(dstLength)}");
 
 
             for (int i = 0; i < 8; ++i)
             for (int i = 0; i < 8; ++i)
             {
             {
-                var pair = p.GetPair(i);
+                var pair = src.GetPair(i);
                 if (pair.Item2 == 0) continue;
                 if (pair.Item2 == 0) continue;
-                var idx = indices
-                    .Slice(0, offset)
+                var idx = dstIndices
+                    .Slice(0, dstLength)
                     .IndexOf(pair.Item1);
                     .IndexOf(pair.Item1);
 
 
                 if (idx < 0)
                 if (idx < 0)
                 {
                 {
-                    indices[offset] = pair.Item1;
-                    weights[offset] = pair.Item2;
-                    ++offset;
+                    dstIndices[dstLength] = pair.Item1;
+                    dstWeights[dstLength] = pair.Item2;
+                    ++dstLength;
                 }
                 }
                 else
                 else
                 {
                 {
-                    weights[idx] = pair.Item2; // should perform ADD (in case there's more than one element?)
+                    dstWeights[idx] = pair.Item2; // should perform ADD (in case there's more than one element?)
                 }
                 }
             }
             }
 
 
-            return offset;
+            return dstLength;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -298,7 +332,7 @@ namespace SharpGLTF.Transforms
             {
             {
                 xxx[i] = operationFunc(xxx[i], yyy[i]);
                 xxx[i] = operationFunc(xxx[i], yyy[i]);
             }
             }
-            
+
             // sort results by relevance, so they can fit
             // sort results by relevance, so they can fit
             // in a new structure in case there's more than
             // in a new structure in case there's more than
             // 8 results
             // 8 results
@@ -330,11 +364,11 @@ namespace SharpGLTF.Transforms
             )
             )
         {
         {
             // prepare buffers in the stack
             // prepare buffers in the stack
-            Span<int> indices = stackalloc int[16];
-            Span<float> xxx = stackalloc float[16];
-            Span<float> yyy = stackalloc float[16];
-            Span<float> zzz = stackalloc float[16];
-            Span<float> www = stackalloc float[16];
+            Span<int> indices = stackalloc int[32];
+            Span<float> xxx = stackalloc float[32];
+            Span<float> yyy = stackalloc float[32];
+            Span<float> zzz = stackalloc float[32];
+            Span<float> www = stackalloc float[32];
 
 
             // fill the buffers so all the elements are aligned by column
             // fill the buffers so all the elements are aligned by column
             int offset = 0;
             int offset = 0;

+ 12 - 9
src/SharpGLTF.Toolkit/Geometry/PrimitiveBuilder.cs

@@ -201,9 +201,9 @@ namespace SharpGLTF.Geometry
         {
         {
             Guard.NotNull(a, nameof(a));
             Guard.NotNull(a, nameof(a));
 
 
-            var expectedType = typeof(VertexBuilder<TvG, TvM, TvS>);
+            var aa = a.ConvertTo<TvG, TvM, TvS>();
 
 
-            var aa = a.GetType() != expectedType ? a.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)a;
+            System.Diagnostics.Debug.Assert(aa.Position == a.GetGeometry().GetPosition());
 
 
             return AddPoint(aa);
             return AddPoint(aa);
         }
         }
@@ -231,10 +231,11 @@ namespace SharpGLTF.Geometry
             Guard.NotNull(a, nameof(a));
             Guard.NotNull(a, nameof(a));
             Guard.NotNull(b, nameof(b));
             Guard.NotNull(b, nameof(b));
 
 
-            var expectedType = typeof(VertexBuilder<TvG, TvM, TvS>);
+            var aa = a.ConvertTo<TvG, TvM, TvS>();
+            var bb = b.ConvertTo<TvG, TvM, TvS>();
 
 
-            var aa = a.GetType() != expectedType ? a.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)a;
-            var bb = b.GetType() != expectedType ? b.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)b;
+            System.Diagnostics.Debug.Assert(aa.Position == a.GetGeometry().GetPosition());
+            System.Diagnostics.Debug.Assert(bb.Position == b.GetGeometry().GetPosition());
 
 
             return AddLine(aa, bb);
             return AddLine(aa, bb);
         }
         }
@@ -282,11 +283,13 @@ namespace SharpGLTF.Geometry
             Guard.NotNull(b, nameof(b));
             Guard.NotNull(b, nameof(b));
             Guard.NotNull(c, nameof(c));
             Guard.NotNull(c, nameof(c));
 
 
-            var expectedType = typeof(VertexBuilder<TvG, TvM, TvS>);
+            var aa = a.ConvertTo<TvG, TvM, TvS>();
+            var bb = b.ConvertTo<TvG, TvM, TvS>();
+            var cc = c.ConvertTo<TvG, TvM, TvS>();
 
 
-            var aa = a.GetType() != expectedType ? a.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)a;
-            var bb = b.GetType() != expectedType ? b.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)b;
-            var cc = c.GetType() != expectedType ? c.ConvertTo<TvG, TvM, TvS>() : (VertexBuilder<TvG, TvM, TvS>)c;
+            System.Diagnostics.Debug.Assert(aa.Position == a.GetGeometry().GetPosition());
+            System.Diagnostics.Debug.Assert(bb.Position == b.GetGeometry().GetPosition());
+            System.Diagnostics.Debug.Assert(cc.Position == c.GetGeometry().GetPosition());
 
 
             return AddTriangle(aa, bb, cc);
             return AddTriangle(aa, bb, cc);
         }
         }

+ 28 - 19
src/SharpGLTF.Toolkit/Geometry/VertexBufferColumns.cs

@@ -231,29 +231,42 @@ namespace SharpGLTF.Geometry
 
 
             return mt;
             return mt;
         }
         }
-        
+
         #endregion
         #endregion
 
 
         #region API - Vertex indexing
         #region API - Vertex indexing
 
 
-        private void CopyTo(int index, IVertexGeometry v)
+        private TvG GetVertexGeometry<TvG>(int index)
+            where TvG : struct, IVertexGeometry
         {
         {
+            var v = default(TvG);
+
             if (Positions != null) v.SetPosition(Positions[index]);
             if (Positions != null) v.SetPosition(Positions[index]);
             if (Normals != null) v.SetNormal(Normals[index]);
             if (Normals != null) v.SetNormal(Normals[index]);
             if (Tangents != null) v.SetTangent(Tangents[index]);
             if (Tangents != null) v.SetTangent(Tangents[index]);
+
+            return v;
         }
         }
 
 
-        private void CopyTo(int index, IVertexMaterial v)
+        private TvM GetVertexMaterial<TvM>(int index)
+            where TvM : struct, IVertexMaterial
         {
         {
+            var v = default(TvM);
+
             if (Colors0 != null && v.MaxColors > 0) v.SetColor(0, Colors0[index]);
             if (Colors0 != null && v.MaxColors > 0) v.SetColor(0, Colors0[index]);
             if (Colors1 != null && v.MaxColors > 1) v.SetColor(1, Colors1[index]);
             if (Colors1 != null && v.MaxColors > 1) v.SetColor(1, Colors1[index]);
 
 
             if (TexCoords0 != null && v.MaxTextCoords > 0) v.SetTexCoord(0, TexCoords0[index]);
             if (TexCoords0 != null && v.MaxTextCoords > 0) v.SetTexCoord(0, TexCoords0[index]);
             if (TexCoords1 != null && v.MaxTextCoords > 1) v.SetTexCoord(1, TexCoords1[index]);
             if (TexCoords1 != null && v.MaxTextCoords > 1) v.SetTexCoord(1, TexCoords1[index]);
+
+            return v;
         }
         }
 
 
-        private void CopyTo(int index, IVertexSkinning v)
+        private TvS GetVertexSkinning<TvS>(int index)
+            where TvS : struct, IVertexSkinning
         {
         {
+            IVertexSkinning v = default(VertexTypes.VertexJoints16x8);
+
             if (Joints0 != null && Weights0 != null)
             if (Joints0 != null && Weights0 != null)
             {
             {
                 var j = Joints0[index];
                 var j = Joints0[index];
@@ -275,24 +288,20 @@ namespace SharpGLTF.Geometry
                 v.SetJointBinding(6, (int)j.Z, w.Z);
                 v.SetJointBinding(6, (int)j.Z, w.Z);
                 v.SetJointBinding(7, (int)j.W, w.W);
                 v.SetJointBinding(7, (int)j.W, w.W);
             }
             }
+
+            return VertexUtils.ConvertToSkinning<TvS>(v);
         }
         }
 
 
         public IVertexBuilder GetVertex(Type vertexType, int index)
         public IVertexBuilder GetVertex(Type vertexType, int index)
         {
         {
-            var v = (IVertexBuilder)Activator.CreateInstance(vertexType);
+            var g = GetVertexGeometry<VertexPositionNormalTangent>(index);
+            var m = GetVertexMaterial<VertexColor2Texture2>(index);
+            var s = GetVertexSkinning<VertexJoints16x8>(index);
 
 
-            var g = v.GetGeometry();
-            CopyTo(index, g);
+            var v = (IVertexBuilder)Activator.CreateInstance(vertexType);
             v.SetGeometry(g);
             v.SetGeometry(g);
-
-            var m = v.GetMaterial();
-            CopyTo(index, m);
             v.SetMaterial(m);
             v.SetMaterial(m);
-
-            var s = v.GetSkinning();
-            CopyTo(index, s);
             v.SetSkinning(s);
             v.SetSkinning(s);
-
             return v;
             return v;
         }
         }
 
 
@@ -300,8 +309,8 @@ namespace SharpGLTF.Geometry
             where TvG : struct, IVertexGeometry
             where TvG : struct, IVertexGeometry
             where TvM : struct, IVertexMaterial
             where TvM : struct, IVertexMaterial
         {
         {
-            var g = default(TvG); CopyTo(index, g);
-            var m = default(TvM); CopyTo(index, m);
+            var g = GetVertexGeometry<TvG>(index);
+            var m = GetVertexMaterial<TvM>(index);
 
 
             return new VertexBuilder<TvG, TvM, VertexEmpty>(g, m);
             return new VertexBuilder<TvG, TvM, VertexEmpty>(g, m);
         }
         }
@@ -311,9 +320,9 @@ namespace SharpGLTF.Geometry
             where TvM : struct, IVertexMaterial
             where TvM : struct, IVertexMaterial
             where TvS : struct, IVertexSkinning
             where TvS : struct, IVertexSkinning
         {
         {
-            var g = default(TvG); CopyTo(index, g);
-            var m = default(TvM); CopyTo(index, m);
-            var s = default(TvS); CopyTo(index, s);
+            var g = GetVertexGeometry<TvG>(index);
+            var m = GetVertexMaterial<TvM>(index);
+            var s = GetVertexSkinning<TvS>(index);
 
 
             return new VertexBuilder<TvG, TvM, TvS>(g, m, s);
             return new VertexBuilder<TvG, TvM, TvS>(g, m, s);
         }
         }

+ 23 - 6
src/SharpGLTF.Toolkit/Geometry/VertexBuilder.cs

@@ -13,8 +13,25 @@ namespace SharpGLTF.Geometry
         IVertexMaterial GetMaterial();
         IVertexMaterial GetMaterial();
         IVertexSkinning GetSkinning();
         IVertexSkinning GetSkinning();
 
 
+        /// <summary>
+        /// Applies a <see cref="IVertexGeometry"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
+        /// Remember we work with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
+        /// </summary>
+        /// <param name="geometry">A <see cref="IVertexGeometry"/> set.</param>
         void SetGeometry(IVertexGeometry geometry);
         void SetGeometry(IVertexGeometry geometry);
+
+        /// <summary>
+        /// Applies a <see cref="IVertexMaterial"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
+        /// Remember we work with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
+        /// </summary>
+        /// <param name="material">A <see cref="IVertexMaterial"/> set.</param>
         void SetMaterial(IVertexMaterial material);
         void SetMaterial(IVertexMaterial material);
+
+        /// <summary>
+        /// Applies a <see cref="IVertexSkinning"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
+        /// Remember we work with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
+        /// </summary>
+        /// <param name="skinning">A <see cref="IVertexSkinning"/> set.</param>
         void SetSkinning(IVertexSkinning skinning);
         void SetSkinning(IVertexSkinning skinning);
 
 
         VertexBuilder<TvPP, TvMM, TvSS> ConvertTo<TvPP, TvMM, TvSS>()
         VertexBuilder<TvPP, TvMM, TvSS> ConvertTo<TvPP, TvMM, TvSS>()
@@ -260,9 +277,9 @@ namespace SharpGLTF.Geometry
             where TvMM : struct, IVertexMaterial
             where TvMM : struct, IVertexMaterial
             where TvSS : struct, IVertexSkinning
             where TvSS : struct, IVertexSkinning
         {
         {
-            var p = Geometry.ConvertTo<TvPP>();
-            var m = Material.ConvertTo<TvMM>();
-            var s = Skinning.ConvertTo<TvSS>();
+            var p = Geometry.ConvertToGeometry<TvPP>();
+            var m = Material.ConvertToMaterial<TvMM>();
+            var s = Skinning.ConvertToSkinning<TvSS>();
 
 
             return new VertexBuilder<TvPP, TvMM, TvSS>(p, m, s);
             return new VertexBuilder<TvPP, TvMM, TvSS>(p, m, s);
         }
         }
@@ -321,19 +338,19 @@ namespace SharpGLTF.Geometry
         void IVertexBuilder.SetGeometry(IVertexGeometry geometry)
         void IVertexBuilder.SetGeometry(IVertexGeometry geometry)
         {
         {
             Guard.NotNull(geometry, nameof(geometry));
             Guard.NotNull(geometry, nameof(geometry));
-            this.Geometry = geometry.GetType() == typeof(TvG) ? (TvG)geometry : geometry.ConvertTo<TvG>();
+            this.Geometry = geometry.GetType() == typeof(TvG) ? (TvG)geometry : geometry.ConvertToGeometry<TvG>();
         }
         }
 
 
         void IVertexBuilder.SetMaterial(IVertexMaterial material)
         void IVertexBuilder.SetMaterial(IVertexMaterial material)
         {
         {
             Guard.NotNull(material, nameof(material));
             Guard.NotNull(material, nameof(material));
-            this.Material = material.GetType() == typeof(TvM) ? (TvM)material : material.ConvertTo<TvM>();
+            this.Material = material.GetType() == typeof(TvM) ? (TvM)material : material.ConvertToMaterial<TvM>();
         }
         }
 
 
         void IVertexBuilder.SetSkinning(IVertexSkinning skinning)
         void IVertexBuilder.SetSkinning(IVertexSkinning skinning)
         {
         {
             Guard.NotNull(skinning, nameof(skinning));
             Guard.NotNull(skinning, nameof(skinning));
-            this.Skinning = skinning.GetType() == typeof(TvS) ? (TvS)skinning : skinning.ConvertTo<TvS>();
+            this.Skinning = skinning.GetType() == typeof(TvS) ? (TvS)skinning : skinning.ConvertToSkinning<TvS>();
         }
         }
 
 
         #endregion
         #endregion

+ 36 - 1
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs

@@ -184,7 +184,7 @@ namespace SharpGLTF.Geometry.VertexTypes
                 this.SetJointBinding(i, bindings[i].Item1, bindings[i].Item2);
                 this.SetJointBinding(i, bindings[i].Item1, bindings[i].Item2);
             }
             }
         }
         }
-
+        
         #endregion
         #endregion
 
 
         #region data
         #region data
@@ -483,6 +483,41 @@ namespace SharpGLTF.Geometry.VertexTypes
             Weights1 = Vector4.Zero;
             Weights1 = Vector4.Zero;
         }
         }
 
 
+        public VertexJoints16x8(in Transforms.SparseWeight8 weights)
+        {
+            Joints0 = new Vector4
+                (
+                weights.Index0,
+                weights.Index1,
+                weights.Index2,
+                weights.Index3
+                );
+
+            Joints1 = new Vector4
+                (
+                weights.Index4,
+                weights.Index5,
+                weights.Index6,
+                weights.Index7
+                );
+
+            Weights0 = new Vector4
+                (
+                weights.Weight0,
+                weights.Weight1,
+                weights.Weight2,
+                weights.Weight3
+                );
+
+            Weights1 = new Vector4
+                (
+                weights.Weight4,
+                weights.Weight5,
+                weights.Weight6,
+                weights.Weight7
+                );
+        }
+
         #endregion
         #endregion
 
 
         #region data
         #region data

+ 108 - 134
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -11,6 +11,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 {
 {
     static class VertexUtils
     static class VertexUtils
     {
     {
+        #region vertex builder
+
         public static Type GetVertexGeometryType(params string[] vertexAttributes)
         public static Type GetVertexGeometryType(params string[] vertexAttributes)
         {
         {
             var t = typeof(VertexPosition);
             var t = typeof(VertexPosition);
@@ -115,6 +117,111 @@ namespace SharpGLTF.Geometry.VertexTypes
             return true;
             return true;
         }
         }
 
 
+        public static TvP ConvertToGeometry<TvP>(this IVertexGeometry src)
+            where TvP : struct, IVertexGeometry
+        {
+            if (src.GetType() == typeof(TvP)) return (TvP)src;
+
+            var dst = default(TvP);
+
+            dst.SetPosition(src.GetPosition());
+            if (src.TryGetNormal(out Vector3 nrm)) dst.SetNormal(nrm);
+            if (src.TryGetTangent(out Vector4 tgt)) dst.SetTangent(tgt);
+
+            return dst;
+        }
+
+        public static TvM ConvertToMaterial<TvM>(this IVertexMaterial src)
+            where TvM : struct, IVertexMaterial
+        {
+            if (src.GetType() == typeof(TvM)) return (TvM)src;
+
+            var dst = default(TvM);
+
+            int i = 0;
+
+            while (i < Math.Min(src.MaxColors, dst.MaxColors))
+            {
+                dst.SetColor(i, src.GetColor(i));
+                ++i;
+            }
+
+            while (i < dst.MaxColors)
+            {
+                dst.SetColor(i, Vector4.One);
+                ++i;
+            }
+
+            i = 0;
+
+            while (i < Math.Min(src.MaxTextCoords, dst.MaxTextCoords))
+            {
+                dst.SetTexCoord(i, src.GetTexCoord(i));
+                ++i;
+            }
+
+            while (i < dst.MaxColors)
+            {
+                dst.SetTexCoord(i, Vector2.Zero);
+                ++i;
+            }
+
+            return dst;
+        }
+
+        public static TvS ConvertToSkinning<TvS>(this IVertexSkinning src)
+            where TvS : struct, IVertexSkinning
+        {
+            if (src.GetType() == typeof(TvS)) return (TvS)src;
+
+            var dst = default(TvS);
+
+            // if there's enough room for all bindings, just fill it up.
+            if (dst.MaxBindings >= src.MaxBindings)
+            {
+                int i;
+
+                for (i = 0; i < src.MaxBindings; ++i)
+                {
+                    var jw = src.GetJointBinding(i);
+
+                    dst.SetJointBinding(i, jw.Joint, jw.Weight);
+                }
+
+                while (i < dst.MaxBindings)
+                {
+                    dst.SetJointBinding(i++, 0, 0);
+                }
+
+                return dst;
+            }
+
+            // if there's more source joints than destination joints,
+            // transfer only the most representative joints, and renormalize.
+
+            Span<JointBinding> srcjw = stackalloc JointBinding[src.MaxBindings];
+
+            for (int i = 0; i < src.MaxBindings; ++i)
+            {
+                srcjw[i] = src.GetJointBinding(i);
+            }
+
+            JointBinding.InPlaceReverseBubbleSort(srcjw);
+
+            var w = JointBinding.CalculateScaleFor(srcjw, dst.MaxBindings);
+
+            for (int i = 0; i < dst.MaxBindings; ++i)
+            {
+                dst.SetJointBinding(i, srcjw[i].Joint, srcjw[i].Weight * w);
+            }
+
+            return dst;
+        }
+
+        #endregion
+
+        #region memory buffers API
+
         public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TVertex>(this IEnumerable<IReadOnlyList<TVertex>> vertexBlocks)
         public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TVertex>(this IEnumerable<IReadOnlyList<TVertex>> vertexBlocks)
             where TVertex : IVertexBuilder
             where TVertex : IVertexBuilder
         {
         {
@@ -276,139 +383,6 @@ namespace SharpGLTF.Geometry.VertexTypes
             return dst;
             return dst;
         }
         }
 
 
-        public static TvP ConvertTo<TvP>(this IVertexGeometry src)
-            where TvP : struct, IVertexGeometry
-        {
-            if (src.GetType() == typeof(TvP)) return (TvP)src;
-
-            var dst = default(TvP);
-            src.CopyTo(dst);
-
-            System.Diagnostics.Debug.Assert(src.GetPosition() == dst.GetPosition());
-
-            return dst;
-        }
-
-        public static TvM ConvertTo<TvM>(this IVertexMaterial src)
-            where TvM : struct, IVertexMaterial
-        {
-            if (src.GetType() == typeof(TvM)) return (TvM)src;
-
-            var dst = default(TvM);
-            src.CopyTo(dst);
-
-            #if DEBUG
-            for (int i = 0; i < Math.Min(src.MaxColors, dst.MaxColors); ++i)
-            {
-                System.Diagnostics.Debug.Assert(src.GetColor(i) == dst.GetColor(i));
-            }
-
-            for (int i = 0; i < Math.Min(src.MaxTextCoords, dst.MaxTextCoords); ++i)
-            {
-                System.Diagnostics.Debug.Assert(src.GetTexCoord(i) == dst.GetTexCoord(i));
-            }
-            #endif
-            return dst;
-        }
-
-        public static TvS ConvertTo<TvS>(this IVertexSkinning src)
-            where TvS : struct, IVertexSkinning
-        {
-            if (src.GetType() == typeof(TvS)) return (TvS)src;
-
-            var dst = default(TvS);
-            src.CopyTo(dst);
-
-            #if DEBUG
-
-            if (src.JointBindings == dst.JointBindings)
-            {
-                // todo, check bindings are the same.
-            }
-
-            #endif
-
-            return dst;
-        }
-
-        public static void CopyTo(this IVertexGeometry src, IVertexGeometry dst)
-        {
-            dst.SetPosition(src.GetPosition());
-            if (src.TryGetNormal(out Vector3 nrm)) dst.SetNormal(nrm);
-            if (src.TryGetTangent(out Vector4 tgt)) dst.SetTangent(tgt);
-        }
-
-        public static void CopyTo(this IVertexMaterial src, IVertexMaterial dst)
-        {
-            int i = 0;
-
-            while (i < Math.Min(src.MaxColors, dst.MaxColors))
-            {
-                dst.SetColor(i, src.GetColor(i));
-                ++i;
-            }
-
-            while (i < dst.MaxColors)
-            {
-                dst.SetColor(i, Vector4.One);
-                ++i;
-            }
-
-            i = 0;
-
-            while (i < Math.Min(src.MaxTextCoords, dst.MaxTextCoords))
-            {
-                dst.SetTexCoord(i, src.GetTexCoord(i));
-                ++i;
-            }
-
-            while (i < dst.MaxColors)
-            {
-                dst.SetTexCoord(i, Vector2.Zero);
-                ++i;
-            }
-        }
-
-        public static unsafe void CopyTo(this IVertexSkinning src, IVertexSkinning dst)
-        {
-            // create copy
-
-            if (dst.MaxBindings >= src.MaxBindings)
-            {
-                int i = 0;
-
-                for (i = 0; i < src.MaxBindings; ++i)
-                {
-                    var jw = src.GetJointBinding(i);
-
-                    dst.SetJointBinding(i, jw.Joint, jw.Weight);
-                }
-
-                while (i < dst.MaxBindings)
-                {
-                    dst.SetJointBinding(i++, 0, 0);
-                }
-
-                return;
-            }
-
-            // if there's more source joints than destination joints, transfer with scale
-
-            Span<JointBinding> srcjw = stackalloc JointBinding[src.MaxBindings];
-
-            for (int i = 0; i < src.MaxBindings; ++i)
-            {
-                srcjw[i] = src.GetJointBinding(i);
-            }
-
-            JointBinding.InPlaceReverseBubbleSort(srcjw);
-
-            var w = JointBinding.CalculateScaleFor(srcjw, dst.MaxBindings);
-
-            for (int i = 0; i < dst.MaxBindings; ++i)
-            {
-                dst.SetJointBinding(i, srcjw[i].Joint, srcjw[i].Weight * w);
-            }
-        }
+        #endregion
     }
     }
 }
 }

+ 4 - 0
src/SharpGLTF.Toolkit/Scenes/Content.cs

@@ -185,6 +185,10 @@ namespace SharpGLTF.Scenes
                 skinnedMeshNode.WithSkinBinding(skinnedJoints);
                 skinnedMeshNode.WithSkinBinding(skinnedJoints);
             }
             }
 
 
+            // set skeleton
+            // var root = _Joints[0].Item1.Root;
+            // skinnedMeshNode.Skin.Skeleton = context.GetNode(root);
+
             _Target.Setup(skinnedMeshNode, context);
             _Target.Setup(skinnedMeshNode, context);
         }
         }
 
 

+ 12 - 4
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.cs

@@ -25,36 +25,44 @@ namespace SharpGLTF.Scenes
 
 
         #region API
         #region API
 
 
-        public void AddMesh(MESHBUILDER mesh, Matrix4x4 transform)
+        public InstanceBuilder AddMesh(MESHBUILDER mesh, Matrix4x4 transform)
         {
         {
             var instance = new InstanceBuilder(this);
             var instance = new InstanceBuilder(this);
             instance.Content = new StaticTransformer(mesh, transform);
             instance.Content = new StaticTransformer(mesh, transform);
 
 
             _Instances.Add(instance);
             _Instances.Add(instance);
+
+            return instance;
         }
         }
 
 
-        public void AddMesh(MESHBUILDER mesh, NodeBuilder node)
+        public InstanceBuilder AddMesh(MESHBUILDER mesh, NodeBuilder node)
         {
         {
             var instance = new InstanceBuilder(this);
             var instance = new InstanceBuilder(this);
             instance.Content = new NodeTransformer(mesh, node);
             instance.Content = new NodeTransformer(mesh, node);
 
 
             _Instances.Add(instance);
             _Instances.Add(instance);
+
+            return instance;
         }
         }
 
 
-        public void AddSkinnedMesh(MESHBUILDER mesh, Matrix4x4 meshBindMatrix, params NodeBuilder[] joints)
+        public InstanceBuilder AddSkinnedMesh(MESHBUILDER mesh, Matrix4x4 meshBindMatrix, params NodeBuilder[] joints)
         {
         {
             var instance = new InstanceBuilder(this);
             var instance = new InstanceBuilder(this);
             instance.Content = new SkinTransformer(mesh, meshBindMatrix, joints);
             instance.Content = new SkinTransformer(mesh, meshBindMatrix, joints);
 
 
             _Instances.Add(instance);
             _Instances.Add(instance);
+
+            return instance;
         }
         }
 
 
-        public void AddSkinnedMesh(MESHBUILDER mesh, params (NodeBuilder, Matrix4x4)[] joints)
+        public InstanceBuilder AddSkinnedMesh(MESHBUILDER mesh, params (NodeBuilder, Matrix4x4)[] joints)
         {
         {
             var instance = new InstanceBuilder(this);
             var instance = new InstanceBuilder(this);
             instance.Content = new SkinTransformer(mesh, joints);
             instance.Content = new SkinTransformer(mesh, joints);
 
 
             _Instances.Add(instance);
             _Instances.Add(instance);
+
+            return instance;
         }
         }
 
 
         #endregion
         #endregion

+ 6 - 0
tests/SharpGLTF.Tests/Geometry/Parametric/SolidMeshUtils.cs

@@ -24,6 +24,12 @@ namespace SharpGLTF.Geometry.Parametric
             _Front = _Back = _Left = _Right = _Top = _Bottom = material;
             _Front = _Back = _Left = _Right = _Top = _Bottom = material;
         }
         }
 
 
+        public Cube(TMaterial material, float width, float height, float length)
+        {
+            _Front = _Back = _Left = _Right = _Top = _Bottom = material;
+            _Size = new Vector3(width, height, length);
+        }
+
         #endregion
         #endregion
 
 
         #region data
         #region data

+ 1 - 1
tests/SharpGLTF.Tests/Geometry/VertexTypes/VertexSkinningTests.cs

@@ -22,7 +22,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             v8.SetJointBinding(4, 5, 0.30f);
             v8.SetJointBinding(4, 5, 0.30f);
 
 
             // we downgrade to 4 bindings; remaining bindings should be interpolated to keep weighting 1.
             // we downgrade to 4 bindings; remaining bindings should be interpolated to keep weighting 1.
-            var v4 = v8.ConvertTo<VertexJoints8x4>();
+            var v4 = v8.ConvertToSkinning<VertexJoints8x4>();
 
 
             Assert.AreEqual(5, v4.GetJointBinding(0).Joint);
             Assert.AreEqual(5, v4.GetJointBinding(0).Joint);
             Assert.AreEqual(3, v4.GetJointBinding(1).Joint);
             Assert.AreEqual(3, v4.GetJointBinding(1).Joint);

+ 11 - 0
tests/SharpGLTF.Tests/Scenes/SceneBuilderTests.cs

@@ -334,6 +334,9 @@ namespace SharpGLTF.Scenes
 
 
             var scene = Schema2.Schema2Toolkit.ToSceneBuilder(modelSrc.DefaultScene);
             var scene = Schema2.Schema2Toolkit.ToSceneBuilder(modelSrc.DefaultScene);
 
 
+            var cube = new Cube<MaterialBuilder>(MaterialBuilder.CreateDefault(), 1, 0.01f, 1);
+            scene.AddMesh(cube.ToMesh(Matrix4x4.Identity), Matrix4x4.Identity);
+
             var modelBis = scene.ToSchema2();
             var modelBis = scene.ToSchema2();
 
 
             // save file
             // save file
@@ -344,6 +347,14 @@ namespace SharpGLTF.Scenes
 
 
             modelSrc.AttachToCurrentTest(path + "_src" + ".gltf");
             modelSrc.AttachToCurrentTest(path + "_src" + ".gltf");
             modelBis.AttachToCurrentTest(path + "_bis" + ".gltf");
             modelBis.AttachToCurrentTest(path + "_bis" + ".gltf");
+
+            modelSrc.AttachToCurrentTest(path + "_src" + ".obj");
+            modelBis.AttachToCurrentTest(path + "_bis" + ".obj");
+
+            modelSrc.AttachToCurrentTest(path + "_src_at01" + ".obj", modelSrc.LogicalAnimations[0], 0.1f);
+
+            if (modelBis.LogicalAnimations.Count > 0)
+                modelBis.AttachToCurrentTest(path + "_bis_at01" + ".obj", modelBis.LogicalAnimations[0], 0.1f);
         }
         }
 
 
     }
     }