UNPKG

aframe-extras

Version:

Add-ons and examples for A-Frame VR.

2 lines 12 kB
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("THREE"));else if("function"==typeof define&&define.amd)define(["THREE"],e);else{var s="object"==typeof exports?e(require("THREE")):e(t.THREE);for(var n in s)("object"==typeof exports?exports:t)[n]=s[n]}}(self,t=>(()=>{var e={612:e=>{"use strict";e.exports=t},866:()=>{AFRAME.registerComponent("nav-mesh",{schema:{nodeName:{type:"string"}},init:function(){this.system=this.el.sceneEl.systems.nav,this.hasLoadedNavMesh=!1,this.nodeName=this.data.nodeName,this.el.addEventListener("object3dset",this.loadNavMesh.bind(this))},play:function(){this.hasLoadedNavMesh||this.loadNavMesh()},loadNavMesh:function(){var t=this;const e=this.el.getObject3D("mesh");if(this.el.sceneEl.object3D,!e)return;let s;if(e.traverse(e=>{!e.isMesh||t.nodeName&&e.name!==t.nodeName||(s=e)}),!s)return;const n=s.geometry.clone();s.updateWorldMatrix(!0,!1),n.applyMatrix4(s.matrixWorld),this.system.setNavMeshGeometry(n),this.hasLoadedNavMesh=!0}})},982:()=>{AFRAME.registerComponent("nav-agent",{schema:{destination:{type:"vec3"},active:{default:!1},speed:{default:2}},init:function(){this.system=this.el.sceneEl.systems.nav,this.system.addAgent(this),this.group=null,this.path=[],this.raycaster=new THREE.Raycaster},remove:function(){this.system.removeAgent(this)},update:function(){this.path.length=0},updateNavLocation:function(){this.group=null,this.path=[]},tick:function(){const t=new THREE.Vector3,e=new THREE.Vector3,s=new THREE.Vector3;return function(n,o){const r=this.el,i=this.data,c=this.raycaster,h=i.speed*o/1e3;if(!i.active)return;if(!this.path.length){const e=this.el.object3D.position;this.group=this.group||this.system.getGroup(e),this.path=this.system.getPath(e,t.copy(i.destination),this.group)||[],r.emit("navigation-start")}if(!this.path.length)return console.warn("[nav] Unable to find path to %o.",i.destination),this.el.setAttribute("nav-agent",{active:!1}),void r.emit("navigation-end");const a=r.object3D.position,u=this.path[0];let l;if(e.subVectors(u,a),e.length()<h){if(this.path.shift(),!this.path.length)return this.el.setAttribute("nav-agent",{active:!1}),void r.emit("navigation-end");s.copy(a),l=this.path[0]}else s.copy(e.setLength(h)).add(a),l=u;l.y=a.y,r.object3D.lookAt(l),c.ray.origin.copy(s),c.ray.origin.y+=1.5,c.ray.direction={x:0,y:-1,z:0};const d=c.intersectObject(this.system.getNavMesh());d.length?(e.subVectors(d[0].point,a),a.add(e.setLength(h))):a.copy(s)}}()})}},s={};function n(t){var o=s[t];if(void 0!==o)return o.exports;var r=s[t]={exports:{}};return e[t](r,r.exports,n),r.exports}return(()=>{"use strict";n(866),n(982);var t=n(612);class e{static roundNumber(t,e){const s=Math.pow(10,e);return Math.round(t*s)/s}static sample(t){return t[Math.floor(Math.random()*t.length)]}static distanceToSquared(t,e){var s=t.x-e.x,n=t.y-e.y,o=t.z-e.z;return s*s+n*n+o*o}static isPointInPoly(t,e){for(var s=!1,n=-1,o=t.length,r=o-1;++n<o;r=n)(t[n].z<=e.z&&e.z<t[r].z||t[r].z<=e.z&&e.z<t[n].z)&&e.x<(t[r].x-t[n].x)*(e.z-t[n].z)/(t[r].z-t[n].z)+t[n].x&&(s=!s);return s}static isVectorInPolygon(t,e,s){var n=1e5,o=-1e5,r=[];return e.vertexIds.forEach(t=>{n=Math.min(s[t].y,n),o=Math.max(s[t].y,o),r.push(s[t])}),!!(t.y<o+.5&&t.y>n-.5&&this.isPointInPoly(r,t))}static triarea2(t,e,s){return(s.x-t.x)*(e.z-t.z)-(e.x-t.x)*(s.z-t.z)}static vequal(t,e){return this.distanceToSquared(t,e)<1e-5}static mergeVertices(e,s=1e-4){s=Math.max(s,Number.EPSILON);for(var n={},o=e.getIndex(),r=e.getAttribute("position"),i=o?o.count:r.count,c=0,h=[],a=[],u=Math.log10(1/s),l=Math.pow(10,u),d=0;d<i;d++){var p=o?o.getX(d):d,g="";g+=~~(r.getX(p)*l)+",",g+=~~(r.getY(p)*l)+",",(g+=~~(r.getZ(p)*l)+",")in n?h.push(n[g]):(a.push(r.getX(p)),a.push(r.getY(p)),a.push(r.getZ(p)),n[g]=c,h.push(c),c++)}const f=new t.BufferAttribute(new Float32Array(a),r.itemSize,r.normalized),v=new t.BufferGeometry;return v.setAttribute("position",f),v.setIndex(h),v}}class s{constructor(t){this.content=[],this.scoreFunction=t}push(t){this.content.push(t),this.sinkDown(this.content.length-1)}pop(){const t=this.content[0],e=this.content.pop();return this.content.length>0&&(this.content[0]=e,this.bubbleUp(0)),t}remove(t){const e=this.content.indexOf(t),s=this.content.pop();e!==this.content.length-1&&(this.content[e]=s,this.scoreFunction(s)<this.scoreFunction(t)?this.sinkDown(e):this.bubbleUp(e))}size(){return this.content.length}rescoreElement(t){this.sinkDown(this.content.indexOf(t))}sinkDown(t){const e=this.content[t];for(;t>0;){const s=(t+1>>1)-1,n=this.content[s];if(!(this.scoreFunction(e)<this.scoreFunction(n)))break;this.content[s]=e,this.content[t]=n,t=s}}bubbleUp(t){const e=this.content.length,s=this.content[t],n=this.scoreFunction(s);for(;;){const o=t+1<<1,r=o-1;let i,c=null;if(r<e&&(i=this.scoreFunction(this.content[r]),i<n&&(c=r)),o<e&&this.scoreFunction(this.content[o])<(null===c?n:i)&&(c=o),null===c)break;this.content[t]=this.content[c],this.content[c]=s,t=c}}}class o{constructor(){this.portals=[]}push(t,e){void 0===e&&(e=t),this.portals.push({left:t,right:e})}stringPull(){const t=this.portals,s=[];let n,o,r,i=0,c=0,h=0;n=t[0].left,o=t[0].left,r=t[0].right,s.push(n);for(let a=1;a<t.length;a++){const u=t[a].left,l=t[a].right;if(e.triarea2(n,r,l)<=0){if(!(e.vequal(n,r)||e.triarea2(n,o,l)>0)){s.push(o),n=o,i=c,o=n,r=n,c=i,h=i,a=i;continue}r=l,h=a}if(e.triarea2(n,o,u)>=0){if(!(e.vequal(n,o)||e.triarea2(n,r,u)<0)){s.push(r),n=r,i=h,o=n,r=n,c=i,h=i,a=i;continue}o=u,c=a}}return 0!==s.length&&e.vequal(s[s.length-1],t[t.length-1].left)||s.push(t[t.length-1].left),this.path=s,s}}class r{constructor(){this.zones={}}static createZone(s,n=1e-4){return class{static buildZone(s,n){const o=this._buildNavigationMesh(s,n),r={};o.vertices.forEach(t=>{t.x=e.roundNumber(t.x,2),t.y=e.roundNumber(t.y,2),t.z=e.roundNumber(t.z,2)}),r.vertices=o.vertices;const i=this._buildPolygonGroups(o);return r.groups=new Array(i.length),i.forEach((s,n)=>{const o=new Map;s.forEach((t,e)=>{o.set(t,e)});const i=new Array(s.length);s.forEach((s,n)=>{const c=[];s.neighbours.forEach(t=>c.push(o.get(t)));const h=[];s.neighbours.forEach(t=>h.push(this._getSharedVerticesInOrder(s,t)));const a=new t.Vector3(0,0,0);a.add(r.vertices[s.vertexIds[0]]),a.add(r.vertices[s.vertexIds[1]]),a.add(r.vertices[s.vertexIds[2]]),a.divideScalar(3),a.x=e.roundNumber(a.x,2),a.y=e.roundNumber(a.y,2),a.z=e.roundNumber(a.z,2),i[n]={id:n,neighbours:c,vertexIds:s.vertexIds,centroid:a,portals:h}}),r.groups[n]=i}),r}static _buildNavigationMesh(t,s){return t=e.mergeVertices(t,s),this._buildPolygonsFromGeometry(t)}static _spreadGroupId(t){let e=new Set([t]);for(;e.size>0;){const s=e;e=new Set,s.forEach(s=>{s.group=t.group,s.neighbours.forEach(t=>{void 0===t.group&&e.add(t)})})}}static _buildPolygonGroups(t){const e=[];return t.polygons.forEach(t=>{void 0!==t.group?e[t.group].push(t):(t.group=e.length,this._spreadGroupId(t),e.push([t]))}),e}static _buildPolygonNeighbours(t,e){const s=new Set,n=e[t.vertexIds[1]],o=e[t.vertexIds[2]];return e[t.vertexIds[0]].forEach(e=>{e!==t&&(n.includes(e)||o.includes(e))&&s.add(e)}),n.forEach(e=>{e!==t&&o.includes(e)&&s.add(e)}),s}static _buildPolygonsFromGeometry(e){const s=[],n=[],o=e.attributes.position,r=e.index,i=[];for(let e=0;e<o.count;e++)n.push((new t.Vector3).fromBufferAttribute(o,e)),i[e]=[];for(let t=0;t<e.index.count;t+=3){const e=r.getX(t),n=r.getX(t+1),o=r.getX(t+2),c={vertexIds:[e,n,o],neighbours:null};s.push(c),i[e].push(c),i[n].push(c),i[o].push(c)}return s.forEach(t=>{t.neighbours=this._buildPolygonNeighbours(t,i)}),{polygons:s,vertices:n}}static _getSharedVerticesInOrder(t,e){const s=t.vertexIds,n=s[0],o=s[1],r=s[2],i=e.vertexIds,c=i.includes(n),h=i.includes(o),a=i.includes(r);return c&&h&&a?Array.from(s):c&&h?[n,o]:h&&a?[o,r]:c&&a?[r,n]:(console.warn("Error processing navigation mesh neighbors; neighbors with <2 shared vertices found."),[])}}.buildZone(s,n)}setZoneData(t,e){this.zones[t]=e}getRandomNode(s,n,o,r){if(!this.zones[s])return new t.Vector3;o=o||null,r=r||0;const i=[];return this.zones[s].groups[n].forEach(t=>{o&&r?e.distanceToSquared(o,t.centroid)<r*r&&i.push(t.centroid):i.push(t.centroid)}),e.sample(i)||new t.Vector3}getClosestNode(t,s,n,o=!1){const r=this.zones[s].vertices;let i=null,c=1/0;return this.zones[s].groups[n].forEach(s=>{const n=e.distanceToSquared(s.centroid,t);n<c&&(!o||e.isVectorInPolygon(t,s,r))&&(i=s,c=n)}),i}findPath(n,r,i,c){const h=this.zones[i].groups[c],a=this.zones[i].vertices,u=this.getClosestNode(n,i,c,!0),l=this.getClosestNode(r,i,c,!0);if(!u||!l)return null;const d=class{static init(t){for(let e=0;e<t.length;e++){const s=t[e];s.f=0,s.g=0,s.h=0,s.cost=1,s.visited=!1,s.closed=!1,s.parent=null}}static cleanUp(t){for(let e=0;e<t.length;e++){const s=t[e];delete s.f,delete s.g,delete s.h,delete s.cost,delete s.visited,delete s.closed,delete s.parent}}static heap(){return new s(function(t){return t.f})}static search(t,e,s){this.init(t);const n=this.heap();for(n.push(e);n.size()>0;){const e=n.pop();if(e===s){let t=e;const s=[];for(;t.parent;)s.push(t),t=t.parent;return this.cleanUp(s),s.reverse()}e.closed=!0;const o=this.neighbours(t,e);for(let t=0,r=o.length;t<r;t++){const r=o[t];if(r.closed)continue;const i=e.g+r.cost,c=r.visited;if(!c||i<r.g){if(r.visited=!0,r.parent=e,!r.centroid||!s.centroid)throw new Error("Unexpected state");r.h=r.h||this.heuristic(r.centroid,s.centroid),r.g=i,r.f=r.g+r.h,c?n.rescoreElement(r):n.push(r)}}}return[]}static heuristic(t,s){return e.distanceToSquared(t,s)}static neighbours(t,e){const s=[];for(let n=0;n<e.neighbours.length;n++)s.push(t[e.neighbours[n]]);return s}}.search(h,u,l),p=function(t,e){for(var s=0;s<t.neighbours.length;s++)if(t.neighbours[s]===e.id)return t.portals[s]},g=new o;g.push(n);for(let t=0;t<d.length;t++){const e=d[t],s=d[t+1];if(s){const t=p(e,s);g.push(a[t[0]],a[t[1]])}}g.push(r),g.stringPull();const f=g.path.map(e=>new t.Vector3(e.x,e.y,e.z));return f.shift(),f}}r.prototype.getGroup=function(){const s=new t.Plane;return function(t,n,o=!1){if(!this.zones[t])return null;let r=null,i=Math.pow(50,2);const c=this.zones[t];for(let t=0;t<c.groups.length;t++){const h=c.groups[t];for(const a of h){if(o&&(s.setFromCoplanarPoints(c.vertices[a.vertexIds[0]],c.vertices[a.vertexIds[1]],c.vertices[a.vertexIds[2]]),Math.abs(s.distanceToPoint(n))<.01)&&e.isPointInPoly([c.vertices[a.vertexIds[0]],c.vertices[a.vertexIds[1]],c.vertices[a.vertexIds[2]]],n))return t;const h=e.distanceToSquared(a.centroid,n);h<i&&(r=t,i=h)}}return r}}(),r.prototype.clampStep=function(){const e=new t.Vector3,s=new t.Plane,n=new t.Triangle,o=new t.Vector3;let r,i,c=new t.Vector3;return function(t,h,a,u,l,d){const p=this.zones[u].vertices,g=this.zones[u].groups[l],f=[a],v={};v[a.id]=0,r=void 0,c.set(0,0,0),i=1/0,s.setFromCoplanarPoints(p[a.vertexIds[0]],p[a.vertexIds[1]],p[a.vertexIds[2]]),s.projectPoint(h,e),o.copy(e);for(let t=f.pop();t;t=f.pop()){n.set(p[t.vertexIds[0]],p[t.vertexIds[1]],p[t.vertexIds[2]]),n.closestPointToPoint(o,e),e.distanceToSquared(o)<i&&(r=t,c.copy(e),i=e.distanceToSquared(o));const s=v[t.id];if(!(s>2))for(let e=0;e<t.neighbours.length;e++){const n=g[t.neighbours[e]];n.id in v||(f.push(n),v[n.id]=s+1)}}return d.copy(c),r}}(),t.Object3D;const i=new r,c="level";AFRAME.registerSystem("nav",{init:function(){this.navMesh=null,this.agents=new Set},setNavMeshGeometry:function(t){this.navMesh=new THREE.Mesh(t),i.setZoneData(c,r.createZone(t)),Array.from(this.agents).forEach(t=>t.updateNavLocation())},getNavMesh:function(){return this.navMesh},addAgent:function(t){this.agents.add(t)},removeAgent:function(t){this.agents.delete(t)},getPath:function(t,e,s){return this.navMesh?i.findPath(t,e,c,s):null},getGroup:function(t){return this.navMesh?i.getGroup(c,t):null},getNode:function(t,e){return this.navMesh?i.getClosestNode(t,c,e,!0):null},clampStep:function(t,e,s,n,o){return this.navMesh?n?i.clampStep(t,e,n,c,s,o):(o.copy(e),this.getNode(e,s)):(o.copy(e),null)}})})(),{}})()); //# sourceMappingURL=aframe-extras.pathfinding.min.js.map