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.

demo.js 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * Augmented Reality demo with three.js and encantar.js
  3. */
  4. (function() {
  5. /**
  6. * Utilities for the Demo scene
  7. */
  8. class DemoUtils
  9. {
  10. async loadGLTF(filepath, yAxisIsUp = true)
  11. {
  12. const loader = new THREE.GLTFLoader();
  13. const gltf = await loader.loadAsync(filepath);
  14. // glTF defines +y as up. We expect +z to be up.
  15. if(yAxisIsUp)
  16. gltf.scene.rotateX(Math.PI / 2);
  17. return gltf;
  18. }
  19. switchToFrontView(root)
  20. {
  21. // top view is the default
  22. root.rotateX(-Math.PI / 2);
  23. }
  24. createAnimationAction(gltf, name = null)
  25. {
  26. const mixer = new THREE.AnimationMixer(gltf.scene);
  27. const clips = gltf.animations;
  28. if(clips.length == 0)
  29. throw new Error('No animation clips');
  30. const clip = (name !== null) ? THREE.AnimationClip.findByName(clips, name) : clips[0];
  31. const action = mixer.clipAction(clip);
  32. return action;
  33. }
  34. createImagePlane(imagepath)
  35. {
  36. const texture = new THREE.TextureLoader().load(imagepath);
  37. const geometry = new THREE.PlaneGeometry(1, 1);
  38. const material = new THREE.MeshBasicMaterial({
  39. map: texture,
  40. side: THREE.DoubleSide,
  41. });
  42. const mesh = new THREE.Mesh(geometry, material);
  43. return mesh;
  44. }
  45. referenceImage(ar)
  46. {
  47. if(ar.frame === null)
  48. return null;
  49. for(const result of ar.frame.results) {
  50. if(result.tracker.type == 'image-tracker') {
  51. if(result.trackables.length > 0) {
  52. const trackable = result.trackables[0];
  53. return trackable.referenceImage;
  54. }
  55. }
  56. }
  57. return null;
  58. }
  59. }
  60. /**
  61. * Demo scene
  62. */
  63. class DemoScene extends ARScene
  64. {
  65. /**
  66. * Constructor
  67. */
  68. constructor()
  69. {
  70. super();
  71. this._utils = new DemoUtils();
  72. this._objects = { };
  73. }
  74. /**
  75. * Start the AR session
  76. * @returns {Promise<Session>}
  77. */
  78. async startSession()
  79. {
  80. if(!AR.isSupported()) {
  81. throw new Error(
  82. 'This device is not compatible with this AR experience.\n\n' +
  83. 'User agent: ' + navigator.userAgent
  84. );
  85. }
  86. //AR.Settings.powerPreference = 'low-power';
  87. const tracker = AR.Tracker.ImageTracker();
  88. await tracker.database.add([{
  89. name: 'my-reference-image',
  90. image: document.getElementById('my-reference-image')
  91. }]);
  92. const viewport = AR.Viewport({
  93. container: document.getElementById('ar-viewport'),
  94. hudContainer: document.getElementById('ar-hud')
  95. });
  96. const video = document.getElementById('my-video');
  97. const useWebcam = (video === null);
  98. const source = useWebcam ?
  99. AR.Source.Camera({ resolution: 'md' }) :
  100. AR.Source.Video(video);
  101. const session = await AR.startSession({
  102. mode: 'immersive',
  103. viewport: viewport,
  104. trackers: [ tracker ],
  105. sources: [ source ],
  106. stats: true,
  107. gizmos: true,
  108. });
  109. const scan = document.getElementById('scan');
  110. tracker.addEventListener('targetfound', event => {
  111. session.gizmos.visible = false;
  112. if(scan)
  113. scan.hidden = true;
  114. });
  115. tracker.addEventListener('targetlost', event => {
  116. session.gizmos.visible = true;
  117. if(scan)
  118. scan.hidden = false;
  119. });
  120. return session;
  121. }
  122. /**
  123. * Initialize the augmented scene
  124. * @param {ARPluginSystem} ar
  125. * @returns {Promise<void>}
  126. */
  127. async init(ar)
  128. {
  129. // Change the point of view. All virtual objects are descendants of
  130. // ar.root, a node that is automatically aligned to the physical scene.
  131. // Adjusting ar.root will adjust all virtual objects.
  132. this._utils.switchToFrontView(ar.root);
  133. ar.root.position.set(0, -0.5, 0);
  134. ar.root.scale.set(0.7, 0.7, 0.7);
  135. // add lights
  136. const ambientLight = new THREE.AmbientLight(0xffffff);
  137. ar.scene.add(ambientLight);
  138. const directionalLight = new THREE.DirectionalLight(0xffffff);
  139. directionalLight.position.set(0, 0, 3);
  140. ar.root.add(directionalLight);
  141. // create the magic circle
  142. const magicCircle = this._utils.createImagePlane('../assets/magic-circle.png');
  143. magicCircle.material.transparent = true;
  144. magicCircle.material.opacity = 0.85;
  145. magicCircle.material.color = new THREE.Color(0xbeefff);
  146. magicCircle.scale.set(6, 6, 1);
  147. ar.root.add(magicCircle);
  148. // load the mage
  149. const gltf = await this._utils.loadGLTF('../assets/mage.glb');
  150. const mage = gltf.scene;
  151. ar.root.add(mage);
  152. // prepare the animation of the mage
  153. const animationAction = this._utils.createAnimationAction(gltf, 'Idle');
  154. animationAction.loop = THREE.LoopRepeat;
  155. animationAction.play();
  156. // save objects
  157. this._objects.mage = mage;
  158. this._objects.magicCircle = magicCircle;
  159. this._objects.animationAction = animationAction;
  160. }
  161. /**
  162. * Update / animate the augmented scene
  163. * @param {ARPluginSystem} ar
  164. * @returns {void}
  165. */
  166. update(ar)
  167. {
  168. const TWO_PI = 2.0 * Math.PI;
  169. const ROTATIONS_PER_SECOND = 0.25;
  170. const delta = ar.session.time.delta; // given in seconds
  171. // animate the mage
  172. const animationAction = this._objects.animationAction;
  173. const mixer = animationAction.getMixer();
  174. mixer.update(delta);
  175. // animate the magic circle
  176. const magicCircle = this._objects.magicCircle;
  177. magicCircle.rotateZ(TWO_PI * ROTATIONS_PER_SECOND * delta);
  178. }
  179. /**
  180. * Release the augmented scene
  181. * @param {ARPluginSystem} ar
  182. * @returns {void}
  183. */
  184. release(ar)
  185. {
  186. // nothing to do
  187. }
  188. }
  189. /**
  190. * Enchant the Demo scene
  191. */
  192. window.addEventListener('load', () => {
  193. const scene = new DemoScene();
  194. encantar(scene);
  195. });
  196. })();