1
0

vrmDiagnosis.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
  2. import { VRMLoaderPlugin } from '@pixiv/three-vrm';
  3. import { EvaluationResult } from './diagnosisScript';
  4. const TIME_OUT = 16000;
  5. const MIN_DURATION = 4000;
  6. // Timeout wrapper function
  7. function timeoutPromise<T>(promise: Promise<T>, ms: number): Promise<T> {
  8. return new Promise((resolve, reject) => {
  9. const id = setTimeout(() => reject(new Error("TimeoutError")), ms);
  10. promise
  11. .then((res) => {
  12. clearTimeout(id);
  13. resolve(res);
  14. })
  15. .catch((err) => {
  16. clearTimeout(id);
  17. reject(err);
  18. });
  19. });
  20. }
  21. export async function vrmDiagnosis(url: string, timeoutMs = TIME_OUT): Promise<EvaluationResult> {
  22. const start = performance.now();
  23. try {
  24. const loader = new GLTFLoader();
  25. loader.register((parser) => new VRMLoaderPlugin(parser)); // Important!
  26. const gltf = await timeoutPromise(loader.loadAsync(url), timeoutMs);
  27. const vrm = gltf.userData.vrm;
  28. const end = performance.now();
  29. const duration = end - start;
  30. const status = !!vrm ? "pass" : "fail"; // If vrm object exists, it's a valid VRM
  31. const score = calculateScore({ status, duration });
  32. return { status, score };
  33. } catch (e: any) {
  34. const end = performance.now();
  35. const duration = end - start;
  36. const isTimeout = e.message === "TimeoutError";
  37. return {
  38. status: "fail",
  39. score: calculateScore({ status: "fail", duration, timeout: isTimeout }),
  40. };
  41. }
  42. }
  43. // Score calculation logic
  44. function calculateScore({
  45. status,
  46. duration,
  47. timeout = false,
  48. }: {
  49. status: "pass" | "fail";
  50. duration: number;
  51. timeout?: boolean;
  52. }): number {
  53. if (timeout) return 0;
  54. let score = 0;
  55. if (status === "pass") score += 50;
  56. if (duration < MIN_DURATION) score += 50 * ((MIN_DURATION - duration) / MIN_DURATION);
  57. return Math.round(score);
  58. }