Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

three-with-encantar.js 5.1KB

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