@hology/core 0.0.237 → 0.0.239
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.
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/gpu-particle-arena.d.ts +57 -0
- package/dist/effects/vfx/gpu-particle-arena.js +4 -0
- package/dist/effects/vfx/gpu-sprite-backend.d.ts +33 -0
- package/dist/effects/vfx/gpu-sprite-backend.js +4 -0
- package/dist/effects/vfx/gpu-sprite-compiler.d.ts +58 -0
- package/dist/effects/vfx/gpu-sprite-compiler.js +4 -0
- package/dist/effects/vfx/gpu-sprite-render-graph.d.ts +10 -0
- package/dist/effects/vfx/gpu-sprite-render-graph.js +4 -0
- package/dist/effects/vfx/gpu-sprite-runtime.d.ts +304 -0
- package/dist/effects/vfx/gpu-sprite-runtime.js +4 -0
- package/dist/effects/vfx/gpu-sprite-scheduler-runtime.d.ts +71 -0
- package/dist/effects/vfx/gpu-sprite-scheduler-runtime.js +4 -0
- package/dist/effects/vfx/gpu-sprite-template.d.ts +47 -0
- package/dist/effects/vfx/gpu-sprite-template.js +4 -0
- package/dist/effects/vfx/gpu-sprite-world-runtime.d.ts +61 -0
- package/dist/effects/vfx/gpu-sprite-world-runtime.js +4 -0
- package/dist/effects/vfx/gpu-vfx-capacity.d.ts +3 -0
- package/dist/effects/vfx/gpu-vfx-capacity.js +4 -0
- package/dist/effects/vfx/gpu-vfx-scheduler.d.ts +52 -0
- package/dist/effects/vfx/gpu-vfx-scheduler.js +4 -0
- package/dist/effects/vfx/gpu-vfx-world-service.d.ts +103 -0
- package/dist/effects/vfx/gpu-vfx-world-service.js +4 -0
- package/dist/effects/vfx/index.d.ts +11 -0
- package/dist/effects/vfx/index.js +1 -1
- package/dist/effects/vfx/trail-renderer.js +1 -1
- package/dist/effects/vfx/vfx-actor.d.ts +19 -2
- package/dist/effects/vfx/vfx-actor.js +1 -1
- package/dist/effects/vfx/vfx-asset.d.ts +2 -0
- package/dist/effects/vfx/vfx-default-sprite-texture.d.ts +3 -0
- package/dist/effects/vfx/vfx-default-sprite-texture.js +4 -0
- package/dist/effects/vfx/vfx-input-runtime.d.ts +3 -1
- package/dist/effects/vfx/vfx-materializer.d.ts +10 -0
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/effects/vfx/vfx-mesh-transform.d.ts +4 -0
- package/dist/effects/vfx/vfx-mesh-transform.js +4 -0
- package/dist/effects/vfx/vfx-param.d.ts +2 -0
- package/dist/effects/vfx/vfx-param.js +1 -1
- package/dist/effects/vfx/vfx-renderers.js +1 -1
- package/dist/effects/vfx/vfx-runtime.d.ts +35 -0
- package/dist/effects/vfx/vfx-runtime.js +4 -0
- package/dist/effects/vfx/vfx-service.d.ts +3 -0
- package/dist/effects/vfx/vfx-service.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +14 -0
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.d.ts +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +8 -3
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/root-motion-constraint.d.ts +10 -0
- package/dist/gameplay/actors/builtin/components/character/root-motion-constraint.js +1 -1
- package/dist/gameplay/ai/behavior-tree/move.d.ts +14 -0
- package/dist/gameplay/ai/behavior-tree/move.js +1 -1
- package/dist/gameplay/initiate.d.ts +3 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/render.d.ts +14 -1
- package/dist/gameplay/services/render.js +1 -1
- package/dist/rendering/webgpu-experimental-backend.d.ts +8 -2
- package/dist/rendering/webgpu-experimental-backend.js +1 -1
- package/dist/rendering.d.ts +32 -3
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/objects/shapes.js +1 -1
- package/dist/shader/builtin/decal-standard-shader.d.ts +1 -0
- package/dist/shader/builtin/decal-standard-shader.js +1 -1
- package/dist/shader/decal-shader.js +1 -1
- package/dist/shader-nodes/effects.js +1 -1
- package/dist/shader-nodes/material-flags.js +1 -1
- package/dist/shader-nodes/particle.d.ts +5 -2
- package/dist/shader-nodes/particle.js +1 -1
- package/dist/test/asset-resource-loader-skinned-merge.test.d.ts +2 -0
- package/dist/test/asset-resource-loader-skinned-merge.test.js +4 -0
- package/dist/test/character-root-motion-constraint.test.js +1 -1
- package/dist/test/gpu-particle-arena.test.d.ts +2 -0
- package/dist/test/gpu-particle-arena.test.js +4 -0
- package/dist/test/gpu-sprite-compiler.test.d.ts +2 -0
- package/dist/test/gpu-sprite-compiler.test.js +4 -0
- package/dist/test/gpu-vfx-scheduler.test.d.ts +2 -0
- package/dist/test/gpu-vfx-scheduler.test.js +4 -0
- package/dist/test/mesh-clone.test.d.ts +2 -0
- package/dist/test/mesh-clone.test.js +4 -0
- package/dist/test/sequence-scene-binding.test.js +1 -1
- package/dist/test/sequence-vfx.test.js +1 -1
- package/dist/test/vfx-mesh-transform.test.d.ts +2 -0
- package/dist/test/vfx-mesh-transform.test.js +4 -0
- package/dist/utils/mesh.d.ts +7 -1
- package/dist/utils/mesh.js +1 -1
- package/package.json +17 -5
- 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 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 m}from"../../gameplay/services/render.js";import{World as p}from"../../gameplay/services/world.js";import{DelayRate as h}from"./rates.js";import{materializeVfx as l}from"./vfx-materializer.js";import{PhysicsSystem as c}from"../../gameplay/services/physics/physics-system.js";import{ShaderProvider as d}from"../../gameplay/services/shader-provider.js";import{AssetResourceLoader as u}from"../../scene/asset-resource-loader.js";import{AssetsProvider as y}from"../../scene/assets-provider.js";import{VfxInputRuntime as f}from"./vfx-input-runtime.js";import{Subject as v}from"rxjs";import{EventGraphCallable as g}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as E}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as w}from"../../gameplay/event-graph/asset-actor-types.js";let S=class extends o{constructor(){super(...arguments),this.onComplete=new v,this.timescale=1,this.paused=!0,this.assetLoader=a(n),this.assetManagerService=a(u),this.assetService=a(y),this.world=a(p),this.view=a(m),this.physics=a(c),this.shaderProvider=a(d),this.inputRuntime=new f,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,this.previewStepSeconds=1/60,this.maxPreviewSteps=240,this.max=0}async fromAsset(t,e){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.sourceAsset=t,this.finishRequested=!1,this.completionEmitted=!1,this.disposeSystem&&this.disposeSystem(),this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const{system:s,dispose:i,container:r}=await l(this.sourceAsset,this.object,{getAsset:t=>this.assetLoader.getAsset(t),getMaterial:t=>this.assetLoader.getMaterialByAssetId(t),getTexture:t=>this.assetLoader.getTextureByAssetId(t),getMesh:t=>this.assetLoader.getModelByAssetId(t).then(t=>t.scene)},this.view,this.physics,this.shaderProvider,this.assetService,this.assetManagerService,this.inputRuntime);this.system=s,this.disposeSystem=i,this.particleSystemContainer=r,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){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)}setInputs(t){for(const[e,s]of Object.entries(t))this.setInput(e,s)}play(){this.prepareForPlayback(),this.paused=!1;this.system.emitters.every(t=>t.dead)&&this.restart()}pause(){this.paused=!0}previewAt(t,e,s,i){if(null==this.system)return;this.prepareForPlayback(),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),m=Math.max(n,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=o<=0?0:a<=0?m:Math.min(m-1,Math.max(1,Math.round(m*o/r)));this.simulatePreview(o,p),a>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(a,m-p))}clearPreview(){this.restart(),this.pause(),this.object.visible=!1,this.particleSystemContainer.visible=!1}stop(){this.finishRequested=!0,null!=this.system?.emitters&&this.system.emitters.forEach(t=>{this.stopEmitterEmission(t)})}applyClipEndBehavior(t,e){const s=t??"finish";if("finish"!==s){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.system&&null!=this.system.emitters){this.finishRequested=!1,this.completionEmitted=!1;for(const t of this.system.emitters)this.restartEmitter(t)}}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){this.paused||(this.updateWorldSpaceEmitterTransforms(),this.updateSystem(t*this.timescale),this.updateCompletionState())}prepareForPlayback(){null==this.particleSystemContainer.parent&&this.world.scene.add(this.particleSystemContainer),this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,this.particleSystemContainer.matrixAutoUpdate=!0,this.particleSystemContainer.matrixWorldAutoUpdate=!0,this.object.visible=!0,this.particleSystemContainer.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._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{"world"===t._space&&(t.setPosition(this._worldPos),t.setRotation(this._worldEul))})}getParticleCount(){return this.system?.getCount()??0}onEndPlay(){this.stop(),null!=this.disposeSystem&&this.disposeSystem(),this.onComplete.complete()}updateCompletionState(){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){this.system?.update(t)}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([g({parameters:[],returns:E}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],S.prototype,"play",null),t([g({parameters:[],returns:E}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],S.prototype,"pause",null),t([g({parameters:[],returns:E}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],S.prototype,"stop",null),t([g({parameters:[],returns:E}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],S.prototype,"restart",null),S=t([r({typeId:w})],S);export{S 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 a}from"../../gameplay/actors/actor.js";import{inject as o}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 m}from"./vfx-materializer.js";import{PhysicsSystem as u}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 y}from"../../scene/assets-provider.js";import{VfxInputRuntime as g}from"./vfx-input-runtime.js";import{Subject as f}from"rxjs";import{EventGraphCallable as v}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as P}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as b}from"../../gameplay/event-graph/asset-actor-types.js";import{GpuVfxWorldService as w}from"./gpu-vfx-world-service.js";import{compileGpuSpriteEmitters as S}from"./gpu-sprite-compiler.js";let E=class extends a{constructor(){super(...arguments),this.onComplete=new f,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=o(n),this.assetManagerService=o(c),this.assetService=o(y),this.world=o(p),this.view=o(l),this.gpuWorld=o(w),this.particleSystemContainer=null,this.gpuPrepared=null,this.gpuHandle=null,this.physics=o(u),this.shaderProvider=o(d),this.inputRuntime=new g,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,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.disposeSystem&&this.disposeSystem(),this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const a=i??this.view.vfxBackendPreference;if("cpu"!==a){if(this.gpuPrepared=await this.gpuWorld.prepare(this.sourceAsset,r),null!=this.gpuPrepared)return this.runtimeBackend="gpu",this.system=null,this.disposeSystem=null,this.particleSystemContainer=null,this.object.visible=!1,this.object.matrixAutoUpdate=!0,void(this.object.matrixWorldAutoUpdate=!0);if("gpu"===a){const t=S(this.sourceAsset,[new s.Vector3]).compatibility;this.backendFallbackReasons=t.issues.filter(t=>"error"===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:n,container:l}=await m(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);this.system=o,this.disposeSystem=n,this.particleSystemContainer=l,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){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 i=this.inputRuntime.getDefinition(t);null!=i&&this.gpuHandle?.setInput(i.id,this.inputRuntime.getValue(i.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){if(null==this.system)return;this.prepareForPlayback(),this.restart(),this.paused=!0;const r=Math.max(0,t),a=Math.min(r,Math.max(0,e)),o=r-a,n=Number(a>0)+Number(o>0),l=Math.max(n,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=a<=0?0:o<=0?l:Math.min(l-1,Math.max(1,Math.round(l*a/r)));this.simulatePreview(a,p),o>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(o,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._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{"world"===t._space&&(t.setPosition(this._worldPos),t.setRotation(this._worldEul))})}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 o=r instanceof s.InstancedMesh?r.count:1,n=a.index?.count??a.getAttribute("position")?.count??0;o<=0||n<=0||(t++,e+=Math.floor(n/3)*o)}),{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:P}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"play",null),t([v({parameters:[],returns:P}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"pause",null),t([v({parameters:[],returns:P}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"stop",null),t([v({parameters:[],returns:P}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"restart",null),E=t([r({typeId:b})],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
|
*/
|
|
@@ -110,6 +110,8 @@ export type StretchedSpriteOutput = {
|
|
|
110
110
|
export type MeshOutput = {
|
|
111
111
|
type: 'mesh';
|
|
112
112
|
assetId: AssetId;
|
|
113
|
+
/** Preserves mesh output authored before imported hierarchy transforms were baked into particle geometry. */
|
|
114
|
+
useLegacyTransform?: boolean;
|
|
113
115
|
material?: AssetId;
|
|
114
116
|
bloom?: boolean;
|
|
115
117
|
} & CommonOutput & Partial<OutputCustomShader> & OutputMaterialSourceSettings;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import*as A from"three";let e=null;export function getDefaultVfxSpriteTexture(){return e??(e=(new A.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=")),e.name="default-vfx-dot",e}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import type { VfxEffectInputDefinition } from './vfx-asset.js';
|
|
3
|
+
type VfxRuntimeInputValue = number | THREE.Vector3 | THREE.Color;
|
|
3
4
|
export declare class VfxInputRuntime {
|
|
4
5
|
private readonly definitions;
|
|
5
6
|
private readonly inputIdsByName;
|
|
@@ -12,6 +13,7 @@ export declare class VfxInputRuntime {
|
|
|
12
13
|
getNumber(inputNameOrId: string, fallback?: number): number;
|
|
13
14
|
getVector3(inputNameOrId: string, fallback?: THREE.Vector3): THREE.Vector3;
|
|
14
15
|
getColor(inputNameOrId: string, fallback?: THREE.Color): THREE.Color;
|
|
15
|
-
|
|
16
|
+
getValue(inputNameOrId: string): VfxRuntimeInputValue | undefined;
|
|
16
17
|
}
|
|
18
|
+
export {};
|
|
17
19
|
//# sourceMappingURL=vfx-input-runtime.d.ts.map
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import System from "@hology/nebula";
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { Object3D } from "three";
|
|
4
|
+
import { NodeShaderMaterial } from "three-shader-graph";
|
|
4
5
|
import type { PhysicsSystem } from '../../gameplay/services/physics/physics-system.js';
|
|
5
6
|
import type { ViewController } from '../../gameplay/services/render.js';
|
|
6
7
|
import type { Asset, VfxAsset } from '../../scene/model.js';
|
|
8
|
+
import type { DecalOutput, EmitterOutput, MeshOutput, ShapeOutput, SpriteOutput, TrailOutput } from './vfx-asset.js';
|
|
7
9
|
import type { ShaderProvider } from "../../gameplay/services/shader-provider.js";
|
|
8
10
|
import type { AssetResourceLoader } from "../../scene/asset-resource-loader.js";
|
|
9
11
|
import type { AssetsProvider } from "../../scene/assets-provider.js";
|
|
10
12
|
import type { VfxInputRuntime } from "./vfx-input-runtime.js";
|
|
13
|
+
import type { ShaderGraphTarget } from "../../shader/graph/model.js";
|
|
11
14
|
export type VfxAssetProvider = {
|
|
12
15
|
getAsset(assetId: string): Promise<Asset>;
|
|
13
16
|
getTexture(assetId: string): Promise<THREE.Texture>;
|
|
@@ -19,6 +22,13 @@ export declare function materializeVfx(asset: VfxAsset, target: Object3D, assetP
|
|
|
19
22
|
system: System;
|
|
20
23
|
dispose: () => void;
|
|
21
24
|
}>;
|
|
25
|
+
export declare function createShaderMaterial(output: SpriteOutput | ShapeOutput | MeshOutput | TrailOutput, assetProvider: VfxAssetProvider, shaderProvider: ShaderProvider): Promise<THREE.Material>;
|
|
26
|
+
/** Builds an authored VFX shader graph for CPU or GPU particle material compilation. */
|
|
27
|
+
export declare function createShaderGraphMaterial(output: EmitterOutput, expectedTarget: ShaderGraphTarget, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, shaderProvider: ShaderProvider, options?: {
|
|
28
|
+
trailBillboard?: boolean;
|
|
29
|
+
}): Promise<THREE.Material | null>;
|
|
30
|
+
/** Creates the authored-material callback consumed by prepareGpuSpriteBackend. */
|
|
31
|
+
export declare function createGpuSpriteShaderGraphResolver(assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, shaderProvider: ShaderProvider, assetProvider?: VfxAssetProvider): (output: SpriteOutput | MeshOutput | DecalOutput | ShapeOutput | TrailOutput) => Promise<NodeShaderMaterial | null>;
|
|
22
32
|
export declare class EmitterPool<T> {
|
|
23
33
|
private creator;
|
|
24
34
|
instances: T[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as o,AttributeVec4Node as l,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as d,Vec3ExpressionNode as h,attributeVec3 as m,attributeVec4 as f,attributes as y,clamp as w,cross as g,float as b,lambertMaterial as E,length as A,log as v,normalize as M,pow as x,rgb as I,rgba as S,smoothstep as P,standardMaterial as T,textureSampler2d as C,uniforms as R,varying as B,varyingAttributes as k,varyingVec3 as j,varyingVec4 as D,vec2 as G,vec3 as F,vec4 as V}from"three-shader-graph";import{prepareClassParameters as L,prepareShaderGraphParameters as W,prepareShapeParameters as O}from"../../scene/materializer.js";import{SerializedParamType as Q}from"../../scene/model.js";import{ShapeLibrary as H}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as U,linearEyeDepth as q}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as z,particleTimeUniformName as J,particleUniforms as N,particleVelcoityUniformName as X}from"../../shader-nodes/particle.js";import{sampleFlipbook as _}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as K,WorldSpaceEmitterRotationInitializer as Y}from"./initializsers.js";import{DelayRate as Z,OnceRate as $}from"./rates.js";import{StretchedSprite as ee}from"./stretched-sprite.js";import{ThreeBlendingMode as te}from"./vfx-asset.js";import{VfxBehaviourLibrary as ae,VfxInitializserLibrary as re}from"./vfx-defs.js";import{MultiRenderer as se}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ie}from"./vfx-collision-behaviour.js";import{getSpritePosition as ne,SpriteNodeShader as oe,SpriteNodeShaderMaterial as le}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ce}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as pe}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as ue,createBoundInitializer as de}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as he}from"../../shader/graph/index.js";import{markMaterialUniformValuesNeedUpdate as me,setMaterialUniformValuesAutoUpdate as fe}from"../../rendering/node-material-webgpu-resolver.js";export async function materializeVfx(t,a,r,s,o,l,c,p,u){let d=a;for(;null!=d.parent;)d=d.parent;const h=new n;h.name="particle system local",a.add(h);const m=new n;m.name="particle system world";const f=new se(m,h,i,s),y=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await ye(e,r,c,p,y,o,l,u,a);return t.setParentRecursive(y),t.emit()}))).forEach(e=>y.addEmitter(e)),y.addRenderer(f).emit({onEnd:()=>{}}),{container:m,system:y,dispose:()=>{m.removeFromParent(),h.removeFromParent(),f.dispose()}}}async function ye(e,t,r,p,x,I,T,j,G){const F=function(e){let t;switch(e.rate.type){case"continuous":t=new Z(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new $(e.rate.delay??0,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),t=new s(0,1/0)}return t}(e);let L;switch(e.output.type){case"decal":L=new a(await async function(e,t,a,r,s){if("shaderGraph"===Ee(e)){const t=await be(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return ve(a,e),a}}const n=!1!==e.unlit?new ce:new pe;n.color=new i.Color(e.color),n instanceof ce?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const o=n.build();o.blending=te[e.blendingMode]??i.NormalBlending,o.transparent=!0,o.side=i.BackSide,o.depthTest=!1,null!=o&&!0===e.bloom&&(o.userData.hasBloom=!0);o.defines.IS_PARTICLE="";const l=new i.BoxGeometry(1,1,1),c=new i.Mesh(l,o);return ve(c,e),c}(e.output,t,r,p,T));break;case"sprite":L=new a(await async function(e,t,a,r,s){let n=null;const o=Ee(e);"shaderGraph"===o&&(n=await be(e,"sprite",a,r,s));null==n&&"shader"===o&&null!=e.shader&&(n=await ge(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):we,r=C(a);let s=r.sample(k.uv);e.flipbook?.enabled&&(s=_(r,y.uv,e.flipbook.columns,e.flipbook.rows,N.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),o=new d("color").rgb,l=q.subtract(U).divide(q);let c=N.opacity;switch(e.opacityChannel??"red"){case"none":break;case"red":c=c.multiply(s.r);break;case"alpha":c=c.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=w(l,0,1e3);c=c.multiply(P(0,.2*e.softness,t))}const p=ne(n,void 0,void 0,!0),h=S(o.multiply(s.rgb).multiplyScalar(e.intensity??1),c);var m=new le({color:h,emissive:h.rgb.multiplyScalar(c),transparent:!0,position:p,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});m.alphaHash=!0,null!=m&&!0===e.bloom&&(m.userData.hasBloom=!0);return m.blending=te[e.blendingMode]??i.NormalBlending,m}(e,t));n.depthWrite=!1,Ae(n,e);const l=new i.Mesh(new i.PlaneGeometry(1,1),n);return l.name="sprite",ve(l,e),l}(e.output,t,r,p,T));break;case"stretchedSprite":L=new a(await async function(e,t){"shaderGraph"===Ee(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):we,r=C(a).sample(k.uv),s=D(new l("particleColor")),n=s.rgb.multiply(r.rgb);let o=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":o=o.multiply(r.r);break;case"alpha":o=o.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=q.subtract(U).divide(v(q)),a=w(t,0,1e3);o=o.multiply(P(0,.2*e.softness,a))}const c=m("offset"),p=f("velocity"),u=m("size"),d=p.w,h=u.x.add(u.y).multiply(.5),E=R.modelViewMatrix.multiplyVec(V(c,1)),x=R.normalMatrix.multiplyVec(p.xyz),I=M(g(E.xyz,x)).multiplyScalar(y.position.y.multiply(h)),T=x.multiplyScalar(y.position.x.add(.5).multiply(b(1).add(d.divide(A(x)))).multiply(h)),B=R.projectionMatrix.multiplyVec(V(E.xyz.add(I).subtract(T),E.w));var j=new le({color:S(n.multiplyScalar(e.intensity??1),o),alphaTest:.1,transparent:!0,position:B,uniforms:{color:{value:new i.Color(e.color)}}});null!=j&&!0===e.bloom&&(j.userData.hasBloom=!0);j.blending=te[e.blendingMode]??i.NormalBlending;const G=new ee(new i.PlaneGeometry(1,1),j);return G.scaleFactor=e.scale,ve(G,e),G}(e.output,t));break;case"shape":L=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const l=H[e.shape];if(null==l)return console.error(`No shape with type ${e.shape}`),new n;const p=O(e.params??{}),u=l.geometry(p);let d=null;const m=Ee(e);"shaderGraph"===m&&(d=await be(e,"surface",a,r,s));null==d&&"shader"===m&&null!=e.shader&&(d=await ge(e,t,s));null==d&&(d="material"===m&&null!=e.material?Me(await t.getMaterial(e.material)):function(){const e=B(new h("instanceColor")).rgb,t=B(new o("particleData")).x;return new c({color:E({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());Ae(d,e);const f=new i.Mesh(u,d);return ve(f,e),f}(e.output,t,r,p,T));break;case"mesh":L=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const o=await t.getMesh(e.assetId),l=await t.getAsset(e.assetId),c=Ee(e);if("shaderGraph"===c||"shader"===c||"material"===c){let n;"shaderGraph"===c?n=await be(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await ge(e,t,s):"material"===c&&null!=e.material&&(n=Me(await t.getMaterial(e.material))),n.transparent&&(n.depthWrite=!1),Ae(n,e),o.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=l.materialAssignments)for(const a of l.materialAssignments)o.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(o.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),ve(o,e),1===p.length){const e=p[0];return e.updateWorldMatrix(!0,!0),e.updateMatrixWorld(),e.matrix.copy(e.matrixWorld),e.matrixWorld.decompose(e.position,e.quaternion,e.scale),e.removeFromParent(),e}return o}(e.output,t,r,p,T));break;case"trail":{const s="shaderGraph"===Ee(e.output)?await be(e.output,"trail",r,p,T,{trailBillboard:e.output.billboard??!1}):null;L=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:s instanceof i.ShaderMaterial?s:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,width:e.output.width,billboard:e.output.billboard??!1,renderOrder:e.output.renderOrder});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const W=new Ie(G);W.parent=x,W.setRate(F),W._space=e.output.space;const z=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=re[e.type]).map(async e=>{const t=re[e.type],a=await O(e.params??{});return de(t,e.params??{},a,j)}));"world"!==e.output.space||"shape"!==e.output.type&&"mesh"!==e.output.type||z.unshift(new Y),z.push(L,new K),W.addInitializers(z);const J=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=ae[e.type]).map(async e=>{const t=ae[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==Q.Curve&&(r.type=Q.Curve);const a=await O(e.params??{},r,p);return ue(t,e.params??{},a,j)}).sort((e,t)=>e instanceof ie?1:0));J.push(new xe);for(const e of J)e instanceof ie&&(e.physics=I);W.addBehaviours(J);for(const a of e.children??[]){const e=await ye(a,t,r,p,x,I,T,j,G),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=W.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&W.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=W.eventDispatcher,n=new Map;W.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(W.detachChildEmitterFromParticle(t,e),n.delete(e.id))});let o="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":o="PARTICLE_COLLISION";break;case"start":o="PARTICLE_CREATED"}i.addEventListener(o,e=>{const t=s.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),W.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=W.system,t.emit()})}return W}const we=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");async function ge(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type;"sprite"===e.type&&s instanceof oe&&(s.instanced=!0);const n=await L(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}async function be(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const o=await a.getAsset(n.assetId),l=o?.shaderGraph;if(null==l)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(l.target!==t)return console.warn(`Shader graph "${o.name}" targets "${l.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await W(e.shaderGraphParams??{},l,a,r,void 0,s.shaders),o=he(l,{parameters:t,trailBillboard:i.trailBillboard});return o.userData.customShaderName=`shaderGraph:${n.assetId}`,Ae(o,e),o}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}function Ee(e){return null!=e.materialSource?e.materialSource:"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}function Ae(e,t){null!=e&&(fe(e,!1),"bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")):"shape"!==t.type&&"mesh"!==t.type||e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE=""))}function ve(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function Me(e){const t=B(new h("instanceColor")).rgb;let a,r=B(new o("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(I(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(k.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(k.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:I(e.emissive),emissiveIntensity:b(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:I(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:E({color:s}).rgb.rgba(r),emissive:I(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class xe extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[z]||null!=t.uniforms[J]||t.uniforms[X])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;if(a instanceof c){let t=!1;null!=a.uniforms[z]&&(a.uniforms[z].value=this.energy,t=!0),null!=a.uniforms[J]&&(a.uniforms[J].value=e.age,t=!0),null!=a.uniforms[X]&&(a.uniforms[X].value=e.velocity,t=!0),t&&me(a)}}})}}class Ie extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(Se.copy(t),"local"===a&&"world"===r?Se.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Pe.copy(this.transformRoot.matrixWorld).invert(),Se.applyMatrix4(Pe)),e.position.copy(Se)):e.position.copy(t)}clone(){const e=new Ie(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const Se=new i.Vector3,Pe=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
|
|
1
|
+
import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as l,AttributeVec4Node as o,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as h,Vec3ExpressionNode as d,attributeVec3 as m,attributeVec4 as f,attributes as y,clamp as w,cross as g,float as b,lambertMaterial as v,length as M,log as A,normalize as E,pow as x,rgb as S,rgba as I,smoothstep as T,standardMaterial as P,textureSampler2d as C,uniforms as R,varying as G,varyingAttributes as B,varyingVec3 as k,varyingVec4 as j,vec2 as D,vec3 as F,vec4 as V}from"three-shader-graph";import{prepareClassParameters as L,prepareShaderGraphParameters as O,prepareShapeParameters as W}from"../../scene/materializer.js";import{SerializedParamType as U}from"../../scene/model.js";import{ShapeLibrary as Q}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as H,linearEyeDepth as N}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as q,particleTimeUniformName as z,particleUniforms as J,particleVelcoityUniformName as X}from"../../shader-nodes/particle.js";import{sampleFlipbook as _}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as K,WorldSpaceEmitterRotationInitializer as Y}from"./initializsers.js";import{DelayRate as Z,OnceRate as $}from"./rates.js";import{StretchedSprite as ee}from"./stretched-sprite.js";import{ThreeBlendingMode as te}from"./vfx-asset.js";import{VfxBehaviourLibrary as ae,VfxInitializserLibrary as re}from"./vfx-defs.js";import{MultiRenderer as se}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ie}from"./vfx-collision-behaviour.js";import{getSpritePosition as ne,SpriteNodeShader as le,SpriteNodeShaderMaterial as oe}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ce}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as pe}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as ue,createBoundInitializer as he}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as de}from"../../shader/graph/index.js";import{markMaterialUniformValuesNeedUpdate as me,setMaterialUniformValuesAutoUpdate as fe}from"../../rendering/node-material-webgpu-resolver.js";import{applyMeshWorldTransformToGeometry as ye}from"./vfx-mesh-transform.js";export async function materializeVfx(t,a,r,s,l,o,c,p,u){let h=a;for(;null!=h.parent;)h=h.parent;const d=new n;d.name="particle system local",a.add(d);const m=new n;m.name="particle system world";const f=new se(m,d,i,s),y=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await we(e,r,c,p,y,l,o,u,a);return t.setParentRecursive(y),t.emit()}))).forEach(e=>y.addEmitter(e)),y.addRenderer(f).emit({onEnd:()=>{}}),{container:m,system:y,dispose:()=>{m.removeFromParent(),d.removeFromParent(),f.dispose()}}}async function we(e,t,r,p,x,S,P,D,F){const L=function(e){let t;switch(e.rate.type){case"continuous":t=new Z(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new $(e.rate.delay??0,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),t=new s(0,1/0)}return t}(e);let O;switch(e.output.type){case"decal":O=new a(await async function(e,t,a,r,s){if("shaderGraph"===be(e)){const t=await createShaderGraphMaterial(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return Ae(a,e),a}}const n=!1!==e.unlit?new ce:new pe;n.color=new i.Color(e.color),n instanceof ce?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const l=n.build();l.blending=te[e.blendingMode]??i.NormalBlending,l.transparent=!0,l.side=i.BackSide,l.depthTest=!1,null!=l&&!0===e.bloom&&(l.userData.hasBloom=!0);l.defines.IS_PARTICLE="";const o=new i.BoxGeometry(1,1,1),c=new i.Mesh(o,l);return Ae(c,e),c}(e.output,t,r,p,P));break;case"sprite":O=new a(await async function(e,t,a,r,s){let n=null;const l=be(e);"shaderGraph"===l&&(n=await createShaderGraphMaterial(e,"sprite",a,r,s));null==n&&"shader"===l&&null!=e.shader&&(n=await createShaderMaterial(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):ge,r=C(a);let s=r.sample(B.uv);e.flipbook?.enabled&&(s=_(r,y.uv,e.flipbook.columns,e.flipbook.rows,J.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),l=new h("color").rgb,o=k(new d("instanceColor")).rgb,c=N.subtract(H).divide(N);let p=J.opacity;switch(e.opacityChannel??"red"){case"none":break;case"red":p=p.multiply(s.r);break;case"alpha":p=p.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=w(c,0,1e3);p=p.multiply(T(0,.2*e.softness,t))}const m=ne(n,void 0,void 0,!0),f=I(l.multiply(o).multiply(s.rgb).multiplyScalar(e.intensity??1),p);var g=new oe({color:f,emissive:f.rgb.multiplyScalar(p),transparent:!0,position:m,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});g.alphaHash=!0,null!=g&&!0===e.bloom&&(g.userData.hasBloom=!0);return g.blending=te[e.blendingMode]??i.NormalBlending,g}(e,t));n.depthWrite=!1,Me(n,e);const o=new i.Mesh(new i.PlaneGeometry(1,1),n);return o.name="sprite",Ae(o,e),o}(e.output,t,r,p,P));break;case"stretchedSprite":O=new a(await async function(e,t){"shaderGraph"===be(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):ge,r=C(a).sample(B.uv),s=j(new o("particleColor")),n=s.rgb.multiply(r.rgb);let l=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":l=l.multiply(r.r);break;case"alpha":l=l.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=N.subtract(H).divide(A(N)),a=w(t,0,1e3);l=l.multiply(T(0,.2*e.softness,a))}const c=m("offset"),p=f("velocity"),u=m("size"),h=p.w,d=u.x.add(u.y).multiply(.5),v=R.modelViewMatrix.multiplyVec(V(c,1)),x=R.normalMatrix.multiplyVec(p.xyz),S=E(g(v.xyz,x)).multiplyScalar(y.position.y.multiply(d)),P=x.multiplyScalar(y.position.x.add(.5).multiply(b(1).add(h.divide(M(x)))).multiply(d)),G=R.projectionMatrix.multiplyVec(V(v.xyz.add(S).subtract(P),v.w));var k=new oe({color:I(n.multiplyScalar(e.intensity??1),l),alphaTest:.1,transparent:!0,position:G,uniforms:{color:{value:new i.Color(e.color)}}});null!=k&&!0===e.bloom&&(k.userData.hasBloom=!0);k.blending=te[e.blendingMode]??i.NormalBlending;const D=new ee(new i.PlaneGeometry(1,1),k);return D.scaleFactor=e.scale,Ae(D,e),D}(e.output,t));break;case"shape":O=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const o=Q[e.shape];if(null==o)return console.error(`No shape with type ${e.shape}`),new n;const p=W(e.params??{}),u=o.geometry(p);let h=null;const m=be(e);"shaderGraph"===m&&(h=await createShaderGraphMaterial(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await createShaderMaterial(e,t,s));null==h&&(h="material"===m&&null!=e.material?Ee(await t.getMaterial(e.material)):function(){const e=G(new d("instanceColor")).rgb,t=G(new l("particleData")).x;return new c({color:v({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());Me(h,e);const f=new i.Mesh(u,h);return Ae(f,e),f}(e.output,t,r,p,P));break;case"mesh":O=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const l=await t.getMesh(e.assetId),o=await t.getAsset(e.assetId),c=be(e);if("shaderGraph"===c||"shader"===c&&null!=e.shader||"material"===c&&null!=e.material){let n;"shaderGraph"===c?n=await createShaderGraphMaterial(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await createShaderMaterial(e,t,s):"material"===c&&null!=e.material&&(n=Ee(await t.getMaterial(e.material))),n?.transparent&&(n.depthWrite=!1),null!=n&&Me(n,e),l.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=o.materialAssignments)for(const a of o.materialAssignments)null!=a.materialId&&l.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(l.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),Ae(l,e),1===p.length){const t=p[0];return!0!==e.useLegacyTransform&&function(e){e.geometry=e.geometry.clone(),ye(e,e.geometry),e.position.set(0,0,0),e.quaternion.identity(),e.scale.set(1,1,1),e.updateMatrix(),e.matrixWorld.identity()}(t),t.removeFromParent(),t}return l}(e.output,t,r,p,P));break;case"trail":{const s="shaderGraph"===be(e.output)?await createShaderGraphMaterial(e.output,"trail",r,p,P,{trailBillboard:e.output.billboard??!1}):null;O=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:s instanceof i.ShaderMaterial?s:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,width:e.output.width,billboard:e.output.billboard??!1,renderOrder:e.output.renderOrder});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const q=new Se(F);q.parent=x,q.setRate(L),q._space=e.output.space;const z=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=re[e.type]).map(async e=>{const t=re[e.type],a=await W(e.params??{});return he(t,e.params??{},a,D)}));"world"!==e.output.space||"shape"!==e.output.type&&"mesh"!==e.output.type||z.unshift(new Y),z.push(O,new K),q.addInitializers(z);const X=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=ae[e.type]).map(async e=>{const t=ae[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==U.Curve&&(r.type=U.Curve);const a=await W(e.params??{},r,p);return ue(t,e.params??{},a,D)}).sort((e,t)=>e instanceof ie?1:0));X.push(new xe);for(const e of X)e instanceof ie&&(e.physics=S);q.addBehaviours(X);for(const a of e.children??[]){const e=await we(a,t,r,p,x,S,P,D,F),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=q.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&q.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=q.eventDispatcher,n=new Map;q.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(q.detachChildEmitterFromParticle(t,e),n.delete(e.id))});let l="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":l="PARTICLE_COLLISION";break;case"start":l="PARTICLE_CREATED"}i.addEventListener(l,e=>{const t=s.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),q.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=q.system,t.emit()})}return q}const ge=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");export async function createShaderMaterial(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type;"sprite"===e.type&&s instanceof le&&(s.instanced=!0);const n=await L(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}export async function createShaderGraphMaterial(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const l=await a.getAsset(n.assetId),o=l?.shaderGraph;if(null==o)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(o.target!==t)return console.warn(`Shader graph "${l.name}" targets "${o.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await O(e.shaderGraphParams??{},o,a,r,void 0,s.shaders),l=de(o,{parameters:t,trailBillboard:i.trailBillboard});return l.userData.customShaderName=`shaderGraph:${n.assetId}`,Me(l,e),l}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}export function createGpuSpriteShaderGraphResolver(e,t,a,r){return async s=>{const n=be(s);let l=null;if("shaderGraph"===n)l=await createShaderGraphMaterial(s,"sprite"===s.type?"sprite":"decal"===s.type?"decal":"trail"===s.type?"trail":"surface",e,t,a,"trail"===s.type?{trailBillboard:s.billboard??!1}:void 0);else if("shader"===n&&"decal"!==s.type&&null!=r)l=await createShaderMaterial(s,r,a);else if("material"!==n||"mesh"!==s.type&&"shape"!==s.type||null==s.material||null==r){if("default"===n&&"mesh"===s.type&&null!=s.assetId&&null!=r){const e=await r.getAsset(s.assetId),t=e.materialAssignments?.find(e=>null!=e.materialId);null!=t&&(l=await ve(t.materialId,r))}else if("default"===n&&"decal"===s.type&&null!=r){const e=!1!==s.unlit?new ce:new pe;e.color=new i.Color(s.color),e instanceof ce?e.intensity=s.intensity??1:e.emissiveIntensity=s.intensity??1,s.colorMap&&(e.colorMap=await r.getTexture(s.colorMap)),s.alphaMap&&(e.alphaMap=await r.getTexture(s.alphaMap)),l=e.build(),l.transparent=!0}}else l="mesh"===s.type?await ve(s.material,r):Ee(await r.getMaterial(s.material));return null==l?null:("mesh"!==s.type&&"shape"!==s.type||!l.transparent||(l.depthWrite=!1),l instanceof c?l:(console.warn(`GPU ${s.type} materials must compile to NodeShaderMaterial; using CPU fallback`),null))}}function be(e){return null!=e.materialSource?("material"!==e.materialSource||"mesh"!==e.type&&"shape"!==e.type||null!=e.material)&&("shaderGraph"!==e.materialSource||"asset"===e.shaderGraph?.source&&null!=e.shaderGraph.assetId)&&("shader"!==e.materialSource||"shader"in e&&null!=e.shader)?e.materialSource:"default":"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}async function ve(e,t){const a=(await t.getAsset(e)).material,r=a?.shaderParams??{},s=a?.params??{},n=r.color?.value??s.color??"#ffffff",l=r.opacity?.value??s.opacity??1,o=r.intensity?.value??s.intensity??1,p=r.map?.value??s.map,u=r.alphaMap?.value??s.alphaMap;let h=J.color.rgb.multiply(S(new i.Color(n))).multiplyScalar(b(o)),d=J.opacity.multiply(b(l));if(null!=p){const e=C(await t.getTexture(p)).sample(B.uv);h=h.multiply(e.rgb),d=d.multiply(e.a)}null!=u&&(d=d.multiply(C(await t.getTexture(u)).sample(B.uv).r));const m=new c({color:h.rgba(d),opacity:d,transparent:!0===a?.transparent||l<1||null!=u});return m.blending=te[a?.blending]??i.NormalBlending,m.alphaTest=a?.alphaTest??0,m.side=a?.side??i.FrontSide,m.transparent&&(m.depthWrite=!1),m}function Me(e,t){null!=e&&(fe(e,!1),"bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")):"shape"!==t.type&&"mesh"!==t.type||e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE=""))}function Ae(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function Ee(e){const t=G(new d("instanceColor")).rgb;let a,r=G(new l("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(S(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(B.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(B.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:P({color:s,emissive:S(e.emissive),emissiveIntensity:b(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:v({color:s}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class xe extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[q]||null!=t.uniforms[z]||t.uniforms[X])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;if(a instanceof c){let t=!1;null!=a.uniforms[q]&&(a.uniforms[q].value=this.energy,t=!0),null!=a.uniforms[z]&&(a.uniforms[z].value=e.age,t=!0),null!=a.uniforms[X]&&(a.uniforms[X].value=e.velocity,t=!0),t&&me(a)}}})}}class Se extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(Ie.copy(t),"local"===a&&"world"===r?Ie.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Te.copy(this.transformRoot.matrixWorld).invert(),Ie.applyMatrix4(Te)),e.position.copy(Ie)):e.position.copy(t)}clone(){const e=new Se(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const Ie=new i.Vector3,Te=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
/** Apply an imported mesh's complete hierarchy transform to geometry vertices and normals. */
|
|
3
|
+
export declare function applyMeshWorldTransformToGeometry(mesh: THREE.Mesh, geometry: THREE.BufferGeometry): void;
|
|
4
|
+
//# sourceMappingURL=vfx-mesh-transform.d.ts.map
|
|
@@ -3,6 +3,7 @@ import type { ActorProvider } from "../../scene/materializer.js";
|
|
|
3
3
|
import type { VfxAsset } from "../../scene/model.js";
|
|
4
4
|
import type { Object3D } from 'three';
|
|
5
5
|
import { BaseActor } from '../../gameplay/actors/actor.js';
|
|
6
|
+
import type { VfxBackendPreference } from './gpu-sprite-compiler.js';
|
|
6
7
|
export declare class VisualEffect {
|
|
7
8
|
private actorProvider;
|
|
8
9
|
private asset;
|
|
@@ -16,6 +17,7 @@ export declare class VisualEffect {
|
|
|
16
17
|
*/
|
|
17
18
|
create(parent: Object3D | BaseActor, options?: {
|
|
18
19
|
inputs?: Record<string, unknown>;
|
|
20
|
+
backend?: VfxBackendPreference;
|
|
19
21
|
}): Promise<VfxActor>;
|
|
20
22
|
/**
|
|
21
23
|
* Create a pool that can be used to create actors and reuse them.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{VfxActor as t}from"./vfx-actor.js";import{BaseActor as s}from"../../gameplay/actors/actor.js";export class VisualEffect{constructor(t,s){this.actorProvider=t,this.asset=s}async create(e,a){const r=await this.actorProvider.create(t);return e instanceof s?e.object.add(r.object):e.add(r.object),await r.fromAsset(this.asset,a?.inputs),r}createPool(t){return new VfxPool(()=>this.create(t))}}export class VfxPool{constructor(t){this.creator=t,this.instances=[]}async get(){0==this.instances.length&&this.instances.push(await this.creator());const t=this.instances.shift();return t.restart(),t}release(t){t.stop(),this.instances.push(t)}dispose(){this.instances.length=0}}/*
|
|
1
|
+
import{VfxActor as t}from"./vfx-actor.js";import{BaseActor as s}from"../../gameplay/actors/actor.js";export class VisualEffect{constructor(t,s){this.actorProvider=t,this.asset=s}async create(e,a){const r=await this.actorProvider.create(t);return e instanceof s?e.object.add(r.object):e.add(r.object),await r.fromAsset(this.asset,a?.inputs,a?.backend),r}createPool(t){return new VfxPool(()=>this.create(t))}}export class VfxPool{constructor(t){this.creator=t,this.instances=[]}async get(){0==this.instances.length&&this.instances.push(await this.creator());const t=this.instances.shift();return t.restart(),t}release(t){t.stop(),this.instances.push(t)}dispose(){this.instances.length=0}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{CustomRenderer as e,MeshRenderer as t,PUID as r}from"@hology/nebula";import*as a from"three";import{InstancedBufferAttribute as o,Object3D as n}from"three";import{NodeShaderMaterial as i}from"three-shader-graph";import{StretchedSprite as s}from"./stretched-sprite.js";import{Trail as l}from"./trail-renderer.js";import{SpriteNodeShaderMaterial as c}from"../../shader/sprite-shader.js";import{particleEnergyUniformName as d}from"../../shader-nodes/particle.js";import{AssetMeshInstance as m}from"../../scene/asset-resource-loader.js";import{markMaterialUniformValuesNeedUpdate as u}from"../../rendering/node-material-webgpu-resolver.js";var h;!function(e){e[e.mesh=0]="mesh",e[e.instanced=1]="instanced",e[e.sprite=2]="sprite",e[e.stretchedBillboard=3]="stretchedBillboard",e[e.trail=4]="trail"}(h||(h={}));export class MultiRenderer extends e{constructor(e,t,r,a){super(),this.worldContainer=e,this.localContainer=t,this.three=r,this.view=a,this.localRenderers=[],this.worldRenderers=[]}onSystemUpdate(){for(const e of this.worldRenderers)e?.onSystemUpdate();for(const e of this.localRenderers)e?.onSystemUpdate()}onParticleCreated(e){e.target=null,this.getRenderer(e)?.onParticleCreated(e)}onParticleUpdate(e){this.getRenderer(e)?.onParticleUpdate(e)}onParticleDead(e){this.getRenderer(e)?.onParticleDead(e),e._renderer=null}getRenderer(e){if(e._renderer)return e._renderer;const t=(null!=e?.parent?e?.parent._space:null)??"world",r="world"===t?this.worldContainer:this.localContainer,o="world"===t?this.worldRenderers:this.localRenderers;return"trail"===e.body.type?(null==o[h.trail]&&(o[h.trail]=new TrailRenderer(r,this.three)),e._renderer=o[h.trail]):e.body instanceof s?(null==o[h.stretchedBillboard]&&(o[h.stretchedBillboard]=new StretchedSpriteInstancedRenderer(r,this.three,this.view)),e._renderer=o[h.stretchedBillboard]):e.body instanceof a.Sprite?(null==o[h.sprite]&&(o[h.sprite]=new CombinedRenderer(r,this.three)),e._renderer=o[h.sprite]):e.body instanceof a.Mesh&&0==e.body.children.length&&e.body.material instanceof i?(null==o[h.instanced]&&(o[h.instanced]=new InstancedRenderer(r,this.three,this.view)),e._renderer=o[h.instanced]):e.body instanceof a.Object3D?(null==o[h.mesh]&&(o[h.mesh]=new CombinedRenderer(r,this.three)),e._renderer=o[h.mesh]):void 0}dispose(){this.localRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()}),this.worldRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()})}}export class TrailRenderer extends t{constructor(){super(...arguments),this.trails=[]}dispose(){}onSystemUpdate(){for(const e of this.trails)e.update()}onParticleCreated(e){const t=e.body,r=new l(this.container,!1),o=new n;this.container.add(o),o.updateMatrixWorld(),o.updateWorldMatrix(!0,!0);const i=t.material?.clone()??l.createBaseMaterial(t.texture,t.scrollSpeed,t.opacityChannel,t.billboard??!1);i.uniforms.taper&&(i.uniforms.taper.value=t.taper??!1);const s=new a.Color(t.color??0).multiplyScalar(t.intensity??1),c=new a.Color(t.colorEnd??0).multiplyScalar(t.intensityEnd??t.intensity??1);i.uniforms.headColor&&i.uniforms.tailColor&&(i.uniforms.headColor.value=new a.Vector4(s.r,s.g,s.b,t.opacityStart??1),i.uniforms.tailColor.value=new a.Vector4(c.r,c.g,c.b,t.opacityEnd??1)),i.uniforms.color&&null==i.uniforms.headColor&&(i.uniforms.color.value=s),i.uniforms.opacity&&null==i.uniforms.headColor&&(i.uniforms.opacity.value=t.opacityStart??1),t.bloom&&(i.userData.hasBloom=!0),r.initialize(i,Math.round(t.length??10),!1,t.width,null,o,t.billboard??!1),null!=t.renderOrder&&null!=r.mesh&&(r.mesh.renderOrder=t.renderOrder);const d=e.rotation;o.rotation.set(d.x,d.y,d.z);e.scale;r.activate(),this.trails.push(r),e.target=o}onParticleUpdate(e){const t=e.target;t.position.copy(e.position);const r=e.body;let a=v;e.old&&e.old.position?a.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z):a.copy(e.velocity),a.lengthSq()>1e-8?a.normalize():a.copy(U);const o=P;o.setFromUnitVectors(a,U),t.rotation.set(0,0,0),t.rotation.set(e.rotation.x,e.rotation.y,e.rotation.z),t.applyQuaternion(o);const n=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=n){const t=this.trails[n];if(e.useAlpha){if(t.material.uniforms.headColor&&t.material.uniforms.tailColor){t.material.uniforms.headColor.value.setW((r.opacityStart??1)*e.alpha);t.material.uniforms.tailColor.value.setW((r.opacityEnd??1)*e.alpha)}null!=t.material.uniforms.opacity&&(t.material.uniforms.opacity.value=e.alpha)}e.useColor&&null!=t.material.uniforms.color&&t.material.uniforms.color.value.copy(e.color),null!=t.material.uniforms[d]&&(t.material.uniforms[d].value=e.energy),u(t.material)}}onParticleDead(e){const t=e.target,r=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=r){const e=this.trails[r];e.removeFromParent(),e.mesh.removeFromParent(),e.targetObject.removeFromParent(),t.removeFromParent(),this.trails.splice(r,1)}}}export class CombinedRenderer extends t{dispose(){}scale(e){const t=e.transform.initialScale;e.target instanceof a.Sprite?null!=t?e.target.scale.set(t.x*e.scale*e.radius,t.y*e.scale*e.radius,1):e.target.scale.set(e.scale*e.radius,e.scale*e.radius,1):null!=t?e.target.scale.set(t.x*e.scale,t.y*e.scale,t.z*e.scale):super.scale(e)}rotate(e){e.target.material.rotation=e.rotation.z}onParticleCreated(e){e.target||(e.target=this._targetPool.get(e.body),(e.useAlpha||e.useColor)&&(e.target instanceof a.Mesh||e.target instanceof a.Sprite&&e.target.material instanceof a.Material)&&(e.target.material.__puid=r.id(e.body.material),e.target.material=this._materialPool.get(e.target.material))),e.target&&e.target instanceof n&&(e.target.position.set(e.position.x,e.position.y,e.position.z),this.container.add(e.target))}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:o,rotation:i}=e;if(t){if(t.position.copy(e.position),this.isThreeSprite(e)||(t instanceof a.Mesh&&t.material instanceof c?e.target.material.rotation=e.rotation.z:t.rotation.set(i.x,i.y,i.z)),this.scale(e),e.transform&&e.transform.orientAlongVelocity&&t instanceof n){const r=p.set(e.velocity.x,e.velocity.y,e.velocity.z).normalize(),a=t.getWorldDirection(f);a.applyAxisAngle(y,Math.PI/-2),g.setFromUnitVectors(a,r),t.quaternion.copy(g)}(r||o)&&this.applyUniforms(t,e)}}applyUniforms(e,t){if(e instanceof m&&e.traverse(r=>r!==e&&this.applyUniforms(r,t)),e instanceof a.Mesh){let r=!1;t.useAlpha&&(e.material instanceof c&&null!=e.material.uniforms.opacity&&(e.material.uniforms.opacity.value=t.alpha,r=!0),e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.opacity?(e.material.uniforms.opacity.value=t.alpha,r=!0):(e.material.opacity=t.alpha,r=!0),e.material.transparent=!0),t.useColor&&(null!=e.material.color?(e.material.color.copy(t.color),r=!0):e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.color&&(e.material.uniforms.color.value=t.color,r=!0)),r&&u(e.material)}}onParticleDead(e){e.target&&(e.target.material&&(e.useAlpha||e.useColor)&&this._materialPool.expire(e.target.material),this._targetPool.expire(e.target),this.container.remove(e.target),e.target=null)}}export class StretchedSpriteInstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>e.mesh.geometry.dispose())}onSystemUpdate(){for(const e of this.meshes){const t=e.mesh.geometry.getAttribute("offset"),r=e.mesh.geometry.getAttribute("size"),o=e.mesh.geometry.getAttribute("velocity"),n=e.mesh.geometry.getAttribute("rotation"),i=e.mesh.geometry.getAttribute("particleColor");let s=0;for(const l of e.particles){if(null==l||l.dead)continue;if(l.useColor||l.color instanceof a.Color){const e=S.copy(l.color).getRGB(z);i.setXYZW(s,e.r,e.g,e.b,1),i.needsUpdate=!0}l.useAlpha&&(i.setW(s,l.alpha),i.needsUpdate=!0),"number"==typeof l.rotation?n.setX(s,l.rotation):n.setX(s,l.rotation.x);const e=l.position;if(t.setXYZ(s,e.x,e.y,e.z),"number"!=typeof l.scale)throw new Error("Particle scale is not a number");r.setXYZ(s,l.scale,l.scale,l.scale);let c=l.body.scaleFactor;0===c&&(c=.001);const d=1,m=l.velocity;o.setXYZW(s,m.x*c,m.y*c,m.z*c,d),s++}s>0&&(t.clearUpdateRanges(),t.addUpdateRange(0,3*s),t.needsUpdate=!0,r.clearUpdateRanges(),r.addUpdateRange(0,3*s),r.needsUpdate=!0,i.clearUpdateRanges(),i.addUpdateRange(0,4*s),i.needsUpdate=!0,o.clearUpdateRanges(),o.addUpdateRange(0,4*s),o.needsUpdate=!0,n.clearUpdateRanges(),n.addUpdateRange(0,s),n.needsUpdate=!0)}}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a;if(!Number.isFinite(r)||r<=0)return t.numPan.b*this.calcMaxCount(e.parent.parentParticle);return Math.min(t.numPan.b*Math.ceil(e.life/Math.min(Math.max(t.timePan.a,.01),1)),1e5)*this.calcMaxCount(e.parent.parentParticle)}onParticleCreated(e){if(e.body instanceof s&&null==e.target){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(null==r){const n=this.calcMaxCount(e),i=new a.InstancedBufferGeometry;i.setIndex(t.geometry.getIndex()),i.setAttribute("position",t.geometry.getAttribute("position")),t.geometry.hasAttribute("normal")&&i.setAttribute("normal",t.geometry.getAttribute("normal")),i.setAttribute("uv",t.geometry.getAttribute("uv"));const s=new o(new Float32Array(3*n),3);s.setUsage(a.DynamicDrawUsage),i.setAttribute("offset",s);const l=new o(new Float32Array(4*n),4);if(l.setUsage(a.DynamicDrawUsage),i.setAttribute("particleColor",l),t.material instanceof c){const e=new a.Color(t.material.color);for(let t=0;t<l.count;t++)l.setXYZW(t,e.r,e.g,e.b,1)}const d=new o(new Float32Array(3*n),3);d.setUsage(a.DynamicDrawUsage),i.setAttribute("size",d);const m=new o(new Float32Array(4*n),4);m.setUsage(a.DynamicDrawUsage),i.setAttribute("velocity",m);const u=new o(new Float32Array(4*n),1);u.setUsage(a.DynamicDrawUsage),i.setAttribute("rotation",u),r={mesh:new a.Mesh(i,t.material),indices:new Float32Array(n),particles:[]},r.mesh.renderOrder=t.renderOrder,this.meshes.push(r),this.container.add(r.mesh)}let n=r.indices.findIndex(e=>0===e);n<0&&(n=function(e){let t=e[0],r=0;for(let a=1;a<e.length;a++)e[a]<t&&(t=e[a],r=a);return r}(r.indices)),r.indices[n]=performance.now(),e.target=n,r.particles[n]=e}}onParticleUpdate(e){}onParticleDead(e){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(r){const t=r.mesh.geometry.getAttribute("size");t.setXYZ(e.target,0,0,0),t.needsUpdate=!0,r.particles[e.target]=null,r.indices[e.target]=0}e.target=null}}const p=new a.Vector3,f=new a.Vector3,g=new a.Quaternion,y=new a.Vector3(1,0,0),b=1e5;function w(e){return Number.isFinite(e)?Math.min(Math.max(Math.ceil(e),1),b):b}export class InstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>e.mesh.dispose())}onSystemUpdate(){for(const e of this.meshes)e.mesh.material.transparent&&e.mesh.material.blending===a.NormalBlending&&F(e,this.view.getCamera())}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a,a=t.numPan.b,o=e.parent.parentParticle;if(!Number.isFinite(r)||r<=0)return w(a*this.calcMaxCount(o));return w(a*Math.ceil(e.life/Math.min(Math.max(r,.01),1))*this.calcMaxCount(o))}onParticleCreated(e){if(e.body instanceof a.Sprite)return;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r){const o=this.calcMaxCount(e);r={mesh:new a.InstancedMesh(t.geometry,t.material,o),indices:new Array(o).fill(null),particles:[],sortOrder:new Array(o),sortDistances:new Float32Array(o),sortedMatrices:new Float32Array(16*o),sortedColors:new Float32Array(4*o),sortedParticleData:new Float32Array(3*o),sortedRotations:new Float32Array(o),sortedParticles:new Array(o),sortedIndices:new Array(o)},r.mesh.renderOrder=t.renderOrder,r.mesh.userData.webGpuCacheMaterial=!0;const n=new Float32Array(4*o);n.fill(1),r.mesh.instanceColor=new a.InstancedBufferAttribute(n,4),r.mesh.setColorAt(0,S.setScalar(1)),r.mesh.instanceColor.needsUpdate=!0,r.mesh.material.defines.USE_INSTANCING="",r.mesh.material.needsUpdate=!0;const i=new Float32Array(3*o);M.makeScale(0,0,0);for(let e=0;e<o;e++)i[3*e+0]=1,i[3*e+1]=1,i[3*e+2]=1,r.mesh.instanceMatrix.array.set(M.elements,16*e);r.mesh.instanceMatrix.needsUpdate=!0,r.mesh.geometry.setAttribute("particleData",new a.InstancedBufferAttribute(i,3));const s=new a.InstancedBufferAttribute(new Float32Array(o),1);s.setUsage(a.DynamicDrawUsage),r.mesh.geometry.setAttribute("rotation",s),this.meshes.push(r),this.container.add(r.mesh)}let o=r.indices.findIndex(e=>null==e);if(o<0&&(o=r.indices.indexOf(Math.min(...r.indices))),o<0||o>=r.mesh.instanceMatrix.count)return void(e.target=null);const n=r.particles[o];if(null!=n&&n!==e&&(n.target=null),r.indices[o]=performance.now(),e.target=o,r.particles[o]=e,r.mesh.count<=o&&(r.mesh.count=o+1),"number"==typeof e.target){e.transform.initialScale;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);C(e,r.mesh),e.useAlpha&&(r.mesh.material.transparent||(r.mesh.material.transparent=!0,r.mesh.material.needsUpdate=!0))}}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:a,rotation:o}=e;if(null==t)return;const n=e.body,i=this.meshes.find(e=>e.mesh.geometry.uuid===n.geometry.uuid&&e.mesh.material.uuid===n.material.uuid);if(null==i)return;if(!A(i,e))return void(e.target=null);if(i.mesh.frustumCulled=!1,C(e,i.mesh),a){S.copy(e.color);const t=i.mesh.instanceColor.array,r=e.target*i.mesh.instanceColor.itemSize;t[r+0]=S.r,t[r+1]=S.g,t[r+2]=S.b,i.mesh.instanceColor.itemSize>=4&&(t[r+3]=1),i.mesh.instanceColor.needsUpdate=!0}const s=i.mesh.geometry.getAttribute("particleData");r&&s.setX(e.target,e.alpha),s.setY(e.target,e.energy),s.needsUpdate=!0;const l=i.mesh.geometry.getAttribute("rotation");l.setX(e.target,o.z),l.needsUpdate=!0}onParticleDead(e){if(null!=e.target){const t=e.body,r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r)return;if(!A(r,e))return void(e.target=null);r.indices[e.target]=null,r.particles[e.target]=null,e.scale=0,C(e,r.mesh),r.mesh.instanceMatrix.needsUpdate=!0,e.target=null}}}const x=new n;function A(e,t){const r=t.target;return"number"==typeof r&&Number.isInteger(r)&&r>=0&&r<e.mesh.instanceMatrix.count&&e.particles[r]===t}function C(e,t){if(!Number.isInteger(e.target)||e.target<0||e.target>=t.instanceMatrix.count)return;if(v.set(e.position.x,e.position.y,e.position.z),e.transform&&e.transform.orientAlongVelocity){const r=p.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z).normalize();t.getMatrixAt(e.target,x.matrix);const a=x.getWorldDirection(R);a.applyAxisAngle(y,Math.PI/-2),P.setFromUnitVectors(a,r)}else D.set(e.rotation.x,e.rotation.y,e.rotation.z),P.setFromEuler(D);const r=e.transform.initialScale;null!=r?R.set(r.x*e.scale,r.y*e.scale,r.z*e.scale):R.set(e.scale,e.scale,e.scale),M.compose(v,P,R),t.instanceMatrix.array.set(M.elements,16*e.target),t.instanceMatrix.needsUpdate=!0}const U=new a.Vector3(0,0,-1),M=new a.Matrix4,P=new a.Quaternion,v=new a.Vector3,R=new a.Vector3,D=new a.Euler,S=new a.Color(0),z={r:0,g:0,b:0};function F(e,t){const r=e.mesh,a=r.instanceMatrix.array,o=r.instanceColor.array,n=r.geometry.getAttribute("particleData"),i=n.array,s=r.geometry.getAttribute("rotation"),l=s.array,c=r.worldToLocal(t.getWorldPosition(I));let d=0;for(let t=0;t<e.particles.length;t++){if(null==e.particles[t])continue;const r=16*t,o=a[r+12]-c.x,n=a[r+13]-c.y,i=a[r+14]-c.z;e.sortDistances[t]=o*o+n*n+i*i,e.sortOrder[d++]=t}e.sortOrder.length=d,e.sortOrder.sort((t,r)=>e.sortDistances[r]-e.sortDistances[t]);for(let t=0;t<d;t++){const r=e.sortOrder[t];for(let o=0;o<16;o++)e.sortedMatrices[16*t+o]=a[16*r+o];for(let a=0;a<4;a++)e.sortedColors[4*t+a]=o[4*r+a];for(let a=0;a<3;a++)e.sortedParticleData[3*t+a]=i[3*r+a];e.sortedRotations[t]=l[r],e.sortedParticles[t]=e.particles[r],e.sortedIndices[t]=e.indices[r]}for(let t=0;t<d;t++){const r=e.sortedParticles[t];e.particles[t]=r,e.indices[t]=e.sortedIndices[t],l[t]=e.sortedRotations[t],r.target=t}for(let t=d;t<e.indices.length;t++)e.particles[t]=null,e.indices[t]=null;for(let t=0;t<16*d;t++)a[t]=e.sortedMatrices[t];for(let t=0;t<4*d;t++)o[t]=e.sortedColors[t];for(let t=0;t<3*d;t++)i[t]=e.sortedParticleData[t];r.count=d,r.instanceMatrix.needsUpdate=!0,r.instanceColor.needsUpdate=!0,n.needsUpdate=!0,s.needsUpdate=!0}export{F as sortInstancedMeshByDistance};const I=new a.Vector3;/*
|
|
1
|
+
import{CustomRenderer as e,MeshRenderer as t,PUID as r}from"@hology/nebula";import*as a from"three";import{InstancedBufferAttribute as o,Object3D as n}from"three";import{NodeShaderMaterial as i}from"three-shader-graph";import{StretchedSprite as s}from"./stretched-sprite.js";import{Trail as l}from"./trail-renderer.js";import{SpriteNodeShaderMaterial as c}from"../../shader/sprite-shader.js";import{particleEnergyUniformName as d}from"../../shader-nodes/particle.js";import{AssetMeshInstance as m}from"../../scene/asset-resource-loader.js";import{markMaterialUniformValuesNeedUpdate as u}from"../../rendering/node-material-webgpu-resolver.js";var h;!function(e){e[e.mesh=0]="mesh",e[e.instanced=1]="instanced",e[e.sprite=2]="sprite",e[e.stretchedBillboard=3]="stretchedBillboard",e[e.trail=4]="trail"}(h||(h={}));export class MultiRenderer extends e{constructor(e,t,r,a){super(),this.worldContainer=e,this.localContainer=t,this.three=r,this.view=a,this.localRenderers=[],this.worldRenderers=[]}onSystemUpdate(){for(const e of this.worldRenderers)e?.onSystemUpdate();for(const e of this.localRenderers)e?.onSystemUpdate()}onParticleCreated(e){e.target=null,this.getRenderer(e)?.onParticleCreated(e)}onParticleUpdate(e){this.getRenderer(e)?.onParticleUpdate(e)}onParticleDead(e){this.getRenderer(e)?.onParticleDead(e),e._renderer=null}getRenderer(e){if(e._renderer)return e._renderer;const t=(null!=e?.parent?e?.parent._space:null)??"world",r="world"===t?this.worldContainer:this.localContainer,o="world"===t?this.worldRenderers:this.localRenderers;return"trail"===e.body.type?(null==o[h.trail]&&(o[h.trail]=new TrailRenderer(r,this.three)),e._renderer=o[h.trail]):e.body instanceof s?(null==o[h.stretchedBillboard]&&(o[h.stretchedBillboard]=new StretchedSpriteInstancedRenderer(r,this.three,this.view)),e._renderer=o[h.stretchedBillboard]):e.body instanceof a.Sprite?(null==o[h.sprite]&&(o[h.sprite]=new CombinedRenderer(r,this.three)),e._renderer=o[h.sprite]):e.body instanceof a.Mesh&&0==e.body.children.length&&e.body.material instanceof i?(null==o[h.instanced]&&(o[h.instanced]=new InstancedRenderer(r,this.three,this.view)),e._renderer=o[h.instanced]):e.body instanceof a.Object3D?(null==o[h.mesh]&&(o[h.mesh]=new CombinedRenderer(r,this.three)),e._renderer=o[h.mesh]):void 0}dispose(){this.localRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()}),this.worldRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()})}}export class TrailRenderer extends t{constructor(){super(...arguments),this.trails=[]}dispose(){}onSystemUpdate(){for(const e of this.trails)e.update()}onParticleCreated(e){const t=e.body,r=new l(this.container,!1),o=new n;this.container.add(o),o.updateMatrixWorld(),o.updateWorldMatrix(!0,!0);const i=t.material?.clone()??l.createBaseMaterial(t.texture,t.scrollSpeed,t.opacityChannel,t.billboard??!1);i.uniforms.taper&&(i.uniforms.taper.value=t.taper??!1);const s=new a.Color(t.color??0).multiplyScalar(t.intensity??1),c=new a.Color(t.colorEnd??0).multiplyScalar(t.intensityEnd??t.intensity??1);i.uniforms.headColor&&i.uniforms.tailColor&&(i.uniforms.headColor.value=new a.Vector4(s.r,s.g,s.b,t.opacityStart??1),i.uniforms.tailColor.value=new a.Vector4(c.r,c.g,c.b,t.opacityEnd??1)),i.uniforms.color&&null==i.uniforms.headColor&&(i.uniforms.color.value=s),i.uniforms.opacity&&null==i.uniforms.headColor&&(i.uniforms.opacity.value=t.opacityStart??1),t.bloom&&(i.userData.hasBloom=!0),r.initialize(i,Math.round(t.length??10),!1,t.width,null,o,t.billboard??!1),null!=t.renderOrder&&null!=r.mesh&&(r.mesh.renderOrder=t.renderOrder);const d=e.rotation;o.rotation.set(d.x,d.y,d.z);e.scale;r.activate(),this.trails.push(r),e.target=o}onParticleUpdate(e){const t=e.target;t.position.copy(e.position);const r=e.body;let a=v;e.old&&e.old.position?a.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z):a.copy(e.velocity),a.lengthSq()>1e-8?a.normalize():a.copy(U);const o=P;o.setFromUnitVectors(a,U),t.rotation.set(0,0,0),t.rotation.set(e.rotation.x,e.rotation.y,e.rotation.z),t.applyQuaternion(o);const n=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=n){const t=this.trails[n];if(e.useAlpha){if(t.material.uniforms.headColor&&t.material.uniforms.tailColor){t.material.uniforms.headColor.value.setW((r.opacityStart??1)*e.alpha);t.material.uniforms.tailColor.value.setW((r.opacityEnd??1)*e.alpha)}null!=t.material.uniforms.opacity&&(t.material.uniforms.opacity.value=e.alpha)}e.useColor&&null!=t.material.uniforms.color&&t.material.uniforms.color.value.copy(e.color),null!=t.material.uniforms[d]&&(t.material.uniforms[d].value=e.energy),u(t.material)}}onParticleDead(e){const t=e.target,r=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=r){const e=this.trails[r];e.removeFromParent(),e.mesh.removeFromParent(),e.targetObject.removeFromParent(),t.removeFromParent(),this.trails.splice(r,1)}}}export class CombinedRenderer extends t{dispose(){}scale(e){const t=e.transform.initialScale;e.target instanceof a.Sprite?null!=t?e.target.scale.set(t.x*e.scale*e.radius,t.y*e.scale*e.radius,1):e.target.scale.set(e.scale*e.radius,e.scale*e.radius,1):null!=t?e.target.scale.set(t.x*e.scale,t.y*e.scale,t.z*e.scale):super.scale(e)}rotate(e){e.target.material.rotation=e.rotation.z}onParticleCreated(e){e.target||(e.target=this._targetPool.get(e.body),(e.useAlpha||e.useColor)&&(e.target instanceof a.Mesh||e.target instanceof a.Sprite&&e.target.material instanceof a.Material)&&(e.target.material.__puid=r.id(e.body.material),e.target.material=this._materialPool.get(e.target.material))),e.target&&e.target instanceof n&&(e.target.position.set(e.position.x,e.position.y,e.position.z),this.container.add(e.target))}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:o,rotation:i}=e;if(t){if(t.position.copy(e.position),this.isThreeSprite(e)||(t instanceof a.Mesh&&t.material instanceof c?e.target.material.rotation=e.rotation.z:t.rotation.set(i.x,i.y,i.z)),this.scale(e),e.transform&&e.transform.orientAlongVelocity&&t instanceof n){const r=p.set(e.velocity.x,e.velocity.y,e.velocity.z).normalize(),a=t.getWorldDirection(f);a.applyAxisAngle(y,Math.PI/-2),g.setFromUnitVectors(a,r),t.quaternion.copy(g)}(r||o)&&this.applyUniforms(t,e)}}applyUniforms(e,t){if(e instanceof m&&e.traverse(r=>r!==e&&this.applyUniforms(r,t)),e instanceof a.Mesh){let r=!1;t.useAlpha&&(e.material instanceof c&&null!=e.material.uniforms.opacity&&(e.material.uniforms.opacity.value=t.alpha,r=!0),e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.opacity?(e.material.uniforms.opacity.value=t.alpha,r=!0):(e.material.opacity=t.alpha,r=!0),e.material.transparent=!0),t.useColor&&(null!=e.material.color?(e.material.color.copy(t.color),r=!0):e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.color&&(e.material.uniforms.color.value=t.color,r=!0)),r&&u(e.material)}}onParticleDead(e){e.target&&(e.target.material&&(e.useAlpha||e.useColor)&&this._materialPool.expire(e.target.material),this._targetPool.expire(e.target),this.container.remove(e.target),e.target=null)}}export class StretchedSpriteInstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>e.mesh.geometry.dispose())}onSystemUpdate(){for(const e of this.meshes){const t=e.mesh.geometry.getAttribute("offset"),r=e.mesh.geometry.getAttribute("size"),o=e.mesh.geometry.getAttribute("velocity"),n=e.mesh.geometry.getAttribute("rotation"),i=e.mesh.geometry.getAttribute("particleColor");let s=0;for(const l of e.particles){if(null==l||l.dead)continue;if(l.useColor||l.color instanceof a.Color){const e=S.copy(l.color).getRGB(z);i.setXYZW(s,e.r,e.g,e.b,1),i.needsUpdate=!0}l.useAlpha&&(i.setW(s,l.alpha),i.needsUpdate=!0),"number"==typeof l.rotation?n.setX(s,l.rotation):n.setX(s,l.rotation.x);const e=l.position;if(t.setXYZ(s,e.x,e.y,e.z),"number"!=typeof l.scale)throw new Error("Particle scale is not a number");r.setXYZ(s,l.scale,l.scale,l.scale);let c=l.body.scaleFactor;0===c&&(c=.001);const d=1,m=l.velocity;o.setXYZW(s,m.x*c,m.y*c,m.z*c,d),s++}s>0&&(t.clearUpdateRanges(),t.addUpdateRange(0,3*s),t.needsUpdate=!0,r.clearUpdateRanges(),r.addUpdateRange(0,3*s),r.needsUpdate=!0,i.clearUpdateRanges(),i.addUpdateRange(0,4*s),i.needsUpdate=!0,o.clearUpdateRanges(),o.addUpdateRange(0,4*s),o.needsUpdate=!0,n.clearUpdateRanges(),n.addUpdateRange(0,s),n.needsUpdate=!0)}}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a;if(!Number.isFinite(r)||r<=0)return t.numPan.b*this.calcMaxCount(e.parent.parentParticle);return Math.min(t.numPan.b*Math.ceil(e.life/Math.min(Math.max(t.timePan.a,.01),1)),1e5)*this.calcMaxCount(e.parent.parentParticle)}onParticleCreated(e){if(e.body instanceof s&&null==e.target){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(null==r){const n=this.calcMaxCount(e),i=new a.InstancedBufferGeometry;i.setIndex(t.geometry.getIndex()),i.setAttribute("position",t.geometry.getAttribute("position")),t.geometry.hasAttribute("normal")&&i.setAttribute("normal",t.geometry.getAttribute("normal")),i.setAttribute("uv",t.geometry.getAttribute("uv"));const s=new o(new Float32Array(3*n),3);s.setUsage(a.DynamicDrawUsage),i.setAttribute("offset",s);const l=new o(new Float32Array(4*n),4);if(l.setUsage(a.DynamicDrawUsage),i.setAttribute("particleColor",l),t.material instanceof c){const e=new a.Color(t.material.color);for(let t=0;t<l.count;t++)l.setXYZW(t,e.r,e.g,e.b,1)}const d=new o(new Float32Array(3*n),3);d.setUsage(a.DynamicDrawUsage),i.setAttribute("size",d);const m=new o(new Float32Array(4*n),4);m.setUsage(a.DynamicDrawUsage),i.setAttribute("velocity",m);const u=new o(new Float32Array(4*n),1);u.setUsage(a.DynamicDrawUsage),i.setAttribute("rotation",u),r={mesh:new a.Mesh(i,t.material),indices:new Float32Array(n),particles:[]},r.mesh.renderOrder=t.renderOrder,this.meshes.push(r),this.container.add(r.mesh)}let n=r.indices.findIndex(e=>0===e);n<0&&(n=function(e){let t=e[0],r=0;for(let a=1;a<e.length;a++)e[a]<t&&(t=e[a],r=a);return r}(r.indices)),r.indices[n]=performance.now(),e.target=n,r.particles[n]=e}}onParticleUpdate(e){}onParticleDead(e){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(r){const t=r.mesh.geometry.getAttribute("size");t.setXYZ(e.target,0,0,0),t.needsUpdate=!0,r.particles[e.target]=null,r.indices[e.target]=0}e.target=null}}const p=new a.Vector3,f=new a.Vector3,g=new a.Quaternion,y=new a.Vector3(1,0,0),b=1e5;function w(e){return Number.isFinite(e)?Math.min(Math.max(Math.ceil(e),1),b):b}export class InstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>{e.mesh.geometry.dispose(),e.mesh.dispose()})}onSystemUpdate(){for(const e of this.meshes)e.mesh.material.transparent&&e.mesh.material.blending===a.NormalBlending&&F(e,this.view.getCamera())}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a,a=t.numPan.b,o=e.parent.parentParticle;if(!Number.isFinite(r)||r<=0)return w(a*this.calcMaxCount(o));return w(a*Math.ceil(e.life/Math.min(Math.max(r,.01),1))*this.calcMaxCount(o))}onParticleCreated(e){if(e.body instanceof a.Sprite)return;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r){const o=this.calcMaxCount(e);r={mesh:new a.InstancedMesh(t.geometry,t.material,o),indices:new Array(o).fill(null),particles:[],sortOrder:new Array(o),sortDistances:new Float32Array(o),sortedMatrices:new Float32Array(16*o),sortedColors:new Float32Array(4*o),sortedParticleData:new Float32Array(3*o),sortedRotations:new Float32Array(o),sortedParticles:new Array(o),sortedIndices:new Array(o)},r.mesh.renderOrder=t.renderOrder,r.mesh.userData.webGpuCacheMaterial=!0;const n=new Float32Array(4*o);n.fill(1),r.mesh.instanceColor=new a.InstancedBufferAttribute(n,4),r.mesh.setColorAt(0,S.setScalar(1)),r.mesh.instanceColor.needsUpdate=!0,r.mesh.material.defines.USE_INSTANCING="",r.mesh.material.needsUpdate=!0;const i=new Float32Array(3*o);M.makeScale(0,0,0);for(let e=0;e<o;e++)i[3*e+0]=1,i[3*e+1]=1,i[3*e+2]=1,r.mesh.instanceMatrix.array.set(M.elements,16*e);r.mesh.instanceMatrix.needsUpdate=!0,r.mesh.geometry.setAttribute("particleData",new a.InstancedBufferAttribute(i,3));const s=new a.InstancedBufferAttribute(new Float32Array(o),1);s.setUsage(a.DynamicDrawUsage),r.mesh.geometry.setAttribute("rotation",s),this.meshes.push(r),this.container.add(r.mesh)}let o=r.indices.findIndex(e=>null==e);if(o<0&&(o=r.indices.indexOf(Math.min(...r.indices))),o<0||o>=r.mesh.instanceMatrix.count)return void(e.target=null);const n=r.particles[o];if(null!=n&&n!==e&&(n.target=null),r.indices[o]=performance.now(),e.target=o,r.particles[o]=e,r.mesh.count<=o&&(r.mesh.count=o+1),"number"==typeof e.target){e.transform.initialScale;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);C(e,r.mesh),e.useAlpha&&(r.mesh.material.transparent||(r.mesh.material.transparent=!0,r.mesh.material.needsUpdate=!0))}}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:a,rotation:o}=e;if(null==t)return;const n=e.body,i=this.meshes.find(e=>e.mesh.geometry.uuid===n.geometry.uuid&&e.mesh.material.uuid===n.material.uuid);if(null==i)return;if(!A(i,e))return void(e.target=null);if(i.mesh.frustumCulled=!1,C(e,i.mesh),a){S.copy(e.color);const t=i.mesh.instanceColor.array,r=e.target*i.mesh.instanceColor.itemSize;t[r+0]=S.r,t[r+1]=S.g,t[r+2]=S.b,i.mesh.instanceColor.itemSize>=4&&(t[r+3]=1),i.mesh.instanceColor.needsUpdate=!0}const s=i.mesh.geometry.getAttribute("particleData");r&&s.setX(e.target,e.alpha),s.setY(e.target,e.energy),s.needsUpdate=!0;const l=i.mesh.geometry.getAttribute("rotation");l.setX(e.target,o.z),l.needsUpdate=!0}onParticleDead(e){if(null!=e.target){const t=e.body,r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r)return;if(!A(r,e))return void(e.target=null);r.indices[e.target]=null,r.particles[e.target]=null,e.scale=0,C(e,r.mesh),r.mesh.instanceMatrix.needsUpdate=!0,e.target=null}}}const x=new n;function A(e,t){const r=t.target;return"number"==typeof r&&Number.isInteger(r)&&r>=0&&r<e.mesh.instanceMatrix.count&&e.particles[r]===t}function C(e,t){if(!Number.isInteger(e.target)||e.target<0||e.target>=t.instanceMatrix.count)return;if(v.set(e.position.x,e.position.y,e.position.z),e.transform&&e.transform.orientAlongVelocity){const r=p.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z).normalize();t.getMatrixAt(e.target,x.matrix);const a=x.getWorldDirection(R);a.applyAxisAngle(y,Math.PI/-2),P.setFromUnitVectors(a,r)}else D.set(e.rotation.x,e.rotation.y,e.rotation.z),P.setFromEuler(D);const r=e.transform.initialScale;null!=r?R.set(r.x*e.scale,r.y*e.scale,r.z*e.scale):R.set(e.scale,e.scale,e.scale),M.compose(v,P,R),t.instanceMatrix.array.set(M.elements,16*e.target),t.instanceMatrix.needsUpdate=!0}const U=new a.Vector3(0,0,-1),M=new a.Matrix4,P=new a.Quaternion,v=new a.Vector3,R=new a.Vector3,D=new a.Euler,S=new a.Color(0),z={r:0,g:0,b:0};function F(e,t){const r=e.mesh,a=r.instanceMatrix.array,o=r.instanceColor.array,n=r.geometry.getAttribute("particleData"),i=n.array,s=r.geometry.getAttribute("rotation"),l=s.array,c=r.worldToLocal(t.getWorldPosition(I));let d=0;for(let t=0;t<e.particles.length;t++){if(null==e.particles[t])continue;const r=16*t,o=a[r+12]-c.x,n=a[r+13]-c.y,i=a[r+14]-c.z;e.sortDistances[t]=o*o+n*n+i*i,e.sortOrder[d++]=t}e.sortOrder.length=d,e.sortOrder.sort((t,r)=>e.sortDistances[r]-e.sortDistances[t]);for(let t=0;t<d;t++){const r=e.sortOrder[t];for(let o=0;o<16;o++)e.sortedMatrices[16*t+o]=a[16*r+o];for(let a=0;a<4;a++)e.sortedColors[4*t+a]=o[4*r+a];for(let a=0;a<3;a++)e.sortedParticleData[3*t+a]=i[3*r+a];e.sortedRotations[t]=l[r],e.sortedParticles[t]=e.particles[r],e.sortedIndices[t]=e.indices[r]}for(let t=0;t<d;t++){const r=e.sortedParticles[t];e.particles[t]=r,e.indices[t]=e.sortedIndices[t],l[t]=e.sortedRotations[t],r.target=t}for(let t=d;t<e.indices.length;t++)e.particles[t]=null,e.indices[t]=null;for(let t=0;t<16*d;t++)a[t]=e.sortedMatrices[t];for(let t=0;t<4*d;t++)o[t]=e.sortedColors[t];for(let t=0;t<3*d;t++)i[t]=e.sortedParticleData[t];r.count=d,r.instanceMatrix.needsUpdate=!0,r.instanceColor.needsUpdate=!0,n.needsUpdate=!0,s.needsUpdate=!0}export{F as sortInstancedMeshByDistance};const I=new a.Vector3;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { System } from '@hology/nebula';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import type { VfxAsset } from '../../scene/model.js';
|
|
4
|
+
import { type VfxAssetProvider } from './vfx-materializer.js';
|
|
5
|
+
export type { VfxAssetProvider } from './vfx-materializer.js';
|
|
6
|
+
export type StandaloneVfxRuntimeOptions = {
|
|
7
|
+
asset: VfxAsset;
|
|
8
|
+
target: THREE.Object3D;
|
|
9
|
+
scene: THREE.Object3D;
|
|
10
|
+
camera: () => THREE.Camera;
|
|
11
|
+
assets: VfxAssetProvider;
|
|
12
|
+
};
|
|
13
|
+
export type StandaloneVfxRuntimeStats = {
|
|
14
|
+
particleCount: number;
|
|
15
|
+
emitterCount: number;
|
|
16
|
+
simulationCpuMs: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Minimal host-independent adapter for VFX previews, benchmarks, and tests.
|
|
20
|
+
* Optional engine services are deliberately absent: fixtures using physics,
|
|
21
|
+
* custom shader classes, shader graphs, decals, or material assets should use
|
|
22
|
+
* the full gameplay materialization context instead.
|
|
23
|
+
*/
|
|
24
|
+
export declare class StandaloneVfxRuntime {
|
|
25
|
+
readonly system: System;
|
|
26
|
+
readonly container: THREE.Object3D;
|
|
27
|
+
private readonly disposeMaterialized;
|
|
28
|
+
private simulationCpuMs;
|
|
29
|
+
private constructor();
|
|
30
|
+
static create(options: StandaloneVfxRuntimeOptions): Promise<StandaloneVfxRuntime>;
|
|
31
|
+
update(deltaTime: number): void;
|
|
32
|
+
getStats(): StandaloneVfxRuntimeStats;
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=vfx-runtime.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{materializeVfx as t}from"./vfx-materializer.js";export class StandaloneVfxRuntime{constructor(t,s,e){this.system=t,this.container=s,this.disposeMaterialized=e,this.simulationCpuMs=0}static async create(s){const e={getCamera:s.camera},i=void 0,a=await t(s.asset,s.target,s.assets,e,i,i,i,i);return s.scene.add(a.container),new StandaloneVfxRuntime(a.system,a.container,a.dispose)}update(t){const s=performance.now();this.system.update(t),this.simulationCpuMs=performance.now()-s}getStats(){return{particleCount:this.system.getCount(),emitterCount:this.system.emitters.length,simulationCpuMs:this.simulationCpuMs}}dispose(){this.system.destroy(),this.disposeMaterialized()}}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -3,8 +3,11 @@ import { BaseActor } from '../../gameplay/actors/actor.js';
|
|
|
3
3
|
import { VfxActor } from './vfx-actor.js';
|
|
4
4
|
import { Asset, AssetId } from '../../scene/model.js';
|
|
5
5
|
import { VfxPool } from './vfx-param.js';
|
|
6
|
+
import type { VfxBackendPreference } from './gpu-sprite-compiler.js';
|
|
6
7
|
export type VfxSpawnOptions = {
|
|
7
8
|
inputs?: Record<string, unknown>;
|
|
9
|
+
/** Experimental per-effect backend selection. Defaults to CPU. */
|
|
10
|
+
backend?: VfxBackendPreference;
|
|
8
11
|
};
|
|
9
12
|
export declare class VfxService {
|
|
10
13
|
private pools;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t}from"tslib";import{ActorFactory as s}from"../../gameplay/actors/factory.js";import{AssetLoader as e}from"../../gameplay/services/asset-loader.js";import{BaseActor as o}from"../../gameplay/actors/actor.js";import{inject as r}from"../../gameplay/inject.js";import{Service as a}from"typedi";import{World as c}from"../../gameplay/services/world.js";import{VfxActor as i}from"./vfx-actor.js";import{VfxPool as m}from"./vfx-param.js";let l=class{constructor(){this.pools=new Map,this.actorFactory=r(s),this.assetService=r(e),this.world=r(c)}async createFromAssetId(t,s=this.world.scene,e){const o=await this.assetService.getAsset(t);return this.createFromAsset(o,s,e)}async createFromAsset(t,s=this.world.scene,e){const r=await this.actorFactory.create(i);return s instanceof o?s.object.add(r.object):s.add(r.object),await r.fromAsset(t,e?.inputs),r}async createPoolFromAssetId(t,s=this.world.scene){const e=await this.assetService.getAsset(t);return this.createPoolFromAsset(e,s)}async createPoolFromAsset(t,s=this.world.scene){let e;return this.pools.has(t.id)||(e=new m(()=>this.createFromAsset(t,s)),this.pools.set(t.id,e)),e}clearPool(t){this.pools.delete(t)}};l=t([a()],l);export{l as VfxService};/*
|
|
1
|
+
import{__decorate as t}from"tslib";import{ActorFactory as s}from"../../gameplay/actors/factory.js";import{AssetLoader as e}from"../../gameplay/services/asset-loader.js";import{BaseActor as o}from"../../gameplay/actors/actor.js";import{inject as r}from"../../gameplay/inject.js";import{Service as a}from"typedi";import{World as c}from"../../gameplay/services/world.js";import{VfxActor as i}from"./vfx-actor.js";import{VfxPool as m}from"./vfx-param.js";let l=class{constructor(){this.pools=new Map,this.actorFactory=r(s),this.assetService=r(e),this.world=r(c)}async createFromAssetId(t,s=this.world.scene,e){const o=await this.assetService.getAsset(t);return this.createFromAsset(o,s,e)}async createFromAsset(t,s=this.world.scene,e){const r=await this.actorFactory.create(i);return s instanceof o?s.object.add(r.object):s.add(r.object),await r.fromAsset(t,e?.inputs,e?.backend),r}async createPoolFromAssetId(t,s=this.world.scene){const e=await this.assetService.getAsset(t);return this.createPoolFromAsset(e,s)}async createPoolFromAsset(t,s=this.world.scene){let e;return this.pools.has(t.id)||(e=new m(()=>this.createFromAsset(t,s)),this.pools.set(t.id,e)),e}clearPool(t){this.pools.delete(t)}};l=t([a()],l);export{l as VfxService};/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -130,6 +130,9 @@ export declare class CharacterAnimationComponent extends ActorComponent {
|
|
|
130
130
|
private ikLegLengths?;
|
|
131
131
|
private ikPelvisBone?;
|
|
132
132
|
private ikPelvisOffsetY;
|
|
133
|
+
private ikPelvisDescendantStack;
|
|
134
|
+
private ikWorldUpdateNodes;
|
|
135
|
+
private footIkStateReset;
|
|
133
136
|
private ikFootAxes?;
|
|
134
137
|
private ikDebugRoot?;
|
|
135
138
|
private ikDebugLegs?;
|
|
@@ -193,6 +196,15 @@ export declare class CharacterAnimationComponent extends ActorComponent {
|
|
|
193
196
|
private updateFootIk;
|
|
194
197
|
private resetFootIkState;
|
|
195
198
|
private updatePelvisOffset;
|
|
199
|
+
/**
|
|
200
|
+
* Pelvis correction only translates the hierarchy in world space. A forced
|
|
201
|
+
* updateMatrixWorld would recompose and multiply every descendant bone even
|
|
202
|
+
* though none of their local transforms changed. Update the pelvis matrix
|
|
203
|
+
* once and apply its world-space delta to the already-current descendants.
|
|
204
|
+
*/
|
|
205
|
+
private updatePelvisWorldTranslation;
|
|
206
|
+
private rebuildFootIkWorldUpdateNodes;
|
|
207
|
+
private syncFootIkWorldMatrices;
|
|
196
208
|
private computeFootVerticalSpeed;
|
|
197
209
|
private updateFootSample;
|
|
198
210
|
private estimateFootContactOffset;
|
|
@@ -216,6 +228,8 @@ export declare class CharacterAnimationComponent extends ActorComponent {
|
|
|
216
228
|
private rotateBoneToward;
|
|
217
229
|
private detectFootAxisBasis;
|
|
218
230
|
private resolveFootAxes;
|
|
231
|
+
private getCurrentWorldQuaternion;
|
|
232
|
+
private getCurrentWorldDirection;
|
|
219
233
|
private clampSlopeNormal;
|
|
220
234
|
private blendLegAfterSolve;
|
|
221
235
|
private blendBoneQuaternion;
|