UNPKG

3d-scene-creator

Version:

A simple utility to create and manage 3D scenes

1 lines 25.8 kB
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("three"),require("three/examples/jsm/controls/OrbitControls.js"),require("three/examples/jsm/loaders/GLTFLoader.js")):typeof define==`function`&&define.amd?define([`exports`,`three`,`three/examples/jsm/controls/OrbitControls.js`,`three/examples/jsm/loaders/GLTFLoader.js`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e[`3d-scene-creator`]={},e.THREE,e.OrbitControls,e.GLTFLoader))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Object.create,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,u=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=s(t),c=0,u=i.length,d;c<u;c++)d=i[c],!l.call(e,d)&&d!==n&&a(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=o(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:i(c(e)),u(t||!e||!e.__esModule?a(n,`default`,{value:e,enumerable:!0}):n,e)))(t);var d=Object.freeze({Linear:Object.freeze({None:function(e){return e},In:function(e){return e},Out:function(e){return e},InOut:function(e){return e}}),Quadratic:Object.freeze({In:function(e){return e*e},Out:function(e){return e*(2-e)},InOut:function(e){return(e*=2)<1?.5*e*e:-.5*(--e*(e-2)-1)}}),Cubic:Object.freeze({In:function(e){return e*e*e},Out:function(e){return--e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e:.5*((e-=2)*e*e+2)}}),Quartic:Object.freeze({In:function(e){return e*e*e*e},Out:function(e){return 1- --e*e*e*e},InOut:function(e){return(e*=2)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2)}}),Quintic:Object.freeze({In:function(e){return e*e*e*e*e},Out:function(e){return--e*e*e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2)}}),Sinusoidal:Object.freeze({In:function(e){return 1-Math.sin((1-e)*Math.PI/2)},Out:function(e){return Math.sin(e*Math.PI/2)},InOut:function(e){return .5*(1-Math.sin(Math.PI*(.5-e)))}}),Exponential:Object.freeze({In:function(e){return e===0?0:1024**(e-1)},Out:function(e){return e===1?1:1-2**(-10*e)},InOut:function(e){return e===0?0:e===1?1:(e*=2)<1?.5*1024**(e-1):.5*(-(2**(-10*(e-1)))+2)}}),Circular:Object.freeze({In:function(e){return 1-Math.sqrt(1-e*e)},Out:function(e){return Math.sqrt(1- --e*e)},InOut:function(e){return(e*=2)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)}}),Elastic:Object.freeze({In:function(e){return e===0?0:e===1?1:-(2**(10*(e-1)))*Math.sin((e-1.1)*5*Math.PI)},Out:function(e){return e===0?0:e===1?1:2**(-10*e)*Math.sin((e-.1)*5*Math.PI)+1},InOut:function(e){return e===0?0:e===1?1:(e*=2,e<1?-.5*2**(10*(e-1))*Math.sin((e-1.1)*5*Math.PI):.5*2**(-10*(e-1))*Math.sin((e-1.1)*5*Math.PI)+1)}}),Back:Object.freeze({In:function(e){var t=1.70158;return e===1?1:e*e*((t+1)*e-t)},Out:function(e){var t=1.70158;return e===0?0:--e*e*((t+1)*e+t)+1},InOut:function(e){var t=1.70158*1.525;return(e*=2)<1?.5*(e*e*((t+1)*e-t)):.5*((e-=2)*e*((t+1)*e+t)+2)}}),Bounce:Object.freeze({In:function(e){return 1-d.Bounce.Out(1-e)},Out:function(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},InOut:function(e){return e<.5?d.Bounce.In(e*2)*.5:d.Bounce.Out(e*2-1)*.5+.5}}),generatePow:function(e){return e===void 0&&(e=4),e=e<2**-52?2**-52:e,e=e>1e4?1e4:e,{In:function(t){return t**+e},Out:function(t){return 1-(1-t)**e},InOut:function(t){return t<.5?(t*2)**e/2:(1-(2-t*2)**e)/2+.5}}}}),f=function(){return performance.now()},p=function(){function e(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this._tweens={},this._tweensAddedDuringUpdate={},this.add.apply(this,e)}return e.prototype.getAll=function(){var e=this;return Object.keys(this._tweens).map(function(t){return e._tweens[t]})},e.prototype.removeAll=function(){this._tweens={}},e.prototype.add=function(){for(var e,t=[],n=0;n<arguments.length;n++)t[n]=arguments[n];for(var r=0,i=t;r<i.length;r++){var a=i[r];(e=a._group)==null||e.remove(a),a._group=this,this._tweens[a.getId()]=a,this._tweensAddedDuringUpdate[a.getId()]=a}},e.prototype.remove=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++){var i=r[n];i._group=void 0,delete this._tweens[i.getId()],delete this._tweensAddedDuringUpdate[i.getId()]}},e.prototype.allStopped=function(){return this.getAll().every(function(e){return!e.isPlaying()})},e.prototype.update=function(e,t){e===void 0&&(e=f()),t===void 0&&(t=!0);var n=Object.keys(this._tweens);if(n.length!==0)for(;n.length>0;){this._tweensAddedDuringUpdate={};for(var r=0;r<n.length;r++){var i=this._tweens[n[r]],a=!t;i&&i.update(e,a)===!1&&!t&&this.remove(i)}n=Object.keys(this._tweensAddedDuringUpdate)}},e}(),m={Linear:function(e,t){var n=e.length-1,r=n*t,i=Math.floor(r),a=m.Utils.Linear;return t<0?a(e[0],e[1],r):t>1?a(e[n],e[n-1],n-r):a(e[i],e[i+1>n?n:i+1],r-i)},Bezier:function(e,t){for(var n=0,r=e.length-1,i=Math.pow,a=m.Utils.Bernstein,o=0;o<=r;o++)n+=i(1-t,r-o)*i(t,o)*e[o]*a(r,o);return n},CatmullRom:function(e,t){var n=e.length-1,r=n*t,i=Math.floor(r),a=m.Utils.CatmullRom;return e[0]===e[n]?(t<0&&(i=Math.floor(r=n*(1+t))),a(e[(i-1+n)%n],e[i],e[(i+1)%n],e[(i+2)%n],r-i)):t<0?e[0]-(a(e[0],e[0],e[1],e[1],-r)-e[0]):t>1?e[n]-(a(e[n],e[n],e[n-1],e[n-1],r-n)-e[n]):a(e[i?i-1:0],e[i],e[n<i+1?n:i+1],e[n<i+2?n:i+2],r-i)},Utils:{Linear:function(e,t,n){return(t-e)*n+e},Bernstein:function(e,t){var n=m.Utils.Factorial;return n(e)/n(t)/n(e-t)},Factorial:(function(){var e=[1];return function(t){var n=1;if(e[t])return e[t];for(var r=t;r>1;r--)n*=r;return e[t]=n,n}})(),CatmullRom:function(e,t,n,r,i){var a=(n-e)*.5,o=(r-t)*.5,s=i*i,c=i*s;return(2*t-2*n+a+o)*c+(-3*t+3*n-2*a-o)*s+a*i+t}}},h=function(){function e(){}return e.nextId=function(){return e._nextId++},e._nextId=0,e}(),g=new p,_=function(){function e(e,t){this._isPaused=!1,this._pauseStart=0,this._valuesStart={},this._valuesEnd={},this._valuesStartRepeat={},this._duration=1e3,this._isDynamic=!1,this._initialRepeat=0,this._repeat=0,this._yoyo=!1,this._isPlaying=!1,this._reversed=!1,this._delayTime=0,this._startTime=0,this._easingFunction=d.Linear.None,this._interpolationFunction=m.Linear,this._chainedTweens=[],this._onStartCallbackFired=!1,this._onEveryStartCallbackFired=!1,this._id=h.nextId(),this._isChainStopped=!1,this._propertiesAreSetUp=!1,this._goToEnd=!1,this._object=e,typeof t==`object`?(this._group=t,t.add(this)):t===!0&&(this._group=g,g.add(this))}return e.prototype.getId=function(){return this._id},e.prototype.isPlaying=function(){return this._isPlaying},e.prototype.isPaused=function(){return this._isPaused},e.prototype.getDuration=function(){return this._duration},e.prototype.to=function(e,t){if(t===void 0&&(t=1e3),this._isPlaying)throw Error(`Can not call Tween.to() while Tween is already started or paused. Stop the Tween first.`);return this._valuesEnd=e,this._propertiesAreSetUp=!1,this._duration=t<0?0:t,this},e.prototype.duration=function(e){return e===void 0&&(e=1e3),this._duration=e<0?0:e,this},e.prototype.dynamic=function(e){return e===void 0&&(e=!1),this._isDynamic=e,this},e.prototype.start=function(e,t){if(e===void 0&&(e=f()),t===void 0&&(t=!1),this._isPlaying)return this;if(this._repeat=this._initialRepeat,this._reversed)for(var n in this._reversed=!1,this._valuesStartRepeat)this._swapEndStartRepeatValues(n),this._valuesStart[n]=this._valuesStartRepeat[n];if(this._isPlaying=!0,this._isPaused=!1,this._onStartCallbackFired=!1,this._onEveryStartCallbackFired=!1,this._isChainStopped=!1,this._startTime=e,this._startTime+=this._delayTime,!this._propertiesAreSetUp||t){if(this._propertiesAreSetUp=!0,!this._isDynamic){var r={};for(var i in this._valuesEnd)r[i]=this._valuesEnd[i];this._valuesEnd=r}this._setupProperties(this._object,this._valuesStart,this._valuesEnd,this._valuesStartRepeat,t)}return this},e.prototype.startFromCurrentValues=function(e){return this.start(e,!0)},e.prototype._setupProperties=function(e,t,n,r,i){for(var a in n){var o=e[a],s=Array.isArray(o),c=s?`array`:typeof o,l=!s&&Array.isArray(n[a]);if(!(c===`undefined`||c===`function`)){if(l){var u=n[a];if(u.length===0)continue;for(var d=[o],f=0,p=u.length;f<p;f+=1){var m=this._handleRelativeValue(o,u[f]);if(isNaN(m)){l=!1,console.warn(`Found invalid interpolation list. Skipping.`);break}d.push(m)}l&&(n[a]=d)}if((c===`object`||s)&&o&&!l){t[a]=s?[]:{};var h=o;for(var g in h)t[a][g]=h[g];r[a]=s?[]:{};var u=n[a];if(!this._isDynamic){var _={};for(var g in u)_[g]=u[g];n[a]=u=_}this._setupProperties(h,t[a],u,r[a],i)}else (t[a]===void 0||i)&&(t[a]=o),s||(t[a]*=1),l?r[a]=n[a].slice().reverse():r[a]=t[a]||0}}},e.prototype.stop=function(){return this._isChainStopped||(this._isChainStopped=!0,this.stopChainedTweens()),this._isPlaying?(this._isPlaying=!1,this._isPaused=!1,this._onStopCallback&&this._onStopCallback(this._object),this):this},e.prototype.end=function(){return this._goToEnd=!0,this.update(this._startTime+this._duration),this},e.prototype.pause=function(e){return e===void 0&&(e=f()),this._isPaused||!this._isPlaying?this:(this._isPaused=!0,this._pauseStart=e,this)},e.prototype.resume=function(e){return e===void 0&&(e=f()),!this._isPaused||!this._isPlaying?this:(this._isPaused=!1,this._startTime+=e-this._pauseStart,this._pauseStart=0,this)},e.prototype.stopChainedTweens=function(){for(var e=0,t=this._chainedTweens.length;e<t;e++)this._chainedTweens[e].stop();return this},e.prototype.group=function(e){return e?(e.add(this),this):(console.warn(`tween.group() without args has been removed, use group.add(tween) instead.`),this)},e.prototype.remove=function(){var e;return(e=this._group)==null||e.remove(this),this},e.prototype.delay=function(e){return e===void 0&&(e=0),this._delayTime=e,this},e.prototype.repeat=function(e){return e===void 0&&(e=0),this._initialRepeat=e,this._repeat=e,this},e.prototype.repeatDelay=function(e){return this._repeatDelayTime=e,this},e.prototype.yoyo=function(e){return e===void 0&&(e=!1),this._yoyo=e,this},e.prototype.easing=function(e){return e===void 0&&(e=d.Linear.None),this._easingFunction=e,this},e.prototype.interpolation=function(e){return e===void 0&&(e=m.Linear),this._interpolationFunction=e,this},e.prototype.chain=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];return this._chainedTweens=e,this},e.prototype.onStart=function(e){return this._onStartCallback=e,this},e.prototype.onEveryStart=function(e){return this._onEveryStartCallback=e,this},e.prototype.onUpdate=function(e){return this._onUpdateCallback=e,this},e.prototype.onRepeat=function(e){return this._onRepeatCallback=e,this},e.prototype.onComplete=function(e){return this._onCompleteCallback=e,this},e.prototype.onStop=function(e){return this._onStopCallback=e,this},e.prototype.update=function(t,n){var r=this;if(t===void 0&&(t=f()),n===void 0&&(n=e.autoStartOnUpdate),this._isPaused)return!0;var i;if(!this._goToEnd&&!this._isPlaying)if(n)this.start(t,!0);else return!1;if(this._goToEnd=!1,t<this._startTime)return!0;this._onStartCallbackFired===!1&&(this._onStartCallback&&this._onStartCallback(this._object),this._onStartCallbackFired=!0),this._onEveryStartCallbackFired===!1&&(this._onEveryStartCallback&&this._onEveryStartCallback(this._object),this._onEveryStartCallbackFired=!0);var a=t-this._startTime,o=this._duration+(this._repeatDelayTime??this._delayTime),s=this._duration+this._repeat*o,c=function(){if(r._duration===0||a>s)return 1;var e=a-Math.trunc(a/o)*o,t=Math.min(e/r._duration,1);return t===0&&a===r._duration?1:t}(),l=this._easingFunction(c);if(this._updateProperties(this._object,this._valuesStart,this._valuesEnd,l),this._onUpdateCallback&&this._onUpdateCallback(this._object,c),this._duration===0||a>=this._duration)if(this._repeat>0){var u=Math.min(Math.trunc((a-this._duration)/o)+1,this._repeat);for(i in isFinite(this._repeat)&&(this._repeat-=u),this._valuesStartRepeat)!this._yoyo&&typeof this._valuesEnd[i]==`string`&&(this._valuesStartRepeat[i]=this._valuesStartRepeat[i]+parseFloat(this._valuesEnd[i])),this._yoyo&&this._swapEndStartRepeatValues(i),this._valuesStart[i]=this._valuesStartRepeat[i];return this._yoyo&&(this._reversed=!this._reversed),this._startTime+=o*u,this._onRepeatCallback&&this._onRepeatCallback(this._object),this._onEveryStartCallbackFired=!1,!0}else{this._onCompleteCallback&&this._onCompleteCallback(this._object);for(var d=0,p=this._chainedTweens.length;d<p;d++)this._chainedTweens[d].start(this._startTime+this._duration,!1);return this._isPlaying=!1,!1}return!0},e.prototype._updateProperties=function(e,t,n,r){for(var i in n)if(t[i]!==void 0){var a=t[i]||0,o=n[i];!Array.isArray(e[i])&&Array.isArray(o)?e[i]=this._interpolationFunction(o,r):typeof o==`object`&&o?this._updateProperties(e[i],a,o,r):(o=this._handleRelativeValue(a,o),typeof o==`number`&&(e[i]=a+(o-a)*r))}},e.prototype._handleRelativeValue=function(e,t){return typeof t==`string`?t.charAt(0)===`+`||t.charAt(0)===`-`?e+parseFloat(t):parseFloat(t):t},e.prototype._swapEndStartRepeatValues=function(e){var t=this._valuesStartRepeat[e],n=this._valuesEnd[e];typeof n==`string`?this._valuesStartRepeat[e]=this._valuesStartRepeat[e]+parseFloat(n):this._valuesStartRepeat[e]=this._valuesEnd[e],this._valuesEnd[e]=t},e.autoStartOnUpdate=!1,e}();h.nextId;var v=g;v.getAll.bind(v),v.removeAll.bind(v),v.add.bind(v),v.remove.bind(v),v.update.bind(v),e.SceneCreator=class{scene;renderer;container;cWidth;cHeight;camera;initialCamPos;initialTargetPos;prevCamPos;controls;additionalRenderFn;stopLoop=!1;scale=1;animating=0;tweens=new p;mixers=[];lastFrameTime;physicsWorld;physicsBodies=[];physicsFixedStep=1/60;physicsMaxSubSteps=3;cannon;raycaster;mouse;selectedObject=null;pickingEnabled=!1;onObjectClick;onObjectHover;onObjectContextMenu;gltfLoader;gltfCache=new Map;clickDragThreshold=6;pointerDownX=0;pointerDownY=0;pointerDragging=!1;constructor(e,n,r,i){if(e&&!(e instanceof HTMLElement))throw Error(`Container must be a valid HTMLElement`);this.scene=new t.Scene,this.renderer=new t.WebGLRenderer({antialias:!0,alpha:!0}),this.raycaster=new t.Raycaster,this.mouse=new t.Vector2,n&&(this.scale=n),this.cWidth=0,this.cHeight=0,this.camera=new t.PerspectiveCamera(50,this.cWidth/this.cHeight,.1*this.scale,2e3*this.scale),r?this.initialCamPos=r:this.initialCamPos=new t.Vector3(10*this.scale,10*this.scale,10*this.scale),this.prevCamPos=new t.Vector3(this.initialCamPos.x+1,1,1),i?this.initialTargetPos=i:this.initialTargetPos=new t.Vector3(0,0,0),this.camera.position.set(this.initialCamPos.x,this.initialCamPos.y,this.initialCamPos.z);var a=this.initialTargetPos;this.camera.lookAt(a),this.resizeListener(),e&&this.attachRenderer(e)}addControls(e={}){this.controls=new n.OrbitControls(this.camera,this.renderer.domElement);let t={enabled:!0,enableDamping:!0,dampingFactor:.25,maxPolarAngle:Math.PI/2,maxDistance:500*this.scale,minDistance:0,rotateSpeed:1,enableZoom:!0,enablePan:!0},r=Object.assign(t,e);return Object.assign(this.controls,r),this.controls.target.set(this.initialTargetPos.x,this.initialTargetPos.y,this.initialTargetPos.z),this}setAdditionalRenderFn(e){return this.additionalRenderFn=e,this}resetSizes(){this.container&&(this.cWidth=this.container.clientWidth,this.cHeight=this.container.clientHeight)}tween(e,t,n,r){return this.animating++,new _(e,this.tweens).to(t,n*1e3).easing(d.Quadratic.Out).onComplete(()=>{this.animating--,r&&r()}).start()}animateModelColor(e,n,r=2){let i=this.scene.getObjectByName(e);if(!i)return console.warn(`Object with name "${e}" not found in scene`),this;let a=new t.Color(n);return i.traverse(e=>{e instanceof t.Mesh&&this.tween(e.material.color,{r:a.r,g:a.g,b:a.b},r)}),this}animateModelOpacity(e,n,r=2){let i=this.scene.getObjectByName(e);return i?(i.traverse(e=>{e instanceof t.Mesh&&(e.material.transparent=!0,e.material.needsUpdate=!0,this.tween(e.material,{opacity:n},r,()=>{e.material.needsUpdate=!0}))}),this):(console.warn(`Object with name "${e}" not found in scene`),this)}animateModelPosition(e,t,n=2){let r=this.scene.getObjectByName(e);return r?(this.tween(r.position,{x:t.x,y:t.y,z:t.z},n),this):(console.warn(`Object with name "${e}" not found in scene`),this)}attachRenderer(e){return this.container=e,this.resetSizes(),this.camera.aspect=this.cWidth/this.cHeight,this.camera.updateProjectionMatrix(),this.renderer.setSize(this.cWidth,this.cHeight),this.container.appendChild(this.renderer.domElement),this.scene.updateMatrixWorld(!0),this.startRenderLoop(),this}addLighting(e={}){let{hemisphere:n={sky:12375295,ground:3812374,intensity:1.4},key:r={},fill:i={color:10404863,intensity:.6,position:new t.Vector3(-10,8,-8)},shadows:a=!0,shadowArea:o=16,shadowMapSize:s=2048,toneMapping:c=!0,exposure:l=1.05}=e;if(n){let e=new t.HemisphereLight(n.sky??12375295,n.ground??3812374,n.intensity??1.4);e.position.set(0,20,0),this.scene.add(e)}let u=new t.DirectionalLight(r.color??16773853,r.intensity??2.6);if(u.position.copy(r.position??new t.Vector3(8,16,10)),this.scene.add(u),i){let e=new t.DirectionalLight(i.color??10404863,i.intensity??.6);e.position.copy(i.position??new t.Vector3(-10,8,-8)),this.scene.add(e)}if(a){this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=t.PCFSoftShadowMap,u.castShadow=!0,u.shadow.mapSize.set(s,s);let e=u.shadow.camera;e.near=1,e.far=60,e.left=-o,e.right=o,e.top=o,e.bottom=-o,e.updateProjectionMatrix(),u.shadow.bias=-4e-4}return c&&(this.renderer.toneMapping=t.ACESFilmicToneMapping,this.renderer.toneMappingExposure=l),this}applyShadows(e=!0,t=!0){return this.scene.traverse(n=>{n.isMesh&&(n.castShadow=e,n.receiveShadow=t)}),this}addSkybox(e,n=`#B2FFFF`,r){let i=new t.SphereGeometry(1e3*this.scale,60,60);i.scale(-1,1,1);let a;e?(t.TextureLoader.prototype.crossOrigin=`anonymous`,a=new t.MeshBasicMaterial({map:new t.TextureLoader().load(e)})):a=new t.MeshStandardMaterial({color:n});let o=new t.Mesh(i,a);return o.name=r||`skybox`,this.scene.add(o),this}resizeListener(){this.resetSizes(),window.addEventListener(`resize`,()=>{this.resetSizes();let e=this.camera,t=this.renderer;e.aspect=this.cWidth/this.cHeight,e.updateProjectionMatrix(),t.setSize(this.cWidth*1,this.cHeight*1),e.position.x=e.position.x+.001},!1)}stopRenderLoop(){return this.stopLoop=!0,this}startRenderLoop(){return this.stopLoop=!1,this.renderLoop(),this}renderLoop(){if(this.stopLoop)return;requestAnimationFrame(this.renderLoop.bind(this));let e=performance.now(),t=this.lastFrameTime===void 0?0:(e-this.lastFrameTime)/1e3;if(this.lastFrameTime=e,this.tweens.update(),this.mixers.length)for(let e of this.mixers)e.update(t);if(this.physicsWorld){this.physicsWorld.step(this.physicsFixedStep,t,this.physicsMaxSubSteps);for(let{mesh:e,body:t}of this.physicsBodies)e.position.set(t.position.x,t.position.y,t.position.z),e.quaternion.set(t.quaternion.x,t.quaternion.y,t.quaternion.z,t.quaternion.w)}let n=this.scene,r=this.renderer,i=this.camera;(i.position.x!==this.prevCamPos.x||i.position.y!==this.prevCamPos.y||i.position.z!==this.prevCamPos.z||this.animating||this.mixers.length||this.physicsWorld||this.additionalRenderFn)&&r.render(n,i),this.prevCamPos=this.camera.position.clone(),this.additionalRenderFn&&this.additionalRenderFn(),this.controls&&this.controls.update()}resetCameraPosition(){return this.moveCamera(this.initialCamPos,this.initialTargetPos),this}moveCamera(e,t,n){let r=this.camera,i;return this.controls&&(i=this.controls.enabled,this.controls.enabled=!1),this.tween(r.position,{x:e.x,y:e.y,z:e.z},3,()=>{this.controls&&typeof i==`boolean`&&(this.controls.enabled=i),typeof n==`function`&&n()}),t&&this.controls&&this.tween(this.controls.target,{x:t.x,y:t.y,z:t.z},3),this}loadModel(e,n){return e?(n||=new t.ObjectLoader,n.loadAsync(e).then((e=>{let t=e;return this.scene.add(t),t})).catch(t=>{throw console.error(`Failed to load model from "${e}":`,t),t})):Promise.reject(Error(`URL is required`))}loadGLTF(e){this.gltfLoader||=new r.GLTFLoader;let t=this.gltfCache.get(e);return t||(t=this.gltfLoader.loadAsync(e).then(e=>e.scene),t.catch(()=>this.gltfCache.delete(e)),this.gltfCache.set(e,t)),t.then(e=>e.clone(!0))}addMixer(e){return this.mixers.includes(e)||this.mixers.push(e),this}removeMixer(e){let t=this.mixers.indexOf(e);return t!==-1&&this.mixers.splice(t,1),this}async loadAnimatedModel(e,n={}){let{add:i=!0,shadows:a=!0,autoplay:o}=n;this.gltfLoader||=new r.GLTFLoader;let s=await this.gltfLoader.loadAsync(e),c=s.scene;a&&c.traverse(e=>{e.isMesh&&(e.castShadow=!0,e.receiveShadow=!0)}),i&&this.scene.add(c);let l=new t.AnimationMixer(c);this.addMixer(l);let u={};for(let e of s.animations)u[e.name]=l.clipAction(e);let d=null,f=(n,r={})=>{let{fade:i=.3,loop:a=!0,clampWhenFinished:o=!0}=r,s=u[n];return s?s===d?s:(s.loop=a?t.LoopRepeat:t.LoopOnce,s.clampWhenFinished=o,d&&d.fadeOut(i),s.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(i).play(),d=s,s):(console.warn(`Animation clip "${n}" not found on model "${e}"`),null)},p=(e=.3)=>{d&&=(d.fadeOut(e),null)},m=s.animations.map(e=>e.name);return o!==!1&&m.length&&f(typeof o==`string`?o:m[0],{fade:0}),{model:c,animations:s.animations,names:m,mixer:l,actions:u,play:f,stop:p}}async enablePhysics(e={}){if(this.physicsWorld)return this;let n=this.cannon??=await import(`cannon-es`),r=e.gravity??new t.Vector3(0,-9.82,0),i=Array.isArray(r)?new n.Vec3(r[0],r[1],r[2]):new n.Vec3(r.x,r.y,r.z),a=new n.World({gravity:i});return a.allowSleep=e.allowSleep??!0,a.defaultContactMaterial.restitution=e.restitution??.3,a.defaultContactMaterial.friction=e.friction??.4,this.physicsWorld=a,this}addBody(e,t={}){if(!this.physicsWorld||!this.cannon)throw Error(`Call (and await) enablePhysics() before addBody().`);let n=this.cannon,{mass:r=1,shape:i=`box`,linearDamping:a=.01,angularDamping:o=.01}=t,s=new n.Body({mass:r,shape:this.shapeFromMesh(e,i)});return s.position.set(e.position.x,e.position.y,e.position.z),s.quaternion.set(e.quaternion.x,e.quaternion.y,e.quaternion.z,e.quaternion.w),s.linearDamping=a,s.angularDamping=o,this.physicsWorld.addBody(s),r>0&&this.physicsBodies.push({mesh:e,body:s}),s}addGround(e=0){if(!this.physicsWorld||!this.cannon)throw Error(`Call (and await) enablePhysics() before addGround().`);let t=this.cannon,n=new t.Body({mass:0,shape:new t.Plane});return n.quaternion.setFromEuler(-Math.PI/2,0,0),n.position.set(0,e,0),this.physicsWorld.addBody(n),n}removeBody(e){return this.physicsWorld&&this.physicsWorld.removeBody(e),this.physicsBodies=this.physicsBodies.filter(t=>t.body!==e),this}shapeFromMesh(e,n){let r=this.cannon,i=e.geometry,a=e.scale;if(n===`sphere`){i&&!i.boundingSphere&&i.computeBoundingSphere();let e=i?.boundingSphere?.radius??.5;return new r.Sphere(e*Math.max(a.x,a.y,a.z))}let o=new t.Vector3(1,1,1);return i&&(i.boundingBox||i.computeBoundingBox(),i.boundingBox?.getSize(o)),new r.Box(new r.Vec3(o.x*a.x/2,o.y*a.y/2,o.z*a.z/2))}enablePicking(e,t,n){if(this.pickingEnabled=!0,this.onObjectClick=e,this.onObjectHover=t,this.onObjectContextMenu=n,this.onObjectHover=t,!this.container)return console.warn(`Container not set. Picking requires attachRenderer to be called first.`),this;this.container.addEventListener(`mousemove`,e=>{let t=this.renderer.domElement.getBoundingClientRect();this.mouse.x=(e.clientX-t.left)/t.width*2-1,this.mouse.y=-((e.clientY-t.top)/t.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);let n=this.raycaster.intersectObjects(this.scene.children,!0);if(n.length>0){let e=n[0].object;e!==this.selectedObject&&(this.selectedObject=e,this.onObjectHover&&this.onObjectHover(e))}else this.selectedObject!==null&&(this.selectedObject=null,this.onObjectHover&&this.onObjectHover(null))}),this.container.addEventListener(`pointerdown`,e=>{this.pointerDownX=e.clientX,this.pointerDownY=e.clientY,this.pointerDragging=!1}),this.container.addEventListener(`pointermove`,e=>{if(this.pointerDragging)return;let t=e.clientX-this.pointerDownX,n=e.clientY-this.pointerDownY;Math.hypot(t,n)>this.clickDragThreshold&&(this.pointerDragging=!0)}),this.container.addEventListener(`click`,()=>{this.pointerDragging||this.selectedObject&&this.onObjectClick&&this.onObjectClick(this.selectedObject)});let r=0,i=0,a=!1;return this.container.addEventListener(`touchstart`,e=>{e.touches.length===1?(r=e.touches[0].clientX,i=e.touches[0].clientY,a=!1):a=!0}),this.container.addEventListener(`touchmove`,e=>{if(a||e.touches.length!==1)return;let t=e.touches[0].clientX-r,n=e.touches[0].clientY-i;Math.hypot(t,n)>this.clickDragThreshold&&(a=!0)}),this.container.addEventListener(`touchend`,e=>{if(a)return;let t=e.changedTouches[0];if(!t)return;let n=this.renderer.domElement.getBoundingClientRect();this.mouse.x=(t.clientX-n.left)/n.width*2-1,this.mouse.y=-((t.clientY-n.top)/n.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);let r=this.raycaster.intersectObjects(this.scene.children,!0);r.length>0&&this.onObjectClick&&this.onObjectClick(r[0].object)}),this.container.addEventListener(`contextmenu`,e=>{e.preventDefault(),this.selectedObject&&this.onObjectContextMenu&&this.onObjectContextMenu(this.selectedObject)}),this}disablePicking(){return this.pickingEnabled=!1,this.selectedObject=null,this.onObjectClick=void 0,this.onObjectHover=void 0,this}getSelectedObject(){return this.selectedObject}pickAt(e,n){this.mouse.set(e,n),this.raycaster.setFromCamera(this.mouse,this.camera);let r=this.raycaster.intersectObjects(this.scene.children,!0);if(r.length>0){let e=r[0];return{object:e.object,distance:e.distance,point:e.point,normal:e.normal||new t.Vector3(0,1,0),uv:e.uv||void 0}}return null}dispose(){this.stopRenderLoop(),this.tweens.removeAll(),this.mixers.forEach(e=>e.stopAllAction()),this.mixers=[],this.physicsBodies=[],this.physicsWorld=void 0,this.animating=0,this.renderer.dispose(),this.scene.clear(),this.container&&this.renderer.domElement.parentNode===this.container&&this.container.removeChild(this.renderer.domElement)}}});