Vicente Penades Armengot 5 месяцев назад
Родитель
Сommit
4b28af2b6e

+ 14 - 4
src/SharpGLTF.Core/Memory/AttributeFormat.cs

@@ -51,10 +51,7 @@ namespace SharpGLTF.Memory
 
         #region constructors
 
-        public static implicit operator AttributeFormat(Schema2.IndexEncodingType indexer)
-        {
-            return new AttributeFormat(indexer.ToComponent());
-        }
+        public static implicit operator AttributeFormat(Schema2.IndexEncodingType indexer) { return new AttributeFormat(indexer); }        
 
         public static implicit operator AttributeFormat(ENCODING enc) { return new AttributeFormat(enc); }
 
@@ -64,6 +61,14 @@ namespace SharpGLTF.Memory
 
         public static implicit operator AttributeFormat((DIMENSIONS dim, ENCODING enc, Boolean nrm) fmt) { return new AttributeFormat(fmt.dim, fmt.enc, fmt.nrm); }
 
+        public AttributeFormat(Schema2.IndexEncodingType enc)
+        {
+            Dimensions = DIMENSIONS.SCALAR;
+            Encoding = enc.ToComponent();
+            Normalized = false;
+            ByteSize = Dimensions.DimCount() * Encoding.ByteLength();
+        }
+
         public AttributeFormat(ENCODING enc)
         {
             Dimensions = DIMENSIONS.SCALAR;
@@ -90,6 +95,11 @@ namespace SharpGLTF.Memory
 
         public AttributeFormat(DIMENSIONS dim, ENCODING enc, Boolean nrm)
         {
+            if (nrm)
+            {
+                Guard.IsFalse(enc == ENCODING.FLOAT, nameof(nrm), "Float encoding must not be normalized");
+            }
+
             Dimensions = dim;
             Encoding = enc;
             Normalized = nrm;

+ 6 - 10
src/SharpGLTF.Core/Memory/MemoryAccessor.Validation.cs

@@ -42,10 +42,10 @@ namespace SharpGLTF.Memory
 
         internal BYTES _GetBytes()
         {
-            var o = this._Slicer.ByteOffset;
-            var l = this._Slicer.StepByteLength * this._Slicer.ItemsCount;
+            var o = this.Attribute.ByteOffset;
+            var l = this.Attribute.StepByteLength * this.Attribute.ItemsCount;
 
-            var data = _Data.Slice(o);
+            var data = Data.Slice(o);
 
             data = data.Slice(0, Math.Min(data.Count, l));
 
@@ -87,7 +87,7 @@ namespace SharpGLTF.Memory
 
             if (weights0 == null) return;
 
-            var len = weights0.Attribute.ItemByteLength;
+            var len = weights0.Attribute.ByteLength;
             Span<Byte> dst = stackalloc byte[len * 2];
 
             var zip = weights0.GetItemsAsRawBytes().Zip(weights1.GetItemsAsRawBytes(), (a, b) => (a, b));
@@ -201,7 +201,7 @@ namespace SharpGLTF.Memory
 
             if (weights0.Attribute.Encoding != weights1.Attribute.Encoding) throw new ArgumentException("WEIGHTS_0 and WEIGHTS_1 format mismatch.", nameof(weights1));
 
-            var len = weights0.Attribute.ItemByteLength;
+            var len = weights0.Attribute.ByteLength;
             Span<Byte> dst = stackalloc byte[len * 2];
 
             var zip = weights0.GetItemsAsRawBytes()
@@ -293,11 +293,7 @@ namespace SharpGLTF.Memory
             }
 
             var minimum = min.Select(item => (float)item).ToArray();
-            var maximum = max.Select(item => (float)item).ToArray();
-
-            var xinfo = memory.Attribute;
-            xinfo.Dimensions = DIMENSIONS.SCALAR;
-            memory = new MemoryAccessor(memory.Data, xinfo);
+            var maximum = max.Select(item => (float)item).ToArray();            
 
             var array = new MultiArray(
                 memory.Data,

+ 54 - 64
src/SharpGLTF.Core/Memory/MemoryAccessor.cs

@@ -19,7 +19,7 @@ namespace SharpGLTF.Memory
 
         internal string _GetDebuggerDisplay()
         {
-            return _Slicer._GetDebuggerDisplay();
+            return Attribute._GetDebuggerDisplay();
         }
 
         #endregion        
@@ -29,40 +29,30 @@ namespace SharpGLTF.Memory
         #if NETSTANDARD
         public MemoryAccessor(Byte[] data, MemoryAccessInfo info)
         {
-            this._Slicer = info;
-            this._Data = new ArraySegment<Byte>(data);
+            this.Attribute = info;
+            this.Data = new ArraySegment<Byte>(data);
         }
         #endif
 
         public MemoryAccessor(BYTES data, MemoryAccessInfo info)
         {
-            this._Slicer = info;
-            this._Data = data;
+            this.Attribute = info;
+            this.Data = data;
         }
 
         public MemoryAccessor(MemoryAccessInfo info)
         {
-            this._Slicer = info;
-            this._Data = default;
+            this.Attribute = info;
+            this.Data = default;
         }        
 
-        #endregion
+        #endregion        
 
         #region data
 
-        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        private MemoryAccessInfo _Slicer;
-
-        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        private BYTES _Data;
-
-        #endregion
-
-        #region properties
-
-        public MemoryAccessInfo Attribute => _Slicer;
+        public MemoryAccessInfo Attribute { get; private set; }
 
-        public BYTES Data => _Data;
+        public BYTES Data { get; private set; }
 
         #endregion
 
@@ -70,8 +60,8 @@ namespace SharpGLTF.Memory
 
         public void Update(BYTES data, MemoryAccessInfo encoding)
         {
-            this._Slicer = encoding;
-            this._Data = data;
+            this.Attribute = encoding;
+            this.Data = data;
         }
 
         public IAccessorArray<T> AsArrayOf<T>()
@@ -108,73 +98,73 @@ namespace SharpGLTF.Memory
 
         public IntegerArray AsIntegerArray()
         {
-            Guard.IsTrue(_Slicer.IsValidIndexer, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.SCALAR, nameof(_Slicer));
-            return new IntegerArray(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.Encoding.ToIndex());
+            Guard.IsTrue(Attribute.IsValidIndexer, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.SCALAR, nameof(Attribute));
+            return new IntegerArray(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.Encoding.ToIndex());
         }
 
         public ScalarArray AsScalarArray()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.SCALAR, nameof(_Slicer));
-            return new ScalarArray(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.SCALAR, nameof(Attribute));
+            return new ScalarArray(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Vector2Array AsVector2Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.VEC2, nameof(_Slicer));
-            return new Vector2Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.VEC2, nameof(Attribute));
+            return new Vector2Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Vector3Array AsVector3Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.VEC3, nameof(_Slicer));
-            return new Vector3Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.VEC3, nameof(Attribute));
+            return new Vector3Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Vector4Array AsVector4Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.VEC4, nameof(_Slicer));
-            return new Vector4Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.VEC4, nameof(Attribute));
+            return new Vector4Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }        
 
         public QuaternionArray AsQuaternionArray()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.VEC4, nameof(_Slicer));
-            return new QuaternionArray(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.VEC4, nameof(Attribute));
+            return new QuaternionArray(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Matrix2x2Array AsMatrix2x2Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.MAT2, nameof(_Slicer));
-            return new Matrix2x2Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.MAT2, nameof(Attribute));
+            return new Matrix2x2Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Matrix3x3Array AsMatrix3x3Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.MAT3, nameof(_Slicer));
-            return new Matrix3x3Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.MAT3, nameof(Attribute));
+            return new Matrix3x3Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Matrix4x3Array AsMatrix4x3Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
             // Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.MAT3, nameof(_Slicer));
 
-            return new Matrix4x3Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            return new Matrix4x3Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
         public Matrix4x4Array AsMatrix4x4Array()
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.MAT4, nameof(_Slicer));
-            return new Matrix4x4Array(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.MAT4, nameof(Attribute));
+            return new Matrix4x4Array(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Encoding, Attribute.Normalized);
         }
 
 
@@ -188,28 +178,28 @@ namespace SharpGLTF.Memory
         /// <returns>An array of colors</returns>
         public ColorArray AsColorArray(Single defaultW = 1)
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.VEC3 || _Slicer.Dimensions == DIMENSIONS.VEC4, nameof(_Slicer));
-            return new ColorArray(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, _Slicer.Dimensions.DimCount(), _Slicer.Encoding, _Slicer.Normalized, defaultW);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.VEC3 || Attribute.Dimensions == DIMENSIONS.VEC4, nameof(Attribute));
+            return new ColorArray(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, Attribute.Dimensions.DimCount(), Attribute.Encoding, Attribute.Normalized, defaultW);
         }
 
         public MultiArray AsMultiArray(int dimensions)
         {
-            Guard.IsTrue(_Slicer.IsValidVertexAttribute, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.Dimensions == DIMENSIONS.SCALAR, nameof(_Slicer));
-            Guard.IsTrue(_Slicer.ByteStride == 0, nameof(_Slicer));
-            return new MultiArray(_Data, _Slicer.ByteOffset, _Slicer.ItemsCount, _Slicer.ByteStride, dimensions, _Slicer.Encoding, _Slicer.Normalized);
+            Guard.IsTrue(Attribute.IsValidVertexAttribute, nameof(Attribute));
+            Guard.IsTrue(Attribute.Dimensions == DIMENSIONS.SCALAR, nameof(Attribute));
+            Guard.IsTrue(Attribute.ByteStride == 0, nameof(Attribute));
+            return new MultiArray(Data, Attribute.ByteOffset, Attribute.ItemsCount, Attribute.ByteStride, dimensions, Attribute.Encoding, Attribute.Normalized);
         }
 
         public IEnumerable<BYTES> GetItemsAsRawBytes()
         {
-            var rowOffset = this._Slicer.ByteOffset;
-            var rowStride = this._Slicer.StepByteLength;
-            var itemSize = this._Slicer.Dimensions.DimCount() * _Slicer.Encoding.ByteLength();
+            var itemSize = this.Attribute.ByteLength;
+            var rowStride = this.Attribute.StepByteLength;
+            var rowOffset = this.Attribute.ByteOffset;            
 
-            for (int i = 0; i < this._Slicer.ItemsCount; ++i)
+            for (int i = 0; i < this.Attribute.ItemsCount; ++i)
             {
-                yield return this._Data.Slice((i * rowStride) + rowOffset, itemSize);
+                yield return this.Data.Slice(i * rowStride + rowOffset, itemSize);
             }
         }
 
@@ -241,7 +231,7 @@ namespace SharpGLTF.Memory
                 System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(indicesBuffer.Slice(i * 4), indices[i]);
             }
 
-            var blen = Attribute.ItemByteLength;
+            var blen = Attribute.ByteLength;
 
             var vertexBuffer = new byte[values.Count * blen];
             for (int i = 0; i < values.Count; ++i)

+ 32 - 36
src/SharpGLTF.Core/Memory/MemoryAccessorInfo.cs

@@ -17,7 +17,7 @@ namespace SharpGLTF.Memory
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     public struct MemoryAccessInfo
     {
-        #region debug
+        #region diagnostics
 
         internal readonly string _GetDebuggerDisplay()
         {
@@ -69,9 +69,7 @@ namespace SharpGLTF.Memory
             this.ByteOffset = byteOffset;
             this.ItemsCount = itemsCount;
             this.ByteStride = byteStride;
-            this.Dimensions = format.Dimensions;
-            this.Encoding = format.Encoding;
-            this.Normalized = format.Normalized;
+            this.Format = format;
         }
 
         public MemoryAccessInfo(string name, int byteOffset, int itemsCount, int byteStride, DIMENSIONS dimensions, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
@@ -80,14 +78,12 @@ namespace SharpGLTF.Memory
             this.ByteOffset = byteOffset;
             this.ItemsCount = itemsCount;
             this.ByteStride = byteStride;
-            this.Dimensions = dimensions;
-            this.Encoding = encoding;
-            this.Normalized = normalized;
+            this.Format = (dimensions, encoding, normalized);
         }
 
         public readonly MemoryAccessInfo Slice(int itemStart, int itemCount)
         {
-            var stride = _GetRowByteLength();
+            var stride = this.StepByteLength;
 
             var clone = this;
             clone.ByteOffset += itemStart * stride;
@@ -96,6 +92,11 @@ namespace SharpGLTF.Memory
             return clone;
         }
 
+        public readonly MemoryAccessInfo WithFormat(AttributeFormat newFormat)
+        {
+            return new MemoryAccessInfo(this.Name, this.ByteOffset, this.ItemsCount, this.ByteStride, newFormat);
+        }
+
         #endregion
 
         #region data
@@ -119,34 +120,47 @@ namespace SharpGLTF.Memory
         /// number of bytes to advance to the beginning of the next item
         /// </summary>
         public int ByteStride;
+        
+        /// <summary>
+        /// Item encoding format.
+        /// </summary>
+        public AttributeFormat Format;
+
+        #endregion
+
+        #region properties
 
         /// <summary>
         /// number of sub-elements of each item.
         /// </summary>
-        public DIMENSIONS Dimensions;
+        public readonly DIMENSIONS Dimensions => Format.Dimensions;
 
         /// <summary>
         /// byte encoding of sub-elements of each item.
         /// </summary>
-        public ENCODING Encoding;
+        public readonly ENCODING Encoding => Format.Encoding;
 
         /// <summary>
         /// normalization of sub-elements of each item.
         /// </summary>
-        public Boolean Normalized;
+        public readonly Boolean Normalized => Format.Normalized;
 
-        #endregion
+        /// <summary>
+        /// Actual item byte length.
+        /// </summary>
+        public readonly int ByteLength => Format.ByteSize;
 
-        #region properties
 
-        public AttributeFormat Format => new AttributeFormat(this.Dimensions, this.Encoding, this.Normalized);
+        /// <summary>
+        /// item byte size, padded to 4 bytes.
+        /// </summary>
+        public readonly int PaddedByteLength => Format.ByteSizePadded;        
 
         /// <summary>
         /// number of bytes to advance to the next item.
         /// </summary>
-        public readonly int StepByteLength => _GetRowByteLength();
-
-        public readonly int ItemByteLength => _GetItemByteLength();
+        public readonly int StepByteLength => Math.Max(ByteStride, Format.ByteSize);
+        
 
         public readonly Boolean IsValidVertexAttribute
         {
@@ -188,25 +202,7 @@ namespace SharpGLTF.Memory
 
         #endregion
 
-        #region API
-
-        private readonly int _GetItemByteLength()
-        {
-            var xlen = Encoding.ByteLength();
-
-            if (Dimensions != DIMENSIONS.SCALAR || Name != "INDEX")
-            {
-                xlen *= this.Dimensions.DimCount();
-                xlen = xlen.WordPadded();
-            }
-
-            return xlen;
-        }
-
-        private readonly int _GetRowByteLength()
-        {
-            return Math.Max(ByteStride, _GetItemByteLength());
-        }
+        #region API        
 
         /// <summary>
         /// Assuming that <paramref name="attributes"/> are sequential and adyacent,

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Accessors.cs

@@ -364,7 +364,7 @@ namespace SharpGLTF.Schema2
             var indicesEncoder = indices.AsIntegerArray();
 
             var valuesEncoding = new MemoryAccessInfo(null, 0, data.Count, 0, this.Format);
-            var values = new MemoryAccessor(new byte[data.Count * valuesEncoding.ItemByteLength], valuesEncoding);
+            var values = new MemoryAccessor(new byte[data.Count * valuesEncoding.ByteLength], valuesEncoding);
             var valuesEncoder = values.AsArrayOf<T>();
 
             int idx = 0;

+ 1 - 1
src/SharpGLTF.Toolkit/Geometry/Packed/PackedPrimitiveBuilder.cs

@@ -216,7 +216,7 @@ namespace SharpGLTF.Geometry
                 foreach (var v in vvv)
                 {
                     var k = v.Attribute.Name;
-                    var s = v.Attribute.ItemByteLength;
+                    var s = v.Attribute.PaddedByteLength;
 
                     if (!vertexBuffers.TryGetValue((k,s), out PackedBuffer packed))
                     {

+ 18 - 7
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Accessors.cs

@@ -120,8 +120,9 @@ namespace SharpGLTF.Geometry.VertexTypes
                 {
                     if (vertexEncoding.ColorEncoding.HasValue)
                     {
-                        a.Encoding = vertexEncoding.ColorEncoding.Value;
-                        a.Normalized = a.Encoding != ENCODING.FLOAT;
+                        var enc = vertexEncoding.ColorEncoding.Value;
+                        var fmt = new AttributeFormat(a.Dimensions, enc, enc != ENCODING.FLOAT);
+                        a = a.WithFormat(fmt);
                     }
                 }
 
@@ -130,15 +131,25 @@ namespace SharpGLTF.Geometry.VertexTypes
 
             foreach (var finfo in tvs)
             {
-                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);                
-                
-                if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
+                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);
+
+                var fmt = a.Format;
+
+                if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase))
+                {
+                    var enc = vertexEncoding.JointsEncoding.Value;
+                    Guard.IsFalse(fmt.Normalized, nameof(firstVertex), "indices should not be normalized");
+                    fmt = (fmt.Dimensions, enc, false);
+                }
+
                 if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
                 {
-                    a.Encoding = vertexEncoding.WeightsEncoding.Value;
-                    if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
+                    var enc = vertexEncoding.WeightsEncoding.Value;
+                    fmt = (fmt.Dimensions, enc, enc != ENCODING.FLOAT);
                 }
 
+                a = a.WithFormat(fmt);
+
                 attributes.Add(a);
                 
             }