Browse Source

WIP: added animation blending
changing how packages are built...

Vicente Penades 6 years ago
parent
commit
85c8fc43c2

+ 20 - 0
src/PackageInfo.props

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup>
+    <Authors>Vicente Penades</Authors>
+    <Copyright>Copyright (c) 2019 Vicente Penades</Copyright>
+    <Description>SharpGLTF is a C# library for reading and writing glTF2 3D models</Description>
+    <PackageProjectUrl>https://github.com/vpenades/SharpGLTF</PackageProjectUrl>
+    <RepositoryUrl>https://github.com/vpenades/SharpGLTF</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <PackageTags>C# glTF 3D</PackageTags>
+    <PackageLicenseFile>LICENSE</PackageLicenseFile>
+    <PackageIconUrl>https://raw.githubusercontent.com/vpenades/SharpGLTF/master/build/Icons/glTF2Sharp.png</PackageIconUrl>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <None Include="$(MsBuildThisFileDirectory)..\LICENSE" Pack="true" PackagePath="" />
+  </ItemGroup>
+	
+</Project>

+ 1 - 1
src/SharpGLTF.Core/Runtime/AnimatableProperty.cs

@@ -38,7 +38,7 @@ namespace SharpGLTF.Runtime
 
 
         #region properties
         #region properties
 
 
-        public bool IsAnimated => Tracks.Count > 0;
+        public bool IsAnimated => _Animations == null ? false : _Animations.Count > 0;
 
 
         public IReadOnlyCollection<string> Tracks => _Animations?.Names;
         public IReadOnlyCollection<string> Tracks => _Animations?.Names;
 
 

+ 33 - 0
src/SharpGLTF.Core/Runtime/SceneInstance.cs

@@ -109,6 +109,12 @@ namespace SharpGLTF.Runtime
             this.LocalMatrix = _Template.GetLocalMatrix(trackLogicalIndex, time);
             this.LocalMatrix = _Template.GetLocalMatrix(trackLogicalIndex, time);
         }
         }
 
 
+        public void SetAnimationFrame(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            this.MorphWeights = _Template.GetMorphWeights(track, time, weight);
+            this.LocalMatrix = _Template.GetLocalMatrix(track, time, weight);
+        }
+
         #endregion
         #endregion
     }
     }
 
 
@@ -223,6 +229,33 @@ namespace SharpGLTF.Runtime
             SetAnimationFrame(_AnimationTracks.IndexOf(trackName), time);
             SetAnimationFrame(_AnimationTracks.IndexOf(trackName), time);
         }
         }
 
 
+        public void SetAnimationFrame(params (int, float, float)[] blended)
+        {
+            SetAnimationFrame(_NodeInstances, blended);
+        }
+
+        public static void SetAnimationFrame(IEnumerable<NodeInstance> nodes, params (int, float, float)[] blended)
+        {
+            Guard.NotNull(nodes, nameof(nodes));
+
+            Span<int> tracks = stackalloc int[blended.Length];
+            Span<float> times = stackalloc float[blended.Length];
+            Span<float> weights = stackalloc float[blended.Length];
+
+            float w = blended.Sum(item => item.Item3);
+
+            w = w == 0 ? 1 : 1 / w;
+
+            for (int i = 0; i < blended.Length; ++i)
+            {
+                tracks[i] = blended[i].Item1;
+                times[i] = blended[i].Item2;
+                weights[i] = blended[i].Item3 * w;
+            }
+
+            foreach (var n in nodes) n.SetAnimationFrame(tracks, times, weights);
+        }
+
         /// <summary>
         /// <summary>
         /// Gets a drawable reference pair, where Item1 is the logical Index
         /// Gets a drawable reference pair, where Item1 is the logical Index
         /// of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>
         /// of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>

+ 46 - 7
src/SharpGLTF.Core/Runtime/SceneTemplate.cs

@@ -25,11 +25,11 @@ namespace SharpGLTF.Runtime
             Name = srcNode.Name;
             Name = srcNode.Name;
 
 
             _LocalMatrix = srcNode.LocalMatrix;
             _LocalMatrix = srcNode.LocalMatrix;
+            _LocalTransform = srcNode.LocalTransform;
 
 
-            var localXform = srcNode.LocalTransform;
-            _Rotation = new AnimatableProperty<Quaternion>(localXform.Rotation);
-            _Scale = new AnimatableProperty<Vector3>(localXform.Scale);
-            _Translation = new AnimatableProperty<Vector3>(localXform.Translation);
+            _Scale = new AnimatableProperty<Vector3>(_LocalTransform.Scale);
+            _Rotation = new AnimatableProperty<Quaternion>(_LocalTransform.Rotation);
+            _Translation = new AnimatableProperty<Vector3>(_LocalTransform.Translation);
 
 
             var mw = Transforms.SparseWeight8.Create(srcNode.MorphWeights);
             var mw = Transforms.SparseWeight8.Create(srcNode.MorphWeights);
             _Morphing = new AnimatableProperty<Transforms.SparseWeight8>(mw);
             _Morphing = new AnimatableProperty<Transforms.SparseWeight8>(mw);
@@ -51,6 +51,8 @@ namespace SharpGLTF.Runtime
                 var mrpAnim = anim.FindSparseMorphSampler(srcNode)?.CreateCurveSampler(isolateMemory);
                 var mrpAnim = anim.FindSparseMorphSampler(srcNode)?.CreateCurveSampler(isolateMemory);
                 if (mrpAnim != null) _Morphing.AddCurve(index, name, mrpAnim);
                 if (mrpAnim != null) _Morphing.AddCurve(index, name, mrpAnim);
             }
             }
+
+            _UsePrecomputed = !(_Scale.IsAnimated | _Rotation.IsAnimated | _Translation.IsAnimated);
         }
         }
 
 
         #endregion
         #endregion
@@ -62,7 +64,9 @@ namespace SharpGLTF.Runtime
         private readonly int _ParentIndex;
         private readonly int _ParentIndex;
         private readonly int[] _ChildIndices;
         private readonly int[] _ChildIndices;
 
 
+        private readonly bool _UsePrecomputed;
         private readonly Matrix4x4 _LocalMatrix;
         private readonly Matrix4x4 _LocalMatrix;
+        private readonly Transforms.AffineTransform _LocalTransform;
 
 
         private readonly AnimatableProperty<Vector3> _Scale;
         private readonly AnimatableProperty<Vector3> _Scale;
         private readonly AnimatableProperty<Quaternion> _Rotation;
         private readonly AnimatableProperty<Quaternion> _Rotation;
@@ -103,24 +107,59 @@ namespace SharpGLTF.Runtime
             return _Morphing.GetValueAt(trackLogicalIndex, time);
             return _Morphing.GetValueAt(trackLogicalIndex, time);
         }
         }
 
 
+        public Transforms.SparseWeight8 GetMorphWeights(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (!_Morphing.IsAnimated) return _Morphing.Value;
+
+            Span<Transforms.SparseWeight8> xforms = stackalloc Transforms.SparseWeight8[track.Length];
+
+            for (int i = 0; i < xforms.Length; ++i)
+            {
+                xforms[i] = GetMorphWeights(track[i], time[i]);
+            }
+
+            return Transforms.SparseWeight8.Blend(xforms, weight);
+        }
+
         public Transforms.AffineTransform GetLocalTransform(int trackLogicalIndex, float time)
         public Transforms.AffineTransform GetLocalTransform(int trackLogicalIndex, float time)
         {
         {
-            if (trackLogicalIndex < 0) return Transforms.AffineTransform.Create(_LocalMatrix);
+            if (_UsePrecomputed || trackLogicalIndex < 0) return _LocalTransform;
 
 
             var s = _Scale?.GetValueAt(trackLogicalIndex, time);
             var s = _Scale?.GetValueAt(trackLogicalIndex, time);
             var r = _Rotation?.GetValueAt(trackLogicalIndex, time);
             var r = _Rotation?.GetValueAt(trackLogicalIndex, time);
             var t = _Translation?.GetValueAt(trackLogicalIndex, time);
             var t = _Translation?.GetValueAt(trackLogicalIndex, time);
 
 
-            return Transforms.AffineTransform.Create(t, r, s);
+            return Transforms.AffineTransform.Create(s, r, t);
+        }
+
+        public Transforms.AffineTransform GetLocalTransform(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (_UsePrecomputed) return _LocalTransform;
+
+            Span<Transforms.AffineTransform> xforms = stackalloc Transforms.AffineTransform[track.Length];
+
+            for (int i = 0; i < xforms.Length; ++i)
+            {
+                xforms[i] = GetLocalTransform(track[i], time[i]);
+            }
+
+            return Transforms.AffineTransform.Blend(xforms, weight);
         }
         }
 
 
         public Matrix4x4 GetLocalMatrix(int trackLogicalIndex, float time)
         public Matrix4x4 GetLocalMatrix(int trackLogicalIndex, float time)
         {
         {
-            if (trackLogicalIndex < 0) return _LocalMatrix;
+            if (_UsePrecomputed || trackLogicalIndex < 0) return _LocalMatrix;
 
 
             return GetLocalTransform(trackLogicalIndex, time).Matrix;
             return GetLocalTransform(trackLogicalIndex, time).Matrix;
         }
         }
 
 
+        public Matrix4x4 GetLocalMatrix(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
+        {
+            if (_UsePrecomputed) return _LocalMatrix;
+
+            return GetLocalTransform(track, time, weight).Matrix;
+        }
+
         #endregion
         #endregion
     }
     }
 
 

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

@@ -157,7 +157,7 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// </summary>
         public Transforms.AffineTransform LocalTransform
         public Transforms.AffineTransform LocalTransform
         {
         {
-            get => new Transforms.AffineTransform(_matrix, _translation, _rotation, _scale);
+            get => new Transforms.AffineTransform(_matrix, _scale, _rotation, _translation);
             set
             set
             {
             {
                 Guard.IsFalse(this._skin.HasValue, _NOTRANSFORMMESSAGE);
                 Guard.IsFalse(this._skin.HasValue, _NOTRANSFORMMESSAGE);

+ 10 - 21
src/SharpGLTF.Core/SharpGLTF.Core.csproj

@@ -4,24 +4,17 @@
     <TargetFramework>netstandard2.0</TargetFramework>
     <TargetFramework>netstandard2.0</TargetFramework>
     <AssemblyName>SharpGLTF.Core</AssemblyName>
     <AssemblyName>SharpGLTF.Core</AssemblyName>
     <RootNamespace>SharpGLTF</RootNamespace>
     <RootNamespace>SharpGLTF</RootNamespace>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>    
-    <PackageProjectUrl>https://github.com/vpenades/SharpGLTF</PackageProjectUrl>
-    <RepositoryUrl>https://github.com/vpenades/SharpGLTF</RepositoryUrl>
-    <RepositoryType>git</RepositoryType>
-    <Authors>Vicente Penades</Authors>
-    <Description>SharpGLTF is a C# library for reading and writing glTF2 3D models</Description>
-    <Copyright>Copyright (c) 2019 Vicente Penades</Copyright>
-    <PackageTags>C# glTF 3D</PackageTags>
-    <Version>1.0.0-alpha0011</Version>
     <LangVersion>latest</LangVersion>
     <LangVersion>latest</LangVersion>
-    <DebugSymbols>true</DebugSymbols>
-    <PackageLicenseFile>LICENSE</PackageLicenseFile>    
-    <PackageIconUrl>https://raw.githubusercontent.com/vpenades/SharpGLTF/master/build/Icons/glTF2Sharp.png</PackageIconUrl>
-  </PropertyGroup>
+    <DebugSymbols>true</DebugSymbols>    
+  </PropertyGroup>  
+  
+  <Import Project="..\Version.props" />
+  
+  <Import Project="..\PackageInfo.props" />
 
 
-  <ItemGroup>
-    <None Include="..\..\LICENSE" Pack="true" PackagePath="" />
-  </ItemGroup>
+  <PropertyGroup>
+    <DocumentationFile>bin\Docs\SharpGLTF.xml</DocumentationFile>
+  </PropertyGroup>  
 
 
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
@@ -32,11 +25,7 @@
     <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
     <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
       <_Parameter1>SharpGLTF.Tests</_Parameter1>
       <_Parameter1>SharpGLTF.Tests</_Parameter1>
     </AssemblyAttribute>    
     </AssemblyAttribute>    
-  </ItemGroup>
-
-  <PropertyGroup>
-    <DocumentationFile>bin\Docs\SharpGLTF.xml</DocumentationFile>
-  </PropertyGroup>
+  </ItemGroup>  
   
   
   <ItemGroup>    
   <ItemGroup>    
     <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />

+ 24 - 4
src/SharpGLTF.Core/Transforms/AffineTransform.cs

@@ -21,12 +21,12 @@ namespace SharpGLTF.Transforms
             return new AffineTransform(matrix, null, null, null);
             return new AffineTransform(matrix, null, null, null);
         }
         }
 
 
-        public static AffineTransform Create(Vector3? translation, Quaternion? rotation, Vector3? scale)
+        public static AffineTransform Create(Vector3? scale, Quaternion? rotation, Vector3? translation)
         {
         {
-            return new AffineTransform(null, translation, rotation, scale);
+            return new AffineTransform(null, scale, rotation, translation);
         }
         }
 
 
-        internal AffineTransform(Matrix4x4? matrix, Vector3? translation, Quaternion? rotation, Vector3? scale)
+        internal AffineTransform(Matrix4x4? matrix, Vector3? scale, Quaternion? rotation, Vector3? translation)
         {
         {
             if (matrix.HasValue)
             if (matrix.HasValue)
             {
             {
@@ -125,7 +125,7 @@ namespace SharpGLTF.Transforms
         {
         {
             if (transform.HasValue) return transform.Value;
             if (transform.HasValue) return transform.Value;
 
 
-            return new AffineTransform(null, translation, rotation, scale).Matrix;
+            return new AffineTransform(null, scale, rotation, translation).Matrix;
         }
         }
 
 
         public static Matrix4x4 LocalToWorld(Matrix4x4 parentWorld, Matrix4x4 childLocal)
         public static Matrix4x4 LocalToWorld(Matrix4x4 parentWorld, Matrix4x4 childLocal)
@@ -138,6 +138,26 @@ namespace SharpGLTF.Transforms
             return childWorld * parentWorld.Inverse();
             return childWorld * parentWorld.Inverse();
         }
         }
 
 
+        public static AffineTransform Blend(ReadOnlySpan<AffineTransform> transforms, ReadOnlySpan<float> weights)
+        {
+            var s = Vector3.Zero;
+            var r = default(Quaternion);
+            var t = Vector3.Zero;
+
+            for (int i = 0; i < transforms.Length; ++i)
+            {
+                var w = weights[i];
+
+                s += transforms[i].Scale * w;
+                r += transforms[i].Rotation * w;
+                t += transforms[i].Translation * w;
+            }
+
+            r = Quaternion.Normalize(r);
+
+            return AffineTransform.Create(s, r, t);
+        }
+
         #endregion
         #endregion
     }
     }
 }
 }

+ 14 - 0
src/SharpGLTF.Core/Transforms/SparseWeight8.cs

@@ -424,6 +424,20 @@ namespace SharpGLTF.Transforms
             yield return (Index7, Weight7);
             yield return (Index7, Weight7);
         }
         }
 
 
+        public static SparseWeight8 Blend(ReadOnlySpan<SparseWeight8> sparses, ReadOnlySpan<float> weight)
+        {
+            var r = default(SparseWeight8);
+
+            for (int i = 0; i < sparses.Length; ++i)
+            {
+                if (sparses[i].IsWeightless) continue;
+
+                r = Add(r, Multiply(sparses[i], weight[i]));
+            }
+
+            return r;
+        }
+
         public override string ToString()
         public override string ToString()
         {
         {
             var sb = new StringBuilder();
             var sb = new StringBuilder();

+ 2 - 2
src/SharpGLTF.Toolkit/Scenes/NodeBuilder.cs

@@ -91,7 +91,7 @@ namespace SharpGLTF.Scenes
                 ?
                 ?
                 Transforms.AffineTransform.Create(_Matrix.Value)
                 Transforms.AffineTransform.Create(_Matrix.Value)
                 :
                 :
-                Transforms.AffineTransform.Create(Translation?.Value, Rotation?.Value, Scale?.Value);
+                Transforms.AffineTransform.Create(Scale?.Value, Rotation?.Value, Translation?.Value);
             set
             set
             {
             {
                 Guard.IsTrue(value.IsValid, nameof(value));
                 Guard.IsTrue(value.IsValid, nameof(value));
@@ -306,7 +306,7 @@ namespace SharpGLTF.Scenes
             var rotation = Rotation?.GetValueAt(animationTrack, time);
             var rotation = Rotation?.GetValueAt(animationTrack, time);
             var translation = Translation?.GetValueAt(animationTrack, time);
             var translation = Translation?.GetValueAt(animationTrack, time);
 
 
-            return Transforms.AffineTransform.Create(translation, rotation, scale);
+            return Transforms.AffineTransform.Create(scale, rotation, translation);
         }
         }
 
 
         public Matrix4x4 GetWorldMatrix(string animationTrack, float time)
         public Matrix4x4 GetWorldMatrix(string animationTrack, float time)

+ 10 - 24
src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj

@@ -3,39 +3,25 @@
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <TargetFramework>netstandard2.0</TargetFramework>
     <AssemblyName>SharpGLTF.Toolkit</AssemblyName>
     <AssemblyName>SharpGLTF.Toolkit</AssemblyName>
-    <RootNamespace>SharpGLTF</RootNamespace>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
-    <PackageProjectUrl>https://github.com/vpenades/SharpGLTF</PackageProjectUrl>
-    <RepositoryUrl>https://github.com/vpenades/SharpGLTF</RepositoryUrl>
-    <RepositoryType>git</RepositoryType>
-    <Authors>Vicente Penades</Authors>
-    <Description>SharpGLTF.Toolkit extends SharpGLTF library with useful tools and helper classes.</Description>
-    <Copyright>Copyright (c) 2019 Vicente Penades</Copyright>
-    <PackageTags>C# glTF 3D</PackageTags>
-    <Version>1.0.0-alpha0011</Version>
+    <RootNamespace>SharpGLTF</RootNamespace>    
     <LangVersion>latest</LangVersion>
     <LangVersion>latest</LangVersion>
-    <DebugSymbols>true</DebugSymbols>
-    <PackageLicenseFile>LICENSE</PackageLicenseFile>
+    <DebugSymbols>true</DebugSymbols>    
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>    
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>    
   </PropertyGroup>
   </PropertyGroup>
 
 
-  <ItemGroup>
-    <None Include="..\..\LICENSE" Pack="true" PackagePath="" />
-  </ItemGroup>
+  <Import Project="..\Version.props" />
+
+  <Import Project="..\PackageInfo.props" />
+
+  <PropertyGroup>
+    <DocumentationFile>bin\Docs\SharpGLTF.Toolkit.xml</DocumentationFile>
+  </PropertyGroup>  
   
   
   <ItemGroup>
   <ItemGroup>
     <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
     <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
       <_Parameter1>SharpGLTF.Tests</_Parameter1>
       <_Parameter1>SharpGLTF.Tests</_Parameter1>
     </AssemblyAttribute>
     </AssemblyAttribute>
-  </ItemGroup>
-
-  <PropertyGroup>
-    <DocumentationFile>bin\Docs\SharpGLTF.Toolkit.xml</DocumentationFile>
-  </PropertyGroup>
-  
-  <PropertyGroup>    
-    <PackageIconUrl>https://raw.githubusercontent.com/vpenades/SharpGLTF/master/build/Icons/glTF2Sharp.png</PackageIconUrl>
-  </PropertyGroup>
+  </ItemGroup>  
   
   
   <ItemGroup>
   <ItemGroup>
     <AdditionalFiles Include="..\..\stylecop.json" />
     <AdditionalFiles Include="..\..\stylecop.json" />

+ 29 - 0
src/Version.props

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- https://andrewlock.net/version-vs-versionsuffix-vs-packageversion-what-do-they-all-mean/ -->
+  <!-- https://stackoverflow.com/questions/43019832/auto-versioning-in-visual-studio-2017-net-core -->
+  <!-- https://stackoverflow.com/questions/23533838/how-to-get-buildid-in-msbuild -->
+
+  <PropertyGroup>
+    <VersionPrefix>1.0.0</VersionPrefix>    
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+    <IncludeSymbols>true</IncludeSymbols>
+  </PropertyGroup>
+
+  <!--
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <VersionSuffix>dev-$([System.DateTime]::UtcNow.ToString(yyyyMMdd-HHmm))</VersionSuffix>
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' != 'Debug' ">
+    <VersionSuffix>preview-$([System.DateTime]::UtcNow.ToString(yyyyMMdd-HHmm))</VersionSuffix>
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+  </PropertyGroup>  
+  -->
+	
+</Project>

+ 32 - 0
src/build.cmd

@@ -0,0 +1,32 @@
+@echo off
+
+:: Check WMIC is available
+WMIC.EXE Alias /? >NUL 2>&1 || GOTO s_error
+
+:: Use WMIC to retrieve date and time
+FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
+   IF "%%~L"=="" goto s_done
+      Set _YYYY=%%L
+      Set _MM=00%%J
+      Set _DD=00%%G
+      Set _HOUR=00%%H
+      SET _MINUTE=00%%I
+)
+:s_done
+
+:: Pad digits with leading zeros
+      Set _MM=%_MM:~-2%
+      Set _DD=%_DD:~-2%
+      Set _HOUR=%_HOUR:~-2%
+      Set _MINUTE=%_MINUTE:~-2%
+
+:: Display the date/time in ISO 8601 format:
+Set _ISODATE=%_YYYY%-%_MM%-%_DD% %_HOUR%:%_MINUTE%
+Echo %_ISODATE%
+
+set VERSIONSUFFIX=Preview-%_YYYY%%_MM%%_DD%-%_HOUR%%_MINUTE%
+
+echo Building %VERSIONSUFFIX%
+
+dotnet build -c:Release --version-suffix %VERSIONSUFFIX% SharpGLTF.Core\SharpGLTF.Core.csproj
+dotnet build -c:Release --version-suffix %VERSIONSUFFIX% SharpGLTF.Toolkit\SharpGLTF.Toolkit.csproj