|
| 1 | +import * as fs from "fs"; |
| 2 | +import * as path from "path"; |
| 3 | +import { NullEngine } from "core/Engines"; |
| 4 | +import { Engine } from "core/Engines/engine"; |
| 5 | +import { Scene } from "core/scene"; |
| 6 | +import { VertexAnimationBaker } from "core/BakedVertexAnimation/vertexAnimationBaker"; |
| 7 | +import { AnimationRange } from "core/Animations"; |
| 8 | +import { ImportMeshAsync } from "core/Loading"; |
| 9 | +import type { Mesh } from "core/Meshes"; |
| 10 | +import "core/Animations/animatable"; |
| 11 | +import { FreeCamera } from "core/Cameras"; |
| 12 | +import { Vector3 } from "core/Maths"; |
| 13 | + |
| 14 | +/** |
| 15 | + * Describes the test suite for VertexAnimationBaker. |
| 16 | + */ |
| 17 | +describe("VertexAnimationBaker", function () { |
| 18 | + let subject: Engine; |
| 19 | + let scene: Scene; |
| 20 | + let mesh: Mesh; |
| 21 | + |
| 22 | + const animationRanges = [ |
| 23 | + { from: 7, to: 31 }, |
| 24 | + { from: 33, to: 61 }, |
| 25 | + { from: 63, to: 91 }, |
| 26 | + { from: 93, to: 130 }, |
| 27 | + ]; |
| 28 | + |
| 29 | + /** |
| 30 | + * Create a new engine, scene, and skeleton before each test. |
| 31 | + */ |
| 32 | + beforeEach(async function () { |
| 33 | + subject = new NullEngine({ |
| 34 | + renderHeight: 256, |
| 35 | + renderWidth: 256, |
| 36 | + textureSize: 256, |
| 37 | + deterministicLockstep: false, |
| 38 | + lockstepMaxSteps: 1, |
| 39 | + }); |
| 40 | + |
| 41 | + // Avoid creating normals in PBR materials. |
| 42 | + subject.getCaps().standardDerivatives = true; |
| 43 | + |
| 44 | + // Create a scene |
| 45 | + scene = new Scene(subject); |
| 46 | + new FreeCamera("camera", new Vector3(0, 0, 0), scene); |
| 47 | + const meshPath = path.join(__dirname, "../../../../../../packages/tools/playground/public/scenes/arr.babylon"); |
| 48 | + const meshBuffer = fs.readFileSync(meshPath); |
| 49 | + const dataUrl = `data:model/gltf-binary;base64,${meshBuffer.toString("base64")}`; |
| 50 | + |
| 51 | + const result = await ImportMeshAsync(dataUrl, scene); |
| 52 | + mesh = result.meshes[0] as Mesh; |
| 53 | + |
| 54 | + subject.runRenderLoop(() => { |
| 55 | + scene.render(); |
| 56 | + }); |
| 57 | + }); |
| 58 | + |
| 59 | + /** |
| 60 | + * Tests for bakeVertexDataSync. |
| 61 | + */ |
| 62 | + describe("#bakeVertexDataSync", () => { |
| 63 | + it("should bake vertex data as Float32Array for given ranges and produce data ~equal to async bake", async () => { |
| 64 | + // Arrange: Create a VertexAnimationBaker with the skeleton |
| 65 | + const baker = new VertexAnimationBaker(scene, mesh); |
| 66 | + |
| 67 | + // Act: Bake vertex data with halfFloat: false |
| 68 | + let start = performance.now(); |
| 69 | + const vertexData = baker.bakeVertexDataSync(animationRanges as AnimationRange[], false); |
| 70 | + let end = performance.now(); |
| 71 | + console.log(`Synchronous bake took: ${end - start} ms`); |
| 72 | + const asyncVertexData = await baker.bakeVertexData(animationRanges as AnimationRange[]); |
| 73 | + end = performance.now(); |
| 74 | + console.log(`Asynchronous bake took: ${end - start} ms`); |
| 75 | + // Assert: Check type and size |
| 76 | + expect(vertexData.length).toEqual(asyncVertexData.length, "Synchronous and asynchronous vertex data should match"); |
| 77 | + expect(vertexData).toBeInstanceOf(Float32Array, "Vertex data should be Float32Array"); |
| 78 | + }); |
| 79 | + |
| 80 | + it("should bake vertex data as Uint16Array for half-float", () => { |
| 81 | + const baker = new VertexAnimationBaker(scene, mesh); |
| 82 | + const vertexData = baker.bakeVertexDataSync(animationRanges as AnimationRange[], true); |
| 83 | + expect(vertexData).toBeInstanceOf(Uint16Array, "Vertex data should be Uint16Array"); |
| 84 | + }); |
| 85 | + |
| 86 | + it("should throw an error if no skeleton is provided", () => { |
| 87 | + const mesh = { skeleton: null }; // Mock mesh with no skeleton |
| 88 | + const baker = new VertexAnimationBaker(scene, mesh as any); |
| 89 | + expect(() => baker.bakeVertexDataSync(animationRanges as AnimationRange[], false)).toThrow("No skeleton provided."); |
| 90 | + }); |
| 91 | + }); |
| 92 | + |
| 93 | + /** |
| 94 | + * Clean up after each test. |
| 95 | + */ |
| 96 | + afterEach(function () { |
| 97 | + subject.dispose(); |
| 98 | + }); |
| 99 | +}); |
0 commit comments