babylon.sceneLoader.tests.ts 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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. .testMode()
  15. .load(function() {
  16. // Force apply promise polyfill for consistent behavior between chrome headless, IE11, and other browsers.
  17. BABYLON.PromisePolyfill.Apply(true);
  18. BABYLON.Engine.audioEngine = new BABYLON.AudioEngine();
  19. done();
  20. });
  21. });
  22. /**
  23. * Create a new engine subject before each test.
  24. */
  25. beforeEach(function() {
  26. subject = new BABYLON.NullEngine({
  27. renderHeight: 256,
  28. renderWidth: 256,
  29. textureSize: 256,
  30. deterministicLockstep: false,
  31. lockstepMaxSteps: 1
  32. });
  33. // Avoid creating normals in PBR materials.
  34. subject.getCaps().standardDerivatives = true;
  35. });
  36. /**
  37. * Integration tests for loading glTF assets.
  38. */
  39. describe('#glTF', () => {
  40. it('Load BoomBox', () => {
  41. const scene = new BABYLON.Scene(subject);
  42. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then((scene) => {
  43. expect(scene.meshes.length, "scene.meshes.length").to.equal(2);
  44. expect(scene.materials.length, "scene.materials.length").to.equal(1);
  45. });
  46. });
  47. it('Load BoomBox GLB', () => {
  48. const scene = new BABYLON.Scene(subject);
  49. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/", "BoomBox.glb", scene).then((scene) => {
  50. expect(scene.meshes.length, "scene.meshes.length").to.equal(2);
  51. expect(scene.materials.length, "scene.materials.length").to.equal(1);
  52. });
  53. });
  54. it('Load BoomBox with ImportMesh', () => {
  55. const scene = new BABYLON.Scene(subject);
  56. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then((result) => {
  57. expect(result.meshes.length, "meshes.length").to.equal(scene.meshes.length);
  58. expect(result.particleSystems.length, "particleSystems.length").to.equal(0);
  59. expect(result.skeletons.length, "skeletons.length").to.equal(0);
  60. expect(result.animationGroups.length, "animationGroups.length").to.equal(0);
  61. });
  62. });
  63. it('Load TwoQuads with ImportMesh and one node name', () => {
  64. const scene = new BABYLON.Scene(subject);
  65. return BABYLON.SceneLoader.ImportMeshAsync("node0", "http://models.babylonjs.com/Tests/TwoQuads/", "TwoQuads.gltf", scene).then(() => {
  66. expect(scene.getMeshByName("node0"), "node0").to.exist;
  67. expect(scene.getMeshByName("node1"), "node1").to.not.exist;
  68. });
  69. });
  70. it('Load TwoQuads with ImportMesh and two node names', () => {
  71. const scene = new BABYLON.Scene(subject);
  72. return BABYLON.SceneLoader.ImportMeshAsync(["node0", "node1"], "http://models.babylonjs.com/Tests/TwoQuads/", "TwoQuads.gltf", scene).then(() => {
  73. expect(scene.getMeshByName("node0"), "node0").to.exist;
  74. expect(scene.getMeshByName("node1"), "node1").to.exist;
  75. });
  76. });
  77. it('Load BoomBox with callbacks', () => {
  78. let parsedCount = 0;
  79. let meshCount = 0;
  80. let materialCount = 0;
  81. let textureCount = 0;
  82. let ready = false;
  83. const promises = new Array<Promise<void>>();
  84. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  85. loader.onParsed = (data) => {
  86. parsedCount++;
  87. };
  88. loader.onMeshLoaded = (mesh) => {
  89. meshCount++;
  90. };
  91. loader.onMaterialLoaded = (material) => {
  92. materialCount++;
  93. };
  94. loader.onTextureLoaded = (texture) => {
  95. textureCount++;
  96. };
  97. promises.push(loader.whenCompleteAsync().then(() => {
  98. expect(ready, "ready").to.be.true;
  99. }));
  100. });
  101. const scene = new BABYLON.Scene(subject);
  102. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(() => {
  103. ready = true;
  104. expect(parsedCount, "parsedCount").to.equal(1);
  105. expect(meshCount, "meshCount").to.equal(scene.meshes.length);
  106. expect(materialCount, "materialCount").to.equal(scene.materials.length);
  107. const filteredTextures = scene.textures.filter((texture) => texture !== scene.environmentBRDFTexture);
  108. expect(textureCount, "textureCount").to.equal(filteredTextures.length);
  109. }));
  110. return Promise.all(promises);
  111. });
  112. it('Load BoomBox with dispose', () => {
  113. let ready = false;
  114. let disposed = false;
  115. const promises = new Array<Promise<void>>();
  116. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  117. loader.onDispose = () => {
  118. disposed = true;
  119. };
  120. promises.push(BABYLON.Tools.DelayAsync(1).then(() => {
  121. loader.dispose();
  122. expect(ready, "ready").to.be.false;
  123. expect(disposed, "disposed").to.be.true;
  124. }));
  125. });
  126. const scene = new BABYLON.Scene(subject);
  127. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(() => {
  128. ready = true;
  129. }));
  130. return Promise.race(promises);
  131. });
  132. it('Load BoomBox with mesh.isEnabled check', () => {
  133. const scene = new BABYLON.Scene(subject);
  134. subject.runRenderLoop(() => {
  135. for (const mesh of scene.meshes) {
  136. if (mesh.getTotalVertices() !== 0) {
  137. expect(mesh.isEnabled(), "mesh.isEnabled").to.be.false;
  138. }
  139. }
  140. });
  141. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then((scene) => {
  142. subject.stopRenderLoop();
  143. for (const mesh of scene.meshes) {
  144. if (mesh.getTotalVertices() !== 0) {
  145. expect(mesh.isEnabled(), "mesh.isEnabled").to.be.true;
  146. }
  147. }
  148. });
  149. });
  150. it('Load CompileMaterials', () => {
  151. const scene = new BABYLON.Scene(subject);
  152. const promises = new Array<Promise<void>>();
  153. let createShaderProgramSpy: sinon.SinonSpy;
  154. subject.runRenderLoop(() => {
  155. for (const mesh of scene.meshes) {
  156. if (mesh.material && mesh.isEnabled()) {
  157. expect(mesh.isReady(true), "mesh is ready").to.be.true;
  158. }
  159. }
  160. });
  161. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  162. loader.compileMaterials = true;
  163. promises.push(loader.whenCompleteAsync().then(() => {
  164. const called = createShaderProgramSpy.called;
  165. createShaderProgramSpy.restore();
  166. expect(called, "createShaderProgramCalled").to.be.false;
  167. }));
  168. });
  169. promises.push(BABYLON.SceneLoader.AppendAsync("http://models.babylonjs.com/Tests/CompileMaterials/", "Test.gltf", scene).then(() => {
  170. createShaderProgramSpy = sinon.spy(subject, "createShaderProgram");
  171. }));
  172. return Promise.all(promises);
  173. });
  174. it('Load BrainStem with compileMaterials', () => {
  175. const scene = new BABYLON.Scene(subject);
  176. const promises = new Array<Promise<void>>();
  177. let createShaderProgramSpy: sinon.SinonSpy;
  178. subject.runRenderLoop(() => {
  179. for (const mesh of scene.meshes) {
  180. if (mesh.material && mesh.isEnabled()) {
  181. expect(mesh.isReady(true), "mesh is ready").to.be.true;
  182. }
  183. }
  184. });
  185. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  186. loader.compileMaterials = true;
  187. promises.push(loader.whenCompleteAsync().then(() => {
  188. const called = createShaderProgramSpy.called;
  189. createShaderProgramSpy.restore();
  190. expect(called, "createShaderProgramCalled").to.be.false;
  191. }));
  192. });
  193. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BrainStem/", "BrainStem.gltf", scene).then(() => {
  194. createShaderProgramSpy = sinon.spy(subject, "createShaderProgram");
  195. }));
  196. return Promise.all(promises);
  197. });
  198. it('Load Alien', () => {
  199. const scene = new BABYLON.Scene(subject);
  200. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/Alien/", "Alien.gltf", scene).then((result) => {
  201. const skeletonsMapping = {
  202. "AlienHead": "skeleton0",
  203. "Collar": "skeleton1",
  204. "LeftEye": "skeleton2",
  205. "RightEye": "skeleton3",
  206. "CollarClasp": "skeleton1",
  207. "Shirt": "skeleton1",
  208. "ShirtPlate": "skeleton1",
  209. "Teeth": "skeleton1",
  210. };
  211. expect(scene.skeletons, "scene.skeletons").to.have.lengthOf(4);
  212. expect(result.skeletons, "skeletons").to.have.lengthOf(4);
  213. for (const meshName in skeletonsMapping) {
  214. const skeletonName = skeletonsMapping[meshName];
  215. expect(scene.getMeshByName(meshName).skeleton.name, `skeleton name of mesh '${meshName}'`).to.equal(skeletonName);
  216. }
  217. const alienHeadMesh = scene.getMeshByName("AlienHead") as BABYLON.Mesh;
  218. expect(alienHeadMesh.morphTargetManager.numTargets, "alienHeadMesh.morphTargetManager.numTargets").to.equal(2);
  219. expect(scene.animationGroups, "scene.animationGroups").to.have.lengthOf(1);
  220. expect(result.animationGroups, "animationGroups").to.have.lengthOf(1);
  221. const animationGroup = result.animationGroups[0];
  222. expect(animationGroup.name, "animationGroup.name").to.equal("TwoTargetBlend");
  223. expect(animationGroup.targetedAnimations, "animationGroup.targetedAnimations").to.have.lengthOf(7);
  224. const influenceAnimations = animationGroup.targetedAnimations.filter((_) => _.animation.targetProperty === "influence");
  225. expect(influenceAnimations, "influenceAnimations").to.have.lengthOf(2);
  226. const rotationAnimations = animationGroup.targetedAnimations.filter((_) => _.animation.targetProperty === "rotationQuaternion");
  227. expect(rotationAnimations, "rotationAnimations").to.have.lengthOf(4);
  228. const positionAnimations = animationGroup.targetedAnimations.filter((_) => _.animation.targetProperty === "position");
  229. expect(positionAnimations, "positionAnimations").to.have.lengthOf(1);
  230. });
  231. });
  232. it('Load LevelOfDetail', () => {
  233. const scene = new BABYLON.Scene(subject);
  234. const promises = new Array<Promise<void>>();
  235. subject.runRenderLoop(() => {
  236. for (const mesh of scene.meshes) {
  237. if (mesh.material && mesh.isEnabled()) {
  238. expect(mesh.isReady(true), "mesh is ready").to.be.true;
  239. }
  240. }
  241. });
  242. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  243. loader.compileMaterials = true;
  244. promises.push(loader.whenCompleteAsync().then(() => {
  245. const meshes = [
  246. scene.getMeshByName("node0"),
  247. scene.getMeshByName("node1")
  248. ];
  249. expect(meshes[0].material.name, "Material for node 0").to.equal("High");
  250. expect(meshes[1].material.name, "Material for node 1").to.equal("High");
  251. expect(scene.materials, "scene.materials").to.have.lengthOf(1);
  252. }));
  253. });
  254. promises.push(BABYLON.SceneLoader.AppendAsync("http://models.babylonjs.com/Tests/LevelOfDetail/", `LevelOfDetail.gltf`, scene).then(() => {
  255. const meshes = [
  256. scene.getMeshByName("node0"),
  257. scene.getMeshByName("node1")
  258. ];
  259. expect(meshes[0].material.name, "Material for node 0").to.equal("Low");
  260. expect(meshes[1].material.name, "Material for node 1").to.equal("Low");
  261. expect(scene.materials, "scene.materials").to.have.lengthOf(3);
  262. const materialLow = scene.getMaterialByName("Low");
  263. const materialMedium = scene.getMaterialByName("Medium");
  264. const materialHigh = scene.getMaterialByName("High");
  265. expect(materialLow.isReady(meshes[0]), "Material 'Low' is ready for node 0").to.be.true;
  266. expect(materialLow.isReady(meshes[1]), "Material 'Low' is ready for node 1").to.be.true;
  267. expect(materialMedium.isReady(meshes[0]), "Material 'Medium' is ready for node 0").to.be.true;
  268. expect(materialMedium.isReady(meshes[1]), "Material 'Medium' is ready for node 1").to.be.true;
  269. expect(materialHigh.isReady(meshes[0]), "Material 'High' is ready for node 0").to.be.true;
  270. expect(materialHigh.isReady(meshes[1]), "Material 'High' is ready for node 1").to.be.true;
  271. }));
  272. return Promise.all(promises);
  273. });
  274. it('Load LevelOfDetail with onMaterialLODsLoadedObservable', () => {
  275. const scene = new BABYLON.Scene(subject);
  276. const promises = new Array<Promise<void>>();
  277. const materialNames = [ "Low", "Medium", "High" ];
  278. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  279. const observer = loader.onExtensionLoadedObservable.add((extension) => {
  280. if (extension instanceof BABYLON.GLTF2.Loader.Extensions.MSFT_lod) {
  281. loader.onExtensionLoadedObservable.remove(observer);
  282. extension.onMaterialLODsLoadedObservable.add((indexLOD) => {
  283. const expectedMaterialName = materialNames[indexLOD];
  284. expect(scene.getMeshByName("node0").material.name, "Material for node 0").to.equal(expectedMaterialName);
  285. expect(scene.getMeshByName("node1").material.name, "Material for node 1").to.equal(expectedMaterialName);
  286. });
  287. }
  288. });
  289. promises.push(loader.whenCompleteAsync());
  290. });
  291. promises.push(BABYLON.SceneLoader.AppendAsync("http://models.babylonjs.com/Tests/LevelOfDetail/", "LevelOfDetail.gltf", scene).then(() => {
  292. // do nothing
  293. }));
  294. return Promise.all(promises);
  295. });
  296. it('Load LevelOfDetail with dispose when onMaterialLODsLoadedObservable', () => {
  297. const scene = new BABYLON.Scene(subject);
  298. const promises = new Array<Promise<void>>();
  299. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  300. const observer = loader.onExtensionLoadedObservable.add((extension) => {
  301. if (extension instanceof BABYLON.GLTF2.Loader.Extensions.MSFT_lod) {
  302. loader.onExtensionLoadedObservable.remove(observer);
  303. extension.onMaterialLODsLoadedObservable.add((indexLOD) => {
  304. expect(indexLOD, "indexLOD").to.equal(0);
  305. loader.dispose();
  306. });
  307. }
  308. });
  309. promises.push(new Promise((resolve) => {
  310. loader.onDisposeObservable.addOnce(() => {
  311. resolve();
  312. });
  313. }));
  314. });
  315. promises.push(BABYLON.SceneLoader.AppendAsync("http://models.babylonjs.com/Tests/LevelOfDetail/", "LevelOfDetail.gltf", scene).then(() => {
  316. // do nothing
  317. }));
  318. return Promise.all(promises);
  319. });
  320. it('Load LevelOfDetailNoTextures', () => {
  321. const scene = new BABYLON.Scene(subject);
  322. const promises = new Array<Promise<any>>();
  323. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  324. promises.push(loader.whenCompleteAsync());
  325. });
  326. promises.push(BABYLON.SceneLoader.AppendAsync("http://models.babylonjs.com/Tests/LevelOfDetail/", "LevelOfDetailNoTextures.gltf", scene));
  327. return Promise.all(promises);
  328. });
  329. it('Load LevelOfDetail with useRangeRequests', () => {
  330. const scene = new BABYLON.Scene(subject);
  331. const promises = new Array<Promise<void>>();
  332. const expectedSetRequestHeaderCalls = [
  333. "Range: bytes=0-19",
  334. "Range: bytes=20-1399",
  335. "Range: bytes=1400-1817",
  336. "Range: bytes=1820-3149",
  337. "Range: bytes=3152-8841",
  338. ];
  339. const setRequestHeaderCalls = new Array<string>();
  340. const origSetRequestHeader = BABYLON.WebRequest.prototype.setRequestHeader;
  341. const setRequestHeaderStub = sinon.stub(BABYLON.WebRequest.prototype, "setRequestHeader").callsFake(function(...args) {
  342. setRequestHeaderCalls.push(args.join(": "));
  343. origSetRequestHeader.apply(this, args);
  344. });
  345. // Simulate default CORS policy on some web servers that reject getResponseHeader calls with `Content-Range`.
  346. const origGetResponseHeader = BABYLON.WebRequest.prototype.getResponseHeader;
  347. const getResponseHeaderStub = sinon.stub(BABYLON.WebRequest.prototype, "getResponseHeader").callsFake(function(...args) {
  348. return (args[0] === "Content-Range") ? null : origGetResponseHeader.apply(this, args);
  349. });
  350. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  351. loader.useRangeRequests = true;
  352. promises.push(loader.whenCompleteAsync());
  353. });
  354. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/", "LevelOfDetail.glb", scene).then(() => {
  355. expect(setRequestHeaderCalls, "setRequestHeaderCalls").to.have.ordered.members(expectedSetRequestHeaderCalls);
  356. setRequestHeaderStub.restore();
  357. getResponseHeaderStub.restore();
  358. }));
  359. return Promise.all(promises);
  360. });
  361. it('Load MultiPrimitive', () => {
  362. const scene = new BABYLON.Scene(subject);
  363. return BABYLON.SceneLoader.ImportMeshAsync(null, "http://models.babylonjs.com/Tests/MultiPrimitive/", "MultiPrimitive.gltf", scene).then((result) => {
  364. expect(result.meshes, "meshes").to.have.lengthOf(3);
  365. const node = scene.getNodeByName("node");
  366. expect(node, "node").to.exist;
  367. expect(node, "node").to.be.an.instanceof(BABYLON.TransformNode);
  368. expect(node.getChildren(), "node children").to.have.lengthOf(2);
  369. for (const childNode of node.getChildren()) {
  370. expect(childNode, "child node").to.be.an.instanceof(BABYLON.Mesh);
  371. const childMesh = childNode as BABYLON.Mesh;
  372. expect(childMesh.geometry).to.exist;
  373. expect(childMesh.material).to.exist;
  374. }
  375. });
  376. });
  377. it('Load BrainStem', () => {
  378. const scene = new BABYLON.Scene(subject);
  379. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/BrainStem/", "BrainStem.gltf", scene).then((result) => {
  380. expect(result.skeletons, "skeletons").to.have.lengthOf(1);
  381. const node1 = scene.getNodeByName("node1");
  382. expect(node1, "node1").to.exist;
  383. expect(node1, "node1").to.be.an.instanceof(BABYLON.TransformNode);
  384. for (const childMesh of node1.getChildMeshes()) {
  385. expect(childMesh.skeleton, "mesh skeleton").to.exist;
  386. expect(childMesh.skeleton.name, "mesh skeleton name").to.equal(result.skeletons[0].name);
  387. }
  388. });
  389. });
  390. it('Load BoomBox with transparencyAsCoverage', () => {
  391. const scene = new BABYLON.Scene(subject);
  392. const promises = new Array<Promise<any>>();
  393. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  394. var specularOverAlpha = false;
  395. var radianceOverAlpha = false;
  396. loader.transparencyAsCoverage = true;
  397. loader.onMaterialLoaded = (material) => {
  398. specularOverAlpha = specularOverAlpha || (material as BABYLON.PBRMaterial).useSpecularOverAlpha;
  399. radianceOverAlpha = radianceOverAlpha || (material as BABYLON.PBRMaterial).useRadianceOverAlpha;
  400. };
  401. promises.push(loader.whenCompleteAsync().then(() => {
  402. expect(specularOverAlpha, "specularOverAlpha").to.be.false;
  403. expect(radianceOverAlpha, "radianceOverAlpha").to.be.false;
  404. }));
  405. });
  406. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene));
  407. return Promise.all(promises);
  408. });
  409. it('Load BoomBox without transparencyAsCoverage', () => {
  410. const scene = new BABYLON.Scene(subject);
  411. const promises = new Array<Promise<any>>();
  412. BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader: BABYLON.GLTFFileLoader) => {
  413. var specularOverAlpha = true;
  414. var radianceOverAlpha = true;
  415. loader.transparencyAsCoverage = false;
  416. loader.onMaterialLoaded = (material) => {
  417. specularOverAlpha = specularOverAlpha && (material as BABYLON.PBRMaterial).useSpecularOverAlpha;
  418. radianceOverAlpha = radianceOverAlpha && (material as BABYLON.PBRMaterial).useRadianceOverAlpha;
  419. };
  420. promises.push(loader.whenCompleteAsync().then(() => {
  421. expect(specularOverAlpha, "specularOverAlpha").to.be.true;
  422. expect(radianceOverAlpha, "radianceOverAlpha").to.be.true;
  423. }));
  424. });
  425. promises.push(BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene));
  426. return Promise.all(promises);
  427. });
  428. it('Load BoomBox twice and check texture instancing', () => {
  429. const scene = new BABYLON.Scene(subject);
  430. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(() => {
  431. const createTextureSpy = sinon.spy(subject, "createTexture");
  432. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(() => {
  433. const called = createTextureSpy.called;
  434. createTextureSpy.restore();
  435. expect(called, "createTextureSpyCalled").to.be.false;
  436. });
  437. });
  438. });
  439. it('Load UFO with MSFT_audio_emitter', () => {
  440. const scene = new BABYLON.Scene(subject);
  441. return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/", "ufo.glb", scene).then((result) => {
  442. expect(result.meshes.length, "meshes.length").to.equal(scene.meshes.length);
  443. expect(result.particleSystems.length, "particleSystems.length").to.equal(0);
  444. expect(result.animationGroups.length, "animationGroups.length").to.equal(3);
  445. expect(scene.soundTracks.length, "scene.soundTracks.length").to.equal(0);
  446. expect(scene.mainSoundTrack.soundCollection.length, "scene.mainSoundTrack.soundCollection.length").to.equal(3);
  447. expect(scene.mainSoundTrack.soundCollection[0].onEndedObservable.hasObservers(), "scene.mainSoundTrack.soundCollection[0].onEndedObservable.hasObservers()").to.be.true;
  448. });
  449. });
  450. it('Load Box with extras', () => {
  451. const scene = new BABYLON.Scene(subject);
  452. return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/Box/", "Box_extras.gltf", scene).then((scene) => {
  453. expect(scene.meshes.length, "scene.meshes.length").to.equal(2);
  454. expect(scene.materials.length, "scene.materials.length").to.equal(1);
  455. const mesh = scene.getMeshByName("Box001");
  456. expect(mesh, "Box001").to.exist;
  457. expect(mesh.metadata, "Box001 metadata").to.exist;
  458. expect(mesh.metadata.gltf, "Box001 metadata.gltf").to.exist;
  459. expect(mesh.metadata.gltf.extras, "Box001 metadata.gltf.extras").to.exist;
  460. expect(mesh.metadata.gltf.extras.kind, "Box001 extras.kind").to.equal("nice cube");
  461. expect(mesh.metadata.gltf.extras.magic, "Box001 extras.magic").to.equal(42);
  462. const camera = scene.getCameraByName("Camera");
  463. expect(camera, "Camera").to.exist;
  464. expect(camera.metadata, "Camera metadata").to.exist;
  465. expect(mesh.metadata.gltf, "Camera metadata.gltf").to.exist;
  466. expect(mesh.metadata.gltf.extras, "Camera metadata.gltf.extras").to.exist;
  467. expect(camera.metadata.gltf.extras.custom, "Camera extras.custom").to.equal("cameraProp");
  468. const material = scene.getMaterialByName("01___Default");
  469. expect(material, "Material").to.exist;
  470. expect(material.metadata, "Material metadata").to.exist;
  471. expect(mesh.metadata.gltf, "Material metadata.gltf").to.exist;
  472. expect(mesh.metadata.gltf.extras, "Material metadata.gltf.extras").to.exist;
  473. expect(material.metadata.gltf.extras.custom, "Material extras.custom").to.equal("materialProp");
  474. });
  475. });
  476. // TODO: test animation group callback
  477. // TODO: test material instancing
  478. // TODO: test KHR_materials_pbrSpecularGlossiness
  479. // TODO: test KHR_lights
  480. });
  481. /**
  482. * Integration tests for loading OBJ assets.
  483. */
  484. describe('#OBJ', () => {
  485. it('should load a tetrahedron (without colors)', () => {
  486. var fileContents = `
  487. g tetrahedron
  488. v 1.00 1.00 1.00 0.666 0 0
  489. v 2.00 1.00 1.00 0.666 0 0
  490. v 1.00 2.00 1.00 0.666 0 0
  491. v 1.00 1.00 2.00 0.666 0 0
  492. f 1 3 2
  493. f 1 4 3
  494. f 1 2 4
  495. f 2 3 4
  496. `;
  497. var scene = new BABYLON.Scene(subject);
  498. return BABYLON.SceneLoader.LoadAssetContainerAsync('', 'data:' + fileContents, scene, () => { }, ".obj").then((container) => {
  499. expect(container.meshes.length).to.eq(1);
  500. let tetrahedron = container.meshes[0];
  501. var positions: BABYLON.FloatArray = tetrahedron.getVerticesData(BABYLON.VertexBuffer.PositionKind);
  502. var colors: BABYLON.FloatArray = tetrahedron.getVerticesData(BABYLON.VertexBuffer.ColorKind);
  503. expect(positions).to.deep.equal([1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2]);
  504. assert.isNull(colors, 'expecting colors vertex buffer to be null');
  505. });
  506. });
  507. it('should parse leniently allowing extra spaces with vertex definitions', () => {
  508. var fileContents = `
  509. g tetrahedron
  510. v 1.00 1.00 1.00 0.666 0 0
  511. v 2.00 1.00 1.00 0.666 0 0
  512. v 1.00 2.00 1.00 0.666 0 0
  513. v 1.00 1.00 2.00 0.666 0 0
  514. # ^
  515. # └── allow extra spaces before position/color
  516. f 1 3 2
  517. f 1 4 3
  518. f 1 2 4
  519. f 2 3 4
  520. `;
  521. var scene = new BABYLON.Scene(subject);
  522. return BABYLON.SceneLoader.LoadAssetContainerAsync('', 'data:' + fileContents, scene, () => { }, ".obj").then((container) => {
  523. expect(container.meshes.length).to.eq(1);
  524. let tetrahedron = container.meshes[0];
  525. var positions: BABYLON.FloatArray = tetrahedron.getVerticesData(BABYLON.VertexBuffer.PositionKind);
  526. expect(positions).to.deep.equal([1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2]);
  527. });
  528. });
  529. });
  530. describe('#AssetContainer', () => {
  531. it('should be loaded from BoomBox GLTF', () => {
  532. var scene = new BABYLON.Scene(subject);
  533. return BABYLON.SceneLoader.LoadAssetContainerAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then((container) => {
  534. expect(container.meshes.length).to.eq(2);
  535. });
  536. });
  537. it('should be adding and removing objects from scene', () => {
  538. // Create a scene with some assets
  539. var scene = new BABYLON.Scene(subject);
  540. var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
  541. var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
  542. var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
  543. var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
  544. // Move all the assets from the scene into a container
  545. var container = new BABYLON.AssetContainer(scene);
  546. var keepAssets = new BABYLON.KeepAssets();
  547. keepAssets.cameras.push(camera);
  548. container.moveAllFromScene(keepAssets);
  549. expect(scene.cameras.length).to.eq(1);
  550. expect(scene.meshes.length).to.eq(0);
  551. expect(scene.lights.length).to.eq(0);
  552. expect(container.cameras.length).to.eq(0);
  553. expect(container.meshes.length).to.eq(2);
  554. expect(container.lights.length).to.eq(1);
  555. // Add them back and then remove again
  556. container.addAllToScene();
  557. expect(scene.cameras.length).to.eq(1);
  558. expect(scene.meshes.length).to.eq(2);
  559. expect(scene.lights.length).to.eq(1);
  560. container.removeAllFromScene();
  561. expect(scene.cameras.length).to.eq(1);
  562. expect(scene.meshes.length).to.eq(0);
  563. expect(scene.lights.length).to.eq(0);
  564. });
  565. });
  566. });