Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. window.addEventListener('load', () => {
  2. const my = { };
  3. // initialize the virtual scene
  4. async function init(ar)
  5. {
  6. // add lights
  7. const ambientLight = new THREE.AmbientLight(0xffffff);
  8. ar.scene.add(ambientLight);
  9. const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
  10. directionalLight.position.set(0, 1, 0);
  11. ar.root.add(directionalLight);
  12. //const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.5);
  13. //ar.scene.add(directionalLightHelper);
  14. // create a group as a child of ar.root, which is aligned to the physical scene
  15. const group = createMainGroup(true);
  16. group.position.set(0, -0.5, 0);
  17. group.scale.set(0.7, 0.7, 0.7);
  18. ar.root.add(group);
  19. // create the magic circle
  20. const magicCircle = createPlane('../assets/magic-circle.png');
  21. magicCircle.material.transparent = true;
  22. magicCircle.material.opacity = 0.85;
  23. magicCircle.material.color = new THREE.Color(0xbeefff);
  24. magicCircle.scale.set(6, 6, 1);
  25. group.add(magicCircle);
  26. // load the mage
  27. const gltf = await loadGLTF('../assets/mage.glb');
  28. const mage = gltf.scene;
  29. group.add(mage);
  30. // prepare the animation of the mage
  31. const animationAction = createAnimationAction(gltf, 'Idle');
  32. animationAction.loop = THREE.LoopRepeat;
  33. animationAction.play();
  34. // export objects
  35. my.group = group;
  36. my.magicCircle = magicCircle;
  37. my.mage = mage;
  38. my.animationAction = animationAction;
  39. }
  40. // animate the virtual scene
  41. function animate(ar, deltaSeconds)
  42. {
  43. const TWO_PI = 2.0 * Math.PI;
  44. const ROTATIONS_PER_SECOND = 0.25;
  45. // animate the mage
  46. const mixer = my.animationAction.getMixer();
  47. mixer.update(deltaSeconds);
  48. // animate the magic circle
  49. my.magicCircle.rotateZ(TWO_PI * ROTATIONS_PER_SECOND * deltaSeconds);
  50. }
  51. function createMainGroup(frontView = false)
  52. {
  53. const group = new THREE.Group();
  54. // top view is the default
  55. if(frontView)
  56. group.rotateX(-Math.PI / 2);
  57. return group;
  58. }
  59. async function loadGLTF(filepath, yAxisIsUp = true)
  60. {
  61. const loader = new THREE.GLTFLoader();
  62. const gltf = await loader.loadAsync(filepath);
  63. // glTF defines +y as up. We expect +z to be up.
  64. if(yAxisIsUp)
  65. gltf.scene.rotateX(Math.PI / 2);
  66. return gltf;
  67. }
  68. function createAnimationAction(gltf, name = null)
  69. {
  70. const mixer = new THREE.AnimationMixer(gltf.scene);
  71. const clips = gltf.animations;
  72. if(clips.length == 0)
  73. throw new Error('No animation clips');
  74. const clip = (name !== null) ? THREE.AnimationClip.findByName(clips, name) : clips[0];
  75. const action = mixer.clipAction(clip);
  76. return action;
  77. }
  78. function createPlane(imagepath)
  79. {
  80. const texture = new THREE.TextureLoader().load(imagepath);
  81. const geometry = new THREE.PlaneGeometry(1, 1);
  82. const material = new THREE.MeshBasicMaterial({
  83. map: texture,
  84. side: THREE.DoubleSide,
  85. });
  86. const mesh = new THREE.Mesh(geometry, material);
  87. return mesh;
  88. }
  89. async function startARSession()
  90. {
  91. if(!AR.isSupported()) {
  92. throw new Error(
  93. 'This device is not compatible with this AR experience.\n\n' +
  94. 'User agent: ' + navigator.userAgent
  95. );
  96. }
  97. //AR.Settings.powerPreference = 'low-power';
  98. const tracker = AR.Tracker.ImageTracker();
  99. await tracker.database.add([{
  100. name: 'my-reference-image',
  101. image: document.getElementById('my-reference-image')
  102. }]);
  103. const viewport = AR.Viewport({
  104. container: document.getElementById('ar-viewport'),
  105. hudContainer: document.getElementById('ar-hud')
  106. });
  107. const video = document.getElementById('my-video');
  108. const useWebcam = (video === null);
  109. const source = useWebcam ?
  110. AR.Source.Camera({ resolution: 'md' }) :
  111. AR.Source.Video(video);
  112. const session = await AR.startSession({
  113. mode: 'immersive',
  114. viewport: viewport,
  115. trackers: [ tracker ],
  116. sources: [ source ],
  117. stats: true,
  118. gizmos: true,
  119. });
  120. const scan = document.getElementById('scan');
  121. tracker.addEventListener('targetfound', event => {
  122. session.gizmos.visible = false;
  123. if(scan)
  124. scan.hidden = true;
  125. });
  126. tracker.addEventListener('targetlost', event => {
  127. session.gizmos.visible = true;
  128. if(scan)
  129. scan.hidden = false;
  130. });
  131. return session;
  132. }
  133. // enchant!
  134. encantar(startARSession, animate, init);
  135. });