LoadSpecialModelsTest.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Numerics;
  5. using System.Text;
  6. using NUnit.Framework;
  7. namespace SharpGLTF.Schema2.LoadAndSave
  8. {
  9. /// <summary>
  10. /// Test cases for models found in <see href="https://github.com/KhronosGroup/glTF-Blender-Exporter"/>
  11. /// </summary>
  12. [TestFixture]
  13. [Category("Model Load and Save")]
  14. public class LoadSpecialModelsTest
  15. {
  16. #region setup
  17. [OneTimeSetUp]
  18. public void Setup()
  19. {
  20. // TestFiles.DownloadReferenceModels();
  21. }
  22. #endregion
  23. [Test]
  24. public void LoadEscapedUriModel()
  25. {
  26. TestContext.CurrentContext.AttachShowDirLink();
  27. var path = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets\\white space.gltf");
  28. var model = ModelRoot.Load(path);
  29. Assert.NotNull(model);
  30. model.AttachToCurrentTest("white space.glb");
  31. }
  32. public void LoadWithCustomImageLoader()
  33. {
  34. TestContext.CurrentContext.AttachShowDirLink();
  35. // load Polly model
  36. var model = ModelRoot.Load(TestFiles.GetPollyFileModelPath());
  37. }
  38. [Test(Description = "Example of traversing the visual tree all the way to individual vertices and indices")]
  39. public void LoadPollyModel()
  40. {
  41. TestContext.CurrentContext.AttachShowDirLink();
  42. // load Polly model
  43. var model = ModelRoot.Load(TestFiles.GetPollyFileModelPath(), Validation.ValidationMode.TryFix);
  44. Assert.NotNull(model);
  45. var triangles = model.DefaultScene
  46. .EvaluateTriangles<Geometry.VertexTypes.VertexPosition, Geometry.VertexTypes.VertexTexture1>(null, model.LogicalAnimations[0], 0.5f)
  47. .ToList();
  48. // Save as GLB, and also evaluate all triangles and save as Wavefront OBJ
  49. model.AttachToCurrentTest("polly_out.glb");
  50. model.AttachToCurrentTest("polly_out.obj");
  51. // hierarchically browse some elements of the model:
  52. var scene = model.DefaultScene;
  53. var pollyNode = scene.FindNode(n => n.Name == "Polly_Display");
  54. var pollyPrimitive = pollyNode.Mesh.Primitives[0];
  55. var pollyIndices = pollyPrimitive.GetIndices();
  56. var pollyPositions = pollyPrimitive.GetVertices("POSITION").AsVector3Array();
  57. var pollyNormals = pollyPrimitive.GetVertices("NORMAL").AsVector3Array();
  58. for (int i = 0; i < pollyIndices.Count; i += 3)
  59. {
  60. var a = (int)pollyIndices[i + 0];
  61. var b = (int)pollyIndices[i + 1];
  62. var c = (int)pollyIndices[i + 2];
  63. var ap = pollyPositions[a];
  64. var bp = pollyPositions[b];
  65. var cp = pollyPositions[c];
  66. var an = pollyNormals[a];
  67. var bn = pollyNormals[b];
  68. var cn = pollyNormals[c];
  69. TestContext.WriteLine($"Triangle {ap} {an} {bp} {bn} {cp} {cn}");
  70. }
  71. // create a clone and apply a global axis transform.
  72. var clonedModel = model.DeepClone();
  73. var basisTransform
  74. = Matrix4x4.CreateScale(1, 2, 1)
  75. * Matrix4x4.CreateFromYawPitchRoll(1, 2, 3)
  76. * Matrix4x4.CreateTranslation(10,5,2);
  77. clonedModel.ApplyBasisTransform(basisTransform);
  78. clonedModel.AttachToCurrentTest("polly_out_transformed.glb");
  79. var wsettings = new WriteSettings();
  80. wsettings.ImageWriting = ResourceWriteMode.BufferView;
  81. wsettings.MergeBuffers = true;
  82. wsettings.BuffersMaxSize = 1024 * 1024 * 10;
  83. clonedModel.AttachToCurrentTest("polly_out_merged_10mb.gltf", wsettings);
  84. }
  85. [Test]
  86. public void LoadUniVRM()
  87. {
  88. TestContext.CurrentContext.AttachShowDirLink();
  89. var path = TestFiles.GetUniVRMModelPath();
  90. var model = ModelRoot.Load(path);
  91. Assert.NotNull(model);
  92. var flattenExtensions = model.GatherUsedExtensions().ToArray();
  93. model.AttachToCurrentTest("AliceModel.glb");
  94. }
  95. // [Test]
  96. public void LoadShrekshaoModel()
  97. {
  98. TestContext.CurrentContext.AttachShowDirLink();
  99. var path = "Assets\\SpecialCases\\shrekshao.glb";
  100. var model = ModelRoot.Load(path);
  101. Assert.NotNull(model);
  102. }
  103. [Test]
  104. public void LoadMouseModel()
  105. {
  106. // this model has several nodes with curve animations containing a single animation key,
  107. // which is causing some problems to the interpolator.
  108. TestContext.CurrentContext.AttachShowDirLink();
  109. var path = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets\\SpecialCases\\mouse.glb");
  110. var model = ModelRoot.Load(path);
  111. var boundingSphere = Runtime.MeshDecoder.EvaluateBoundingSphere(model.DefaultScene);
  112. var sampler = model
  113. .LogicalNodes[5]
  114. .GetCurveSamplers(model.LogicalAnimations[1])
  115. .Rotation
  116. .CreateCurveSampler(true);
  117. var node5_R_00 = sampler.GetPoint(0);
  118. var node5_R_01 = sampler.GetPoint(1);
  119. Assert.AreEqual(node5_R_00, node5_R_01);
  120. model.AttachToCurrentTest("mouse_00.obj", model.LogicalAnimations[1], 0f);
  121. model.AttachToCurrentTest("mouse_01.obj", model.LogicalAnimations[1], 1f);
  122. }
  123. [TestCase("SketchfabExport-WhatIsPBR.glb")] // model has exported tangents in the form <0,0,0,1>
  124. public void LoadSketchfabModels(string path)
  125. {
  126. // this model has several nodes with curve animations containing a single animation key,
  127. // which is causing some problems to the interpolator.
  128. TestContext.CurrentContext.AttachShowDirLink();
  129. path = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, $"Assets\\SpecialCases\\{path}");
  130. var model = ModelRoot.Load(path, Validation.ValidationMode.TryFix);
  131. model.AttachToCurrentTest("output.glb");
  132. }
  133. // these models show normal mapping but lack tangents, which are expected to be
  134. // generated at runtime; These tests generate the tangents and check them against the baseline.
  135. [TestCase("NormalTangentTest.glb")]
  136. [TestCase("NormalTangentMirrorTest.glb")]
  137. public void LoadGeneratedTangetsTest(string fileName)
  138. {
  139. TestContext.CurrentContext.AttachShowDirLink();
  140. var path = TestFiles.GetSampleModelsPaths().FirstOrDefault(item => item.EndsWith(fileName));
  141. var model = ModelRoot.Load(path);
  142. var mesh = model.DefaultScene
  143. .EvaluateTriangles<Geometry.VertexTypes.VertexPositionNormalTangent, Geometry.VertexTypes.VertexTexture1>()
  144. .ToMeshBuilder( m => m.ToMaterialBuilder() );
  145. var editableScene = new Scenes.SceneBuilder();
  146. editableScene.AddRigidMesh(mesh, Matrix4x4.Identity);
  147. model.AttachToCurrentTest("original.glb");
  148. editableScene.ToGltf2().AttachToCurrentTest("WithTangents.glb");
  149. }
  150. [Test]
  151. public void LoadAndSaveToMemory()
  152. {
  153. var path = TestFiles.GetSampleModelsPaths().FirstOrDefault(item => item.EndsWith("Avocado.glb"));
  154. var model = ModelRoot.Load(path);
  155. // model.LogicalImages[0].TransferToSatelliteFile(); // TODO
  156. // we will use this dictionary as our in-memory model container.
  157. var dictionary = new Dictionary<string, ArraySegment<Byte>>();
  158. // write to dictionary
  159. var wcontext = WriteContext.CreateFromDictionary(dictionary);
  160. model.Save("avocado.gltf", wcontext);
  161. Assert.IsTrue(dictionary.ContainsKey("avocado.gltf"));
  162. Assert.IsTrue(dictionary.ContainsKey("avocado.bin"));
  163. // read back from dictionary
  164. var rcontext = ReadContext.CreateFromDictionary(dictionary);
  165. var model2 = ModelRoot.Load("avocado.gltf", rcontext);
  166. // TODO: verify
  167. }
  168. }
  169. }