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 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /**
  2. * @file MARTINS.js WebAR demo with three.js and touch interaction
  3. * @version 1.1.0
  4. * @author Alexandre Martins (https://github.com/alemart)
  5. * @license LGPL-3.0-or-later
  6. */
  7. window.addEventListener('load', () => {
  8. const my = { };
  9. async function initialize(ar)
  10. {
  11. // add lights
  12. const ambientLight = new THREE.AmbientLight(0x808080);
  13. const directionalLight = new THREE.DirectionalLight(0xffffff, 0.75);
  14. directionalLight.position.set(0, 0, -1);
  15. ar.scene.add(ambientLight);
  16. ar.scene.add(directionalLight);
  17. // create cubes
  18. my.cubes = [
  19. createCube(ar, 1.0, -0.5, 0x00ff00),
  20. createCube(ar, -1.0, -0.5, 0xffff00),
  21. createCube(ar, 0.0, -0.5, 0x0077ff),
  22. ];
  23. // create text
  24. my.text = await createText(ar, 'Tap on any cube', 0x88ffee);
  25. my.text.position.set(-1.5, 0.25, 0.5);
  26. // setup interactivity
  27. my.pointer = createPointer(ar);
  28. my.raycaster = new THREE.Raycaster();
  29. }
  30. function createCube(ar, x, y, color, length = 0.7)
  31. {
  32. const geometry = new THREE.BoxGeometry(length, length, length);
  33. const material = new THREE.MeshPhongMaterial({ color });
  34. const cube = new THREE.Mesh(geometry, material);
  35. cube.position.x = x;
  36. cube.position.y = y;
  37. cube.position.z = length / 2;
  38. cube.userData.color = color;
  39. material.opacity = 1.0;
  40. material.transparent = true;
  41. ar.root.add(cube);
  42. return cube;
  43. }
  44. async function createText(ar, text, color = 0xffffff)
  45. {
  46. const loader = new THREE.FontLoader();
  47. const fontURL = '../assets/helvetiker_bold.typeface.json';
  48. const font = await loader.loadAsync(fontURL);
  49. const material = new THREE.MeshPhongMaterial({ color });
  50. const geometry = new THREE.TextGeometry(text, {
  51. font: font,
  52. size: 0.3,
  53. height: 0.05,
  54. });
  55. const mesh = new THREE.Mesh(geometry, material);
  56. ar.root.add(mesh);
  57. return mesh;
  58. }
  59. function createPointer(ar)
  60. {
  61. const pointer = {
  62. position: new THREE.Vector2(),
  63. down: false,
  64. get active()
  65. {
  66. return this.down && Math.max(Math.abs(this.position.x), Math.abs(this.position.y)) <= 1.0;
  67. }
  68. };
  69. function updatePosition(event)
  70. {
  71. const canvas = ar.renderer.domElement;
  72. const rect = canvas.getBoundingClientRect();
  73. const x = event.pageX - (rect.left + window.scrollX);
  74. const y = event.pageY - (rect.top + window.scrollY);
  75. // normalize to [-1,1] x [-1,1]
  76. pointer.position.x = 2.0 * x / rect.width - 1.0;
  77. pointer.position.y = -2.0 * y / rect.height + 1.0;
  78. }
  79. // setup pointer interactivity
  80. window.addEventListener('pointermove', event => {
  81. updatePosition(event);
  82. });
  83. window.addEventListener('pointerdown', event => {
  84. updatePosition(event);
  85. pointer.down = true;
  86. });
  87. window.addEventListener('pointerup', event => {
  88. pointer.down = false;
  89. });
  90. // done!
  91. return pointer;
  92. }
  93. function animate(ar)
  94. {
  95. // reset all cubes
  96. for(let i = 0; i < my.cubes.length; i++) {
  97. my.cubes[i].material.color.setHex(my.cubes[i].userData.color);
  98. my.cubes[i].scale.z = 1.0;
  99. }
  100. // interact with objects via raycasting
  101. if(my.pointer.active) {
  102. my.raycaster.setFromCamera(my.pointer.position, ar.camera);
  103. const intersections = my.raycaster.intersectObjects(my.cubes);
  104. for(let i = 0; i < intersections.length; i++) {
  105. // create the appearance of a pushed button
  106. const object = intersections[i].object;
  107. object.material.color.setHex(0xff3333);
  108. object.scale.z = 0.2;
  109. }
  110. }
  111. }
  112. async function startARSession()
  113. {
  114. if(!Martins.isSupported()) {
  115. throw new Error(
  116. 'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
  117. 'Your user agent is ' + navigator.userAgent
  118. );
  119. }
  120. //Martins.Settings.powerPreference = 'low-power';
  121. const tracker = Martins.Tracker.ImageTracker();
  122. await tracker.database.add([{
  123. name: 'my-reference-image',
  124. image: document.getElementById('my-reference-image')
  125. }]);
  126. const viewport = Martins.Viewport({
  127. container: document.getElementById('ar-viewport'),
  128. hudContainer: document.getElementById('ar-hud')
  129. });
  130. const video = document.getElementById('my-video');
  131. const useWebcam = (video === null);
  132. const source = useWebcam ?
  133. Martins.Source.Camera({ resolution: 'md' }) :
  134. Martins.Source.Video(video);
  135. const session = await Martins.startSession({
  136. mode: 'immersive',
  137. viewport: viewport,
  138. trackers: [ tracker ],
  139. sources: [ source ],
  140. stats: true,
  141. gizmos: true,
  142. });
  143. const scan = document.getElementById('scan');
  144. tracker.addEventListener('targetfound', event => {
  145. session.gizmos.visible = false;
  146. if(scan)
  147. scan.hidden = true;
  148. });
  149. tracker.addEventListener('targetlost', event => {
  150. session.gizmos.visible = true;
  151. if(scan)
  152. scan.hidden = false;
  153. });
  154. return session;
  155. }
  156. // link MARTINS.js to THREE.js
  157. linkMartinsToTHREE(startARSession, animate, initialize);
  158. });