@hology/core 0.0.263 → 0.0.264

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/effects/sequence/sequence-player.d.ts +1 -0
  2. package/dist/effects/sequence/sequence-player.js +1 -1
  3. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  4. package/dist/effects/vfx/vfx-actor.js +1 -1
  5. package/dist/gameplay/services/render.d.ts +3 -0
  6. package/dist/gameplay/services/render.js +1 -1
  7. package/dist/rendering/node-material-webgpu-resolver.d.ts +1 -0
  8. package/dist/rendering/node-material-webgpu-resolver.js +1 -1
  9. package/dist/rendering/webgpu-experimental-backend.d.ts +1 -0
  10. package/dist/rendering/webgpu-experimental-backend.js +1 -1
  11. package/dist/secondary-motion/budget.d.ts +26 -0
  12. package/dist/secondary-motion/budget.js +4 -0
  13. package/dist/secondary-motion/cache.d.ts +16 -0
  14. package/dist/secondary-motion/cache.js +4 -0
  15. package/dist/secondary-motion/runtime.d.ts +15 -0
  16. package/dist/secondary-motion/runtime.js +1 -1
  17. package/dist/secondary-motion/skinned-targets.d.ts +35 -0
  18. package/dist/secondary-motion/skinned-targets.js +4 -0
  19. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  20. package/dist/test/node-material-webgpu-resolver.test.js +1 -1
  21. package/dist/test/secondary-motion-budget.test.d.ts +2 -0
  22. package/dist/test/secondary-motion-budget.test.js +4 -0
  23. package/dist/test/secondary-motion-cache.test.d.ts +2 -0
  24. package/dist/test/secondary-motion-cache.test.js +4 -0
  25. package/dist/test/secondary-motion-gpu-check.d.ts +2 -0
  26. package/dist/test/secondary-motion-gpu-check.js +4 -0
  27. package/dist/test/sequence-scene-binding.test.js +1 -1
  28. package/dist/test/vfx-playback-transform.test.d.ts +2 -0
  29. package/dist/test/vfx-playback-transform.test.js +4 -0
  30. package/package.json +4 -1
  31. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{__decorate as t,__metadata as e}from"tslib";import*as s from"three";import{Rate as i}from"@hology/nebula";import{Actor as r,BaseActor as a}from"../../gameplay/actors/actor.js";import{inject as n}from"../../gameplay/inject.js";import{AssetLoader as o}from"../../gameplay/services/asset-loader.js";import{ViewController as l}from"../../gameplay/services/render.js";import{World as p}from"../../gameplay/services/world.js";import{DelayRate as h}from"./rates.js";import{materializeVfx as u}from"./vfx-materializer.js";import{PhysicsSystem as m}from"../../gameplay/services/physics/physics-system.js";import{ShaderProvider as c}from"../../gameplay/services/shader-provider.js";import{AssetResourceLoader as d}from"../../scene/asset-resource-loader.js";import{AssetsProvider as f}from"../../scene/assets-provider.js";import{VfxInputRuntime as g}from"./vfx-input-runtime.js";import{Subject as y}from"rxjs";import{EventGraphCallable as v}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as b}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as w}from"../../gameplay/event-graph/asset-actor-types.js";import{GpuVfxWorldService as P}from"./gpu-vfx-world-service.js";import{compileGpuSpriteEmitters as S,requiresCpuVfxBackend as j}from"./gpu-sprite-compiler.js";import{withSeededRandom as E}from"./seeded-random.js";let x=class extends a{constructor(){super(...arguments),this.onComplete=new y,this.collisionEvent={emitterId:"",emitterName:"",position:new s.Vector3,normal:new s.Vector3},this._timescale=1,this.paused=!0,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.profilingEnabled=!1,this.simulationCpuMs=0,this.system=null,this.disposeSystem=null,this.assetLoader=n(o),this.assetManagerService=n(d),this.assetService=n(f),this.world=n(p),this.view=n(l),this.gpuWorld=n(P),this.particleSystemContainer=null,this.gpuPrepared=null,this.gpuHandle=null,this.physics=n(m),this.shaderProvider=n(c),this.inputRuntime=new g,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,this._worldScale=new s.Vector3,this.previewStepSeconds=1/60,this.maxPreviewSteps=240,this.max=0}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(0,t),this.gpuHandle?.setTimescale(this._timescale)}async fromAsset(t,e,i,r){if("vfx"!==t.type)throw"Asset must be a VFX asset but is "+t.type;null!=this.system&&(this.system.destroy(),this.system.emitters.forEach(t=>t.reset())),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.simulationCpuMs=0,this.sourceAsset=t,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this.disposeSystem&&this.disposeSystem(),null==this.object.parent&&this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const t of this.inputRuntime.getDefinitions()){if("mesh"!==t.type||"string"!=typeof t.defaultValue||0===t.defaultValue.length)continue;const e=await this.assetService.getAsset(t.defaultValue);if(null==e)continue;const s=await this.assetManagerService.getMesh(e,{applyMaterials:!0,rescale:!0});this.inputRuntime.setInput(t.id,s.scene)}for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const a=i??this.view.vfxBackendPreference,n=j(this.sourceAsset);if("cpu"===a&&(this.backendFallbackReasons=["GPU VFX was not requested; the selected VFX backend preference is CPU."]),"cpu"!==a&&!n){const t=new Map;for(const e of this.inputRuntime.getDefinitions()){if("mesh"!==e.type)continue;const s=this.inputRuntime.getMesh(e.id);null!=s&&t.set(e.id,s)}if(this.gpuPrepared=await this.gpuWorld.prepare(this.sourceAsset,r,t),null!=this.gpuPrepared)return this.runtimeBackend="gpu",this.system=null,this.disposeSystem=null,this.particleSystemContainer=null,this.object.visible=!1,this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,void(this.inputsMaterialized=!0);if(this.backendFallbackReasons=this.gpuWorld.getFallbackReasons(this.sourceAsset,r),"gpu"===a){const t=S(this.sourceAsset,[new s.Vector3]).compatibility;this.backendFallbackReasons=t.issues.filter(t=>"warning"!==t.severity).map(t=>`${t.emitter}: ${t.message}`),0===this.backendFallbackReasons.length&&(this.backendFallbackReasons=["GPU template or material preparation failed; inspect earlier shader diagnostics."])}}const{system:o,dispose:l,container:p}=await u(this.sourceAsset,this.object,{getAsset:t=>this.assetLoader.getAsset(t),getMaterial:t=>this.assetLoader.getMaterialByAssetId(t),getTexture:t=>this.assetLoader.getTextureByAssetId(t),getMesh:async t=>(await this.assetManagerService.getMesh(await this.assetService.getAsset(t),{applyMaterials:!0,rescale:!0})).scene},this.view,this.physics,this.shaderProvider,this.assetService,this.assetManagerService,this.inputRuntime,(t,e,s,i,r)=>{if(null==this.onCollision)return;const a=this.collisionEvent;a.emitterId=t,a.emitterName=e,a.position.copy(s),a.normal.copy(i),r&&(a.position.applyMatrix4(this.object.matrixWorld),a.normal.transformDirection(this.object.matrixWorld)),this.onCollision(a)});this.system=o,this.disposeSystem=l,this.particleSystemContainer=p,this.inputsMaterialized=!0,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){const i=this.inputRuntime.getDefinition(t);if(this.inputsMaterialized&&"mesh"===i?.type)return void console.warn(`VFX mesh input "${i.name}" is creation-time only; recreate the VFX to replace it.`);this.inputOverrides.set(t,function(t){if(t instanceof s.Vector3||t instanceof s.Color)return t.clone();if(Array.isArray(t))return[...t];return t}(e)),this.inputRuntime.setInput(t,e);const r=this.inputRuntime.getDefinition(t);null!=r&&this.gpuHandle?.setInput(r.id,this.inputRuntime.getValue(r.id))}setInputs(t){for(const[e,s]of Object.entries(t))this.setInput(e,s)}play(){if(this.prepareForPlayback(),this.paused=!1,null!=this.gpuPrepared){if(this.object.getWorldPosition(this._worldPos),null!=this.gpuHandle&&this.gpuHandle.active)this.gpuHandle.play();else{this.gpuHandle=this.gpuPrepared.spawn(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),this.gpuHandle?.setTimescale(this._timescale);for(const t of this.inputRuntime.getDefinitions())this.gpuHandle?.setInput(t.id,this.inputRuntime.getValue(t.id))}return}this.system.emitters.every(t=>t.dead)&&this.restart()}pause(){this.paused=!0,this.gpuHandle?.pause()}previewAt(t,e,s,i,r=0){null!=this.system&&(this.prepareForPlayback(),E(r,()=>{this.restart(),this.paused=!0;const r=Math.max(0,t),a=Math.min(r,Math.max(0,e)),n=r-a,o=Number(a>0)+Number(n>0),l=Math.max(o,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=a<=0?0:n<=0?l:Math.min(l-1,Math.max(1,Math.round(l*a/r)));this.simulatePreview(a,p),n>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(n,l-p))}))}clearPreview(){this.restart(),this.pause(),this.object.visible=!1,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!1)}stop(){this.finishRequested=!0,null==this.gpuPrepared?null!=this.system?.emitters&&this.system.emitters.forEach(t=>{this.stopEmitterEmission(t)}):this.gpuHandle?.stop()}applyClipEndBehavior(t,e){const s=t??"finish";if("finish"!==s){if(null!=this.gpuPrepared)return this.finishRequested=!0,void("kill"===s?this.gpuHandle?.kill():this.gpuHandle?.expire(Math.max(0,e??0)));if(null!=this.system&&null!=this.system.emitters)for(const t of this.system.emitters)this.applyEmitterClipEndBehavior(t,s,e)}else this.stop()}restart(){if(null==this.gpuPrepared){if(null!=this.system&&null!=this.system.emitters){this.finishRequested=!1,this.completionEmitted=!1;for(const t of this.system.emitters)this.restartEmitter(t)}}else if(this.finishRequested=!1,this.completionEmitted=!1,null!=this.gpuHandle){if(!this.gpuHandle.active&&!this.paused)return void this.play();this.gpuHandle.restart()}}restartEmitter(t){const e=t.rate;e instanceof h?e.restart():e instanceof i&&(e.nextTime=0),null==t.clearParticlesRecursive?this.removeEmitterParticlesRecursive(t):t.clearParticlesRecursive()}removeEmitterParticlesRecursive(t){const e=t.childEmitters??[];for(const t of e)this.removeEmitterParticlesRecursive(t);t.removeAllParticles?.()}onUpdate(t){if(this.paused)null!=this.gpuHandle&&(this.object.getWorldPosition(this._worldPos),this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld));else{if(null!=this.gpuPrepared)return this.object.getWorldPosition(this._worldPos),this.gpuHandle?.setPosition(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),void this.updateCompletionState();this.updateWorldSpaceEmitterTransforms(),this.updateSystem(t*this.timescale),this.updateCompletionState()}}prepareForPlayback(){null==this.gpuPrepared?(null!=this.particleSystemContainer&&null==this.particleSystemContainer.parent&&this.world.scene.add(this.particleSystemContainer),this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.matrixAutoUpdate=!0,this.particleSystemContainer.matrixWorldAutoUpdate=!0),this.object.visible=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!0)):this.object.visible=!0}simulatePreview(t,e){if(t<=0)return;const s=t/e;for(let t=0;t<e;t++)this.updateWorldSpaceEmitterTransforms(),this.updateSystem(s)}updateWorldSpaceEmitterTransforms(){this.object.getWorldPosition(this._worldPos),this.object.getWorldQuaternion(this._worldRot),this.object.getWorldScale(this._worldScale),this._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{if("world"===t._space){t.setPosition(this._worldPos),t.setRotation(this._worldEul);(t._worldScale??(t._worldScale=new s.Vector3)).copy(this._worldScale)}})}getParticleCount(){return null!=this.gpuPrepared?0:this.system?.getCount()??0}getProfilingStats(){let t=0,e=0;return this.particleSystemContainer?.traverse(i=>{const r=i,a=r.geometry;if(null==a||!1===r.visible)return;const n=r instanceof s.InstancedMesh?r.count:1,o=a.index?.count??a.getAttribute("position")?.count??0;n<=0||o<=0||(t++,e+=Math.floor(o/3)*n)}),{particles:this.system?.getCount()??0,drawCalls:t,triangles:e,cpuTimeMs:this.simulationCpuMs}}onEndPlay(){this.stop(),null!=this.disposeSystem&&this.disposeSystem(),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.onComplete.complete()}updateCompletionState(){if(null!=this.gpuPrepared){if(this.completionEmitted||!1!==this.gpuHandle?.active)return;return this.completionEmitted=!0,void this.onComplete.next()}if(this.completionEmitted||null==this.system||!this.onComplete.observed)return;const t=this.system.emitters.every(t=>t.dead),e=this.finishRequested&&0===this.system.getCount();(t||e)&&(this.completionEmitted=!0,this.onComplete.next())}updateSystem(t){if(null==this.system)return;if(!this.profilingEnabled)return void this.system.update(t);const e=performance.now();this.system.update(t),this.simulationCpuMs=performance.now()-e}applyEmitterClipEndBehavior(t,e,s,i=!1){this.stopEmitterEmission(t,i);const r=t.particles??[];if("kill"===e)t.removeAllParticles?.();else{const t=Math.max(0,s??0);for(const e of r)e.life=Math.min(e.life,e.age+t)}const a=t.childEmitters??[];for(const t of a)this.applyEmitterClipEndBehavior(t,e,s,!0)}stopEmitterEmission(t,e=!1){const s=t.rate;s instanceof i&&(s.nextTime=1/0),e&&t.stopEmit?.()}};t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"play",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"pause",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"stop",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"restart",null),x=t([r({typeId:w})],x);export{x as VfxActor};/*
1
+ import{__decorate as t,__metadata as e}from"tslib";import*as s from"three";import{Rate as i}from"@hology/nebula";import{Actor as r,BaseActor as o}from"../../gameplay/actors/actor.js";import{inject as a}from"../../gameplay/inject.js";import{AssetLoader as n}from"../../gameplay/services/asset-loader.js";import{ViewController as l}from"../../gameplay/services/render.js";import{World as p}from"../../gameplay/services/world.js";import{DelayRate as h}from"./rates.js";import{materializeVfx as u}from"./vfx-materializer.js";import{PhysicsSystem as m}from"../../gameplay/services/physics/physics-system.js";import{ShaderProvider as d}from"../../gameplay/services/shader-provider.js";import{AssetResourceLoader as c}from"../../scene/asset-resource-loader.js";import{AssetsProvider as f}from"../../scene/assets-provider.js";import{VfxInputRuntime as g}from"./vfx-input-runtime.js";import{Subject as y}from"rxjs";import{EventGraphCallable as v}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as b}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as w}from"../../gameplay/event-graph/asset-actor-types.js";import{GpuVfxWorldService as P}from"./gpu-vfx-world-service.js";import{compileGpuSpriteEmitters as S,requiresCpuVfxBackend as j}from"./gpu-sprite-compiler.js";import{withSeededRandom as x}from"./seeded-random.js";let E=class extends o{constructor(){super(...arguments),this.onComplete=new y,this.collisionEvent={emitterId:"",emitterName:"",position:new s.Vector3,normal:new s.Vector3},this._timescale=1,this.paused=!0,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.profilingEnabled=!1,this.simulationCpuMs=0,this.system=null,this.disposeSystem=null,this.assetLoader=a(n),this.assetManagerService=a(c),this.assetService=a(f),this.world=a(p),this.view=a(l),this.gpuWorld=a(P),this.particleSystemContainer=null,this.gpuPrepared=null,this.gpuHandle=null,this.physics=a(m),this.shaderProvider=a(d),this.inputRuntime=new g,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,this._worldScale=new s.Vector3,this.previewStepSeconds=1/60,this.maxPreviewSteps=240,this.max=0}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(0,t),this.gpuHandle?.setTimescale(this._timescale)}async fromAsset(t,e,i,r){if("vfx"!==t.type)throw"Asset must be a VFX asset but is "+t.type;null!=this.system&&(this.system.destroy(),this.system.emitters.forEach(t=>t.reset())),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.simulationCpuMs=0,this.sourceAsset=t,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this.disposeSystem&&this.disposeSystem(),null==this.object.parent&&this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const t of this.inputRuntime.getDefinitions()){if("mesh"!==t.type||"string"!=typeof t.defaultValue||0===t.defaultValue.length)continue;const e=await this.assetService.getAsset(t.defaultValue);if(null==e)continue;const s=await this.assetManagerService.getMesh(e,{applyMaterials:!0,rescale:!0});this.inputRuntime.setInput(t.id,s.scene)}for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const o=i??this.view.vfxBackendPreference,a=j(this.sourceAsset);if("cpu"===o&&(this.backendFallbackReasons=["GPU VFX was not requested; the selected VFX backend preference is CPU."]),"cpu"!==o&&!a){const t=new Map;for(const e of this.inputRuntime.getDefinitions()){if("mesh"!==e.type)continue;const s=this.inputRuntime.getMesh(e.id);null!=s&&t.set(e.id,s)}if(this.gpuPrepared=await this.gpuWorld.prepare(this.sourceAsset,r,t),null!=this.gpuPrepared)return this.runtimeBackend="gpu",this.system=null,this.disposeSystem=null,this.particleSystemContainer=null,this.object.visible=!1,this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,void(this.inputsMaterialized=!0);if(this.backendFallbackReasons=this.gpuWorld.getFallbackReasons(this.sourceAsset,r),"gpu"===o){const t=S(this.sourceAsset,[new s.Vector3]).compatibility;this.backendFallbackReasons=t.issues.filter(t=>"warning"!==t.severity).map(t=>`${t.emitter}: ${t.message}`),0===this.backendFallbackReasons.length&&(this.backendFallbackReasons=["GPU template or material preparation failed; inspect earlier shader diagnostics."])}}const{system:n,dispose:l,container:p}=await u(this.sourceAsset,this.object,{getAsset:t=>this.assetLoader.getAsset(t),getMaterial:t=>this.assetLoader.getMaterialByAssetId(t),getTexture:t=>this.assetLoader.getTextureByAssetId(t),getMesh:async t=>(await this.assetManagerService.getMesh(await this.assetService.getAsset(t),{applyMaterials:!0,rescale:!0})).scene},this.view,this.physics,this.shaderProvider,this.assetService,this.assetManagerService,this.inputRuntime,(t,e,s,i,r)=>{if(null==this.onCollision)return;const o=this.collisionEvent;o.emitterId=t,o.emitterName=e,o.position.copy(s),o.normal.copy(i),r&&(o.position.applyMatrix4(this.object.matrixWorld),o.normal.transformDirection(this.object.matrixWorld)),this.onCollision(o)});this.system=n,this.disposeSystem=l,this.particleSystemContainer=p,this.inputsMaterialized=!0,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){const i=this.inputRuntime.getDefinition(t);if(this.inputsMaterialized&&"mesh"===i?.type)return void console.warn(`VFX mesh input "${i.name}" is creation-time only; recreate the VFX to replace it.`);this.inputOverrides.set(t,function(t){if(t instanceof s.Vector3||t instanceof s.Color)return t.clone();if(Array.isArray(t))return[...t];return t}(e)),this.inputRuntime.setInput(t,e);const r=this.inputRuntime.getDefinition(t);null!=r&&this.gpuHandle?.setInput(r.id,this.inputRuntime.getValue(r.id))}setInputs(t){for(const[e,s]of Object.entries(t))this.setInput(e,s)}play(){if(this.prepareForPlayback(),this.paused=!1,null!=this.gpuPrepared){if(this.object.getWorldPosition(this._worldPos),null!=this.gpuHandle&&this.gpuHandle.active)this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld),this.gpuHandle.play();else{this.gpuHandle=this.gpuPrepared.spawn(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),this.gpuHandle?.setTimescale(this._timescale);for(const t of this.inputRuntime.getDefinitions())this.gpuHandle?.setInput(t.id,this.inputRuntime.getValue(t.id))}return}this.system.emitters.every(t=>t.dead)&&this.restart()}pause(){this.paused=!0,this.gpuHandle?.pause()}previewAt(t,e,s,i,r=0){null!=this.system&&(this.prepareForPlayback(),x(r,()=>{this.restart(),this.paused=!0;const r=Math.max(0,t),o=Math.min(r,Math.max(0,e)),a=r-o,n=Number(o>0)+Number(a>0),l=Math.max(n,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=o<=0?0:a<=0?l:Math.min(l-1,Math.max(1,Math.round(l*o/r)));this.simulatePreview(o,p),a>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(a,l-p))}))}clearPreview(){this.restart(),this.pause(),this.object.visible=!1,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!1)}stop(){this.finishRequested=!0,null==this.gpuPrepared?null!=this.system?.emitters&&this.system.emitters.forEach(t=>{this.stopEmitterEmission(t)}):this.gpuHandle?.stop()}applyClipEndBehavior(t,e){const s=t??"finish";if("finish"!==s){if(null!=this.gpuPrepared)return this.finishRequested=!0,void("kill"===s?this.gpuHandle?.kill():this.gpuHandle?.expire(Math.max(0,e??0)));if(null!=this.system&&null!=this.system.emitters)for(const t of this.system.emitters)this.applyEmitterClipEndBehavior(t,s,e)}else this.stop()}restart(){if(null==this.gpuPrepared){if(null!=this.system&&null!=this.system.emitters){this.finishRequested=!1,this.completionEmitted=!1;for(const t of this.system.emitters)this.restartEmitter(t)}}else if(this.finishRequested=!1,this.completionEmitted=!1,null!=this.gpuHandle){if(!this.gpuHandle.active&&!this.paused)return void this.play();this.object.getWorldPosition(this._worldPos),this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld),this.gpuHandle.restart()}}restartEmitter(t){const e=t.rate;e instanceof h?e.restart():e instanceof i&&(e.nextTime=0),null==t.clearParticlesRecursive?this.removeEmitterParticlesRecursive(t):t.clearParticlesRecursive()}removeEmitterParticlesRecursive(t){const e=t.childEmitters??[];for(const t of e)this.removeEmitterParticlesRecursive(t);t.removeAllParticles?.()}onUpdate(t){if(this.paused)null!=this.gpuHandle&&(this.object.getWorldPosition(this._worldPos),this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld));else{if(null!=this.gpuPrepared)return this.object.getWorldPosition(this._worldPos),this.gpuHandle?.setPosition(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),void this.updateCompletionState();this.updateWorldSpaceEmitterTransforms(),this.updateSystem(t*this.timescale),this.updateCompletionState()}}prepareForPlayback(){null==this.gpuPrepared?(null!=this.particleSystemContainer&&null==this.particleSystemContainer.parent&&this.world.scene.add(this.particleSystemContainer),this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.matrixAutoUpdate=!0,this.particleSystemContainer.matrixWorldAutoUpdate=!0),this.object.visible=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!0)):this.object.visible=!0}simulatePreview(t,e){if(t<=0)return;const s=t/e;for(let t=0;t<e;t++)this.updateWorldSpaceEmitterTransforms(),this.updateSystem(s)}updateWorldSpaceEmitterTransforms(){this.object.getWorldPosition(this._worldPos),this.object.getWorldQuaternion(this._worldRot),this.object.getWorldScale(this._worldScale),this._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{if("world"===t._space){t.setPosition(this._worldPos),t.setRotation(this._worldEul);(t._worldScale??(t._worldScale=new s.Vector3)).copy(this._worldScale)}})}getParticleCount(){return null!=this.gpuPrepared?0:this.system?.getCount()??0}getProfilingStats(){let t=0,e=0;return this.particleSystemContainer?.traverse(i=>{const r=i,o=r.geometry;if(null==o||!1===r.visible)return;const a=r instanceof s.InstancedMesh?r.count:1,n=o.index?.count??o.getAttribute("position")?.count??0;a<=0||n<=0||(t++,e+=Math.floor(n/3)*a)}),{particles:this.system?.getCount()??0,drawCalls:t,triangles:e,cpuTimeMs:this.simulationCpuMs}}onEndPlay(){this.stop(),null!=this.disposeSystem&&this.disposeSystem(),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.onComplete.complete()}updateCompletionState(){if(null!=this.gpuPrepared){if(this.completionEmitted||!1!==this.gpuHandle?.active)return;return this.completionEmitted=!0,void this.onComplete.next()}if(this.completionEmitted||null==this.system||!this.onComplete.observed)return;const t=this.system.emitters.every(t=>t.dead),e=this.finishRequested&&0===this.system.getCount();(t||e)&&(this.completionEmitted=!0,this.onComplete.next())}updateSystem(t){if(null==this.system)return;if(!this.profilingEnabled)return void this.system.update(t);const e=performance.now();this.system.update(t),this.simulationCpuMs=performance.now()-e}applyEmitterClipEndBehavior(t,e,s,i=!1){this.stopEmitterEmission(t,i);const r=t.particles??[];if("kill"===e)t.removeAllParticles?.();else{const t=Math.max(0,s??0);for(const e of r)e.life=Math.min(e.life,e.age+t)}const o=t.childEmitters??[];for(const t of o)this.applyEmitterClipEndBehavior(t,e,s,!0)}stopEmitterEmission(t,e=!1){const s=t.rate;s instanceof i&&(s.nextTime=1/0),e&&t.stopEmit?.()}};t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"play",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"pause",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"stop",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"restart",null),E=t([r({typeId:w})],E);export{E as VfxActor};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -58,6 +58,9 @@ export declare class ViewController {
58
58
  registerWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
59
59
  /** @deprecated Use registerWebGpuRenderGraphExtension. */
60
60
  registerExperimentalWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
61
+ private _updateFrameIndex;
62
+ /** Monotonic frame token shared by per-frame gameplay preparation jobs. */
63
+ get updateFrameIndex(): number;
61
64
  private handleFrame;
62
65
  set timeScale(value: number);
63
66
  get timeScale(): number;
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as u,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get webGpuDevice(){return this.view.webGpuDevice}get experimentalWebGpuDevice(){return this.webGpuDevice}registerWebGpuRenderGraphExtension(e){return this.view.registerWebGpuRenderGraphExtension(e)}registerExperimentalWebGpuRenderGraphExtension(e){return this.registerWebGpuRenderGraphExtension(e)}handleFrame(e){let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setProfilingEnabled(e){this.view.setProfilingEnabled(e)}getLastFrameProfile(){return this.view.getLastFrameProfile()}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(S)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){u(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),P.setFromEuler(x),e.quaternion.copy(k).multiply(P),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=g){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(e=!0){e&&this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(v.setFromProjectionMatrix(p),!v.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,g=new o.Vector2,v=new o.Frustum,S=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),P=new o.Quaternion;/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as u,resetCameraShakeSample as l,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=u(),this.scratchCameraShakeSample=u(),this._updateFrameIndex=0,this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get webGpuDevice(){return this.view.webGpuDevice}get experimentalWebGpuDevice(){return this.webGpuDevice}registerWebGpuRenderGraphExtension(e){return this.view.registerWebGpuRenderGraphExtension(e)}registerExperimentalWebGpuRenderGraphExtension(e){return this.registerWebGpuRenderGraphExtension(e)}get updateFrameIndex(){return this._updateFrameIndex}handleFrame(e){this._updateFrameIndex++;let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setProfilingEnabled(e){this.view.setProfilingEnabled(e)}getLastFrameProfile(){return this.view.getLastFrameProfile()}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(S)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){l(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),P.setFromEuler(x),e.quaternion.copy(k).multiply(P),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=g){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(e=!0){e&&this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(v.setFromProjectionMatrix(p),!v.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,g=new o.Vector2,v=new o.Frustum,S=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),P=new o.Quaternion;/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -63,6 +63,7 @@ export declare class NodeMaterialWebGpuResolver {
63
63
  private readonly mappedMaterialsSignatures;
64
64
  private readonly observedNodeMaterials;
65
65
  private readonly outlineMaterials;
66
+ private readonly outlineUniformVersions;
66
67
  private readonly worldEnvironmentMaterials;
67
68
  private worldEnvironment;
68
69
  private worldEnvironmentTexture;
@@ -1,4 +1,4 @@
1
- import*as e from"three";import{compileNodeWebGpuFullscreen as t,compileNodeShaderMaterialForWebGpu as a,NodeShaderMaterial as n,webGpuRendererBindings as i,webGpuTiledRendererBindings as s,textureSampler2d as o,float as r,length as l,max as u,rgba as p,isWgslCompiler as m,isWgslFragmentCompiler as c,sqrt as d,normalize as h,transformed as f,uniformFloat as M,uniforms as v,vec4 as y,Vec3Node as g,toonMaterial as V}from"three-shader-graph";import{StandardShader as w}from"../shader/builtin/standard-shader.js";import{LambertShader as S}from"../shader/builtin/lambert-shader.js";import{ToonShader as x}from"../shader/builtin/toon-shader.js";import{UnlitShader as I}from"../shader/builtin/unlit-shader.js";import{SpriteShader as T}from"../shader/sprite-shader.js";import{elapsedTimeUniformName as E}from"../shader-nodes/time.js";import{depthUniformName as b,farUniformName as C,nearUniformName as W,resolutionUniformName as U,sceneNormalUniformName as A}from"../shader-nodes/depth.js";import{sceneMapUniformName as N}from"../shader-nodes/scene-sample.js";const k={...i,uniformExpressions:{...i.uniformExpressions,ambientLightColor:{type:"vec3",expression:"rendererAmbientLight()"},[E]:{type:"float",expression:"rendererElapsedTime()"},[W]:{type:"float",expression:"rendererCameraNear()"},[C]:{type:"float",expression:"rendererCameraFar()"},[U]:{type:"vec2",expression:"rendererViewportSize()"}},sceneTextures:{[N]:{semantic:"sceneColor",sampleType:"float"},[b]:{semantic:"sceneDepth",sampleType:"depth"}},attributes:{material:{shaderLocation:6,format:"float32x4",defaultValue:[0,0,0,0]},material2:{shaderLocation:7,format:"float32x4",defaultValue:[0,0,0,0]},hole:{shaderLocation:8,format:"float32",defaultValue:[0]},offset:{shaderLocation:9,format:"float32x3",stepMode:"instance",defaultValue:[0,0,0]},velocity:{shaderLocation:10,format:"float32x4",stepMode:"instance",defaultValue:[0,0,0,0]},size:{shaderLocation:11,format:"float32x3",stepMode:"instance",defaultValue:[0,0,0]},rotation:{shaderLocation:12,format:"float32",stepMode:"instance",defaultValue:[0]},particleData:{shaderLocation:13,format:"float32x3",stepMode:"instance",defaultValue:[1,1,0]},particleColor:{shaderLocation:14,format:"float32x4",stepMode:"instance",defaultValue:[1,1,1,1]}}};class L extends g{constructor(e){super(),this.fallback=e}compile(e){if(!m(e))return{out:e.get(this.fallback)};if(c(e))throw new Error("OutlineLocalPositionNode can only be used in the vertex stage");const t=`outline_local_position_${e.variable()}`;return{chunk:`\n#ifdef USE_SKINNING\n let ${t} = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight).xyz;\n#else\n let ${t} = input.position;\n#endif`,out:t}}}class R extends g{constructor(e){super(),this.fallback=e}compile(e){if(!m(e))return{out:e.get(this.fallback)};if(c(e))throw new Error("OutlineLocalNormalNode can only be used in the vertex stage");const t=`outline_local_normal_${e.variable()}`;return{chunk:`\n#ifdef USE_SKINNING\n let ${t} = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let ${t} = input.normal;\n#endif`,out:t}}}export function setMaterialUniformValuesAutoUpdate(e,t){e.uniformValuesAutoUpdate=t}export function markMaterialUniformValuesNeedUpdate(e){const t=e;"uniformValuesNeedsUpdate"in t?t.uniformValuesNeedsUpdate=!0:t.uniformValuesAutoVersion=(t.uniformValuesAutoVersion??0)+1}function F(e){return!1!==e.uniformValuesAutoUpdate}function D(e){return e.uniformValuesAutoVersion??0}export function withThreeDefaultVertexAttributeValues(e){return e.map(e=>"uv1"===e.name&&null==e.defaultValue?{...e,defaultValue:[0,0]}:e)}const O=new WeakMap,j=new WeakMap;export function createNodeMaterialSignature(e){const t=j.get(e);if(null!=t)return t;const a=JSON.stringify({version:e.version,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader,alphaTest:e.alphaTest,alphaToCoverage:e.alphaToCoverage,blending:e.blending,colorWrite:e.colorWrite,depthFunc:e.depthFunc,depthTest:e.depthTest,depthWrite:e.depthWrite,polygonOffset:e.polygonOffset,polygonOffsetFactor:e.polygonOffsetFactor,polygonOffsetUnits:e.polygonOffsetUnits,premultipliedAlpha:e.premultipliedAlpha,side:e.side,stencilWrite:e.stencilWrite,transparent:e.transparent,wireframe:e.wireframe});return j.set(e,a),a}export class NodeMaterialWebGpuResolver{constructor(e,t,a){this.webGpu=e,this.mrtResolver=t,this.environmentTextureResolver=a,this.cache=new WeakMap,this.failedSignatures=new WeakMap,this.mappedMaterialsCache=new WeakMap,this.mappedMaterialsSignatures=new WeakMap,this.observedNodeMaterials=new Map,this.outlineMaterials=new WeakMap,this.worldEnvironmentMaterials=new WeakSet,this.worldEnvironment=null,this.worldEnvironmentTexture=null,this.worldEnvironmentIntensity=0,this.worldEnvironmentRevision=0,this.cacheValues=new Set}setWorldEnvironment(e){const t=e?.texture??null,a=e?.intensity??0;if(this.worldEnvironmentTexture!==t||this.worldEnvironmentIntensity!==a){if(this.worldEnvironmentTexture!==t)this.worldEnvironmentRevision++;else if(null!=e)for(const e of this.cacheValues)e.inheritsWorldEnvironment&&null!=e.material.uniforms.envMapIntensity&&(e.material.uniforms.envMapIntensity.value=a,e.material.uniformValuesNeedsUpdate=!0);this.worldEnvironment=e,this.worldEnvironmentTexture=t,this.worldEnvironmentIntensity=a}}resolve(e,t=void 0){let i,o=!1;if(e instanceof n)i=e,this.observeNodeMaterial(i);else{const t=this.getOrCreateMappedNodeMaterial(e);if(null==t)return;i=t,o=!0}if("outline"===t){if(null==i.outputAlbedo)return;o&&G(e,i),i.userData.outlineParameters=e.userData?.outlineParameters,i=this.getOrCreateOutlineMaterial(i),o=!1}i.visible=e.visible,o&&(i.userData.receiveDecals=e.userData.receiveDecals);const r=t??"default",l=this.cache.get(i),u=l?.get(r);if(o&&null!=u&&u.sourceVersion===e.version&&u.worldEnvironmentRevision===this.worldEnvironmentRevision){const t=F(e),a=D(e);return u.material.uniformValuesAutoUpdate=t,this.syncInheritedWorldEnvironmentSource(i,u),t||u.sourceUniformValuesAutoVersion!==a?(G(e,i),u.compiled.syncLiveUniforms(u.material.uniforms),$(i,u.material.uniforms),z(i,u.material),u.sourceUniformValuesAutoVersion=a,t||(u.material.uniformValuesNeedsUpdate=!0),u.material):u.material}if(!o&&null!=u&&u.sourceVersion===e.version&&u.worldEnvironmentRevision===this.worldEnvironmentRevision&&B(i,u.compiled))return this.syncInheritedWorldEnvironmentSource(i,u),P(i,u),u.material;o&&G(e,i);const p=this.prepareWorldEnvironment(i),m=this.getNodeMaterialSignature(i,p);if(u?.signature===m&&B(i,u.compiled))return o?(u.material.uniformValuesAutoUpdate=F(e),u.compiled.syncLiveUniforms(u.material.uniforms),$(i,u.material.uniforms),z(i,u.material),u.sourceUniformValuesAutoVersion=D(e),u.material.uniformValuesAutoUpdate||(u.material.uniformValuesNeedsUpdate=!0)):P(i,u,!0),u.sourceVersion=e.version,u.worldEnvironmentRevision=this.worldEnvironmentRevision,u.material;try{const n=this.mrtResolver?.(i,t),c=a(i,"opaque"===t?{...k,arrays:s.arrays}:k,n),d=new this.webGpu.WGSLShaderMaterial({vertexShader:c.vertexShader,fragmentShader:c.fragmentShader,depthVertexShader:c.depthVertexShader,depthFragmentShader:c.depthFragmentShader,pointShadowVertexShader:c.pointShadowVertexShader,pointShadowFragmentShader:c.pointShadowFragmentShader,uniforms:c.uniforms,textures:c.textures,sceneTextures:c.sceneTextures,graphTextures:c.graphTextures,vertexAttributes:withThreeDefaultVertexAttributeValues(c.vertexAttributes),uniformValuesAutoUpdate:o?F(e):i.uniformValuesAutoUpdate,transparent:c.renderState?.transparent,alphaTest:c.renderState?.alphaTest,depthTest:c.renderState?.depthTest,depthWrite:c.renderState?.depthWrite,side:c.renderState?.side,wireframe:i.wireframe});d.name=e.name||i.name||e.uuid,d.uniformValuesAutoUpdate=o?F(e):i.uniformValuesAutoUpdate,function(e,t){if(null==e)return;Object.assign(t,e)}(c.renderState,d),null!=u&&(u.material.dispose(),this.cacheValues.delete(u));const h={signature:m,compiled:c,material:d,inheritsWorldEnvironment:p,sourceVersion:e.version,sourceUniformValuesAutoVersion:o?D(e):i.uniformValuesAutoVersion,worldEnvironmentRevision:this.worldEnvironmentRevision},f=l??new Map;return f.set(r,h),this.cache.set(i,f),this.cacheValues.add(h),$(i,d.uniforms),z(i,d),d}catch(e){let t=this.failedSignatures.get(i);if(null==t&&(t=new Map,this.failedSignatures.set(i,t)),t.get(r)!==m){t.set(r,m);const a=e instanceof Error?e.message:String(e),n=i.name||i.uuid;console.warn(`[Hology WebGPU experiment] Falling back for NodeShaderMaterial "${n}": ${a}`,{material:i,error:e})}return}}getOrCreateOutlineMaterial(t){let a=this.outlineMaterials.get(t);if(null==a){const i=t.nodeMaterialDefinition,s=t.outputAlbedo;if(null==s)throw new Error("Cannot derive an outline material without an albedo output");const o=M("outlineThickness",.003),m=M("outlineDarkening",.65),c=M("outlineAlpha",1),g=new L(f.position.xyz),w=new R(f.normal),S=i.transform?.multiplyVec(y(g,1))??y(g,1),x=v.modelViewMatrix.multiplyVec(S),I=h(v.normalMatrix.multiplyVec(w)),T=d(u(l(x.xyz),r(1e-4))).multiply(.5),E=x.xyz.add(I.multiplyScalar(o.multiply(T))),b=v.projectionMatrix.multiplyVec(x),C=v.projectionMatrix.multiplyVec(y(E,1)),W=(i.position??b).add(C.subtract(b)),U=p(V({color:s.rgb.multiplyScalar(r(1).subtract(m))}),t.outputOpacity.multiply(c));a=new n({color:U,position:W,opacity:t.outputOpacity,discard:i.discard,alphaTest:t.alphaTest,transparent:!0,fog:!1,outputEncoding:i.outputEncoding,uniforms:i.uniforms,uniformNodes:i.uniformNodes}),a.side=e.BackSide,a.depthTest=!0,a.depthWrite=!0,this.outlineMaterials.set(t,a)}const i=t.userData?.outlineParameters;a.uniforms.outlineThickness.value=i?.thickness??.003,a.uniforms.outlineDarkening.value=e.MathUtils.clamp(i?.darkening??.65,0,1),a.uniforms.outlineAlpha.value=e.MathUtils.clamp(i?.alpha??t.opacity,0,1),a.userData.outlineSource=t;for(const e in t.uniforms)null!=a.uniforms[e]&&(a.uniforms[e].value=t.uniforms[e].value);return a}compileFullscreen(e){const a=t({color:e.outputColor,wgslBindings:{...k,uniformExpressions:{},graphTextures:{...k.graphTextures,[A]:{resource:"hologyNormalRoughness",dimension:"2d",sampleType:"float",sampler:"filtering"}}}}),n=a.syncLiveUniforms;return{...a,syncLiveUniforms(t){n(t),$(e,t)}}}getOrCreateMappedNodeMaterial(t){const a=function(t){const a=[t.vertexColors,t.transparent,t.alphaTest,t.side,t.depthTest,t.depthWrite,t.wireframe??!1];t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.roughnessMap?t.roughnessMap.uuid:null,t.metalnessMap?t.metalnessMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshLambertMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshToonMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.gradientMap?t.gradientMap.uuid:null):t instanceof e.MeshBasicMaterial?a.push(t.map?t.map.uuid:null,t.aoMap?t.aoMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshPhongMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.SpriteMaterial&&a.push(t.map?t.map.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.sizeAttenuation);return a.join(",")}(t),n=this.mappedMaterialsCache.get(t),i=this.mappedMaterialsSignatures.get(t);if(null!=n&&i===a)return n;if(null!=n){n.dispose();const e=this.cache.get(n);if(null!=e){for(const t of e.values())t.material.dispose(),this.cacheValues.delete(t);this.cache.delete(n)}}const s=function(t){if(t instanceof e.SpriteMaterial){const e=new T;e.color=t.color,e.opacity=t.opacity,e.rotation=t.rotation,e.screenSpaceSize=t.sizeAttenuation?0:1,e.alphaTest=t.alphaTest,t.map&&(e.map=t.map),t.alphaMap&&(e.alphaMap=t.alphaMap);const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a}if(t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial){const e=new w;e.color=t.color,e.opacity=t.opacity,e.roughness=t.roughness,e.metalness=t.metalness,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.roughnessMap&&(e.roughnessMap=o(t.roughnessMap)),t.metalnessMap&&(e.metalnessMap=o(t.metalnessMap)),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.envMapIntensity=t.envMapIntensity,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshLambertMaterial){const e=new S;e.color=t.color,e.opacity=t.opacity,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshToonMaterial){const e=new x;e.color=t.color,e.opacity=t.opacity,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshBasicMaterial||t instanceof e.LineBasicMaterial){const a=new I;a.color=t.color,a.opacity=t.opacity,a.vertexColor=t.vertexColors,t instanceof e.MeshBasicMaterial&&(t.map&&(a.map=o(t.map)),t.aoMap&&(a.aoMap=o(t.aoMap),a.aoMapIntensity=t.aoMapIntensity),t.lightMap&&(a.lightMap=o(t.lightMap),a.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(a.alphaMap=o(t.alphaMap)),a.envMap=t.envMap),a.alphaTest=t.alphaTest;const n=a.build();return n.transparent=t.transparent,n.side=t.side,n.depthTest=t.depthTest,n.depthWrite=t.depthWrite,n.wireframe=t instanceof e.MeshBasicMaterial&&t.wireframe,n}if(t instanceof e.MeshPhongMaterial){const e=new w;e.color=t.color,e.opacity=t.opacity,e.roughness=Math.max(0,1-t.shininess/100),e.metalness=0,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}return null}(t);return null==s?null:(s.wireframe=t.wireframe??!1,this.mappedMaterialsCache.set(t,s),this.mappedMaterialsSignatures.set(t,a),t.addEventListener("dispose",()=>{const e=this.mappedMaterialsCache.get(t);if(null!=e){e.dispose(),this.mappedMaterialsCache.delete(t),this.mappedMaterialsSignatures.delete(t);const a=this.cache.get(e);if(null!=a){for(const e of a.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(e)}}}),s)}canResolve(e){return null!=this.resolve(e)}dispose(){for(const[e,t]of this.observedNodeMaterials)e.removeEventListener("dispose",t);this.observedNodeMaterials.clear();for(const e of this.cacheValues)e.material.dispose();this.cacheValues.clear()}syncInheritedWorldEnvironmentSource(e,t){t.inheritsWorldEnvironment&&null!=this.worldEnvironment&&(e.uniforms.envMap.value=this.worldEnvironment.texture,e.uniforms.envMapIntensity.value=this.worldEnvironment.intensity)}getNodeMaterialSignature(e,t){const a=`${createNodeMaterialSignature(e)}|receiveDecals:${!1!==e.userData.receiveDecals}`;return t?`${a}|worldEnvironment:${this.worldEnvironmentRevision}`:a}prepareWorldEnvironment(t){var a,n,i,s,o,r;if(null!=t.envMap){const s=this.environmentTextureResolver?.(t.envMap)??t.envMap;return(a=t.uniforms).envMap??(a.envMap={value:s}),t.uniforms.envMap.value=s,(n=t.uniforms).envMapIntensity??(n.envMapIntensity={value:1}),(i=t.uniforms).envMapRotation??(i.envMapRotation={value:new e.Matrix3}),this.worldEnvironmentMaterials.delete(t),!1}return null==this.worldEnvironment?(this.worldEnvironmentMaterials.has(t)&&(delete t.uniforms.envMap,delete t.uniforms.envMapIntensity,delete t.uniforms.envMapRotation,this.worldEnvironmentMaterials.delete(t)),!1):((s=t.uniforms).envMap??(s.envMap={value:this.worldEnvironment.texture}),t.uniforms.envMap.value=this.worldEnvironment.texture,(o=t.uniforms).envMapIntensity??(o.envMapIntensity={value:this.worldEnvironment.intensity}),t.uniforms.envMapIntensity.value=this.worldEnvironment.intensity,(r=t.uniforms).envMapRotation??(r.envMapRotation={value:new e.Matrix3}),this.worldEnvironmentMaterials.add(t),!0)}observeNodeMaterial(e){if(this.observedNodeMaterials.has(e))return;const t=()=>{e.removeEventListener("dispose",t),this.observedNodeMaterials.delete(e);const a=this.cache.get(e);if(null!=a){for(const e of a.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(e)}const n=this.outlineMaterials.get(e);if(null!=n){const t=this.cache.get(n);if(null!=t){for(const e of t.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(n)}this.failedSignatures.delete(n),j.delete(n),n.dispose(),this.outlineMaterials.delete(e)}this.failedSignatures.delete(e),j.delete(e)};this.observedNodeMaterials.set(e,t),e.addEventListener("dispose",t)}}function P(e,t,a=!1){const n=t.material;n.uniformValuesAutoUpdate=e.uniformValuesAutoUpdate,(a||e.uniformValuesAutoUpdate||t.sourceUniformValuesAutoVersion!==e.uniformValuesAutoVersion)&&(t.compiled.syncLiveUniforms(n.uniforms),$(e,n.uniforms),z(e,n),t.sourceUniformValuesAutoVersion=e.uniformValuesAutoVersion,n.uniformValuesAutoUpdate||(n.uniformValuesNeedsUpdate=!0))}function $(e,t){let a=O.get(t);if(null==a){a=[];for(const e in t){const n=t[e],i=n.value,s=!0===i?.isVector2?2:!0===i?.isVector3?3:!0===i?.isVector4?4:!0===i?.isColor?5:0;a.push({name:e,target:n,copyKind:s})}O.set(t,a)}const n=e.uniforms;for(let e=0;e<a.length;e++){const t=a[e],i=n[t.name];if(null==i)continue;const s=i.value,o=t.target.value;if(s!==o){if(0!==t.copyKind){const e=s,a=o;if((2===t.copyKind?!0===e?.isVector2:3===t.copyKind?!0===e?.isVector3:4===t.copyKind?!0===e?.isVector4:!0===e?.isColor)&&"function"==typeof a?.copy){a.copy(s);continue}}t.target.value=s}}}function z(t,a){const n=t.uniforms.envMapIntensity,i=a.uniforms.envMapIntensity;null!=n&&null!=i&&(i.value=n.value);const s=t.uniforms.envMapRotation?.value,o=a.uniforms.envMapRotation?.value;s instanceof e.Matrix3&&o instanceof e.Matrix3&&o.copy(s)}function B(e,t){for(const a in t.textures){const n=t.textures[a],i=e.uniforms[a]?.value;if(_(i)&&i!==n)return!1}return!0}function _(e){return!0===e?.isTexture}function G(t,a){if(t instanceof e.SpriteMaterial){const n=a;a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),n.rotation=t.rotation,n.screenSpaceSize=t.sizeAttenuation?0:1}else t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.roughness&&(a.uniforms.roughness.value=t.roughness),a.uniforms.metalness&&(a.uniforms.metalness.value=t.metalness),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity),a.uniforms.envMapIntensity&&(a.uniforms.envMapIntensity.value=t.envMapIntensity)):t instanceof e.MeshLambertMaterial||t instanceof e.MeshToonMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity)):t instanceof e.MeshBasicMaterial||t instanceof e.LineBasicMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),t instanceof e.MeshBasicMaterial&&(a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity))):t instanceof e.MeshPhongMaterial&&(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.roughness&&(a.uniforms.roughness.value=Math.max(0,1-t.shininess/100)),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity))}/*
1
+ import*as e from"three";import{compileNodeWebGpuFullscreen as t,compileNodeShaderMaterialForWebGpu as a,NodeShaderMaterial as n,webGpuRendererBindings as i,webGpuTiledRendererBindings as s,textureSampler2d as o,float as r,length as l,max as u,rgba as p,isWgslCompiler as m,isWgslFragmentCompiler as c,sqrt as f,normalize as d,transformed as h,uniformFloat as M,uniforms as v,vec4 as y,Vec3Node as g,toonMaterial as V}from"three-shader-graph";import{StandardShader as w}from"../shader/builtin/standard-shader.js";import{LambertShader as S}from"../shader/builtin/lambert-shader.js";import{ToonShader as x}from"../shader/builtin/toon-shader.js";import{UnlitShader as I}from"../shader/builtin/unlit-shader.js";import{SpriteShader as T}from"../shader/sprite-shader.js";import{elapsedTimeUniformName as E}from"../shader-nodes/time.js";import{depthUniformName as b,farUniformName as U,nearUniformName as A,resolutionUniformName as C,sceneNormalUniformName as W}from"../shader-nodes/depth.js";import{sceneMapUniformName as N}from"../shader-nodes/scene-sample.js";const k={...i,uniformExpressions:{...i.uniformExpressions,ambientLightColor:{type:"vec3",expression:"rendererAmbientLight()"},[E]:{type:"float",expression:"rendererElapsedTime()"},[A]:{type:"float",expression:"rendererCameraNear()"},[U]:{type:"float",expression:"rendererCameraFar()"},[C]:{type:"vec2",expression:"rendererViewportSize()"}},sceneTextures:{[N]:{semantic:"sceneColor",sampleType:"float"},[b]:{semantic:"sceneDepth",sampleType:"depth"}},attributes:{material:{shaderLocation:6,format:"float32x4",defaultValue:[0,0,0,0]},material2:{shaderLocation:7,format:"float32x4",defaultValue:[0,0,0,0]},hole:{shaderLocation:8,format:"float32",defaultValue:[0]},offset:{shaderLocation:9,format:"float32x3",stepMode:"instance",defaultValue:[0,0,0]},velocity:{shaderLocation:10,format:"float32x4",stepMode:"instance",defaultValue:[0,0,0,0]},size:{shaderLocation:11,format:"float32x3",stepMode:"instance",defaultValue:[0,0,0]},rotation:{shaderLocation:12,format:"float32",stepMode:"instance",defaultValue:[0]},particleData:{shaderLocation:13,format:"float32x3",stepMode:"instance",defaultValue:[1,1,0]},particleColor:{shaderLocation:14,format:"float32x4",stepMode:"instance",defaultValue:[1,1,1,1]}}};class L extends g{constructor(e){super(),this.fallback=e}compile(e){if(!m(e))return{out:e.get(this.fallback)};if(c(e))throw new Error("OutlineLocalPositionNode can only be used in the vertex stage");const t=`outline_local_position_${e.variable()}`;return{chunk:`\n#ifdef USE_SKINNING\n let ${t} = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight).xyz;\n#else\n let ${t} = input.position;\n#endif`,out:t}}}class R extends g{constructor(e){super(),this.fallback=e}compile(e){if(!m(e))return{out:e.get(this.fallback)};if(c(e))throw new Error("OutlineLocalNormalNode can only be used in the vertex stage");const t=`outline_local_normal_${e.variable()}`;return{chunk:`\n#ifdef USE_SKINNING\n let ${t} = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let ${t} = input.normal;\n#endif`,out:t}}}export function setMaterialUniformValuesAutoUpdate(e,t){e.uniformValuesAutoUpdate=t}export function markMaterialUniformValuesNeedUpdate(e){const t=e;"uniformValuesNeedsUpdate"in t?t.uniformValuesNeedsUpdate=!0:t.uniformValuesAutoVersion=(t.uniformValuesAutoVersion??0)+1}function D(e){return!1!==e.uniformValuesAutoUpdate}function F(e){return e.uniformValuesAutoVersion??0}export function withThreeDefaultVertexAttributeValues(e){return e.map(e=>"uv1"===e.name&&null==e.defaultValue?{...e,defaultValue:[0,0]}:e)}const O=new WeakMap,j=new WeakMap;export function createNodeMaterialSignature(e){const t=j.get(e);if(null!=t)return t;const a=JSON.stringify({version:e.version,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader,alphaTest:e.alphaTest,alphaToCoverage:e.alphaToCoverage,blending:e.blending,colorWrite:e.colorWrite,depthFunc:e.depthFunc,depthTest:e.depthTest,depthWrite:e.depthWrite,polygonOffset:e.polygonOffset,polygonOffsetFactor:e.polygonOffsetFactor,polygonOffsetUnits:e.polygonOffsetUnits,premultipliedAlpha:e.premultipliedAlpha,side:e.side,stencilWrite:e.stencilWrite,transparent:e.transparent,wireframe:e.wireframe});return j.set(e,a),a}export class NodeMaterialWebGpuResolver{constructor(e,t,a){this.webGpu=e,this.mrtResolver=t,this.environmentTextureResolver=a,this.cache=new WeakMap,this.failedSignatures=new WeakMap,this.mappedMaterialsCache=new WeakMap,this.mappedMaterialsSignatures=new WeakMap,this.observedNodeMaterials=new Map,this.outlineMaterials=new WeakMap,this.outlineUniformVersions=new WeakMap,this.worldEnvironmentMaterials=new WeakSet,this.worldEnvironment=null,this.worldEnvironmentTexture=null,this.worldEnvironmentIntensity=0,this.worldEnvironmentRevision=0,this.cacheValues=new Set}setWorldEnvironment(e){const t=e?.texture??null,a=e?.intensity??0;if(this.worldEnvironmentTexture!==t||this.worldEnvironmentIntensity!==a){if(this.worldEnvironmentTexture!==t)this.worldEnvironmentRevision++;else if(null!=e)for(const e of this.cacheValues)e.inheritsWorldEnvironment&&null!=e.material.uniforms.envMapIntensity&&(e.material.uniforms.envMapIntensity.value=a,e.material.uniformValuesNeedsUpdate=!0);this.worldEnvironment=e,this.worldEnvironmentTexture=t,this.worldEnvironmentIntensity=a}}resolve(e,t=void 0){let i,o=!1;if(e instanceof n)i=e,this.observeNodeMaterial(i);else{const t=this.getOrCreateMappedNodeMaterial(e);if(null==t)return;i=t,o=!0}if("outline"===t){if(null==i.outputAlbedo)return;o&&G(e,i),i.userData.outlineParameters=e.userData?.outlineParameters,i=this.getOrCreateOutlineMaterial(i),o=!1}i.visible=e.visible,o&&(i.userData.receiveDecals=e.userData.receiveDecals);const r=t??"default",l=this.cache.get(i),u=l?.get(r);if(o&&null!=u&&u.sourceVersion===e.version&&u.worldEnvironmentRevision===this.worldEnvironmentRevision){const t=D(e),a=F(e);return u.material.uniformValuesAutoUpdate=t,this.syncInheritedWorldEnvironmentSource(i,u),t||u.sourceUniformValuesAutoVersion!==a?(G(e,i),u.compiled.syncLiveUniforms(u.material.uniforms),$(i,u.material.uniforms),z(i,u.material),u.sourceUniformValuesAutoVersion=a,t||(u.material.uniformValuesNeedsUpdate=!0),u.material):u.material}if(!o&&null!=u&&u.sourceVersion===e.version&&u.worldEnvironmentRevision===this.worldEnvironmentRevision&&B(i,u.compiled))return this.syncInheritedWorldEnvironmentSource(i,u),P(i,u),u.material;o&&G(e,i);const p=this.prepareWorldEnvironment(i),m=this.getNodeMaterialSignature(i,p);if(u?.signature===m&&B(i,u.compiled))return o?(u.material.uniformValuesAutoUpdate=D(e),u.compiled.syncLiveUniforms(u.material.uniforms),$(i,u.material.uniforms),z(i,u.material),u.sourceUniformValuesAutoVersion=F(e),u.material.uniformValuesAutoUpdate||(u.material.uniformValuesNeedsUpdate=!0)):P(i,u,!0),u.sourceVersion=e.version,u.worldEnvironmentRevision=this.worldEnvironmentRevision,u.material;try{const n=this.mrtResolver?.(i,t),c=a(i,"opaque"===t?{...k,arrays:s.arrays}:k,n),f=new this.webGpu.WGSLShaderMaterial({vertexShader:c.vertexShader,fragmentShader:c.fragmentShader,depthVertexShader:c.depthVertexShader,depthFragmentShader:c.depthFragmentShader,pointShadowVertexShader:c.pointShadowVertexShader,pointShadowFragmentShader:c.pointShadowFragmentShader,uniforms:c.uniforms,textures:c.textures,sceneTextures:c.sceneTextures,graphTextures:c.graphTextures,vertexAttributes:withThreeDefaultVertexAttributeValues(c.vertexAttributes),uniformValuesAutoUpdate:o?D(e):i.uniformValuesAutoUpdate,transparent:c.renderState?.transparent,alphaTest:c.renderState?.alphaTest,depthTest:c.renderState?.depthTest,depthWrite:c.renderState?.depthWrite,side:c.renderState?.side,wireframe:i.wireframe});f.name=e.name||i.name||e.uuid,f.uniformValuesAutoUpdate=o?D(e):i.uniformValuesAutoUpdate,function(e,t){if(null==e)return;Object.assign(t,e)}(c.renderState,f),null!=u&&(u.material.dispose(),this.cacheValues.delete(u));const d={signature:m,compiled:c,material:f,inheritsWorldEnvironment:p,sourceVersion:e.version,sourceUniformValuesAutoVersion:o?F(e):i.uniformValuesAutoVersion,worldEnvironmentRevision:this.worldEnvironmentRevision},h=l??new Map;return h.set(r,d),this.cache.set(i,h),this.cacheValues.add(d),$(i,f.uniforms),z(i,f),f}catch(e){let t=this.failedSignatures.get(i);if(null==t&&(t=new Map,this.failedSignatures.set(i,t)),t.get(r)!==m){t.set(r,m);const a=e instanceof Error?e.message:String(e),n=i.name||i.uuid;console.warn(`[Hology WebGPU experiment] Falling back for NodeShaderMaterial "${n}": ${a}`,{material:i,error:e})}return}}getOrCreateOutlineMaterial(t){let a=this.outlineMaterials.get(t);if(null==a){const i=t.nodeMaterialDefinition,s=t.outputAlbedo;if(null==s)throw new Error("Cannot derive an outline material without an albedo output");const o=M("outlineThickness",.003),m=M("outlineDarkening",.65),c=M("outlineAlpha",1),g=new L(h.position.xyz),w=new R(h.normal),S=i.transform?.multiplyVec(y(g,1))??y(g,1),x=v.modelViewMatrix.multiplyVec(S),I=d(v.normalMatrix.multiplyVec(w)),T=f(u(l(x.xyz),r(1e-4))).multiply(.5),E=x.xyz.add(I.multiplyScalar(o.multiply(T))),b=v.projectionMatrix.multiplyVec(x),U=v.projectionMatrix.multiplyVec(y(E,1)),A=(i.position??b).add(U.subtract(b)),C=p(V({color:s.rgb.multiplyScalar(r(1).subtract(m))}),t.outputOpacity.multiply(c));a=new n({color:C,position:A,opacity:t.outputOpacity,discard:i.discard,alphaTest:t.alphaTest,transparent:!0,fog:!1,outputEncoding:i.outputEncoding,uniforms:i.uniforms,uniformNodes:i.uniformNodes}),a.side=e.BackSide,a.depthTest=!0,a.depthWrite=!0,this.outlineMaterials.set(t,a),this.outlineUniformVersions.delete(t)}const i=t.userData?.outlineParameters,s=i?.thickness??.003,o=e.MathUtils.clamp(i?.darkening??.65,0,1),m=e.MathUtils.clamp(i?.alpha??t.opacity,0,1),c=a.uniforms.outlineThickness.value!==s||a.uniforms.outlineDarkening.value!==o||a.uniforms.outlineAlpha.value!==m;a.uniforms.outlineThickness.value=s,a.uniforms.outlineDarkening.value=o,a.uniforms.outlineAlpha.value=m,a.userData.outlineSource=t,a.uniformValuesAutoUpdate=t.uniformValuesAutoUpdate;let g=this.outlineUniformVersions.get(t);const w=t.uniformValuesAutoUpdate||null==g||g.version!==t.uniformValuesAutoVersion||g.uniforms!==t.uniforms;if(w){for(const e in t.uniforms)null!=a.uniforms[e]&&(a.uniforms[e].value=t.uniforms[e].value);g?(g.version=t.uniformValuesAutoVersion,g.uniforms=t.uniforms):(g={version:t.uniformValuesAutoVersion,uniforms:t.uniforms},this.outlineUniformVersions.set(t,g))}return t.uniformValuesAutoUpdate||!c&&!w||(a.uniformValuesNeedsUpdate=!0),a}compileFullscreen(e){const a=t({color:e.outputColor,wgslBindings:{...k,uniformExpressions:{},graphTextures:{...k.graphTextures,[W]:{resource:"hologyNormalRoughness",dimension:"2d",sampleType:"float",sampler:"filtering"}}}}),n=a.syncLiveUniforms;return{...a,syncLiveUniforms(t){n(t),$(e,t)}}}getOrCreateMappedNodeMaterial(t){const a=function(t){const a=[t.vertexColors,t.transparent,t.alphaTest,t.side,t.depthTest,t.depthWrite,t.wireframe??!1];t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.roughnessMap?t.roughnessMap.uuid:null,t.metalnessMap?t.metalnessMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshLambertMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshToonMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.gradientMap?t.gradientMap.uuid:null):t instanceof e.MeshBasicMaterial?a.push(t.map?t.map.uuid:null,t.aoMap?t.aoMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.MeshPhongMaterial?a.push(t.map?t.map.uuid:null,t.normalMap?t.normalMap.uuid:null,t.aoMap?t.aoMap.uuid:null,t.emissiveMap?t.emissiveMap.uuid:null,t.lightMap?t.lightMap.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.envMap?t.envMap.uuid:null):t instanceof e.SpriteMaterial&&a.push(t.map?t.map.uuid:null,t.alphaMap?t.alphaMap.uuid:null,t.sizeAttenuation);return a.join(",")}(t),n=this.mappedMaterialsCache.get(t),i=this.mappedMaterialsSignatures.get(t);if(null!=n&&i===a)return n;if(null!=n){n.dispose();const e=this.cache.get(n);if(null!=e){for(const t of e.values())t.material.dispose(),this.cacheValues.delete(t);this.cache.delete(n)}}const s=function(t){if(t instanceof e.SpriteMaterial){const e=new T;e.color=t.color,e.opacity=t.opacity,e.rotation=t.rotation,e.screenSpaceSize=t.sizeAttenuation?0:1,e.alphaTest=t.alphaTest,t.map&&(e.map=t.map),t.alphaMap&&(e.alphaMap=t.alphaMap);const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a}if(t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial){const e=new w;e.color=t.color,e.opacity=t.opacity,e.roughness=t.roughness,e.metalness=t.metalness,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.roughnessMap&&(e.roughnessMap=o(t.roughnessMap)),t.metalnessMap&&(e.metalnessMap=o(t.metalnessMap)),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.envMapIntensity=t.envMapIntensity,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshLambertMaterial){const e=new S;e.color=t.color,e.opacity=t.opacity,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshToonMaterial){const e=new x;e.color=t.color,e.opacity=t.opacity,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}if(t instanceof e.MeshBasicMaterial||t instanceof e.LineBasicMaterial){const a=new I;a.color=t.color,a.opacity=t.opacity,a.vertexColor=t.vertexColors,t instanceof e.MeshBasicMaterial&&(t.map&&(a.map=o(t.map)),t.aoMap&&(a.aoMap=o(t.aoMap),a.aoMapIntensity=t.aoMapIntensity),t.lightMap&&(a.lightMap=o(t.lightMap),a.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(a.alphaMap=o(t.alphaMap)),a.envMap=t.envMap),a.alphaTest=t.alphaTest;const n=a.build();return n.transparent=t.transparent,n.side=t.side,n.depthTest=t.depthTest,n.depthWrite=t.depthWrite,n.wireframe=t instanceof e.MeshBasicMaterial&&t.wireframe,n}if(t instanceof e.MeshPhongMaterial){const e=new w;e.color=t.color,e.opacity=t.opacity,e.roughness=Math.max(0,1-t.shininess/100),e.metalness=0,e.vertexColor=t.vertexColors,t.map&&(e.map=o(t.map)),t.normalMap&&(e.normalMap=o(t.normalMap),e.normalScale=t.normalScale),t.aoMap&&(e.aoMap=o(t.aoMap),e.aoMapIntensity=t.aoMapIntensity),t.emissiveMap&&(e.emissiveMap=o(t.emissiveMap)),t.lightMap&&(e.lightMap=o(t.lightMap),e.lightMapIntensity=t.lightMapIntensity),t.alphaMap&&(e.alphaMap=o(t.alphaMap)),e.emissive=t.emissive,e.emissiveIntensity=t.emissiveIntensity,e.envMap=t.envMap,e.alphaTest=t.alphaTest;const a=e.build();return a.transparent=t.transparent,a.side=t.side,a.depthTest=t.depthTest,a.depthWrite=t.depthWrite,a.wireframe=t.wireframe,a}return null}(t);return null==s?null:(s.wireframe=t.wireframe??!1,this.mappedMaterialsCache.set(t,s),this.mappedMaterialsSignatures.set(t,a),t.addEventListener("dispose",()=>{const e=this.mappedMaterialsCache.get(t);if(null!=e){e.dispose(),this.mappedMaterialsCache.delete(t),this.mappedMaterialsSignatures.delete(t);const a=this.cache.get(e);if(null!=a){for(const e of a.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(e)}}}),s)}canResolve(e){return null!=this.resolve(e)}dispose(){for(const[e,t]of this.observedNodeMaterials)e.removeEventListener("dispose",t);this.observedNodeMaterials.clear();for(const e of this.cacheValues)e.material.dispose();this.cacheValues.clear()}syncInheritedWorldEnvironmentSource(e,t){t.inheritsWorldEnvironment&&null!=this.worldEnvironment&&(e.uniforms.envMap.value=this.worldEnvironment.texture,e.uniforms.envMapIntensity.value=this.worldEnvironment.intensity)}getNodeMaterialSignature(e,t){const a=`${createNodeMaterialSignature(e)}|receiveDecals:${!1!==e.userData.receiveDecals}`;return t?`${a}|worldEnvironment:${this.worldEnvironmentRevision}`:a}prepareWorldEnvironment(t){var a,n,i,s,o,r;if(null!=t.envMap){const s=this.environmentTextureResolver?.(t.envMap)??t.envMap;return(a=t.uniforms).envMap??(a.envMap={value:s}),t.uniforms.envMap.value=s,(n=t.uniforms).envMapIntensity??(n.envMapIntensity={value:1}),(i=t.uniforms).envMapRotation??(i.envMapRotation={value:new e.Matrix3}),this.worldEnvironmentMaterials.delete(t),!1}return null==this.worldEnvironment?(this.worldEnvironmentMaterials.has(t)&&(delete t.uniforms.envMap,delete t.uniforms.envMapIntensity,delete t.uniforms.envMapRotation,this.worldEnvironmentMaterials.delete(t)),!1):((s=t.uniforms).envMap??(s.envMap={value:this.worldEnvironment.texture}),t.uniforms.envMap.value=this.worldEnvironment.texture,(o=t.uniforms).envMapIntensity??(o.envMapIntensity={value:this.worldEnvironment.intensity}),t.uniforms.envMapIntensity.value=this.worldEnvironment.intensity,(r=t.uniforms).envMapRotation??(r.envMapRotation={value:new e.Matrix3}),this.worldEnvironmentMaterials.add(t),!0)}observeNodeMaterial(e){if(this.observedNodeMaterials.has(e))return;const t=()=>{e.removeEventListener("dispose",t),this.observedNodeMaterials.delete(e);const a=this.cache.get(e);if(null!=a){for(const e of a.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(e)}const n=this.outlineMaterials.get(e);if(null!=n){const t=this.cache.get(n);if(null!=t){for(const e of t.values())e.material.dispose(),this.cacheValues.delete(e);this.cache.delete(n)}this.failedSignatures.delete(n),j.delete(n),n.dispose(),this.outlineMaterials.delete(e),this.outlineUniformVersions.delete(e)}this.failedSignatures.delete(e),j.delete(e)};this.observedNodeMaterials.set(e,t),e.addEventListener("dispose",t)}}function P(e,t,a=!1){const n=t.material;n.uniformValuesAutoUpdate=e.uniformValuesAutoUpdate,(a||e.uniformValuesAutoUpdate||t.sourceUniformValuesAutoVersion!==e.uniformValuesAutoVersion)&&(t.compiled.syncLiveUniforms(n.uniforms),$(e,n.uniforms),z(e,n),t.sourceUniformValuesAutoVersion=e.uniformValuesAutoVersion,n.uniformValuesAutoUpdate||(n.uniformValuesNeedsUpdate=!0))}function $(e,t){let a=O.get(t);if(null==a){a=[];for(const e in t){const n=t[e],i=n.value,s=!0===i?.isVector2?2:!0===i?.isVector3?3:!0===i?.isVector4?4:!0===i?.isColor?5:0;a.push({name:e,target:n,copyKind:s})}O.set(t,a)}const n=e.uniforms;for(let e=0;e<a.length;e++){const t=a[e],i=n[t.name];if(null==i)continue;const s=i.value,o=t.target.value;if(s!==o){if(0!==t.copyKind){const e=s,a=o;if((2===t.copyKind?!0===e?.isVector2:3===t.copyKind?!0===e?.isVector3:4===t.copyKind?!0===e?.isVector4:!0===e?.isColor)&&"function"==typeof a?.copy){a.copy(s);continue}}t.target.value=s}}}function z(t,a){const n=t.uniforms.envMapIntensity,i=a.uniforms.envMapIntensity;null!=n&&null!=i&&(i.value=n.value);const s=t.uniforms.envMapRotation?.value,o=a.uniforms.envMapRotation?.value;s instanceof e.Matrix3&&o instanceof e.Matrix3&&o.copy(s)}function B(e,t){for(const a in t.textures){const n=t.textures[a],i=e.uniforms[a]?.value;if(_(i)&&i!==n)return!1}return!0}function _(e){return!0===e?.isTexture}function G(t,a){if(t instanceof e.SpriteMaterial){const n=a;a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),n.rotation=t.rotation,n.screenSpaceSize=t.sizeAttenuation?0:1}else t instanceof e.MeshStandardMaterial||t instanceof e.MeshPhysicalMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.roughness&&(a.uniforms.roughness.value=t.roughness),a.uniforms.metalness&&(a.uniforms.metalness.value=t.metalness),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity),a.uniforms.envMapIntensity&&(a.uniforms.envMapIntensity.value=t.envMapIntensity)):t instanceof e.MeshLambertMaterial||t instanceof e.MeshToonMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity)):t instanceof e.MeshBasicMaterial||t instanceof e.LineBasicMaterial?(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),t instanceof e.MeshBasicMaterial&&(a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity))):t instanceof e.MeshPhongMaterial&&(a.uniforms.color&&(a.uniforms.color.value instanceof e.Vector3?a.uniforms.color.value.setFromColor(t.color):a.uniforms.color.value instanceof e.Color&&a.uniforms.color.value.copy(t.color)),a.uniforms.opacity&&(a.uniforms.opacity.value=t.opacity),a.uniforms.roughness&&(a.uniforms.roughness.value=Math.max(0,1-t.shininess/100)),a.uniforms.emissive&&(a.uniforms.emissive.value instanceof e.Vector3?a.uniforms.emissive.value.setFromColor(t.emissive):a.uniforms.emissive.value instanceof e.Color&&a.uniforms.emissive.value.copy(t.emissive)),a.uniforms.emissiveIntensity&&(a.uniforms.emissiveIntensity.value=t.emissiveIntensity),a.uniforms.normalScale&&t.normalScale&&(a.uniforms.normalScale.value=t.normalScale.x),a.uniforms.aoMapIntensity&&(a.uniforms.aoMapIntensity.value=t.aoMapIntensity),a.uniforms.lightMapIntensity&&(a.uniforms.lightMapIntensity.value=t.lightMapIntensity))}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -118,6 +118,7 @@ export declare class ExperimentalWebGpuBackend implements RenderingBackendDriver
118
118
  private readonly pmremResults;
119
119
  private readonly ownedPmremResults;
120
120
  private readonly warnedUnsupportedPostProcessStages;
121
+ private secondaryMotionPrepared;
121
122
  private constructor();
122
123
  static probeAvailability(): Promise<{
123
124
  available: true;
@@ -1,4 +1,4 @@
1
- import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{configureWebGpuRuntimeBindings as i}from"./webgpu-runtime-bridge.js";import{float as n,varyingTransformed as r,vec4 as o}from"three-shader-graph";import{NodeShaderMaterial as s}from"../shader-nodes/index.js";import{sceneMapUniformName as a}from"../shader-nodes/scene-sample.js";import{depthUniformName as l}from"../shader-nodes/depth.js";import{MATERIAL_FLAG_ALPHA_TEST as d,MATERIAL_FLAG_RECEIVE_DECALS as c}from"../shader-nodes/material-flags.js";import{createMotionVectorOutput as h}from"./motion-vector-node.js";export class ExperimentalWebGpuBackend{constructor(e,t,i,n,r,o,s,a,l,d,c,h,u,p,m,g,f,v,S,b,x,P){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=i,this.gBufferFallbackSource=n,this.bloom=r,this.fxaa=o,this.smaa=s,this.gtao=a,this.ssr=l,this.taa=d,this.motionBlur=c,this.volumetricFog=h,this.colorGrading=u,this.depthOfField=p,this.outline=m,this.postProcessEffects=g,this.renderGraphExtensions=f,this.presentationExtensions=v,this.antiAliasingState=S,this.directionalShadowState=b,this.nativeDlss=x,this.kind="webgpu",this.renderScale=1,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.canvas=P}static async probeAvailability(){if("undefined"==typeof navigator||!("gpu"in navigator))return{available:!1,reason:"The runtime does not expose navigator.gpu."};try{const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});return null==e?{available:!1,reason:"No WebGPU adapter is available."}:{available:!0,adapter:e}}catch(e){return{available:!1,reason:`Requesting a WebGPU adapter failed: ${e instanceof Error?e.message:String(e)}`}}}static async create(m={},g){const f=await import("@hology/webgpu-renderer");i({createComputeKernel:(e,t)=>new f.ComputeKernel(e,t),buildParticleLightingShaderHeader:f.buildParticleLightingShaderHeader});const v=document.createElement("canvas");v.dataset.hologyRenderer="webgpu-experimental";const S=new f.WGSLShaderMaterial({vertexShader:u,fragmentShader:p}),b=!1!==m.nativeUpscaling&&"dlss"===m.nativeUpscaling?.method,x=b?(await import("./native-dlss-upscaler.js")).createNativeDlssUpscaler(m.nativeUpscaling?.mode??"quality"):null,P=null!=x;S.side=f.DoubleSide;const w=f,y=null!=m.motionBlur&&!1!==m.motionBlur,E=!1!==m.gtao&&(null==m.gtao||!1!==m.gtao.temporal),F=!1!==m.volumetricFog&&(null==m.volumetricFog||!1!==m.volumetricFog.temporal),M=P?"off":b?"taa":null!=(L=m).antiAliasing?L.antiAliasing:null!=L.taa&&!1!==L.taa?"taa":null!=L.smaa&&!1!==L.smaa?"smaa":null!=L.fxaa&&!1!==L.fxaa?"fxaa":!1===L.taa?"off":"taa";var L;const C=null!=m.antiAliasing,D=y||E||F||(C||"taa"===M)||P;let O=null;const G=new t(w,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(n(e.alphaTest>0?d:0).add(!1===e.userData.receiveDecals?0:c)),o((e.outputNormal??r.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??n(1)),...D?[h(e)]:[]]:void 0,e=>O?.getEnvironmentTexture(e)??e),R=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==G.resolve(R,"opaque"))throw S.dispose(),R.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const T=!1===m.gtao?null:new f.GTAOEffect({normalSpace:"view",...f.GTAO_PRESETS.high,...m.gtao??{}}),A=!1===m.ssr||null==m.ssr?null:new f.SSREffect({normalSpace:"view",resolutionScale:.5,...m.ssr??{}}),B=!1===m.bloom?null:new f.BloomEffect({threshold:1,strength:.9,radius:.2,...m.bloom??{}}),W=C||!1!==m.fxaa&&"fxaa"===M?new f.FXAAEffect(!1===m.fxaa?{}:m.fxaa):null,V=C||!1!==m.smaa&&"smaa"===M?new f.SMAAEffect(!1===m.smaa?{}:m.smaa):null,k=P||C||!1!==m.taa&&"taa"===M?new f.TemporalAAEffect({renderScale:1,...!1===m.taa?{}:m.taa}):null,U={mode:M},I=!1===m.motionBlur||null==m.motionBlur?null:new f.MotionBlurEffect(m.motionBlur),j=m.volumetricFog||void 0,N=!1===m.volumetricFog?null:new f.VolumetricFogEffect(void 0,{...f.VOLUMETRIC_FOG_PRESETS.high,maxDistance:64,spatialJitter:!0,scatteringIntensity:Math.PI,...j,temporal:!1!==j?.temporal&&{...f.VOLUMETRIC_FOG_PRESETS.high.temporal,...j?.temporal},blur:!1!==j?.blur&&{...!1===f.VOLUMETRIC_FOG_PRESETS.high.blur?{}:f.VOLUMETRIC_FOG_PRESETS.high.blur,depthAwareUpsample:!0,...j?.blur}}),H=!1===m.colorGrading?null:new f.ColorGradingEffect({enabled:!1,...m.colorGrading??{}}),$=!1===m.depthOfField?null:new f.DepthOfFieldEffect({enabled:!1,...m.depthOfField??{}}),_=!1===m.outline?null:new f.OutlineEffect({enabled:!1,...m.outline??{}}),q=[],z=new WeakMap,J=new Set,K=[],Z=[],Q=(e,t,i)=>{let n=i;const r=q.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of r){if(!(t.material instanceof s)){const e=`${t.id}:material`;J.has(e)||(J.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let i=z.get(t.material);null!=i&&i.version===t.material.version||(i={version:t.material.version,shader:G.compileFullscreen(t.material)},z.set(t.material,i));const r=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:i.shader,inputOverrides:{[a]:n},outputs:r}),n=r}catch(e){const i=`${t.id}:compile:${t.material.version}`;J.has(i)||(J.add(i),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return n},X={enabled:!0},Y=new f.WebGpuRenderer({canvas:v,fallbackMaterial:S,materialResolver:(e,t)=>G.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1,nativePostSubmit:x?.postSubmit,presentationOverlay:e=>{for(const t of Z)t(e)}});Y.setRenderScale("taa"===M?k?.renderScale??1:1),Y.setRenderGraphBuilder((e,t)=>{const i=new f.FrameGraphBuilder(t),n=i.createColorTarget("hologyNormalRoughness",{format:"rgba8unorm"}),r=D?i.createColorTarget("hologyMotionVectors",{format:"rgba16float"}):null;for(const e of K)"beforeScene"===e.stage&&e(i,i.sceneColor);X.enabled&&i.addDirectionalShadowPass(),i.addPointShadowPass(),i.addSpotShadowPass(),i.addDepthPrepass(),i.addHiZPasses(),i.addVisibilityPass(),i.addMaterialPass({name:"OpaqueGBufferPass",outputs:null==r?[i.sceneColor,n]:[i.sceneColor,n,r],drawStage:"opaque",loadDepth:!0}),i.addHiZHistoryPass("OpaqueGBufferPass");let o=i.sceneColor;if(T?.enabled){const e=T.addPasses(i,{depth:i.mainDepth,normal:n,velocity:r??void 0});o=T.addCompositePass(i,o,e)}null!=A&&(o=A.addPasses(i,{sceneColor:o,depth:i.mainDepth,normalRoughness:n}));const s=new Set(K.flatMap(e=>e.getSceneTextureReads?.()??[]));i.addSceneTextureCopyPass(o,{sceneColor:s.has("sceneColorSnapshot"),sceneDepth:s.has("sceneDepthSnapshot")||q.some(e=>e.enabled&&null!=e.material.uniforms[l])}),o=Q(i,"beforeFog",o),i.addLatePass(o);for(const e of K)null!=e.stage&&"afterScene"!==e.stage||e(i,o);null!=N&&(o=N.addPasses(i,{sceneColor:o,depth:i.mainDepth,velocity:r??void 0,volumeObjects:t.fogVolumeObjects,lights:t.extractedLights})),null!=I&&null!=r&&(o=I.addPass(i,o,r,i.mainDepth)),null!=B&&(o=B.addPass(i,o)),o=Q(i,"beforeOutline",o),null!=_&&(o=_.addPass(i,o)),o=Q(i,"beforeDepthOfField",o),null!=$&&(o=$.addPass(i,o,i.mainDepth)),o=Q(i,"beforeColorAdjustment",o),null!=H&&(o=H.addPass(i,o)),o=Q(i,"beforeAntiAliasing",o);let a="taa"===U.mode&&null!=k?k.addPass(i,o,i.mainDepth,r??void 0):o;"smaa"===U.mode&&null!=V?a=V.addPass(i,a):"fxaa"===U.mode&&null!=W&&(a=W.addPass(i,a)),a=Q(i,"beforeOutput",a);for(const e of K)"beforePresent"===e.stage&&e(i,a);!0===x?.enabled&&null!=r?x.addInputPass(i,a,r):i.present(a)});try{return await Y.initialize(g),O=new ExperimentalWebGpuBackend(Y,S,G,R,B,W,V,T,A,k,I,N,H,$,_,q,K,Z,U,X,x,v),O}catch(e){throw Y.destroy(),S.dispose(),G.dispose(),R.dispose(),T?.dispose(),V?.dispose(),I?.dispose(),N?.dispose(),_?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,i,n=1){const r=this.canvas.width,o=this.canvas.height;let s=Math.min(1,Math.max(.25,n));if(!0===this.nativeDlss?.enabled){const n=Math.max(1,Math.floor(e*i)),r=Math.max(1,Math.floor(t*i));s=this.nativeDlss.getRenderScale(n,r)}const a=s!==this.renderScale;this.renderScale=s,this.renderer.setRenderScale(s),this.taa?.setRenderScale(s),this.renderer.setSize(e,t,i),(a||this.canvas.width!==r||this.canvas.height!==o)&&this.resetViewHistory()}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}getDevice(){return this.renderer.getDevice()}setRenderGraphExtensions(e){this.renderGraphExtensions.length=0;for(const t of e)this.renderGraphExtensions.push(t)}setPresentationExtensions(e){this.presentationExtensions.length=0;for(const t of e)this.presentationExtensions.push(t)}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setTiledLightingEnabled(e){this.renderer.setTiledLightingEnabled(e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setDirectionalShadowOptions(e,t){this.directionalShadowState.enabled=e,this.renderer.setDirectionalShadowsEnabled(e),this.renderer.setDirectionalShadowMapSize(t)}setWorldEnvironment(e){if(null==e)return void this.nodeMaterialResolver.setWorldEnvironment(null);const t=this.getEnvironmentTexture(e.source);this.nodeMaterialResolver.setWorldEnvironment({texture:t,intensity:e.intensity})}getEnvironmentTexture(t){if(t.mapping===e.CubeUVReflectionMapping)return t;let i=this.pmremResults.get(t);return null==i&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),i=this.pmremGenerator.fromEquirectangular(t),this.pmremResults.set(t,i),this.ownedPmremResults.add(i)),i.texture}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.nativeDlss?.reset()}async compile(e,t){await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t,i=!1){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip",allowUnsortedLateDraws:i});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,i){const n="taa"===this.antiAliasingState.mode?this.taa:null;this.volumetricFog?.setScene(e),this.renderer.setMotionVectorProjection(t.projectionMatrix),this.motionBlur?.prepareCamera(t,this.canvas.width,this.canvas.height,i),this.motionBlur?.requiresRendererHistoryReset()&&(this.renderer.resetViewHistory(),this.gtao?.reset(),this.volumetricFog?.reset()),n?.prepareCamera(t,this.canvas.width,this.canvas.height),this.nativeDlss?.prepareFrame(t);const r=!0===this.nativeDlss?.enabled?this.nativeDlss.jitter:null;this.motionBlur?.setJitterUv(n?.currentJitterUv.x??(null==r?0:r.x/Math.max(1,this.canvas.width*this.renderScale)),n?.currentJitterUv.y??(null==r?0:-r.y/Math.max(1,this.canvas.height*this.renderScale))),null!=r&&this.renderer.setProjectionJitter(r.x,r.y);let o=!1;try{this.renderer.render(e,t,i),o=!0}finally{null!=r&&this.renderer.clearProjectionJitter(),n?.finishCamera(t),o&&this.motionBlur?.commitCamera(),o&&this.nativeDlss?.finishFrame(t)}}setMotionBlurOptions(e){null!=this.motionBlur&&Object.assign(this.motionBlur.options,e)}setGTAOOptions(e){this.gtao?.setOptions(e)}setAntiAliasingMode(e){e!==this.antiAliasingState.mode&&("taa"===e&&null==this.taa||"smaa"===e&&null==this.smaa||"fxaa"===e&&null==this.fxaa?console.warn(`[Hology WebGPU experiment] Anti-aliasing mode "${e}" was not initialized. Set webgpuPostProcessing.antiAliasing in the initial rendering configuration to enable runtime switching.`):(this.antiAliasingState.mode=e,this.resetTemporalHistory()))}setGTAOQuality(e){this.gtao?.applyPreset(e)}setVolumetricFogOptions(e){this.volumetricFog?.setOptions(e)}setVolumetricFogQuality(e){this.volumetricFog?.applyPreset(e)}pushMotionBlurOverride(e){return this.motionBlur?.pushOverride(e)??null}invalidateObjectMotion(e){this.renderer.invalidateObjectMotion(e)}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.renderer.resetViewHistory(),this.nativeDlss?.reset()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nativeDlss?.dispose(),this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.motionBlur?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,i){const n={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void n.sprites++;if(e.isPoints)return void n.points++;if(e.isLine)return void n.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?n.batchedMeshes++:t.isInstancedMesh?n.instancedMeshes++:t.isSkinnedMesh?n.skinnedMeshes++:n.meshes++,null==t.geometry?.getAttribute("position")&&n.missingPositionGeometry++;const r=Array.isArray(t.material)?t.material:[t.material];for(const e of r){if(null==e)continue;e.transparent&&n.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,r=!t&&!0===i?.canResolve(e);t||r||(n.materialsReplaced++,e.isShaderMaterial&&n.shaderMaterialsReplaced++)}}),n}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const u="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",p="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, cutoffDistance: f32, decayExponent: f32) -> f32 {\n var distanceFalloff = 1.0 / max(pow(distanceToLight, decayExponent), 0.01);\n if (cutoffDistance > 0.0) {\n let ratio = distanceToLight / cutoffDistance;\n let cutoff = clamp(1.0 - ratio * ratio * ratio * ratio, 0.0, 1.0);\n distanceFalloff *= cutoff * cutoff;\n }\n return distanceFalloff;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index), rendererPointLightDecayForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index), rendererSpotLightDecayForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
1
+ import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{configureWebGpuRuntimeBindings as i}from"./webgpu-runtime-bridge.js";import{float as n,varyingTransformed as r,vec4 as o}from"three-shader-graph";import{NodeShaderMaterial as s}from"../shader-nodes/index.js";import{sceneMapUniformName as a}from"../shader-nodes/scene-sample.js";import{depthUniformName as l}from"../shader-nodes/depth.js";import{MATERIAL_FLAG_ALPHA_TEST as d,MATERIAL_FLAG_RECEIVE_DECALS as c}from"../shader-nodes/material-flags.js";import{createMotionVectorOutput as h}from"./motion-vector-node.js";export class ExperimentalWebGpuBackend{constructor(e,t,i,n,r,o,s,a,l,d,c,h,u,p,m,g,f,v,S,b,P,x){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=i,this.gBufferFallbackSource=n,this.bloom=r,this.fxaa=o,this.smaa=s,this.gtao=a,this.ssr=l,this.taa=d,this.motionBlur=c,this.volumetricFog=h,this.colorGrading=u,this.depthOfField=p,this.outline=m,this.postProcessEffects=g,this.renderGraphExtensions=f,this.presentationExtensions=v,this.antiAliasingState=S,this.directionalShadowState=b,this.nativeDlss=P,this.kind="webgpu",this.renderScale=1,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.secondaryMotionPrepared=!1,this.canvas=x}static async probeAvailability(){if("undefined"==typeof navigator||!("gpu"in navigator))return{available:!1,reason:"The runtime does not expose navigator.gpu."};try{const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});return null==e?{available:!1,reason:"No WebGPU adapter is available."}:{available:!0,adapter:e}}catch(e){return{available:!1,reason:`Requesting a WebGPU adapter failed: ${e instanceof Error?e.message:String(e)}`}}}static async create(m={},g){const f=await import("@hology/webgpu-renderer");i({createComputeKernel:(e,t)=>new f.ComputeKernel(e,t),buildParticleLightingShaderHeader:f.buildParticleLightingShaderHeader});const v=document.createElement("canvas");v.dataset.hologyRenderer="webgpu-experimental";const S=new f.WGSLShaderMaterial({vertexShader:u,fragmentShader:p}),b=!1!==m.nativeUpscaling&&"dlss"===m.nativeUpscaling?.method,P=b?(await import("./native-dlss-upscaler.js")).createNativeDlssUpscaler(m.nativeUpscaling?.mode??"quality"):null,x=null!=P;S.side=f.DoubleSide;const w=f,y=null!=m.motionBlur&&!1!==m.motionBlur,M=!1!==m.gtao&&(null==m.gtao||!1!==m.gtao.temporal),E=!1!==m.volumetricFog&&(null==m.volumetricFog||!1!==m.volumetricFog.temporal),F=x?"off":b?"taa":null!=(D=m).antiAliasing?D.antiAliasing:null!=D.taa&&!1!==D.taa?"taa":null!=D.smaa&&!1!==D.smaa?"smaa":null!=D.fxaa&&!1!==D.fxaa?"fxaa":!1===D.taa?"off":"taa";var D;const L=null!=m.antiAliasing,C=y||M||E||(L||"taa"===F)||x;let O=null;const G=new t(w,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(n(e.alphaTest>0?d:0).add(!1===e.userData.receiveDecals?0:c)),o((e.outputNormal??r.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??n(1)),...C?[h(e)]:[]]:void 0,e=>O?.getEnvironmentTexture(e)??e),R=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==G.resolve(R,"opaque"))throw S.dispose(),R.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const T=!1===m.gtao?null:new f.GTAOEffect({normalSpace:"view",...f.GTAO_PRESETS.high,...m.gtao??{}}),A=!1===m.ssr||null==m.ssr?null:new f.SSREffect({normalSpace:"view",resolutionScale:.5,...m.ssr??{}}),B=!1===m.bloom?null:new f.BloomEffect({threshold:1,strength:.9,radius:.2,...m.bloom??{}}),W=L||!1!==m.fxaa&&"fxaa"===F?new f.FXAAEffect(!1===m.fxaa?{}:m.fxaa):null,V=L||!1!==m.smaa&&"smaa"===F?new f.SMAAEffect(!1===m.smaa?{}:m.smaa):null,k=x||L||!1!==m.taa&&"taa"===F?new f.TemporalAAEffect({renderScale:1,...!1===m.taa?{}:m.taa}):null,U={mode:F},j=!1===m.motionBlur||null==m.motionBlur?null:new f.MotionBlurEffect(m.motionBlur),I=m.volumetricFog||void 0,N=!1===m.volumetricFog?null:new f.VolumetricFogEffect(void 0,{...f.VOLUMETRIC_FOG_PRESETS.high,maxDistance:64,spatialJitter:!0,scatteringIntensity:Math.PI,...I,temporal:!1!==I?.temporal&&{...f.VOLUMETRIC_FOG_PRESETS.high.temporal,...I?.temporal},blur:!1!==I?.blur&&{...!1===f.VOLUMETRIC_FOG_PRESETS.high.blur?{}:f.VOLUMETRIC_FOG_PRESETS.high.blur,depthAwareUpsample:!0,...I?.blur}}),H=!1===m.colorGrading?null:new f.ColorGradingEffect({enabled:!1,...m.colorGrading??{}}),$=!1===m.depthOfField?null:new f.DepthOfFieldEffect({enabled:!1,...m.depthOfField??{}}),_=!1===m.outline?null:new f.OutlineEffect({enabled:!1,...m.outline??{}}),q=[],z=new WeakMap,J=new Set,K=[],Z=[],Q=(e,t,i)=>{let n=i;const r=q.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of r){if(!(t.material instanceof s)){const e=`${t.id}:material`;J.has(e)||(J.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let i=z.get(t.material);null!=i&&i.version===t.material.version||(i={version:t.material.version,shader:G.compileFullscreen(t.material)},z.set(t.material,i));const r=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:i.shader,inputOverrides:{[a]:n},outputs:r}),n=r}catch(e){const i=`${t.id}:compile:${t.material.version}`;J.has(i)||(J.add(i),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return n},X={enabled:!0},Y=new f.WebGpuRenderer({canvas:v,fallbackMaterial:S,materialResolver:(e,t)=>G.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1,nativePostSubmit:P?.postSubmit,presentationOverlay:e=>{for(const t of Z)t(e)}});Y.setRenderScale("taa"===F?k?.renderScale??1:1),Y.setRenderGraphBuilder((e,t)=>{const i=new f.FrameGraphBuilder(t),n=i.createColorTarget("hologyNormalRoughness",{format:"rgba8unorm"}),r=C?i.createColorTarget("hologyMotionVectors",{format:"rgba16float"}):null;for(const e of K)"beforeScene"===e.stage&&e(i,i.sceneColor);X.enabled&&i.addDirectionalShadowPass(),i.addPointShadowPass(),i.addSpotShadowPass(),i.addDepthPrepass(),i.addHiZPasses(),i.addVisibilityPass(),i.addMaterialPass({name:"OpaqueGBufferPass",outputs:null==r?[i.sceneColor,n]:[i.sceneColor,n,r],drawStage:"opaque",loadDepth:!0}),i.addHiZHistoryPass("OpaqueGBufferPass");let o=i.sceneColor;if(T?.enabled){const e=T.addPasses(i,{depth:i.mainDepth,normal:n,velocity:r??void 0});o=T.addCompositePass(i,o,e)}null!=A&&(o=A.addPasses(i,{sceneColor:o,depth:i.mainDepth,normalRoughness:n}));const s=new Set(K.flatMap(e=>e.getSceneTextureReads?.()??[]));i.addSceneTextureCopyPass(o,{sceneColor:s.has("sceneColorSnapshot"),sceneDepth:s.has("sceneDepthSnapshot")||q.some(e=>e.enabled&&null!=e.material.uniforms[l])}),o=Q(i,"beforeFog",o),i.addLatePass(o);for(const e of K)null!=e.stage&&"afterScene"!==e.stage||e(i,o);null!=N&&(o=N.addPasses(i,{sceneColor:o,depth:i.mainDepth,velocity:r??void 0,volumeObjects:t.fogVolumeObjects,lights:t.extractedLights})),null!=j&&null!=r&&(o=j.addPass(i,o,r,i.mainDepth)),null!=B&&(o=B.addPass(i,o)),o=Q(i,"beforeOutline",o),null!=_&&(o=_.addPass(i,o)),o=Q(i,"beforeDepthOfField",o),null!=$&&(o=$.addPass(i,o,i.mainDepth)),o=Q(i,"beforeColorAdjustment",o),null!=H&&(o=H.addPass(i,o)),o=Q(i,"beforeAntiAliasing",o);let a="taa"===U.mode&&null!=k?k.addPass(i,o,i.mainDepth,r??void 0):o;"smaa"===U.mode&&null!=V?a=V.addPass(i,a):"fxaa"===U.mode&&null!=W&&(a=W.addPass(i,a)),a=Q(i,"beforeOutput",a);for(const e of K)"beforePresent"===e.stage&&e(i,a);!0===P?.enabled&&null!=r?P.addInputPass(i,a,r):i.present(a)});try{return await Y.initialize(g),O=new ExperimentalWebGpuBackend(Y,S,G,R,B,W,V,T,A,k,j,N,H,$,_,q,K,Z,U,X,P,v),O}catch(e){throw Y.destroy(),S.dispose(),G.dispose(),R.dispose(),T?.dispose(),V?.dispose(),j?.dispose(),N?.dispose(),_?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,i,n=1){const r=this.canvas.width,o=this.canvas.height;let s=Math.min(1,Math.max(.25,n));if(!0===this.nativeDlss?.enabled){const n=Math.max(1,Math.floor(e*i)),r=Math.max(1,Math.floor(t*i));s=this.nativeDlss.getRenderScale(n,r)}const a=s!==this.renderScale;this.renderScale=s,this.renderer.setRenderScale(s),this.taa?.setRenderScale(s),this.renderer.setSize(e,t,i),(a||this.canvas.width!==r||this.canvas.height!==o)&&this.resetViewHistory()}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}getDevice(){return this.renderer.getDevice()}setRenderGraphExtensions(e){this.renderGraphExtensions.length=0;for(const t of e)this.renderGraphExtensions.push(t)}setPresentationExtensions(e){this.presentationExtensions.length=0;for(const t of e)this.presentationExtensions.push(t)}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setTiledLightingEnabled(e){this.renderer.setTiledLightingEnabled(e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setDirectionalShadowOptions(e,t){this.directionalShadowState.enabled=e,this.renderer.setDirectionalShadowsEnabled(e),this.renderer.setDirectionalShadowMapSize(t)}setWorldEnvironment(e){if(null==e)return void this.nodeMaterialResolver.setWorldEnvironment(null);const t=this.getEnvironmentTexture(e.source);this.nodeMaterialResolver.setWorldEnvironment({texture:t,intensity:e.intensity})}getEnvironmentTexture(t){if(t.mapping===e.CubeUVReflectionMapping)return t;let i=this.pmremResults.get(t);return null==i&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),i=this.pmremGenerator.fromEquirectangular(t),this.pmremResults.set(t,i),this.ownedPmremResults.add(i)),i.texture}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.nativeDlss?.reset()}async compile(e,t){if(!this.secondaryMotionPrepared){let t=!1;e.traverse(e=>{const i=e.userData.secondaryMotion?.regions;Array.isArray(i)&&i.some(e=>e.enabled)&&(t=!0)});const i=this.renderer.getDevice();if(t&&i){const{prepareSecondaryMotionRuntime:e}=await import("../secondary-motion/runtime.js");e(i),this.secondaryMotionPrepared=!0}}await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t,i=!1){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip",allowUnsortedLateDraws:i});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,i){const n="taa"===this.antiAliasingState.mode?this.taa:null;this.volumetricFog?.setScene(e),this.renderer.setMotionVectorProjection(t.projectionMatrix),this.motionBlur?.prepareCamera(t,this.canvas.width,this.canvas.height,i),this.motionBlur?.requiresRendererHistoryReset()&&(this.renderer.resetViewHistory(),this.gtao?.reset(),this.volumetricFog?.reset()),n?.prepareCamera(t,this.canvas.width,this.canvas.height),this.nativeDlss?.prepareFrame(t);const r=!0===this.nativeDlss?.enabled?this.nativeDlss.jitter:null;this.motionBlur?.setJitterUv(n?.currentJitterUv.x??(null==r?0:r.x/Math.max(1,this.canvas.width*this.renderScale)),n?.currentJitterUv.y??(null==r?0:-r.y/Math.max(1,this.canvas.height*this.renderScale))),null!=r&&this.renderer.setProjectionJitter(r.x,r.y);let o=!1;try{this.renderer.render(e,t,i),o=!0}finally{null!=r&&this.renderer.clearProjectionJitter(),n?.finishCamera(t),o&&this.motionBlur?.commitCamera(),o&&this.nativeDlss?.finishFrame(t)}}setMotionBlurOptions(e){null!=this.motionBlur&&Object.assign(this.motionBlur.options,e)}setGTAOOptions(e){this.gtao?.setOptions(e)}setAntiAliasingMode(e){e!==this.antiAliasingState.mode&&("taa"===e&&null==this.taa||"smaa"===e&&null==this.smaa||"fxaa"===e&&null==this.fxaa?console.warn(`[Hology WebGPU experiment] Anti-aliasing mode "${e}" was not initialized. Set webgpuPostProcessing.antiAliasing in the initial rendering configuration to enable runtime switching.`):(this.antiAliasingState.mode=e,this.resetTemporalHistory()))}setGTAOQuality(e){this.gtao?.applyPreset(e)}setVolumetricFogOptions(e){this.volumetricFog?.setOptions(e)}setVolumetricFogQuality(e){this.volumetricFog?.applyPreset(e)}pushMotionBlurOverride(e){return this.motionBlur?.pushOverride(e)??null}invalidateObjectMotion(e){this.renderer.invalidateObjectMotion(e)}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.renderer.resetViewHistory(),this.nativeDlss?.reset()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nativeDlss?.dispose(),this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.motionBlur?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,i){const n={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void n.sprites++;if(e.isPoints)return void n.points++;if(e.isLine)return void n.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?n.batchedMeshes++:t.isInstancedMesh?n.instancedMeshes++:t.isSkinnedMesh?n.skinnedMeshes++:n.meshes++,null==t.geometry?.getAttribute("position")&&n.missingPositionGeometry++;const r=Array.isArray(t.material)?t.material:[t.material];for(const e of r){if(null==e)continue;e.transparent&&n.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,r=!t&&!0===i?.canResolve(e);t||r||(n.materialsReplaced++,e.isShaderMaterial&&n.shaderMaterialsReplaced++)}}),n}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const u="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",p="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, cutoffDistance: f32, decayExponent: f32) -> f32 {\n var distanceFalloff = 1.0 / max(pow(distanceToLight, decayExponent), 0.01);\n if (cutoffDistance > 0.0) {\n let ratio = distanceToLight / cutoffDistance;\n let cutoff = clamp(1.0 - ratio * ratio * ratio * ratio, 0.0, 1.0);\n distanceFalloff *= cutoff * cutoff;\n }\n return distanceFalloff;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index), rendererPointLightDecayForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index), rendererSpotLightDecayForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -0,0 +1,26 @@
1
+ import { Camera, Object3D } from 'three';
2
+ export interface SecondaryMotionBudgetHandle {
3
+ target: Object3D;
4
+ enabled: boolean;
5
+ /** Positive priority reserves a slot before distance-based candidates. */
6
+ priority: number;
7
+ readonly active: boolean;
8
+ dispose(): void;
9
+ }
10
+ /** Selects once per simulation frame. Entries and selection scratch are persistent. */
11
+ export declare class SecondaryMotionBudget {
12
+ readonly maxCharacters: number;
13
+ readonly maxDistance: number;
14
+ private readonly entries;
15
+ private readonly frustum;
16
+ private readonly viewProjection;
17
+ private readonly sphere;
18
+ private readonly cameraPosition;
19
+ private selectionFrame;
20
+ private nextId;
21
+ private readonly selected;
22
+ constructor(maxCharacters?: number, maxDistance?: number);
23
+ register(target: Object3D): SecondaryMotionBudgetHandle;
24
+ select(frame: number, camera: Camera): void;
25
+ }
26
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{Frustum as e,Matrix4 as t,Sphere as i,Vector3 as s}from"three";export class SecondaryMotionBudget{constructor(r=8,o=24){if(this.maxCharacters=r,this.maxDistance=o,this.entries=[],this.frustum=new e,this.viewProjection=new t,this.sphere=new i(new s,2),this.cameraPosition=new s,this.selectionFrame=-1,this.nextId=0,!Number.isInteger(r)||r<0||!Number.isFinite(o)||o<0)throw new Error("Invalid secondary-motion budget");this.selected=new Array(r)}register(e){const t={target:e,enabled:!0,priority:0,active:!1,score:1/0,id:this.nextId++,dispose:()=>{const e=this.entries.indexOf(t);e>=0&&this.entries.splice(e,1);for(let e=0;e<this.selected.length;e++)this.selected[e]===t&&(this.selected[e]=void 0);t.active=!1,t.enabled=!1,this.selectionFrame=-1}};return this.entries.push(t),this.selectionFrame=-1,t}select(e,t){if(this.selectionFrame===e)return;this.selectionFrame=e,this.cameraPosition.setFromMatrixPosition(t.matrixWorld),this.viewProjection.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.frustum.setFromProjectionMatrix(this.viewProjection);for(const e of this.entries){this.sphere.center.setFromMatrixPosition(e.target.matrixWorld);const t=this.sphere.center.distanceToSquared(this.cameraPosition),i=this.maxDistance*(e.active?1.15:1),s=e.enabled&&e.target.visible&&(e.priority>0||t<=i*i&&this.frustum.intersectsSphere(this.sphere));e.score=s?t*(e.active?.8:1):1/0}let i=0;for(const e of this.entries){if(!Number.isFinite(e.score))continue;let t=0;for(;t<i&&r(this.selected[t],e)<=0;)t++;if(t>=this.maxCharacters)continue;for(let e=Math.min(i,this.maxCharacters-1);e>t;e--)this.selected[e]=this.selected[e-1];this.selected[t]=e,i=Math.min(i+1,this.maxCharacters)}for(const e of this.entries)e.active=!1;for(let e=0;e<this.selected.length;e++)e<i?this.selected[e].active=!0:this.selected[e]=void 0}}function r(e,t){const i=Number.isFinite(e.score);return i!==Number.isFinite(t.score)?i?-1:1:t.priority-e.priority||e.score-t.score||e.id-t.id}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -0,0 +1,16 @@
1
+ import type { BufferGeometry } from 'three';
2
+ import type { SecondaryMotionGeneratedRegion } from './data.js';
3
+ /** Borrowed immutable CPU data. GPU buffers and simulation state remain instance-owned. */
4
+ export interface SharedClothRegion {
5
+ readonly data: Readonly<SecondaryMotionGeneratedRegion>;
6
+ readonly activeParticleMask: Uint8Array;
7
+ readonly activeParticles: Uint32Array;
8
+ readonly hasSkinning: boolean;
9
+ }
10
+ /** Identity/version checks only on configuration/activation, never per simulation step. */
11
+ export declare class SharedClothRegionCache {
12
+ private readonly geometries;
13
+ get(geometry: BufferGeometry, id: string, paint?: readonly (readonly [number, number])[]): SharedClothRegion;
14
+ }
15
+ export declare const sharedClothRegionCache: SharedClothRegionCache;
16
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{generateClothSecondaryMotionRegion as t}from"./generation.js";const e=[],n=new WeakSet;export function isSharedClothRegionData(t){return n.has(t)}export class SharedClothRegionCache{constructor(){this.geometries=new WeakMap}get(i,s,a=e){const c=i.getAttribute("position");if(!c)throw new Error("Secondary-motion geometry needs positions");const l=i.getIndex(),u=i.getAttribute("skinIndex"),g=i.getAttribute("skinWeight");let h=this.geometries.get(i);h&&o(h.sources[0],c)&&o(h.sources[1],l)&&o(h.sources[2],u)&&o(h.sources[3],g)||(h={sources:[r(c),r(l),r(u),r(g)],variants:new Map},this.geometries.set(i,h));const f=h.variants.get(s);if(f&&function(t,e){if(t.length!==2*e.length)return!1;for(let n=0;n<e.length;n++)if(t[2*n]!==e[n][0]||t[2*n+1]!==e[n][1])return!1;return!0}(f.paint,a))return f.region;const d=new Float32Array(3*c.count);for(let t=0;t<c.count;t++)d[3*t]=c.getX(t),d[3*t+1]=c.getY(t),d[3*t+2]=c.getZ(t);const m=new Float32Array(c.count),y=new Float64Array(2*a.length);for(let t=0;t<a.length;t++){const[e,n]=a[t];y[2*t]=e,y[2*t+1]=n,e>=0&&e<m.length&&(m[e]=n)}const p=l?Uint32Array.from(l.array):Uint32Array.from({length:c.count},(t,e)=>e),v=null!=u&&null!=g,w=v?new Uint16Array(4*c.count):void 0,A=v?new Float32Array(4*c.count):void 0;if(w&&A)for(let t=0;t<c.count;t++)for(let e=0;e<4;e++)w[4*t+e]=u.getComponent(t,e),A[4*t+e]=g.getComponent(t,e);const z=t(s,{positions:d,indices:p},m,w,A);Object.freeze(z),n.add(z);const C=new Uint8Array(z.particleInverseMass.length);for(let t=0;t<C.length;t++)z.particleInverseMass[t]>0&&(C[t]=1);for(const t of z.constraints)C[t]=1;let S=0;for(const t of C)S+=t;const b=new Uint32Array(S);for(let t=0,e=0;t<C.length;t++)C[t]&&(b[e++]=t);const k={data:z,activeParticleMask:C,activeParticles:b,hasSkinning:v};return h.variants.set(s,{paint:y,region:k}),k}}function r(t){const e=i(t);return{attribute:t,array:e?.array??null,version:e?.version??0,count:t?.count??0,size:t?.itemSize??0,normalized:t?.normalized??!1}}function o(t,e){const n=i(e);return t.attribute===e&&t.array===(n?.array??null)&&t.version===(n?.version??0)&&t.count===(e?.count??0)&&t.size===(e?.itemSize??0)&&t.normalized===(e?.normalized??!1)}function i(t){return t?.isInterleavedBufferAttribute?t.data:t}export const sharedClothRegionCache=new SharedClothRegionCache;/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -2,7 +2,10 @@ import type { RendererCustomPassContext } from '@hology/webgpu-renderer';
2
2
  import type { BufferGeometry } from 'three';
3
3
  import type { ExperimentalWebGpuRenderGraphExtension } from '../rendering/webgpu-experimental-backend.js';
4
4
  import type { SecondaryMotionGeneratedRegion } from './data.js';
5
+ import { type SecondaryMotionSkinningTargets } from './skinned-targets.js';
6
+ export type { SecondaryMotionSkinningTargets } from './skinned-targets.js';
5
7
  export interface SecondaryMotionComputeRuntime {
8
+ readonly enabled?: boolean;
6
9
  execute(context: RendererCustomPassContext): void;
7
10
  dispose(): void;
8
11
  }
@@ -35,9 +38,15 @@ export interface WebGpuSecondaryMotionRegionHandle {
35
38
  readonly positionBuffer: GPUBuffer;
36
39
  setRenderGeometry(geometry: BufferGeometry | null): void;
37
40
  updateTargets(positions: Float32Array): void;
41
+ /** Installs persistent particle inputs and consumes the renderer's shared GPU bone palette. */
42
+ setSkinningTargets(source: SecondaryMotionSkinningTargets): void;
43
+ /** Resets particles to their current GPU-skinned pose, including animation seeks. */
44
+ resetToSkinningTargets(): void;
38
45
  reset(positions?: Float32Array): void;
39
46
  dispose(): void;
40
47
  }
48
+ /** Prepares immutable pipelines at loading time; simulation buffers stay instance-owned. */
49
+ export declare function prepareSecondaryMotionRuntime(device: GPUDevice): void;
41
50
  /**
42
51
  * First-stage GPU secondary-motion solver. Positions use vec4 storage so the
43
52
  * same buffers can later be consumed directly by render/skinning pipelines.
@@ -57,6 +66,8 @@ export declare class WebGpuSecondaryMotionRuntime implements SecondaryMotionComp
57
66
  private readonly previousCollisionSpheres;
58
67
  private readonly collisionParams;
59
68
  private readonly collisionColliderData;
69
+ private readonly collisionNextData;
70
+ private readonly collisionCountData;
60
71
  private collisionCollidersInitialized;
61
72
  private readonly collisionBindGroups;
62
73
  private readonly integrationParamsData;
@@ -64,12 +75,16 @@ export declare class WebGpuSecondaryMotionRuntime implements SecondaryMotionComp
64
75
  private readonly regions;
65
76
  private pendingSteps;
66
77
  private disposed;
78
+ private _enabled;
67
79
  private readonly constraintIterations;
68
80
  private readonly constraintStiffness;
69
81
  private readonly autoAdvance;
70
82
  private lastExecuteSeconds;
83
+ private skinningTargetKernels;
71
84
  constructor(device: GPUDevice, options?: WebGpuSecondaryMotionOptions);
72
85
  /** Updates non-inertial reference-frame motion before the next render. */
86
+ get enabled(): boolean;
87
+ setEnabled(enabled: boolean): void;
73
88
  setFrameMotion(motion: SecondaryMotionFrameMotion): void;
74
89
  /** Sets up to eight mesh-local spheres used to keep simulated particles outside the body. */
75
90
  setSphereColliders(colliders: readonly SecondaryMotionSphereCollider[]): void;