aframe-curve-component.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /******/ (function(modules) { // webpackBootstrap
  2. /******/ // The module cache
  3. /******/ var installedModules = {};
  4. /******/ // The require function
  5. /******/ function __webpack_require__(moduleId) {
  6. /******/ // Check if module is in cache
  7. /******/ if(installedModules[moduleId])
  8. /******/ return installedModules[moduleId].exports;
  9. /******/ // Create a new module (and put it into the cache)
  10. /******/ var module = installedModules[moduleId] = {
  11. /******/ exports: {},
  12. /******/ id: moduleId,
  13. /******/ loaded: false
  14. /******/ };
  15. /******/ // Execute the module function
  16. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  17. /******/ // Flag the module as loaded
  18. /******/ module.loaded = true;
  19. /******/ // Return the exports of the module
  20. /******/ return module.exports;
  21. /******/ }
  22. /******/ // expose the modules object (__webpack_modules__)
  23. /******/ __webpack_require__.m = modules;
  24. /******/ // expose the module cache
  25. /******/ __webpack_require__.c = installedModules;
  26. /******/ // __webpack_public_path__
  27. /******/ __webpack_require__.p = "";
  28. /******/ // Load entry module and return exports
  29. /******/ return __webpack_require__(0);
  30. /******/ })
  31. /************************************************************************/
  32. /******/ ([
  33. /* 0 */
  34. /***/ (function(module, exports) {
  35. /* global AFRAME */
  36. if (typeof AFRAME === 'undefined') {
  37. throw new Error('Component attempted to register before AFRAME was available.');
  38. }
  39. /**
  40. * Curve component for A-Frame to deal with spline curves
  41. */
  42. var zAxis = new THREE.Vector3(0, 0, 1);
  43. var degToRad = THREE.Math.degToRad;
  44. AFRAME.registerComponent('curve-point', {
  45. //dependencies: ['position'],
  46. schema: {},
  47. init: function () {
  48. this.el.addEventListener("componentchanged", this.changeHandler.bind(this));
  49. this.el.emit("curve-point-change");
  50. },
  51. changeHandler: function (event) {
  52. if (event.detail.name == "position") {
  53. this.el.emit("curve-point-change");
  54. }
  55. }
  56. });
  57. AFRAME.registerComponent('curve', {
  58. //dependencies: ['curve-point'],
  59. schema: {
  60. type: {
  61. type: 'string',
  62. default: 'CurvePath',
  63. oneOf: ['CatmullRom', 'CubicBezier', 'QuadraticBezier', 'Line', 'CurvePath']
  64. },
  65. closed: {
  66. type: 'boolean',
  67. default: false
  68. }
  69. },
  70. init: function () {
  71. this.pathPoints = null;
  72. this.curve = null;
  73. this.el.addEventListener("curve-point-change", this.update.bind(this));
  74. },
  75. update: function (oldData) {
  76. this.points = Array.from(this.el.querySelectorAll("a-curve-point, [curve-point]"));
  77. if (this.points.length <= 1) {
  78. console.warn("At least 2 curve-points needed to draw a curve");
  79. this.curve = null;
  80. } else {
  81. // Get Array of Positions from Curve-Points
  82. var pointsArray = this.points.map(function (point) {
  83. if (point.x !== undefined && point.y !== undefined && point.z !== undefined) {
  84. return point;
  85. }
  86. return point.object3D.getWorldPosition();
  87. });
  88. // Update the Curve if either the Curve-Points or other Properties changed
  89. if (!AFRAME.utils.deepEqual(pointsArray, this.pathPoints) || (oldData !== 'CustomEvent' && !AFRAME.utils.deepEqual(this.data, oldData))) {
  90. this.curve = null;
  91. this.pathPoints = pointsArray;
  92. // Create Curve
  93. switch (this.data.type) {
  94. case 'CubicBezier':
  95. if (this.pathPoints.length != 4) {
  96. throw new Error('The Three constructor of type CubicBezierCurve3 requires 4 points');
  97. }
  98. this.curve = new THREE.CubicBezierCurve3(this.pathPoints[0], this.pathPoints[1], this.pathPoints[2], this.pathPoints[3]);
  99. break;
  100. case 'QuadraticBezier':
  101. if (this.pathPoints.length != 3) {
  102. throw new Error('The Three constructor of type QuadraticBezierCurve3 requires 3 points');
  103. }
  104. this.curve = new THREE.QuadraticBezierCurve3(this.pathPoints[0], this.pathPoints[1], this.pathPoints[2]);
  105. break;
  106. case 'Line':
  107. if (this.pathPoints.length != 2) {
  108. throw new Error('The Three constructor of type LineCurve3 requires 2 points');
  109. }
  110. this.curve = new THREE.LineCurve3(this.pathPoints[0], this.pathPoints[1]);
  111. break;
  112. case 'CatmullRom':
  113. this.curve = new THREE.CatmullRomCurve3(this.pathPoints);
  114. break;
  115. case 'Spline':
  116. this.curve = new THREE.SplineCurve3(this.pathPoints);
  117. break;
  118. // Patrick
  119. case 'CurvePath':
  120. this.curve = new THREE.CurvePath();
  121. for(var i = 0, p = this.pathPoints.length - 1; i < p; i++) {
  122. var curveSegment = new THREE.LineCurve3(this.pathPoints[i], this.pathPoints[i + 1]);
  123. this.curve.add(curveSegment);
  124. }
  125. break;
  126. default:
  127. throw new Error('No Three constructor of type (case sensitive): ' + this.data.type + 'Curve3');
  128. }
  129. this.curve.closed = this.data.closed;
  130. this.el.emit('curve-updated');
  131. }
  132. }
  133. },
  134. remove: function () {
  135. this.el.removeEventListener("curve-point-change", this.update.bind(this));
  136. },
  137. closestPointInLocalSpace: function closestPoint(point, resolution, testPoint, currentRes) {
  138. if (!this.curve) throw Error('Curve not instantiated yet.');
  139. resolution = resolution || 0.1 / this.curve.getLength();
  140. currentRes = currentRes || 0.5;
  141. testPoint = testPoint || 0.5;
  142. currentRes /= 2;
  143. var aTest = testPoint + currentRes;
  144. var bTest = testPoint - currentRes;
  145. var a = this.curve.getPointAt(aTest);
  146. var b = this.curve.getPointAt(bTest);
  147. var aDistance = a.distanceTo(point);
  148. var bDistance = b.distanceTo(point);
  149. var aSmaller = aDistance < bDistance;
  150. if (currentRes < resolution) {
  151. var tangent = this.curve.getTangentAt(aSmaller ? aTest : bTest);
  152. if (currentRes < resolution) return {
  153. result: aSmaller ? aTest : bTest,
  154. location: aSmaller ? a : b,
  155. distance: aSmaller ? aDistance : bDistance,
  156. normal: normalFromTangent(tangent),
  157. tangent: tangent
  158. };
  159. }
  160. if (aDistance < bDistance) {
  161. return this.closestPointInLocalSpace(point, resolution, aTest, currentRes);
  162. } else {
  163. return this.closestPointInLocalSpace(point, resolution, bTest, currentRes);
  164. }
  165. }
  166. });
  167. var tempQuaternion = new THREE.Quaternion();
  168. function normalFromTangent(tangent) {
  169. var lineEnd = new THREE.Vector3(0, 1, 0);
  170. tempQuaternion.setFromUnitVectors(zAxis, tangent);
  171. lineEnd.applyQuaternion(tempQuaternion);
  172. return lineEnd;
  173. }
  174. AFRAME.registerShader('line', {
  175. schema: {
  176. color: {default: '#ff0000'},
  177. },
  178. init: function (data) {
  179. this.material = new THREE.LineBasicMaterial(data);
  180. },
  181. update: function (data) {
  182. this.material = new THREE.LineBasicMaterial(data);
  183. },
  184. });
  185. AFRAME.registerComponent('draw-curve', {
  186. //dependencies: ['curve', 'material'],
  187. schema: {
  188. curve: {type: 'selector'}
  189. },
  190. init: function () {
  191. console.log(this.data);
  192. this.data.curve.addEventListener('curve-updated', this.update.bind(this));
  193. },
  194. update: function () {
  195. if (this.data.curve) {
  196. this.curve = this.data.curve.components.curve;
  197. }
  198. if (this.curve && this.curve.curve) {
  199. var lineGeometry = new THREE.BufferGeometry().setFromPoints(this.curve.curve.getPoints(this.curve.curve.getPoints().length * 10));
  200. var mesh = this.el.getOrCreateObject3D('mesh', THREE.Line);
  201. lineMaterial = mesh.material ? mesh.material : new THREE.LineBasicMaterial({
  202. color: "#ff0000"
  203. });
  204. this.el.setObject3D('mesh', new THREE.Line(lineGeometry, lineMaterial));
  205. }
  206. },
  207. remove: function () {
  208. this.data.curve.removeEventListener('curve-updated', this.update.bind(this));
  209. this.el.getObject3D('mesh').geometry = new THREE.Geometry();
  210. }
  211. });
  212. AFRAME.registerComponent('clone-along-curve', {
  213. //dependencies: ['curve'],
  214. schema: {
  215. curve: {type: 'selector'},
  216. spacing: {default: 1},
  217. rotation: {
  218. type: 'vec3',
  219. default: '0 0 0'
  220. },
  221. scale: {
  222. type: 'vec3',
  223. default: '1 1 1'
  224. }
  225. },
  226. init: function () {
  227. this.el.addEventListener('model-loaded', this.update.bind(this));
  228. this.data.curve.addEventListener('curve-updated', this.update.bind(this));
  229. },
  230. update: function () {
  231. this.remove();
  232. if (this.data.curve) {
  233. this.curve = this.data.curve.components.curve;
  234. }
  235. console.log(this.curve);
  236. if (!this.el.getObject3D('clones') && this.curve && this.curve.curve) {
  237. var mesh = this.el.getObject3D('mesh');
  238. var length = this.curve.curve.getLength();
  239. var start = 0;
  240. var counter = start;
  241. var cloneMesh = this.el.getOrCreateObject3D('clones', THREE.Group);
  242. var parent = new THREE.Object3D();
  243. mesh.scale.set(this.data.scale.x, this.data.scale.y, this.data.scale.z);
  244. mesh.rotation.set(degToRad(this.data.rotation.x), degToRad(this.data.rotation.y), degToRad(this.data.rotation.z));
  245. mesh.rotation.order = 'YXZ';
  246. parent.add(mesh);
  247. while (counter <= length) {
  248. var child = parent.clone(true);
  249. child.position.copy(this.curve.curve.getPointAt(counter / length));
  250. tangent = this.curve.curve.getTangentAt(counter / length).normalize();
  251. child.quaternion.setFromUnitVectors(zAxis, tangent);
  252. cloneMesh.add(child);
  253. counter += this.data.spacing;
  254. }
  255. }
  256. },
  257. remove: function () {
  258. this.curve = null;
  259. if (this.el.getObject3D('clones')) {
  260. this.el.removeObject3D('clones');
  261. }
  262. }
  263. });
  264. AFRAME.registerPrimitive('a-draw-curve', {
  265. defaultComponents: {
  266. 'draw-curve': {},
  267. },
  268. mappings: {
  269. curveref: 'draw-curve.curve',
  270. }
  271. });
  272. AFRAME.registerPrimitive('a-curve-point', {
  273. defaultComponents: {
  274. 'curve-point': {},
  275. },
  276. mappings: {}
  277. });
  278. AFRAME.registerPrimitive('a-curve', {
  279. defaultComponents: {
  280. 'curve': {}
  281. },
  282. mappings: {
  283. type: 'curve.type',
  284. }
  285. });
  286. /***/ })
  287. /******/ ]);