aframe-components.js 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2018 Nikolai Suslov and the Krestianstvo.org project contributors. (https://github.com/NikolaySuslov/livecodingspace/blob/master/LICENSE.md)
  4. */
  5. if (typeof AFRAME === 'undefined') {
  6. throw new Error('Component attempted to register before AFRAME was available.');
  7. }
  8. AFRAME.registerComponent('scene-utils', {
  9. init: function () {
  10. const sceneEnterVR = (e) => {
  11. //vwf_view.kernel.callMethod(vwf.application(), "enterVR");
  12. let avatarEl = document.querySelector('#avatarControlParent');
  13. if (AFRAME.utils.device.isGearVR()) {
  14. } else if (AFRAME.utils.device.isMobile()) {
  15. avatarEl.setAttribute('position', '0 0 0')
  16. } else {
  17. avatarEl.setAttribute('position', '0 1.6 0');
  18. }
  19. // if (!AFRAME.utils.device.isGearVR() && !AFRAME.utils.device.isMobile()) {
  20. // avatarEl.setAttribute('position', '0 1.6 0');
  21. // }
  22. }
  23. const sceneExitVR = (e) => {
  24. //vwf_view.kernel.callMethod(vwf.application(), "exitVR");
  25. let avatarEl = document.querySelector('#avatarControlParent');
  26. if (AFRAME.utils.device.isGearVR()) {
  27. } else if (AFRAME.utils.device.isMobile()) {
  28. avatarEl.setAttribute('position', '0 1.6 0');
  29. } else {
  30. avatarEl.setAttribute('position', '0 0 0');
  31. }
  32. }
  33. this.el.sceneEl.addEventListener('enter-vr', sceneEnterVR);
  34. this.el.sceneEl.addEventListener('exit-vr', sceneExitVR);
  35. },
  36. update: function () {
  37. },
  38. tick: function (t) {
  39. }
  40. })
  41. AFRAME.registerComponent('linepath', {
  42. schema: {
  43. color: { default: '#000' },
  44. width: { default: 0.01 },
  45. path: {
  46. default: [
  47. { x: -0.5, y: 0, z: 0 },
  48. { x: 0.5, y: 0, z: 0 }
  49. ]
  50. // Deserialize path in the form of comma-separated vec3s: `0 0 0, 1 1 1, 2 0 3`.
  51. // parse: function (value) {
  52. // return value.split(',').map(coordinates.parse);
  53. // },
  54. // Serialize array of vec3s in case someone does setAttribute('line', 'path', [...]).
  55. // stringify: function (data) {
  56. // return data.map(coordinates.stringify).join(',');
  57. // }
  58. }
  59. },
  60. update: function () {
  61. var material = new MeshLineMaterial({
  62. color: new THREE.Color(this.data.color), //this.data.color
  63. lineWidth: this.data.width
  64. });
  65. var geometry = new THREE.Geometry();
  66. this.data.path.forEach(function (vec3) {
  67. geometry.vertices.push(
  68. new THREE.Vector3(vec3.x, vec3.y, vec3.z)
  69. );
  70. });
  71. let line = new MeshLine();
  72. line.setGeometry(geometry);
  73. //new THREE.Line(geometry, material)
  74. this.el.setObject3D('mesh', new THREE.Mesh(line.geometry, material));
  75. },
  76. remove: function () {
  77. this.el.removeObject3D('mesh');
  78. }
  79. });
  80. AFRAME.registerComponent('gizmo', {
  81. schema: {
  82. mode: { default: 'translate' }
  83. },
  84. update: function (old) {
  85. let modes = ['translate', 'rotate', 'scale'];
  86. if (!this.gizmo) {
  87. let newMode = modes.filter(el => {
  88. return el == this.data.mode
  89. })
  90. if (newMode.length !== 0) {
  91. this.mode = this.data.mode
  92. this.transformControls.setMode(this.mode)
  93. }
  94. }
  95. },
  96. init: function () {
  97. let self = this
  98. this.mode = this.data.mode
  99. let activeCamera = document.querySelector('#avatarControl').getObject3D('camera');
  100. let renderer = this.el.sceneEl.renderer;
  101. this.transformControls = new THREE.TransformControls(activeCamera, renderer.domElement);
  102. this.transformControls.attach(this.el.object3D);
  103. this.el.sceneEl.setObject3D('control-' + this.el.id, this.transformControls);
  104. this.transformControls.addEventListener('change', function (evt) {
  105. // console.log('changed');
  106. var object = self.transformControls.object;
  107. if (object === undefined) {
  108. return;
  109. }
  110. var transformMode = self.transformControls.getMode();
  111. switch (transformMode) {
  112. case 'translate':
  113. vwf_view.kernel.setProperty(object.el.id, 'position',
  114. [object.position.x, object.position.y, object.position.z])
  115. break;
  116. case 'rotate':
  117. // let q = (new THREE.Quaternion()).setFromEuler(new THREE.Euler(
  118. // (object.rotation.x),
  119. // (object.rotation.y),
  120. // (object.rotation.z), 'XYZ'
  121. // ));
  122. // let angle = (new THREE.Euler()).setFromQuaternion(q, 'YXZ');
  123. // vwf_view.kernel.setProperty(object.el.id, 'rotation', [THREE.Math.radToDeg(angle.x), THREE.Math.radToDeg(angle.y), THREE.Math.radToDeg(angle.z)])
  124. vwf_view.kernel.setProperty(object.el.id, 'rotation',
  125. [THREE.Math.radToDeg(object.rotation.x), THREE.Math.radToDeg(object.rotation.y), THREE.Math.radToDeg(object.rotation.z)])
  126. break;
  127. case 'scale':
  128. vwf_view.kernel.setProperty(object.el.id, 'scale',
  129. [object.scale.x, object.scale.y, object.scale.z])
  130. break;
  131. }
  132. //vwf_view.kernel.fireEvent(evt.detail.target.id, "clickEvent")
  133. });
  134. },
  135. remove: function () {
  136. this.transformControls.detach();
  137. this.el.sceneEl.removeObject3D('control-' + this.el.id);
  138. },
  139. tick: function (t) {
  140. this.transformControls.update();
  141. }
  142. });
  143. AFRAME.registerComponent('cursor-listener', {
  144. init: function () {
  145. this.el.addEventListener('click', function (evt) {
  146. console.log('I was clicked at: ', evt.detail.intersection.point);
  147. let cursorID = 'cursor-avatar-' + vwf_view.kernel.moniker();
  148. if (evt.detail.cursorEl.id.includes(vwf_view.kernel.moniker())) {
  149. vwf_view.kernel.fireEvent(evt.detail.intersection.object.el.id, "clickEvent", [vwf_view.kernel.moniker()])
  150. }
  151. //vwf_view.kernel.fireEvent(evt.detail.target.id, "clickEvent")
  152. });
  153. }
  154. });
  155. AFRAME.registerComponent('raycaster-listener', {
  156. init: function () {
  157. let self = this;
  158. this.intersected = false;
  159. this.casters = {}
  160. this.me = vwf_view.kernel.moniker();
  161. this.el.addEventListener('raycaster-intersected', function (evt) {
  162. if (evt.detail.el.nodeName == 'A-CURSOR') {
  163. //console.log('CURSOR was intersected at: ', evt.detail.intersection.point);
  164. } else {
  165. if (self.intersected) {
  166. } else {
  167. console.log('I was intersected at: ', evt.target);//evt.detail.getIntersection().point);
  168. //evt.detail.intersection.object.el.id
  169. let ownedby = evt.detail.el.getAttribute('ownedby');
  170. if (ownedby == self.me || (evt.detail.el.id.includes(self.me))) { //if (evt.detail.el.id.includes(self.me)) {
  171. vwf_view.kernel.fireEvent(evt.target.id, "intersectEvent", [self.me]);
  172. }
  173. }
  174. self.casters[evt.target.id] = evt.target;
  175. self.intersected = true;
  176. }
  177. });
  178. this.el.addEventListener('raycaster-intersected-cleared', function (evt) {
  179. if (evt.detail.el.nodeName == 'A-CURSOR') {
  180. //console.log('CURSOR was intersected at: ', evt.detail.intersection.point);
  181. } else {
  182. if (self.intersected) {
  183. console.log('Clear intersection');
  184. if (Object.entries(self.casters).length == 1 && (self.casters[evt.target.id] !== undefined)) {
  185. let ownedby = evt.detail.el.getAttribute('ownedby');
  186. if (ownedby == self.me || (evt.detail.el.id.includes(self.me))) { //if (evt.detail.el.id.includes(self.me)) {
  187. vwf_view.kernel.fireEvent(evt.target.id, "clearIntersectEvent", [vwf_view.kernel.moniker()])
  188. }
  189. }
  190. delete self.casters[evt.target.id]
  191. } else { }
  192. self.intersected = false;
  193. }
  194. });
  195. }
  196. });
  197. AFRAME.registerComponent('envmap', {
  198. /**
  199. * Creates a new THREE.ShaderMaterial using the two shaders defined
  200. * in vertex.glsl and fragment.glsl.
  201. */
  202. init: function () {
  203. const data = this.data;
  204. //this.applyToMesh();
  205. this.el.addEventListener('model-loaded', () => this.applyToMesh());
  206. },
  207. /**
  208. * Update the ShaderMaterial when component data changes.
  209. */
  210. update: function () {
  211. },
  212. getEnvMap: function () {
  213. var path = './assets/textures/skybox2/';
  214. var format = '.jpg';
  215. var urls = [
  216. path + 'px' + format, path + 'nx' + format,
  217. path + 'py' + format, path + 'ny' + format,
  218. path + 'pz' + format, path + 'nz' + format
  219. ];
  220. envMap = new THREE.CubeTextureLoader().load(urls);
  221. envMap.format = THREE.RGBFormat;
  222. return envMap;
  223. },
  224. /**
  225. * Apply the material to the current entity.
  226. */
  227. applyToMesh: function () {
  228. const mesh = this.el.getObject3D('mesh');
  229. //var scene = mesh;
  230. var envMap = this.getEnvMap();
  231. mesh.traverse(function (node) {
  232. if (node.material) {
  233. node.material.side = THREE.BackSide;
  234. node.material.needsUpdate = true;
  235. //side = THREE.DoubleSide; break;
  236. }
  237. });
  238. mesh.traverse(function (node) {
  239. if (node.material && (node.material.isMeshStandardMaterial ||
  240. (node.material.isShaderMaterial && node.material.envMap !== undefined))) {
  241. node.material.envMap = envMap;
  242. node.material.needsUpdate = true;
  243. }
  244. });
  245. // const mesh = this.el.getObject3D('mesh');
  246. // if (mesh) {
  247. // mesh.material = this.material;
  248. // }
  249. },
  250. /**
  251. * On each frame, update the 'time' uniform in the shaders.
  252. */
  253. tick: function (t) {
  254. }
  255. })
  256. //https://threejs.org/examples/webgl_shaders_sky.html
  257. AFRAME.registerComponent('skyshader', {
  258. makeSun: function () {
  259. let sunSphere = new THREE.Mesh(
  260. new THREE.SphereBufferGeometry(20000, 16, 8),
  261. new THREE.MeshBasicMaterial({ color: 0xffffff })
  262. );
  263. sunSphere.position.y = - 700000;
  264. sunSphere.visible = true;
  265. let scene = this.el.sceneEl;
  266. this.el.sceneEl.setObject3D('sun', sunSphere);
  267. },
  268. init: function () {
  269. //let sunSphereEl = document.querySelector('a-scene').querySelector('#sun');
  270. //this.sunSphere = sunSphereEl.object3D;
  271. this.makeSun();
  272. this.sunSphere = this.el.sceneEl.getObject3D('sun');
  273. this.sky = new THREE.Sky();
  274. let scene = this.el.sceneEl;
  275. let effectController = {
  276. turbidity: 5,
  277. rayleigh: 2,
  278. mieCoefficient: 0.005,
  279. mieDirectionalG: 0.8,
  280. luminance: 1,
  281. inclination: 0, // elevation / inclination
  282. azimuth: 0.25, // Facing front,
  283. sun: ! true
  284. };
  285. let uniforms = this.sky.uniforms;
  286. uniforms.turbidity.value = effectController.turbidity;
  287. uniforms.rayleigh.value = effectController.rayleigh;
  288. uniforms.luminance.value = effectController.luminance;
  289. uniforms.mieCoefficient.value = effectController.mieCoefficient;
  290. uniforms.mieDirectionalG.value = effectController.mieDirectionalG;
  291. this.el.setObject3D('mesh', this.sky.mesh);
  292. let distance = 400000;
  293. var theta = Math.PI * (effectController.inclination - 0.5);
  294. var phi = 2 * Math.PI * (effectController.azimuth - 0.5);
  295. this.sunSphere.position.x = distance * Math.cos(phi);
  296. this.sunSphere.position.y = distance * Math.sin(phi) * Math.sin(theta);
  297. this.sunSphere.position.z = distance * Math.sin(phi) * Math.cos(theta);
  298. this.sunSphere.visible = effectController.sun;
  299. this.sky.uniforms.sunPosition.value.copy(this.sunSphere.position);
  300. },
  301. update: function () {
  302. },
  303. tick: function (t) {
  304. }
  305. })
  306. AFRAME.registerComponent('sun', {
  307. init: function () {
  308. this.sunSphere = new THREE.Mesh(
  309. new THREE.SphereBufferGeometry(20000, 16, 8),
  310. new THREE.MeshBasicMaterial({ color: 0xffffff })
  311. );
  312. this.sunSphere.position.y = - 700000;
  313. this.sunSphere.visible = true;
  314. this.el.setObject3D('mesh', this.sunSphere);
  315. },
  316. update: function () {
  317. },
  318. tick: function (t) {
  319. }
  320. })
  321. AFRAME.registerComponent('gearvrcontrol', {
  322. init: function () {
  323. var self = this;
  324. var controllerID = 'gearvr-' + vwf_view.kernel.moniker();
  325. this.el.addEventListener('triggerdown', function (event) {
  326. vwf_view.kernel.callMethod(controllerID, "triggerdown", []);
  327. });
  328. this.el.addEventListener('triggerup', function (event) {
  329. vwf_view.kernel.callMethod(controllerID, "triggerup", []);
  330. });
  331. },
  332. update: function () {
  333. },
  334. tick: function (t) {
  335. }
  336. })
  337. AFRAME.registerComponent('wmrvrcontrol', {
  338. schema: {
  339. hand: { default: 'right' }
  340. },
  341. update: function (old) {
  342. this.hand = this.data.hand;
  343. },
  344. init: function () {
  345. var self = this;
  346. this.hand = this.data.hand;
  347. var controllerID = 'wrmr-' + this.hand + '-' + vwf_view.kernel.moniker();
  348. //this.gearel = document.querySelector('#gearvrcontrol');
  349. this.el.addEventListener('triggerdown', function (event) {
  350. vwf_view.kernel.callMethod(controllerID, "triggerdown", []);
  351. });
  352. this.el.addEventListener('triggerup', function (event) {
  353. vwf_view.kernel.callMethod(controllerID, "triggerup", []);
  354. });
  355. },
  356. tick: function (t) {
  357. }
  358. })
  359. AFRAME.registerComponent('streamsound', {
  360. schema: {
  361. positional: { default: true }
  362. },
  363. init: function () {
  364. var self = this;
  365. let driver = vwf.views["vwf/view/webrtc"];
  366. this.listener = null;
  367. this.stream = null;
  368. if (!this.sound) {
  369. this.setupSound();
  370. }
  371. if (driver) {
  372. //let avatarID = 'avatar-' + vwf.moniker();
  373. let avatarID = this.el.id.slice(0, 27); //avatar-0RtnYBBTBU84OCNcAAFY
  374. let client = driver.state.clients[avatarID];
  375. if (client) {
  376. if (client.connection) {
  377. this.stream = client.connection.stream;
  378. if (this.stream) {
  379. this.audioEl = new Audio();
  380. this.audioEl.srcObject = this.stream;
  381. this.sound.setNodeSource(this.sound.context.createMediaStreamSource(this.stream));
  382. }
  383. }
  384. }
  385. }
  386. },
  387. setupSound: function () {
  388. var el = this.el;
  389. var sceneEl = el.sceneEl;
  390. if (this.sound) {
  391. el.removeObject3D(this.attrName);
  392. }
  393. if (!sceneEl.audioListener) {
  394. sceneEl.audioListener = new THREE.AudioListener();
  395. sceneEl.camera && sceneEl.camera.add(sceneEl.audioListener);
  396. sceneEl.addEventListener('camera-set-active', function (evt) {
  397. evt.detail.cameraEl.getObject3D('camera').add(sceneEl.audioListener);
  398. });
  399. }
  400. this.listener = sceneEl.audioListener;
  401. this.sound = this.data.positional
  402. ? new THREE.PositionalAudio(this.listener)
  403. : new THREE.Audio(this.listener);
  404. el.setObject3D(this.attrName, this.sound);
  405. },
  406. remove: function () {
  407. if (!this.sound) return;
  408. this.el.removeObject3D(this.attrName);
  409. if (this.stream) {
  410. this.sound.disconnect();
  411. }
  412. },
  413. update: function (old) {
  414. },
  415. tick: function (t) {
  416. }
  417. })
  418. AFRAME.registerComponent('viewoffset', {
  419. // fullWidth:
  420. // fullHeight:
  421. // xoffset:
  422. // yoffset:
  423. // width:
  424. // height:
  425. schema: {
  426. fullWidth: { default: window.innerWidth },
  427. fullHeight: { default: window.innerHeight },
  428. xoffset: { default: window.innerWidth / 2 },
  429. yoffset: { default: window.innerHeight / 2 },
  430. width: { default: window.innerWidth },
  431. height: { default: window.innerHeight }
  432. },
  433. init: function () {
  434. var self = this;
  435. this.el.sceneEl.addEventListener('loaded', setOffset);
  436. function setOffset() {
  437. this.setNewOffset();
  438. }
  439. },
  440. update: function (old) {
  441. this.fullWidth = this.data.fullWidth;
  442. this.fullHeight = this.data.fullHeight;
  443. this.xoffset = this.data.xoffset;
  444. this.yoffset = this.data.yoffset;
  445. this.width = this.data.width;
  446. this.height = this.data.height;
  447. //console.log(this.data);
  448. this.setNewOffset();
  449. },
  450. setNewOffset: function () {
  451. this.el.object3DMap.camera.setViewOffset(
  452. this.data.fullWidth,
  453. this.data.fullHeight,
  454. this.data.xoffset,
  455. this.data.yoffset,
  456. this.data.width,
  457. this.data.height)
  458. },
  459. tick: function (t) {
  460. }
  461. })
  462. AFRAME.registerComponent("virtual-gamepad-controls", {
  463. schema: {},
  464. init() {
  465. this.onEnterVr = this.onEnterVr.bind(this);
  466. this.onExitVr = this.onExitVr.bind(this);
  467. this.onFirstInteraction = this.onFirstInteraction.bind(this);
  468. this.onMoveJoystickChanged = this.onMoveJoystickChanged.bind(this);
  469. this.onMoveJoystickEnd = this.onMoveJoystickEnd.bind(this);
  470. // this.onLookJoystickChanged = this.onLookJoystickChanged.bind(this);
  471. // this.onLookJoystickEnd = this.onLookJoystickEnd.bind(this);
  472. this.mockJoystickContainer = document.createElement("div");
  473. this.mockJoystickContainer.classList.add('mockJoystickContainer');
  474. const leftMock = document.createElement("div");
  475. leftMock.classList.add('mockJoystick');
  476. const leftMockSmall = document.createElement("div");
  477. leftMockSmall.classList.add('mockJoystick', 'inner');
  478. leftMock.appendChild(leftMockSmall);
  479. this.mockJoystickContainer.appendChild(leftMock);
  480. // const rightMock = document.createElement("div");
  481. // rightMock.classList.add('mockJoystick');
  482. // const rightMockSmall = document.createElement("div");
  483. // rightMockSmall.classList.add('mockJoystick', 'inner');
  484. // rightMock.appendChild(rightMockSmall);
  485. // this.mockJoystickContainer.appendChild(rightMock);
  486. document.body.appendChild(this.mockJoystickContainer);
  487. // Setup gamepad elements
  488. const leftTouchZone = document.createElement("div");
  489. leftTouchZone.classList.add('touchZone', 'left');
  490. document.body.appendChild(leftTouchZone);
  491. this.leftTouchZone = leftTouchZone;
  492. this.leftStick = nipplejs.create({
  493. zone: this.leftTouchZone,
  494. color: "white",
  495. fadeTime: 0
  496. });
  497. this.leftStick.on("start", this.onFirstInteraction);
  498. this.leftStick.on("move", this.onMoveJoystickChanged);
  499. this.leftStick.on("end", this.onMoveJoystickEnd);
  500. // const rightTouchZone = document.createElement("div");
  501. // rightTouchZone.classList.add('touchZone', 'right');
  502. // document.body.appendChild(rightTouchZone);
  503. // this.rightTouchZone = rightTouchZone;
  504. // this.rightStick = nipplejs.create({
  505. // zone: this.rightTouchZone,
  506. // color: "white",
  507. // fadeTime: 0
  508. // });
  509. // this.rightStick.on("start", this.onFirstInteraction);
  510. // this.rightStick.on("move", this.onLookJoystickChanged);
  511. // this.rightStick.on("end", this.onLookJoystickEnd);
  512. this.inVr = false;
  513. this.moving = false;
  514. this.rotating = false;
  515. this.moveEvent = {
  516. axis: [0, 0]
  517. };
  518. // this.rotateYEvent = {
  519. // value: 0
  520. // };
  521. // this.rotateXEvent = {
  522. // value: 0
  523. // };
  524. this.el.sceneEl.addEventListener("enter-vr", this.onEnterVr);
  525. this.el.sceneEl.addEventListener("exit-vr", this.onExitVr);
  526. },
  527. onFirstInteraction() {
  528. this.leftStick.off("start", this.onFirstInteraction);
  529. //this.rightStick.off("start", this.onFirstInteraction);
  530. document.body.removeChild(this.mockJoystickContainer);
  531. },
  532. onMoveJoystickChanged(event, joystick) {
  533. const angle = joystick.angle.radian;
  534. const force = joystick.force < 1 ? joystick.force : 1;
  535. const moveStrength = 1.85;
  536. const x = Math.cos(angle) * force * moveStrength;
  537. const z = Math.sin(angle) * force * moveStrength;
  538. this.moving = true;
  539. this.moveEvent.axis[0] = x;
  540. this.moveEvent.axis[1] = z;
  541. },
  542. onMoveJoystickEnd() {
  543. this.moving = false;
  544. this.moveEvent.axis[0] = 0;
  545. this.moveEvent.axis[1] = 0;
  546. this.el.emit("move", this.moveEvent);
  547. },
  548. onLookJoystickChanged(event, joystick) {
  549. // Set pitch and yaw angles on right stick move
  550. const angle = joystick.angle.radian;
  551. const force = joystick.force < 1 ? joystick.force : 1;
  552. const turnStrength = 0.5;
  553. this.rotating = true;
  554. this.rotateYEvent.value = Math.cos(angle) * force * turnStrength;
  555. this.rotateXEvent.value = Math.sin(angle) * force * turnStrength;
  556. },
  557. onLookJoystickEnd() {
  558. this.rotating = false;
  559. this.rotateYEvent.value = 0;
  560. this.rotateXEvent.value = 0;
  561. this.el.emit("rotateY", this.rotateYEvent);
  562. this.el.emit("rotateX", this.rotateXEvent);
  563. },
  564. tick() {
  565. if (!this.inVr) {
  566. if (this.moving) {
  567. this.el.emit("move", this.moveEvent);
  568. }
  569. // if (this.rotating) {
  570. // this.el.emit("rotateY", this.rotateYEvent);
  571. // this.el.emit("rotateX", this.rotateXEvent);
  572. // }
  573. }
  574. },
  575. onEnterVr() {
  576. // Hide the joystick controls
  577. this.inVr = true;
  578. this.leftTouchZone.style.display = "none";
  579. // this.rightTouchZone.style.display = "none";
  580. },
  581. onExitVr() {
  582. // Show the joystick controls
  583. this.inVr = false;
  584. this.leftTouchZone.style.display = "block";
  585. // this.rightTouchZone.style.display = "block";
  586. },
  587. remove() {
  588. this.el.sceneEl.removeEventListener("entervr", this.onEnterVr);
  589. this.el.sceneEl.removeEventListener("exitvr", this.onExitVr);
  590. if (document.getElementsByClassName('mockJoystickContainer').length > 0){
  591. document.body.removeChild(this.mockJoystickContainer);
  592. }
  593. document.body.removeChild(this.leftTouchZone);
  594. // document.body.removeChild(this.rightTouchZone);
  595. }
  596. });
  597. /////////////////////////////////AR_JS/////////////////////////////////////////////
  598. // arjs-anchor
  599. //////////////////////////////////////////////////////////////////////////////
  600. AFRAME.registerComponent('arjs-anchor', {
  601. dependencies: ['arjs', 'artoolkit'],
  602. schema: {
  603. preset: {
  604. type: 'string',
  605. },
  606. markerhelpers : { // IIF preset === 'area'
  607. type: 'boolean',
  608. default: false,
  609. },
  610. // controls parameters
  611. size: {
  612. type: 'number',
  613. default: 1
  614. },
  615. type: {
  616. type: 'string',
  617. },
  618. patternUrl: {
  619. type: 'string',
  620. },
  621. barcodeValue: {
  622. type: 'number'
  623. },
  624. changeMatrixMode: {
  625. type: 'string',
  626. default : 'modelViewMatrix',
  627. },
  628. minConfidence: {
  629. type: 'number',
  630. default: 0.6,
  631. },
  632. },
  633. init: function () {
  634. var _this = this
  635. // get arjsSystem
  636. var arjsSystem = this.el.sceneEl.systems.arjs || this.el.sceneEl.systems.artoolkit;
  637. //////////////////////////////////////////////////////////////////////////////
  638. // Code Separator
  639. //////////////////////////////////////////////////////////////////////////////
  640. _this.isReady = false
  641. _this._arAnchor = null
  642. if(arjsSystem) {
  643. // honor object visibility
  644. if( _this.data.changeMatrixMode === 'modelViewMatrix' ){
  645. _this.el.object3D.visible = false
  646. }else if( _this.data.changeMatrixMode === 'cameraTransformMatrix' ){
  647. _this.el.sceneEl.object3D.visible = false
  648. }else console.assert(false)
  649. // trick to wait until arjsSystem is isReady
  650. var startedAt = Date.now()
  651. var timerId = setInterval(function(){
  652. // wait until the system is isReady
  653. if( arjsSystem.isReady === false ) return
  654. clearInterval(timerId)
  655. //////////////////////////////////////////////////////////////////////////////
  656. // update arProfile
  657. //////////////////////////////////////////////////////////////////////////////
  658. var arProfile = arjsSystem._arProfile
  659. // arProfile.changeMatrixMode('modelViewMatrix')
  660. arProfile.changeMatrixMode(_this.data.changeMatrixMode)
  661. // honor this.data.preset
  662. var markerParameters = Object.assign({}, arProfile.defaultMarkerParameters)
  663. if( _this.data.preset === 'hiro' ){
  664. markerParameters.type = 'pattern'
  665. markerParameters.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-hiro.patt'
  666. markerParameters.markersAreaEnabled = false
  667. }else if( _this.data.preset === 'kanji' ){
  668. markerParameters.type = 'pattern'
  669. markerParameters.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-kanji.patt'
  670. markerParameters.markersAreaEnabled = false
  671. }else if( _this.data.preset === 'area' ){
  672. markerParameters.type = 'barcode'
  673. markerParameters.barcodeValue = 1001
  674. markerParameters.markersAreaEnabled = true
  675. }else if( _this.data.type === 'barcode' ){
  676. markerParameters = {
  677. type: _this.data.type,
  678. changeMatrixMode: 'modelViewMatrix',
  679. barcodeValue: _this.data.barcodeValue,
  680. markersAreaEnabled: false
  681. }
  682. }else if( _this.data.type === 'pattern' ){
  683. markerParameters.type = _this.data.type
  684. markerParameters.patternUrl = _this.data.patternUrl;
  685. markerParameters.markersAreaEnabled = false
  686. }else {
  687. // console.assert( this.data.preset === '', 'illegal preset value '+this.data.preset)
  688. }
  689. //////////////////////////////////////////////////////////////////////////////
  690. // create arAnchor
  691. //////////////////////////////////////////////////////////////////////////////
  692. var arSession = arjsSystem._arSession
  693. var arAnchor = _this._arAnchor = new ARjs.Anchor(arSession, markerParameters)
  694. // it is now considered isReady
  695. _this.isReady = true
  696. //////////////////////////////////////////////////////////////////////////////
  697. // honor .debugUIEnabled
  698. //////////////////////////////////////////////////////////////////////////////
  699. if( arjsSystem.data.debugUIEnabled ){
  700. // get or create containerElement
  701. var containerElement = document.querySelector('#arjsDebugUIContainer')
  702. if( containerElement === null ){
  703. containerElement = document.createElement('div')
  704. containerElement.id = 'arjsDebugUIContainer'
  705. containerElement.setAttribute('style', 'position: fixed; bottom: 10px; width:100%; text-align: center; z-index: 1; color: grey;')
  706. document.body.appendChild(containerElement)
  707. }
  708. // create anchorDebugUI
  709. var anchorDebugUI = new ARjs.AnchorDebugUI(arAnchor)
  710. containerElement.appendChild(anchorDebugUI.domElement)
  711. }
  712. }, 1000/60)
  713. }
  714. },
  715. remove : function(){
  716. },
  717. update: function () {
  718. },
  719. tick: function(){
  720. var _this = this
  721. // if not yet isReady, do nothing
  722. if( this.isReady === false ) return
  723. //////////////////////////////////////////////////////////////////////////////
  724. // update arAnchor
  725. //////////////////////////////////////////////////////////////////////////////
  726. var arjsSystem = this.el.sceneEl.systems.arjs || this.el.sceneEl.systems.artoolkit
  727. this._arAnchor.update()
  728. //////////////////////////////////////////////////////////////////////////////
  729. // honor pose
  730. //////////////////////////////////////////////////////////////////////////////
  731. var arWorldRoot = this._arAnchor.object3d
  732. arWorldRoot.updateMatrixWorld(true)
  733. arWorldRoot.matrixWorld.decompose(this.el.object3D.position, this.el.object3D.quaternion, this.el.object3D.scale)
  734. //////////////////////////////////////////////////////////////////////////////
  735. // honor visibility
  736. //////////////////////////////////////////////////////////////////////////////
  737. if( _this._arAnchor.parameters.changeMatrixMode === 'modelViewMatrix' ){
  738. var wasVisible = _this.el.object3D.visible
  739. _this.el.object3D.visible = this._arAnchor.object3d.visible
  740. }else if( _this._arAnchor.parameters.changeMatrixMode === 'cameraTransformMatrix' ){
  741. var wasVisible = _this.el.sceneEl.object3D.visible
  742. _this.el.sceneEl.object3D.visible = this._arAnchor.object3d.visible
  743. }else console.assert(false)
  744. // emit markerFound markerLost
  745. if( _this._arAnchor.object3d.visible === true && wasVisible === false ){
  746. _this.el.emit('markerFound')
  747. }else if( _this._arAnchor.object3d.visible === false && wasVisible === true ){
  748. _this.el.emit('markerLost')
  749. }
  750. }
  751. })
  752. //////////////////////////////////////////////////////////////////////////////
  753. // define some primitives shortcuts
  754. //////////////////////////////////////////////////////////////////////////////
  755. AFRAME.registerPrimitive('a-anchor', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), {
  756. defaultComponents: {
  757. 'arjs-anchor': {},
  758. 'arjs-hit-testing': {},
  759. },
  760. mappings: {
  761. 'type': 'arjs-anchor.type',
  762. 'size': 'arjs-anchor.size',
  763. 'url': 'arjs-anchor.patternUrl',
  764. 'value': 'arjs-anchor.barcodeValue',
  765. 'preset': 'arjs-anchor.preset',
  766. 'minConfidence': 'arjs-anchor.minConfidence',
  767. 'markerhelpers': 'arjs-anchor.markerhelpers',
  768. 'hit-testing-renderDebug': 'arjs-hit-testing.renderDebug',
  769. 'hit-testing-enabled': 'arjs-hit-testing.enabled',
  770. }
  771. }))
  772. AFRAME.registerPrimitive('a-camera-static', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), {
  773. defaultComponents: {
  774. 'camera': {},
  775. },
  776. mappings: {
  777. }
  778. }))
  779. //////////////////////////////////////////////////////////////////////////////
  780. // backward compatibility
  781. //////////////////////////////////////////////////////////////////////////////
  782. // FIXME
  783. AFRAME.registerPrimitive('a-marker', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), {
  784. defaultComponents: {
  785. 'arjs-anchor': {},
  786. 'arjs-hit-testing': {},
  787. },
  788. mappings: {
  789. 'type': 'arjs-anchor.type',
  790. 'size': 'arjs-anchor.size',
  791. 'url': 'arjs-anchor.patternUrl',
  792. 'value': 'arjs-anchor.barcodeValue',
  793. 'preset': 'arjs-anchor.preset',
  794. 'minConfidence': 'arjs-anchor.minConfidence',
  795. 'markerhelpers': 'arjs-anchor.markerhelpers',
  796. 'hit-testing-renderDebug': 'arjs-hit-testing.renderDebug',
  797. 'hit-testing-enabled': 'arjs-hit-testing.enabled',
  798. }
  799. }))
  800. AFRAME.registerPrimitive('a-marker-camera', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), {
  801. defaultComponents: {
  802. 'arjs-anchor': {
  803. changeMatrixMode: 'cameraTransformMatrix'
  804. },
  805. 'camera': {},
  806. },
  807. mappings: {
  808. 'type': 'arjs-anchor.type',
  809. 'size': 'arjs-anchor.size',
  810. 'url': 'arjs-anchor.patternUrl',
  811. 'value': 'arjs-anchor.barcodeValue',
  812. 'preset': 'arjs-anchor.preset',
  813. 'minConfidence': 'arjs-anchor.minConfidence',
  814. 'markerhelpers': 'arjs-anchor.markerhelpers',
  815. }
  816. }))
  817. //////////////////////////////////////////////////////////////////////////////
  818. // arjs-hit-testing
  819. //////////////////////////////////////////////////////////////////////////////
  820. AFRAME.registerComponent('arjs-hit-testing', {
  821. dependencies: ['arjs', 'artoolkit'],
  822. schema: {
  823. enabled : {
  824. type: 'boolean',
  825. default: false,
  826. },
  827. renderDebug : {
  828. type: 'boolean',
  829. default: false,
  830. },
  831. },
  832. init: function () {
  833. var _this = this
  834. var arjsSystem = this.el.sceneEl.systems.arjs || this.el.sceneEl.systems.artoolkit;
  835. // TODO make it work on cameraTransformMatrix too
  836. //
  837. _this.isReady = false
  838. _this._arAnchor = null
  839. _this._arHitTesting = null
  840. if(arjsSystem) {
  841. // trick to wait until arjsSystem is isReady
  842. var startedAt = Date.now()
  843. var timerId = setInterval(function(){
  844. var anchorEl = _this.el
  845. var anchorComponent = anchorEl.components['arjs-anchor']
  846. // wait until anchorComponent is isReady
  847. if( anchorComponent === undefined || anchorComponent.isReady === false ) return
  848. clearInterval(timerId)
  849. //////////////////////////////////////////////////////////////////////////////
  850. // create arAnchor
  851. //////////////////////////////////////////////////////////////////////////////
  852. var arAnchor = anchorComponent._arAnchor
  853. var arSession = arjsSystem._arSession
  854. var renderer = arSession.parameters.renderer
  855. var hitTesting = _this._arHitTesting = new ARjs.HitTesting(arSession)
  856. hitTesting.enabled = _this.data.enabled
  857. // tango only - picking to set object position
  858. // renderer.domElement.addEventListener("click", function(domEvent){
  859. // var hitTestResults = hitTesting.testDomEvent(domEvent)
  860. // if( hitTestResults.length === 0 ) return
  861. // var hitTestResult = hitTestResults[0]
  862. // hitTestResult.apply(arAnchor.object3d)
  863. // })
  864. _this.isReady = true
  865. }, 1000/60)
  866. }
  867. },
  868. remove : function(){
  869. },
  870. update: function () {
  871. },
  872. tick: function(){
  873. var _this = this
  874. // if not yet isReady, do nothing
  875. if( this.isReady === false ) return
  876. var arjsSystem = this.el.sceneEl.systems.arjs || this.el.sceneEl.systems.artoolkit
  877. var arSession = arjsSystem._arSession
  878. var anchorEl = _this.el
  879. var anchorComponent = anchorEl.components['arjs-anchor']
  880. var arAnchor = anchorComponent._arAnchor
  881. var hitTesting = this._arHitTesting
  882. var camera = arSession.parameters.camera
  883. // console.log(camera.position)
  884. hitTesting.update(camera, arAnchor.object3d, arAnchor.parameters.changeMatrixMode)
  885. }
  886. });