Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

three-with-martins.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * @file MARTINS.js & THREE.js glue code
  3. * @version 1.0.1
  4. * @author Alexandre Martins (https://github.com/alemart)
  5. * @license AGPL-3.0-only or PolyForm-Perimeter-1.0.0
  6. */
  7. /* Usage of the indicated versions is encouraged */
  8. __THIS_GLUE_CODE_HAS_BEEN_TESTED_WITH__({
  9. 'MARTINS.js': { version: '0.1.1' },
  10. 'THREE.js': { version: '138' }
  11. });
  12. /**
  13. * Use this object to create your augmented scene
  14. * @typedef {object} ARSystem
  15. * @property {Session} session MARTINS.js Session
  16. * @property {Frame} frame current Frame
  17. * @property {ReferenceImage | null} referenceImage corresponds to the target being tracked (if any)
  18. * @property {THREE.Scene} scene THREE.js Scene
  19. * @property {THREE.Group} root a 3D object that is automatically aligned with the physical target
  20. * @property {THREE.Camera} camera a camera adjusted for AR
  21. * @property {THREE.WebGLRenderer} renderer THREE.js renderer
  22. */
  23. /**
  24. * Connect MARTINS.js to THREE.js
  25. * @param {() => Promise<Session> | SpeedyPromise<Session>} startARSession
  26. * @param {(ar: ARSystem) => void} [animateVirtualScene] animation callback
  27. * @param {(ar: ARSystem) => void | Promise<void> | SpeedyPromise<Session>} [initializeVirtualScene] initialization callback
  28. * @returns {Promise<ARSystem> | SpeedyPromise<ARSystem>}
  29. */
  30. function linkMartinsToTHREE(startARSession, animateVirtualScene, initializeVirtualScene)
  31. {
  32. const ar = /** @type {ARSystem} */ ({
  33. session: null,
  34. frame: null,
  35. referenceImage: null,
  36. scene: null,
  37. root: null,
  38. camera: null,
  39. renderer: null,
  40. });
  41. function mix(frame)
  42. {
  43. ar.root.visible = false;
  44. ar.referenceImage = null;
  45. for(const result of frame.results) {
  46. if(result.tracker.type == 'image-tracker') {
  47. if(result.trackables.length > 0) {
  48. const trackable = result.trackables[0];
  49. const projectionMatrix = result.viewer.view.projectionMatrix;
  50. const viewMatrixInverse = result.viewer.pose.transform.matrix;
  51. const modelMatrix = trackable.pose.transform.matrix;
  52. ar.root.visible = true;
  53. ar.referenceImage = trackable.referenceImage;
  54. align(projectionMatrix, viewMatrixInverse, modelMatrix);
  55. }
  56. }
  57. }
  58. }
  59. function align(projectionMatrix, viewMatrixInverse, modelMatrix)
  60. {
  61. ar.camera.projectionMatrix.fromArray(projectionMatrix.read());
  62. ar.camera.projectionMatrixInverse.copy(ar.camera.projectionMatrix).invert();
  63. ar.camera.matrix.fromArray(viewMatrixInverse.read());
  64. ar.camera.updateMatrixWorld(true);
  65. ar.root.matrix.fromArray(modelMatrix.read());
  66. ar.root.updateMatrixWorld(true);
  67. }
  68. function animate(time, frame)
  69. {
  70. ar.frame = frame;
  71. mix(ar.frame);
  72. animateVirtualScene.call(undefined, ar);
  73. ar.renderer.render(ar.scene, ar.camera);
  74. ar.session.requestAnimationFrame(animate);
  75. }
  76. if(typeof animateVirtualScene !== 'function')
  77. animateVirtualScene = (ar => void 0);
  78. if(typeof initializeVirtualScene !== 'function')
  79. initializeVirtualScene = (ar => void 0);
  80. return startARSession().then(session => {
  81. ar.session = session;
  82. ar.scene = new THREE.Scene();
  83. ar.camera = new THREE.PerspectiveCamera();
  84. ar.camera.matrixAutoUpdate = false;
  85. ar.root = new THREE.Group();
  86. ar.root.matrixAutoUpdate = false;
  87. ar.scene.add(ar.root);
  88. ar.renderer = new THREE.WebGLRenderer({
  89. canvas: ar.session.viewport.canvas,
  90. alpha: true,
  91. });
  92. ar.session.addEventListener('end', event => {
  93. ar.root.visible = false;
  94. ar.frame = null;
  95. ar.referenceImage = null;
  96. });
  97. ar.session.viewport.addEventListener('resize', event => {
  98. const size = ar.session.viewport.virtualSize;
  99. ar.renderer.setPixelRatio(1.0);
  100. ar.renderer.setSize(size.width, size.height, false);
  101. });
  102. let init = initializeVirtualScene.call(undefined, ar);
  103. if(!(typeof init === 'object' && 'then' in init))
  104. init = Promise.resolve();
  105. return init.then(() => {
  106. ar.session.requestAnimationFrame(animate);
  107. return ar;
  108. });
  109. }).catch(error => {
  110. console.error(error);
  111. alert(error.message);
  112. return ar;
  113. });
  114. }
  115. /**
  116. * Version check
  117. * @param {object} json
  118. */
  119. function __THIS_GLUE_CODE_HAS_BEEN_TESTED_WITH__(json)
  120. {
  121. window.addEventListener('load', () => {
  122. try { Martins, __THREE__;
  123. const versionOf = { 'MARTINS.js': Martins.version.replace(/-.*$/, ''), 'THREE.js': __THREE__ };
  124. const check = (x,v,w) => v !== w ? console.warn(`\n\n\nWARNING\n\nThis glue code has been tested with ${x} version ${v}. The version in use is ${w}. Usage of ${x} version ${v} is recommended instead.\n\n\n`) : void 0;
  125. for(const [x, expected] of Object.entries(json)) check(x, expected.version, versionOf[x]);
  126. } catch(e) { alert(e.message); }
  127. });
  128. }