aframe-components.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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. })