babylon.sceneLoader.tests.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**
  2. * Describes the test suite.
  3. */
  4. describe('Babylon Scene Loader', function () {
  5. let subject: BABYLON.Engine;
  6. this.timeout(10000);
  7. /**
  8. * Loads the dependencies.
  9. */
  10. before(function (done) {
  11. this.timeout(180000);
  12. (BABYLONDEVTOOLS).Loader
  13. .useDist()
  14. .load(function () {
  15. // Force apply promise polyfill for consistent behavior between PhantomJS, IE11, and other browsers.
  16. BABYLON.PromisePolyfill.Apply(true);
  17. done();
  18. });
  19. });
  20. /**
  21. * Create a new engine subject before each test.
  22. */
  23. beforeEach(function () {
  24. subject = new BABYLON.NullEngine({
  25. renderHeight: 256,
  26. renderWidth: 256,
  27. textureSize: 256,
  28. deterministicLockstep: false,
  29. lockstepMaxSteps: 1
  30. });
  31. // Avoid creating normals in PBR materials.
  32. subject.getCaps().standardDerivatives = true;
  33. });
  34. /**
  35. * Integration tests for loading glTF assets.
  36. */
  37. describe('#glTF', () => {
  38. it('Load BoomBox', () => {
  39. const scene = new BABYLON.Scene(subject);
  40. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(scene => {
  41. expect(scene.meshes.length, "scene.meshes.length").to.equal(2);
  42. expect(scene.materials.length, "scene.materials.length").to.equal(1);
  43. });
  44. });
  45. it('Load BoomBox GLB', () => {
  46. const scene = new BABYLON.Scene(subject);
  47. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/", "BoomBox.glb", scene).then(scene => {
  48. expect(scene.meshes.length, "scene.meshes.length").to.equal(2);
  49. expect(scene.materials.length, "scene.materials.length").to.equal(1);
  50. });
  51. });
  52. it('Load BoomBox with ImportMesh', () => {
  53. const scene = new BABYLON.Scene(subject);
  54. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(result => {
  55. expect(result.meshes.length, "meshes.length").to.equal(scene.meshes.length);
  56. expect(result.particleSystems.length, "particleSystems.length").to.equal(0);
  57. expect(result.skeletons.length, "skeletons.length").to.equal(0);
  58. });
  59. });
  60. it('Load BoomBox with callbacks', () => {
  61. let parsedCount = 0;
  62. let meshCount = 0;
  63. let materialCount = 0;
  64. let textureCounts: { [name: string]: number } = {};
  65. let ready = false;
  66. const promises = new Array<Promise<void>>();
  67. BABYLON.SceneLoader.OnPluginActivatedObservable.add((loader: BABYLON.GLTFFileLoader) => {
  68. loader.onParsed = data => {
  69. parsedCount++;
  70. };
  71. loader.onMeshLoaded = mesh => {
  72. meshCount++;
  73. };
  74. loader.onMaterialLoaded = material => {
  75. materialCount++;
  76. };
  77. loader.onTextureLoaded = texture => {
  78. textureCounts[texture.name] = textureCounts[texture.name] || 0;
  79. textureCounts[texture.name]++;
  80. };
  81. promises.push(loader.whenCompleteAsync().then(() => {
  82. expect(ready, "ready").to.be.true;
  83. }));
  84. }, undefined, undefined, undefined, true);
  85. const scene = new BABYLON.Scene(subject);
  86. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(() => {
  87. ready = true;
  88. expect(parsedCount, "parsedCount").to.equal(1);
  89. expect(meshCount, "meshCount").to.equal(scene.meshes.length);
  90. expect(materialCount, "materialCount").to.equal(scene.materials.length);
  91. const expectedTextureLoadCounts = {
  92. "baseColor": 1,
  93. "occlusionRoughnessMetallic": 2,
  94. "normal": 1,
  95. "emissive": 1
  96. };
  97. expect(Object.keys(textureCounts), "Object.keys(textureCounts)").to.have.lengthOf(Object.keys(expectedTextureLoadCounts).length);
  98. for (const textureName in expectedTextureLoadCounts) {
  99. expect(textureCounts, "textureCounts").to.have.property(textureName, expectedTextureLoadCounts[textureName]);
  100. }
  101. }));
  102. return Promise.all(promises);
  103. });
  104. it('Load BoomBox with dispose', () => {
  105. let ready = false;
  106. let disposed = false;
  107. const promises = new Array<Promise<void>>();
  108. BABYLON.SceneLoader.OnPluginActivatedObservable.add((loader: BABYLON.GLTFFileLoader) => {
  109. loader.onDispose = () => {
  110. disposed = true;
  111. };
  112. promises.push(BABYLON.Tools.DelayAsync(50).then(() => {
  113. loader.dispose();
  114. expect(ready, "ready").to.be.false;
  115. expect(disposed, "disposed").to.be.true;
  116. }));
  117. }, undefined, undefined, undefined, true);
  118. const scene = new BABYLON.Scene(subject);
  119. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox2.gltf", scene).then(() => {
  120. ready = true;
  121. }));
  122. return Promise.race(promises);
  123. });
  124. it('Load BoomBox with rootMesh.isEnabled check', () => {
  125. const scene = new BABYLON.Scene(subject);
  126. let rootMesh: BABYLON.AbstractMesh;
  127. subject.runRenderLoop(() => {
  128. if (!rootMesh) {
  129. for (const mesh of scene.meshes) {
  130. if (!mesh.parent) {
  131. rootMesh = mesh;
  132. break;
  133. }
  134. }
  135. }
  136. if (rootMesh) {
  137. expect(rootMesh.isEnabled(), "rootMesh.isEnabled").to.be.false;
  138. }
  139. });
  140. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(scene => {
  141. expect(rootMesh.isEnabled(), "rootMesh.isEnabled").to.be.true;
  142. subject.stopRenderLoop();
  143. });
  144. });
  145. it('Load CompileMaterialsTest', () => {
  146. const scene = new BABYLON.Scene(subject);
  147. const promises = new Array<Promise<void>>();
  148. let createShaderProgramSpy: sinon.SinonSpy;
  149. subject.runRenderLoop(() => {
  150. for (const mesh of scene.meshes) {
  151. if (mesh.material && mesh.isEnabled()) {
  152. expect(mesh.material.isReady(mesh), "mesh material is ready").to.be.true;
  153. }
  154. }
  155. });
  156. BABYLON.SceneLoader.OnPluginActivatedObservable.add((loader: BABYLON.GLTFFileLoader) => {
  157. loader.compileMaterials = true;
  158. promises.push(loader.whenCompleteAsync().then(() => {
  159. try {
  160. expect(createShaderProgramSpy.called, "createShaderProgramSpy.called").to.be.false;
  161. }
  162. finally {
  163. createShaderProgramSpy.restore();
  164. }
  165. }));
  166. }, undefined, undefined, undefined, true);
  167. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/CompileMaterialsTest/", "Test.gltf", scene).then(() => {
  168. createShaderProgramSpy = sinon.spy(subject, "createShaderProgram");
  169. }));
  170. return Promise.all(promises);
  171. });
  172. it('Load Alien', () => {
  173. const scene = new BABYLON.Scene(subject);
  174. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/Alien/", "Alien.gltf", scene).then(result => {
  175. expect(result.skeletons.length, "skeletons.length").to.equal(scene.skeletons.length);
  176. const mapping = {
  177. "AlienHead": "skeleton0",
  178. "Collar": "skeleton1",
  179. "LeftEye": "skeleton2",
  180. "RightEye": "skeleton3",
  181. "CollarClasp": "skeleton1",
  182. "Shirt": "skeleton1",
  183. "ShirtPlate": "skeleton1",
  184. "Teeth": "skeleton1",
  185. };
  186. for (const meshName in mapping) {
  187. const skeletonName = mapping[meshName];
  188. expect(scene.getMeshByName(meshName).skeleton.name, `skeleton name of mesh '${meshName}'`).to.equal(skeletonName);
  189. }
  190. });
  191. });
  192. it('Load TwoQuads with LODs', () => {
  193. const scene = new BABYLON.Scene(subject);
  194. const promises = new Array<Promise<void>>();
  195. subject.runRenderLoop(() => {
  196. for (const mesh of scene.meshes) {
  197. if (mesh.material && mesh.isEnabled()) {
  198. expect(mesh.material.isReady(mesh), "mesh material is ready").to.be.true;
  199. }
  200. }
  201. });
  202. BABYLON.SceneLoader.OnPluginActivatedObservable.add((loader: BABYLON.GLTFFileLoader) => {
  203. loader.compileMaterials = true;
  204. promises.push(loader.whenCompleteAsync().then(() => {
  205. const meshes = [
  206. scene.getMeshByName("node0"),
  207. scene.getMeshByName("node1")
  208. ];
  209. expect(meshes[0].material.name, "Material for node 0").to.equal("LOD0");
  210. expect(meshes[1].material.name, "Material for node 1").to.equal("LOD0");
  211. expect(scene.materials, "scene.materials").to.have.lengthOf(1);
  212. const materials = [
  213. scene.getMaterialByName("LOD0")
  214. ];
  215. expect(materials[0].isReady(meshes[0]), "Material of LOD 0 is ready for node 0").to.be.true;
  216. expect(materials[0].isReady(meshes[1]), "Material of LOD 0 is ready for node 1").to.be.true;
  217. }));
  218. }, undefined, undefined, undefined, true);
  219. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/TwoQuads/", "TwoQuads.gltf", scene).then(() => {
  220. const meshes = [
  221. scene.getMeshByName("node0"),
  222. scene.getMeshByName("node1")
  223. ];
  224. expect(meshes[0].material.name, "Material for node 0").to.equal("LOD2");
  225. expect(meshes[1].material.name, "Material for node 1").to.equal("LOD2");
  226. expect(scene.materials, "scene.materials").to.have.lengthOf(3);
  227. const materials = [
  228. scene.getMaterialByName("LOD0"),
  229. scene.getMaterialByName("LOD1"),
  230. scene.getMaterialByName("LOD2")
  231. ];
  232. expect(materials[0].isReady(meshes[0]), "Material of LOD 0 is ready for node 0").to.be.false;
  233. expect(materials[0].isReady(meshes[1]), "Material of LOD 0 is ready for node 1").to.be.false;
  234. expect(materials[1].isReady(meshes[0]), "Material of LOD 1 is ready for node 0").to.be.false;
  235. expect(materials[1].isReady(meshes[1]), "Material of LOD 1 is ready for node 1").to.be.false;
  236. expect(materials[2].isReady(meshes[0]), "Material of LOD 2 is ready for node 0").to.be.true;
  237. expect(materials[2].isReady(meshes[1]), "Material of LOD 2 is ready for node 1").to.be.true;
  238. }));
  239. return Promise.all(promises);
  240. });
  241. // TODO: test animation group callback
  242. // TODO: test material instancing
  243. // TODO: test ImportMesh with specific node name
  244. // TODO: test KHR_materials_pbrSpecularGlossiness
  245. // TODO: test KHR_lights
  246. });
  247. describe('#AssetContainer', () => {
  248. it('should be loaded from BoomBox GLTF', () => {
  249. var scene = new BABYLON.Scene(subject);
  250. return BABYLON.SceneLoader.LoadAssetContainerAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(container => {
  251. expect(container.meshes.length).to.eq(2);
  252. });
  253. });
  254. it('should be adding and removing objects from scene', () => {
  255. // Create a scene with some assets
  256. var scene = new BABYLON.Scene(subject);
  257. var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
  258. var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
  259. var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
  260. var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
  261. // Move all the assets from the scene into a container
  262. var container = new BABYLON.AssetContainer(scene);
  263. var keepAssets = new BABYLON.KeepAssets();
  264. keepAssets.cameras.push(camera);
  265. container.moveAllFromScene(keepAssets);
  266. expect(scene.cameras.length).to.eq(1);
  267. expect(scene.meshes.length).to.eq(0);
  268. expect(scene.lights.length).to.eq(0);
  269. expect(container.cameras.length).to.eq(0);
  270. expect(container.meshes.length).to.eq(2);
  271. expect(container.lights.length).to.eq(1);
  272. // Add them back and then remove again
  273. container.addAllToScene();
  274. expect(scene.cameras.length).to.eq(1);
  275. expect(scene.meshes.length).to.eq(2);
  276. expect(scene.lights.length).to.eq(1);
  277. container.removeAllFromScene();
  278. expect(scene.cameras.length).to.eq(1);
  279. expect(scene.meshes.length).to.eq(0);
  280. expect(scene.lights.length).to.eq(0);
  281. });
  282. });
  283. });