@hology/core 0.0.213 → 0.0.214
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/vfx/initializsers.d.ts +4 -0
- package/dist/effects/vfx/initializsers.js +1 -1
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +6 -0
- package/dist/gameplay/actors/component.d.ts +6 -0
- package/dist/gameplay/animation/retarget.js +1 -1
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/world.js +1 -1
- package/dist/scene/assets-provider.d.ts +1 -0
- package/dist/scene/assets-provider.js +1 -1
- package/dist/scene/materializer.d.ts +8 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/runtime-asset-service.d.ts +7 -1
- package/dist/scene/runtime-asset-service.js +1 -1
- package/dist/test/animation-retarget.test.js +1 -1
- package/dist/test/prefab-instance-params.test.js +1 -1
- package/dist/test/runtime-asset-service.test.js +1 -1
- package/dist/test/vfx-world-space-emitter-rotation.test.d.ts +2 -0
- package/dist/test/vfx-world-space-emitter-rotation.test.js +4 -0
- package/dist/test/world-prefab-spawn.test.js +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,6 +4,10 @@ export declare class DefaultInitializer extends Initializer {
|
|
|
4
4
|
init(emitter: Emitter, particle: Particle): void;
|
|
5
5
|
initialize(target: Emitter | Particle): void;
|
|
6
6
|
}
|
|
7
|
+
export declare class WorldSpaceEmitterRotationInitializer extends Initializer {
|
|
8
|
+
init(emitter: Emitter, particle: Particle): void;
|
|
9
|
+
initialize(target: Emitter | Particle): void;
|
|
10
|
+
}
|
|
7
11
|
export declare class Rotation extends Initializer {
|
|
8
12
|
private rotation;
|
|
9
13
|
constructor(rotation: Vector3);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Vector3 as t,Quaternion as e,Euler as i,Color as s}from"three";import{Span as o,Initializer as n}from"@hology/nebula";export class DefaultInitializer extends n{init(t,e){e.parent=t}initialize(t){}}export class Rotation extends n{constructor(t){super(),this.rotation=t}setRotation(t){this.rotation=t.clone()}initialize(t){"number"!=typeof t.rotation&&t.rotation.copy(this.rotation)}}export const randomRotationAxis=["XYZ","X","Y","Z"];export class RandomRotation extends n{constructor(t){super(),this.axis=t}initialize(t){switch(this.axis){case"XYZ":t.rotation.set(this.randomAngle(),this.randomAngle(),this.randomAngle());break;case"X":t.rotation.x=this.randomAngle();break;case"Y":t.rotation.y=this.randomAngle();break;case"Z":t.rotation.z=this.randomAngle()}}randomAngle(){return 2*Math.PI*Math.random()}}export class InitialScale extends n{constructor(t){super(),this.scale=t}setScale(t){this.scale=t}initialize(t){t.scale=this.scale}}export class RandomScale extends n{constructor(t,e){super(),this.min=t,this.max=e}setRange(t,e){this.min=t,this.max=e}initialize(t){t.scale=h(this.min,this.max)}}export class RandomColor extends n{constructor(t,e){super(),this.min=new s,this.max=new s,this.setRange(t,e)}setRange(t,e){this.min.set(t),this.max.set(e)}initialize(t){const e=Math.random();t.color.r=h(this.min.r,this.max.r,e),t.color.g=h(this.min.g,this.max.g,e),t.color.b=h(this.min.b,this.max.b,e),t.useColor=!0}}export class InitialScaleComponents extends n{constructor(t){super(),this.scale=t}setScaleComponents(t){this.scale=t.clone()}initialize(t){t.transform.initialScale=this.scale.clone()}}export class AdditiveVelocity extends n{constructor(t,e){super(),this.min=t,this.max=e}initialize(t){const e=m(this.min),i=null!=this.max?m(this.max):void 0;t.velocity.x+=null!=i?h(e.x,i.x):e.x,t.velocity.y+=null!=i?h(e.y,i.y):e.y,t.velocity.z+=null!=i?h(e.z,i.z):e.z}}export class RandomDirection extends n{constructor(t){super(),this.speed=t}setSpeed(t){this.speed=t}initialize(t){l.set(2*Math.random()-1,2*Math.random()-1,2*Math.random()-1).normalize().multiplyScalar(this.speed),t.velocity.x+=l.x,t.velocity.y+=l.y,t.velocity.z+=l.z}}export class RandomVelocity extends n{constructor(t,e){super(),this.min=t,this.max=e,this.x=new o(this.min.x,this.max.x),this.y=new o(this.min.y,this.max.y),this.z=new o(this.min.z,this.max.z)}initialize(t){t.velocity.x+=this.x.getValue(),t.velocity.y+=this.y.getValue(),t.velocity.z+=this.z.getValue()}}export const alignRotationAxes=["+X","-X","+Y","-Y","+Z","-Z"];export const alignRotationModes=["AwayFromCenter","TowardsCenter","AlongVelocity"];export class AlignRotation extends n{constructor(e,i,s=new t,o=new t){super(),this.axis=e,this.mode=i,this.offset=s,this.center=o,this.axisVec=new t(0,1,0),this.setAxis(e)}setAxis(t){switch(t){case"+X":this.axisVec.set(1,0,0);break;case"-X":this.axisVec.set(-1,0,0);break;case"+Y":this.axisVec.set(0,1,0);break;case"-Y":this.axisVec.set(0,-1,0);break;case"+Z":this.axisVec.set(0,0,1);break;case"-Z":this.axisVec.set(0,0,-1)}}initialize(t){if("number"!=typeof t.rotation){switch(this.mode){case"AwayFromCenter":l.copy(t.position).sub(this.center).normalize();break;case"TowardsCenter":l.copy(t.position).sub(this.center).normalize().multiplyScalar(-1);break;case"AlongVelocity":l.copy(t.velocity).normalize()}l.lengthSq()<1e-4&&l.set(0,1,0),a.setFromUnitVectors(this.axisVec,l),this.offset.lengthSq()>0&&(r.setFromEuler(c.set(this.offset.x,this.offset.y,this.offset.z)),a.multiply(r)),c.setFromQuaternion(a),t.rotation.x=c.x,t.rotation.y=c.y,t.rotation.z=c.z}}}const a=new e,r=new e,c=new i,l=new t;function h(t,e,i=Math.random()){return i*(e-t)+t}function m(t){return"function"==typeof t?t():t}/*
|
|
1
|
+
import{Vector3 as t,Quaternion as e,Euler as i,Color as s}from"three";import{Span as o,Initializer as n}from"@hology/nebula";export class DefaultInitializer extends n{init(t,e){e.parent=t}initialize(t){}}export class WorldSpaceEmitterRotationInitializer extends n{init(t,e){"number"!=typeof e.rotation&&(a.setFromEuler(c.set(t.rotation.x,t.rotation.y,t.rotation.z)),r.setFromEuler(c.set(e.rotation.x,e.rotation.y,e.rotation.z)),a.multiply(r),c.setFromQuaternion(a),e.rotation.set(c.x,c.y,c.z))}initialize(t){}}export class Rotation extends n{constructor(t){super(),this.rotation=t}setRotation(t){this.rotation=t.clone()}initialize(t){"number"!=typeof t.rotation&&t.rotation.copy(this.rotation)}}export const randomRotationAxis=["XYZ","X","Y","Z"];export class RandomRotation extends n{constructor(t){super(),this.axis=t}initialize(t){switch(this.axis){case"XYZ":t.rotation.set(this.randomAngle(),this.randomAngle(),this.randomAngle());break;case"X":t.rotation.x=this.randomAngle();break;case"Y":t.rotation.y=this.randomAngle();break;case"Z":t.rotation.z=this.randomAngle()}}randomAngle(){return 2*Math.PI*Math.random()}}export class InitialScale extends n{constructor(t){super(),this.scale=t}setScale(t){this.scale=t}initialize(t){t.scale=this.scale}}export class RandomScale extends n{constructor(t,e){super(),this.min=t,this.max=e}setRange(t,e){this.min=t,this.max=e}initialize(t){t.scale=h(this.min,this.max)}}export class RandomColor extends n{constructor(t,e){super(),this.min=new s,this.max=new s,this.setRange(t,e)}setRange(t,e){this.min.set(t),this.max.set(e)}initialize(t){const e=Math.random();t.color.r=h(this.min.r,this.max.r,e),t.color.g=h(this.min.g,this.max.g,e),t.color.b=h(this.min.b,this.max.b,e),t.useColor=!0}}export class InitialScaleComponents extends n{constructor(t){super(),this.scale=t}setScaleComponents(t){this.scale=t.clone()}initialize(t){t.transform.initialScale=this.scale.clone()}}export class AdditiveVelocity extends n{constructor(t,e){super(),this.min=t,this.max=e}initialize(t){const e=m(this.min),i=null!=this.max?m(this.max):void 0;t.velocity.x+=null!=i?h(e.x,i.x):e.x,t.velocity.y+=null!=i?h(e.y,i.y):e.y,t.velocity.z+=null!=i?h(e.z,i.z):e.z}}export class RandomDirection extends n{constructor(t){super(),this.speed=t}setSpeed(t){this.speed=t}initialize(t){l.set(2*Math.random()-1,2*Math.random()-1,2*Math.random()-1).normalize().multiplyScalar(this.speed),t.velocity.x+=l.x,t.velocity.y+=l.y,t.velocity.z+=l.z}}export class RandomVelocity extends n{constructor(t,e){super(),this.min=t,this.max=e,this.x=new o(this.min.x,this.max.x),this.y=new o(this.min.y,this.max.y),this.z=new o(this.min.z,this.max.z)}initialize(t){t.velocity.x+=this.x.getValue(),t.velocity.y+=this.y.getValue(),t.velocity.z+=this.z.getValue()}}export const alignRotationAxes=["+X","-X","+Y","-Y","+Z","-Z"];export const alignRotationModes=["AwayFromCenter","TowardsCenter","AlongVelocity"];export class AlignRotation extends n{constructor(e,i,s=new t,o=new t){super(),this.axis=e,this.mode=i,this.offset=s,this.center=o,this.axisVec=new t(0,1,0),this.setAxis(e)}setAxis(t){switch(t){case"+X":this.axisVec.set(1,0,0);break;case"-X":this.axisVec.set(-1,0,0);break;case"+Y":this.axisVec.set(0,1,0);break;case"-Y":this.axisVec.set(0,-1,0);break;case"+Z":this.axisVec.set(0,0,1);break;case"-Z":this.axisVec.set(0,0,-1)}}initialize(t){if("number"!=typeof t.rotation){switch(this.mode){case"AwayFromCenter":l.copy(t.position).sub(this.center).normalize();break;case"TowardsCenter":l.copy(t.position).sub(this.center).normalize().multiplyScalar(-1);break;case"AlongVelocity":l.copy(t.velocity).normalize()}l.lengthSq()<1e-4&&l.set(0,1,0),a.setFromUnitVectors(this.axisVec,l),this.offset.lengthSq()>0&&(r.setFromEuler(c.set(this.offset.x,this.offset.y,this.offset.z)),a.multiply(r)),c.setFromQuaternion(a),t.rotation.x=c.x,t.rotation.y=c.y,t.rotation.z=c.z}}}const a=new e,r=new e,c=new i,l=new t;function h(t,e,i=Math.random()){return i*(e-t)+t}function m(t){return"function"==typeof t?t():t}/*
|
|
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 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 h,Vec3ExpressionNode as d,Vec4Node as m,attributeFloat as f,attributeVec3 as y,attributeVec4 as g,attributes as w,clamp as b,float as v,glslFunction as E,lambertMaterial as A,log as M,pow as x,rgb as P,rgba as S,smoothstep as I,standardMaterial as T,textureSampler2d as C,uniformFloat as R,uniforms as B,varying as k,varyingAttributes as j,varyingVec3 as D,varyingVec4 as G}from"three-shader-graph";import{prepareClassParameters as V,prepareShaderGraphParameters as F,prepareShapeParameters as z}from"../../scene/materializer.js";import{SerializedParamType as L}from"../../scene/model.js";import{ShapeLibrary as O}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as W,linearEyeDepth as Q}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as H,particleTimeUniformName as U,particleUniforms as q,particleVelcoityUniformName as J}from"../../shader-nodes/particle.js";import{sampleFlipbook as N}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as X}from"./initializsers.js";import{DelayRate as _,OnceRate as K}from"./rates.js";import{StretchedSprite as Y}from"./stretched-sprite.js";import{ThreeBlendingMode as Z}from"./vfx-asset.js";import{VfxBehaviourLibrary as $,VfxInitializserLibrary as ee}from"./vfx-defs.js";import{MultiRenderer as te}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ae}from"./vfx-collision-behaviour.js";import{getSpritePosition as re,SpriteNodeShaderMaterial as se}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ie}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as ne}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as oe,createBoundInitializer as le}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as ce}from"../../shader/graph/index.js";export async function materializeVfx(t,a,r,s,o,l,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 te(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 pe(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(),d.removeFromParent(),f.dispose()}}}async function pe(e,t,r,p,v,x,P,T,D){const V=function(e){let t;switch(e.rate.type){case"continuous":t=new _(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new K(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 F;switch(e.output.type){case"decal":F=new a(await async function(e,t,a,r,s){if("shaderGraph"===me(e)){const t=await de(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return ye(a,e),a}}const n=!1!==e.unlit?new ie:new ne;n.color=new i.Color(e.color),n instanceof ie?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=Z[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 ye(c,e),c}(e.output,t,r,p,P));break;case"sprite":F=new a(await async function(e,t,a,r,s){let n=null;const o=me(e);"shaderGraph"===o&&(n=await de(e,"sprite",a,r,s));null==n&&"shader"===o&&null!=e.shader&&(n=await he(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):ue,r=C(a);let s=r.sample(j.uv);e.flipbook?.enabled&&(s=N(r,w.uv,e.flipbook.columns,e.flipbook.rows,q.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),o=new h("color").rgb,l=R("opacity",1),c=Q.subtract(W).divide(Q);let p=l;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=b(c,0,1e3);p=p.multiply(I(0,.2*e.softness,t))}const d=re(n),m=S(o.multiply(s.rgb).multiplyScalar(e.intensity??1),p);var f=new se({color:m,emissive:m.rgb.multiplyScalar(p),transparent:!0,position:d,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});f.alphaHash=!0,null!=f&&!0===e.bloom&&(f.userData.hasBloom=!0);return f.blending=Z[e.blendingMode]??i.NormalBlending,f}(e,t));fe(n,e);const l=new i.Mesh(new i.PlaneGeometry(1,1),n);return l.name="sprite",ye(l,e),l}(e.output,t,r,p,P));break;case"stretchedSprite":F=new a(await async function(e,t){"shaderGraph"===me(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):ue,r=C(a).sample(j.uv),s=G(new l("color")),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(W).divide(M(Q)),a=b(t,0,1e3);o=o.multiply(I(0,.2*e.softness,a))}const c=E(m,{position:w.position,offset:y("offset"),modelViewMatrix:B.modelViewMatrix,velocity:g("velocity"),size:y("size"),rotation:f("rotation")},"\n float lengthFactor = velocity.w;\n float avgSize = (size.x + size.y) * 0.5;\n\n vec4 mvPosition = modelViewMatrix * vec4( offset , 1.0 );\n vec3 viewVelocity = normalMatrix * velocity.xyz;\n float vlength = length(viewVelocity); \n mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, viewVelocity)) * avgSize; \n mvPosition.xyz -= (position.x + 0.5) * viewVelocity * (1.0 + lengthFactor / vlength) * avgSize;\n return projectionMatrix * mvPosition;\n ");var p=new se({color:S(n.multiplyScalar(e.intensity??1),o),alphaTest:.1,transparent:!0,position:c,uniforms:{color:{value:new i.Color(e.color)}}});null!=p&&!0===e.bloom&&(p.userData.hasBloom=!0);p.blending=Z[e.blendingMode]??i.NormalBlending;const u=new Y(new i.PlaneGeometry(1,1),p);return u.scaleFactor=e.scale,ye(u,e),u}(e.output,t));break;case"shape":F=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const l=O[e.shape];if(null==l)return console.error(`No shape with type ${e.shape}`),new n;const p=z(e.params??{}),u=l.geometry(p);let h=null;const m=me(e);"shaderGraph"===m&&(h=await de(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await he(e,t,s));null==h&&(h="material"===m&&null!=e.material?ge(await t.getMaterial(e.material)):function(){const e=k(new d("instanceColor")).rgb,t=k(new o("particleData")).x;return new c({color:A({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());fe(h,e);const f=new i.Mesh(u,h);return ye(f,e),f}(e.output,t,r,p,P));break;case"mesh":F=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=me(e);if("shaderGraph"===c||"shader"===c||"material"===c){let n;"shaderGraph"===c?n=await de(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await he(e,t,s):"material"===c&&null!=e.material&&(n=ge(await t.getMaterial(e.material))),fe(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)}),ye(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,P));break;case"trail":{const s="shaderGraph"===me(e.output)?await de(e.output,"trail",r,p,P,{trailBillboard:e.output.billboard??!1}):null;F=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 H=new be(D);H.parent=v,H.setRate(V),H._space=e.output.space;const U=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=ee[e.type]).map(async e=>{const t=ee[e.type],a=await z(e.params??{});return le(t,e.params??{},a,T)}));U.push(F,new X),H.addInitializers(U);const J=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=$[e.type]).map(async e=>{const t=$[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==L.Curve&&(r.type=L.Curve);const a=await z(e.params??{},r,p);return oe(t,e.params??{},a,T)}).sort((e,t)=>e instanceof ae?1:0));J.push(new we);for(const e of J)e instanceof ae&&(e.physics=x);H.addBehaviours(J);for(const a of e.children??[]){const e=await pe(a,t,r,p,v,x,P,T,D),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=H.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&H.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=H.eventDispatcher,n=new Map;H.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(H.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(),H.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=H.system,t.emit()})}return H}const ue=(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 he(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,n=await V(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 de(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 F(e.shaderGraphParams??{},l,a,r,void 0,s.shaders),o=ce(l,{parameters:t,trailBillboard:i.trailBillboard});return o.userData.customShaderName=`shaderGraph:${n.assetId}`,fe(o,e),o}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}function me(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 fe(e,t){null!=e&&("bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=Z[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=Z[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 ye(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function ge(e){const t=k(new d("instanceColor")).rgb;let a,r=k(new o("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(P(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(j.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(j.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:P(e.emissive),emissiveIntensity:v(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:A({color:s}).rgb.rgba(r),emissive:P(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 we 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[H]||null!=t.uniforms[U]||t.uniforms[J])}})}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;a instanceof c&&(null!=a.uniforms[H]&&(a.uniforms[H].value=this.energy),null!=a.uniforms[U]&&(a.uniforms[U].value=e.age),null!=a.uniforms[J]&&(a.uniforms[J].value=e.velocity))}})}}class be 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?(ve.copy(t),"local"===a&&"world"===r?ve.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Ee.copy(this.transformRoot.matrixWorld).invert(),ve.applyMatrix4(Ee)),e.position.copy(ve)):e.position.copy(t)}clone(){const e=new be(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 ve=new i.Vector3,Ee=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 o,AttributeVec4Node as l,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as h,Vec3ExpressionNode as d,Vec4Node as m,attributeFloat as f,attributeVec3 as y,attributeVec4 as w,attributes as g,clamp as b,float as v,glslFunction as E,lambertMaterial as A,log as M,pow as x,rgb as P,rgba as S,smoothstep as I,standardMaterial as T,textureSampler2d as C,uniformFloat as R,uniforms as B,varying as k,varyingAttributes as j,varyingVec3 as D,varyingVec4 as G}from"three-shader-graph";import{prepareClassParameters as V,prepareShaderGraphParameters as F,prepareShapeParameters as z}from"../../scene/materializer.js";import{SerializedParamType as L}from"../../scene/model.js";import{ShapeLibrary as O}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as W,linearEyeDepth as Q}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as H,particleTimeUniformName as U,particleUniforms as q,particleVelcoityUniformName as J}from"../../shader-nodes/particle.js";import{sampleFlipbook as N}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as X,WorldSpaceEmitterRotationInitializer as _}from"./initializsers.js";import{DelayRate as K,OnceRate as Y}from"./rates.js";import{StretchedSprite as Z}from"./stretched-sprite.js";import{ThreeBlendingMode as $}from"./vfx-asset.js";import{VfxBehaviourLibrary as ee,VfxInitializserLibrary as te}from"./vfx-defs.js";import{MultiRenderer as ae}from"./vfx-renderers.js";import{WorldCollisionBehaviour as re}from"./vfx-collision-behaviour.js";import{getSpritePosition as se,SpriteNodeShaderMaterial as ie}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ne}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as oe}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as le,createBoundInitializer as ce}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as pe}from"../../shader/graph/index.js";export async function materializeVfx(t,a,r,s,o,l,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 ae(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 ue(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(),d.removeFromParent(),f.dispose()}}}async function ue(e,t,r,p,v,x,P,T,D){const V=function(e){let t;switch(e.rate.type){case"continuous":t=new K(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new Y(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 F;switch(e.output.type){case"decal":F=new a(await async function(e,t,a,r,s){if("shaderGraph"===fe(e)){const t=await me(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return we(a,e),a}}const n=!1!==e.unlit?new ne:new oe;n.color=new i.Color(e.color),n instanceof ne?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=$[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 we(c,e),c}(e.output,t,r,p,P));break;case"sprite":F=new a(await async function(e,t,a,r,s){let n=null;const o=fe(e);"shaderGraph"===o&&(n=await me(e,"sprite",a,r,s));null==n&&"shader"===o&&null!=e.shader&&(n=await de(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):he,r=C(a);let s=r.sample(j.uv);e.flipbook?.enabled&&(s=N(r,g.uv,e.flipbook.columns,e.flipbook.rows,q.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),o=new h("color").rgb,l=R("opacity",1),c=Q.subtract(W).divide(Q);let p=l;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=b(c,0,1e3);p=p.multiply(I(0,.2*e.softness,t))}const d=se(n),m=S(o.multiply(s.rgb).multiplyScalar(e.intensity??1),p);var f=new ie({color:m,emissive:m.rgb.multiplyScalar(p),transparent:!0,position:d,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});f.alphaHash=!0,null!=f&&!0===e.bloom&&(f.userData.hasBloom=!0);return f.blending=$[e.blendingMode]??i.NormalBlending,f}(e,t));ye(n,e);const l=new i.Mesh(new i.PlaneGeometry(1,1),n);return l.name="sprite",we(l,e),l}(e.output,t,r,p,P));break;case"stretchedSprite":F=new a(await async function(e,t){"shaderGraph"===fe(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):he,r=C(a).sample(j.uv),s=G(new l("color")),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(W).divide(M(Q)),a=b(t,0,1e3);o=o.multiply(I(0,.2*e.softness,a))}const c=E(m,{position:g.position,offset:y("offset"),modelViewMatrix:B.modelViewMatrix,velocity:w("velocity"),size:y("size"),rotation:f("rotation")},"\n float lengthFactor = velocity.w;\n float avgSize = (size.x + size.y) * 0.5;\n\n vec4 mvPosition = modelViewMatrix * vec4( offset , 1.0 );\n vec3 viewVelocity = normalMatrix * velocity.xyz;\n float vlength = length(viewVelocity); \n mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, viewVelocity)) * avgSize; \n mvPosition.xyz -= (position.x + 0.5) * viewVelocity * (1.0 + lengthFactor / vlength) * avgSize;\n return projectionMatrix * mvPosition;\n ");var p=new ie({color:S(n.multiplyScalar(e.intensity??1),o),alphaTest:.1,transparent:!0,position:c,uniforms:{color:{value:new i.Color(e.color)}}});null!=p&&!0===e.bloom&&(p.userData.hasBloom=!0);p.blending=$[e.blendingMode]??i.NormalBlending;const u=new Z(new i.PlaneGeometry(1,1),p);return u.scaleFactor=e.scale,we(u,e),u}(e.output,t));break;case"shape":F=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const l=O[e.shape];if(null==l)return console.error(`No shape with type ${e.shape}`),new n;const p=z(e.params??{}),u=l.geometry(p);let h=null;const m=fe(e);"shaderGraph"===m&&(h=await me(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await de(e,t,s));null==h&&(h="material"===m&&null!=e.material?ge(await t.getMaterial(e.material)):function(){const e=k(new d("instanceColor")).rgb,t=k(new o("particleData")).x;return new c({color:A({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());ye(h,e);const f=new i.Mesh(u,h);return we(f,e),f}(e.output,t,r,p,P));break;case"mesh":F=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=fe(e);if("shaderGraph"===c||"shader"===c||"material"===c){let n;"shaderGraph"===c?n=await me(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await de(e,t,s):"material"===c&&null!=e.material&&(n=ge(await t.getMaterial(e.material))),ye(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)}),we(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,P));break;case"trail":{const s="shaderGraph"===fe(e.output)?await me(e.output,"trail",r,p,P,{trailBillboard:e.output.billboard??!1}):null;F=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 H=new ve(D);H.parent=v,H.setRate(V),H._space=e.output.space;const U=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=te[e.type]).map(async e=>{const t=te[e.type],a=await z(e.params??{});return ce(t,e.params??{},a,T)}));"world"!==e.output.space||"shape"!==e.output.type&&"mesh"!==e.output.type||U.unshift(new _),U.push(F,new X),H.addInitializers(U);const J=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=ee[e.type]).map(async e=>{const t=ee[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==L.Curve&&(r.type=L.Curve);const a=await z(e.params??{},r,p);return le(t,e.params??{},a,T)}).sort((e,t)=>e instanceof re?1:0));J.push(new be);for(const e of J)e instanceof re&&(e.physics=x);H.addBehaviours(J);for(const a of e.children??[]){const e=await ue(a,t,r,p,v,x,P,T,D),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=H.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&H.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=H.eventDispatcher,n=new Map;H.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(H.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(),H.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=H.system,t.emit()})}return H}const he=(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 de(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,n=await V(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 me(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 F(e.shaderGraphParams??{},l,a,r,void 0,s.shaders),o=pe(l,{parameters:t,trailBillboard:i.trailBillboard});return o.userData.customShaderName=`shaderGraph:${n.assetId}`,ye(o,e),o}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}function fe(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 ye(e,t){null!=e&&("bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=$[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=$[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 we(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function ge(e){const t=k(new d("instanceColor")).rgb;let a,r=k(new o("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(P(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(j.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(j.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:P(e.emissive),emissiveIntensity:v(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:A({color:s}).rgb.rgba(r),emissive:P(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 be 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[H]||null!=t.uniforms[U]||t.uniforms[J])}})}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;a instanceof c&&(null!=a.uniforms[H]&&(a.uniforms[H].value=this.energy),null!=a.uniforms[U]&&(a.uniforms[U].value=e.age),null!=a.uniforms[J]&&(a.uniforms[J].value=e.velocity))}})}}class ve 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?(Ee.copy(t),"local"===a&&"world"===r?Ee.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Ae.copy(this.transformRoot.matrixWorld).invert(),Ee.applyMatrix4(Ae)),e.position.copy(Ee)):e.position.copy(t)}clone(){const e=new ve(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 Ee=new i.Vector3,Ae=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
|
*/
|
|
@@ -37,6 +37,12 @@ export declare abstract class BaseActor {
|
|
|
37
37
|
onInit(): Promise<void> | void;
|
|
38
38
|
onBeginPlay(): void;
|
|
39
39
|
onEndPlay(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Applies saved authoring parameter changes without recreating the actor.
|
|
42
|
+
* Return true only when every supplied change was applied. Returning false
|
|
43
|
+
* means unsupported and must leave the actor unchanged.
|
|
44
|
+
*/
|
|
45
|
+
applySceneParameters(parameters: Record<string, unknown>, changedParameters: ReadonlySet<string>): boolean | Promise<boolean>;
|
|
40
46
|
/**
|
|
41
47
|
* Code that has to run before every rendered frame. This will run after the
|
|
42
48
|
* actor's onInit method has run.
|
|
@@ -7,6 +7,12 @@ export declare abstract class ActorComponent<ActorType extends BaseActor = BaseA
|
|
|
7
7
|
onInit(): Promise<void> | void;
|
|
8
8
|
onBeginPlay(): void;
|
|
9
9
|
onEndPlay(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Applies saved authoring parameter changes without recreating the owning
|
|
12
|
+
* actor. Return true only when every supplied change was applied. Returning
|
|
13
|
+
* false means unsupported and must leave the component unchanged.
|
|
14
|
+
*/
|
|
15
|
+
applySceneParameters(parameters: Record<string, unknown>, changedParameters: ReadonlySet<string>): boolean | Promise<boolean>;
|
|
10
16
|
/**
|
|
11
17
|
* Code that has to run before every rendered frame. This will run after the
|
|
12
18
|
* actor's onInit method has run.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{AnimationClip as e,AnimationMixer as n,Bone as t,LoopOnce as o,Matrix4 as r,Quaternion as i,QuaternionKeyframeTrack as a,Skeleton as s,SkinnedMesh as l,Vector3 as u,VectorKeyframeTrack as c}from"three";import*as d from"three/addons/utils/SkeletonUtils.js";export const ANIMATION_RETARGET_GENERATOR_VERSION=9;export function resolveAnimationRigBasisRotation(e){const n=e.basisPreset??"yUp";let t;t="custom"===n&&null!=e.basisRotation?(new i).fromArray(e.basisRotation).normalize():"yUp"===n?new i:"unrealZUp"===n?(new i).setFromAxisAngle(new u(1,0,0),-Math.PI/2):detectAnimationRigBasisRotation(e);const o=(e.basisYawDegrees??0)*Math.PI/180;return(new i).setFromAxisAngle(new u(0,1,0),o).multiply(t).normalize()}export function detectAnimationRigBasisRotation(e){const n=x(e,{}),t=e.bones.findIndex(n=>n.id===e.pelvisBoneId),o=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),r=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);let a=new u;if(o>=0&&r.length>0){const e=r.reduce((e,t)=>e.add(n.worldPositions[t]),new u).multiplyScalar(1/r.length);a.copy(n.worldPositions[o]).sub(e)}else t>=0&&o>=0&&a.copy(n.worldPositions[o]).sub(n.worldPositions[t]);if(a.lengthSq()<1e-8)return new i;a.normalize();const s=[new u(Math.sign(a.x)||1,0,0),new u(0,Math.sign(a.y)||1,0),new u(0,0,Math.sign(a.z)||1)].sort((e,n)=>Math.abs(n.dot(a))-Math.abs(e.dot(a)))[0];return(new i).setFromUnitVectors(s,new u(0,1,0))}export function extractAnimationRigs(e){const n=[],o=new Set,r=new Set;e.updateMatrixWorld(!0),e.traverse(e=>{if($(e)){for(const n of e.skeleton.bones)r.add(n);o.has(e.skeleton)||(o.add(e.skeleton),n.push({name:e.name,mesh:e,skeleton:e.skeleton}))}}),e.traverse(e=>{if(!(e instanceof t)||e.parent instanceof t)return;const o=[];e.traverse(e=>{e instanceof t&&!r.has(e)&&o.push(e)}),0!==o.length&&n.push({name:e.name,skeleton:new s(o)})});const i=new Map;for(const e of n){const n=f(e.skeleton),t=m(e.skeleton);i.set(n,Math.min(i.get(n)??Number.POSITIVE_INFINITY,t))}const a=[],l=[],u=[];for(const{name:e,mesh:t,skeleton:o}of n){const n=m(o);if(n>(i.get(f(o))??n))continue;const r=g(t,o),s=a.findIndex(e=>e.topologyFingerprint===r.topologyFingerprint&&e.bindPoseFingerprint===r.bindPoseFingerprint);s>=0?n<u[s]&&(a[s]=r,l[s]=e,u[s]=n):(a.push(r),l.push(e),u.push(n))}return{rigs:a,skinnedMeshNames:l}}export function areAnimationRigsCompatible(e,n){return e.topologyFingerprint===n.topologyFingerprint&&e.bindPoseFingerprint===n.bindPoseFingerprint}export function validateAnimationRig(e){const n=[],t=new Set(e.bones.map(e=>e.id)),o=new Map;for(const n of e.bones)o.set(n.name,(o.get(n.name)??0)+1);const r=[...o].filter(([,e])=>e>1).map(([e])=>e);r.length>0&&n.push({severity:"error",code:"duplicate-bone-names",message:`Bone names must be unique for animation tracks. Duplicates: ${r.join(", ")}`});for(const o of e.chains)t.has(o.startBoneId)&&t.has(o.endBoneId)?0===v(e,o).length&&n.push({severity:"error",code:"invalid-chain-hierarchy",message:`Chain "${o.name}" does not follow a parent-to-child hierarchy.`}):n.push({severity:"error",code:"invalid-chain-bone",message:`Chain "${o.name}" references a missing start or end bone.`});return null!=e.retargetRootBoneId&&t.has(e.retargetRootBoneId)||n.push({severity:"error",code:"missing-retarget-root",message:"Select a valid retarget root bone."}),null!=e.pelvisBoneId&&t.has(e.pelvisBoneId)||n.push({severity:"warning",code:"missing-pelvis",message:"Select a pelvis bone for reliable root-motion and height scaling."}),n}export function validateAnimationRetargeter(e,n,t){const o=[...validateAnimationRig(n).map(e=>({...e,message:`Source rig: ${e.message}`})),...validateAnimationRig(t).map(e=>({...e,message:`Target rig: ${e.message}`}))];e.sourceRigFingerprint?.topology===n.topologyFingerprint&&e.sourceRigFingerprint?.bindPose===n.bindPoseFingerprint||o.push({severity:"error",code:"source-rig-changed",message:"The source rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."}),e.targetRigFingerprint?.topology===t.topologyFingerprint&&e.targetRigFingerprint?.bindPose===t.bindPoseFingerprint||o.push({severity:"error",code:"target-rig-changed",message:"The target rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."});for(const r of e.chainMappings)!1!==r.enabled&&(n.chains.some(e=>e.id===r.sourceChainId)||o.push({severity:"error",code:"missing-source-chain",message:`Mapped source chain "${r.sourceChainId}" no longer exists.`}),t.chains.some(e=>e.id===r.targetChainId)||o.push({severity:"error",code:"missing-target-chain",message:`Mapped target chain "${r.targetChainId}" no longer exists.`}));return o}export function createDefaultAnimationRetargeter(e,n,t,o){const r=new Map(o.chains.map(e=>[e.role,e])),i=t.chains.flatMap(e=>{const n=r.get(e.role);return null==n?[]:[{sourceChainId:e.id,targetChainId:n.id,enabled:!0,rotationMode:"interpolated",translationMode:"root"===e.role?"scaled":"none"}]});return{version:1,solverVersion:9,sourceRigId:e,targetRigId:n,sourceRigFingerprint:{topology:t.topologyFingerprint,bindPose:t.bindPoseFingerprint},targetRigFingerprint:{topology:o.topologyFingerprint,bindPose:o.bindPoseFingerprint},sourcePoseId:t.defaultPoseId,targetPoseId:o.defaultPoseId,chainMappings:i,rootSettings:{scaleTranslation:!0,translationAxes:[!0,!0,!0],translationAxisMap:[1,2,3],scaleMultiplier:1},bakeSettings:{framesPerSecond:60},generatedOutputs:{}}}export function createAutoAlignedRetargetPose(e,n,t,o="auto-aligned",r="Auto Aligned"){const a=P(e,t.sourcePoseId),s=P(n,t.targetPoseId),l={...s?.rotationOffsets??{}},u=R(e,a?.rotationOffsets??{}),c=h(e,n,t),d=new Map(e.bones.map((e,n)=>[e.name,n]));new Map(n.bones.map((e,n)=>[e.name,n]));let p=R(n,l);for(let e=0;e<n.bones.length;e++){const t=n.bones[e],o=c[t.name],r=null==o?null:d.get(o);if(null==r)continue;const a=n.bones.map((e,n)=>({bone:e,index:n})).filter(n=>n.bone.parentIndex===e&&null!=c[n.bone.name]);if(1!==a.length)continue;const s=a[0],g=c[s.bone.name],m=null==g?null:d.get(g);if(null==m)continue;const f=u.worldPositions[m].clone().sub(u.worldPositions[r]),h=p.worldPositions[s.index].clone().sub(p.worldPositions[e]);if(f.lengthSq()<1e-8||h.lengthSq()<1e-8)continue;f.normalize(),h.normalize();const w=(new i).setFromUnitVectors(h,f).multiply(p.worldQuaternions[e]),b=(t.parentIndex>=0?p.worldQuaternions[t.parentIndex].clone().invert():new i).multiply(w);l[t.id]=(new i).fromArray(t.quaternion).invert().multiply(b).normalize().toArray(),p=R(n,l)}return{id:o,name:r,rotationOffsets:l,rootOffset:null==s?.rootOffset?void 0:[...s.rootOffset]}}export function bakeRetargetedAnimationClip(r){const p=validateAnimationRetargeter(r.retargeter,r.sourceRig,r.targetRig).filter(e=>"error"===e.severity);if(p.length>0)throw new Error(p.map(e=>e.message).join(" "));const g=S(r.sourceObject,r.sourceRig),m=S(r.targetObject,r.targetRig);if(null==g)throw new Error("The source model does not contain a skinned mesh.");if(null==m)throw new Error("The target model does not contain a skinned mesh.");r.sourceObject.updateMatrixWorld(!0);const f=F(r.sourceRig,r.sourceRig.retargetRootBoneId)??g.skeleton.bones[0]?.name;if(null==f)throw new Error("The source rig has no retarget root.");const w=g.skeleton.getBoneByName(f),b=w?.parent?.getWorldQuaternion(new i)??new i,y=function(e){const n=new l;n.name="RetargetSourceRig";const o=e.bones.map(e=>{const n=new t;return n.name=e.name,n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale),n});for(let t=0;t<o.length;t++){const r=e.bones[t].parentIndex;r>=0?o[r].add(o[t]):n.add(o[t])}return n.bind(new s(o)),n}(r.sourceRig),I=y,x=d.clone(r.targetObject);I.quaternion.copy(resolveAnimationRigBasisRotation(r.sourceRig)).multiply(b),x.quaternion.premultiply(resolveAnimationRigBasisRotation(r.targetRig)),I.updateMatrixWorld(!0),x.updateMatrixWorld(!0);const R=S(x,r.targetRig);if(null==R)throw new Error("Failed to clone the target skeleton.");A(y,r.sourceRig,P(r.sourceRig,r.retargeter.sourcePoseId)),A(R,r.targetRig,P(r.targetRig,r.retargeter.targetPoseId));const v=h(r.sourceRig,r.targetRig,r.retargeter),$=function(t,r,s,l,u,c,d){const p=P(s,u.sourcePoseId),g=P(l,u.targetPoseId),m=new Map(t.skeleton.bones.map(e=>[e.name,e]));A(t,s,p),A(r,l,g);const f=new Map;for(const e of t.skeleton.bones)f.set(e.name,e.getWorldQuaternion(new i));const h=new Map,w=new Map;for(const e of r.skeleton.bones)h.set(e.name,e.getWorldQuaternion(new i)),w.set(e.name,{position:e.position.clone(),quaternion:e.quaternion.clone(),scale:e.scale.clone()});const b=r.skeleton.bones.flatMap(e=>{const n=d[e.name],t=null==n?null:m.get(n),o=null==n?null:f.get(n),r=h.get(e.name);return null==t||null==o||null==r?[]:[{targetBone:e,sourceBone:t,sourceReference:o,targetReference:r,times:[],values:[],previous:null}]}),y=Math.max(60,u.bakeSettings.framesPerSecond),I=Math.max(1,Math.ceil(c.duration*y)),x=I+1,R=new n(t),v=R.clipAction(c);v.setLoop(o,1),v.clampWhenFinished=!0,v.play();const k=new i,F=new i,S=new i,$=new i,O=new i;for(let e=0;e<x;e++){const n=c.duration*e/I;M(t,s),R.setTime(n),B(t,s,p),t.updateMatrixWorld(!0);for(const e of r.skeleton.bones){const n=w.get(e.name);null!=n&&(e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.scale.copy(n.scale))}r.updateMatrixWorld(!0);for(const e of b)e.sourceBone.getWorldQuaternion(F),k.copy(F).multiply($.copy(e.sourceReference).invert()),S.copy(k).multiply(e.targetReference),null!=e.targetBone.parent?(e.targetBone.parent.getWorldQuaternion($).invert(),O.copy($).multiply(S)):O.copy(S),O.normalize(),null!=e.previous&&e.previous.dot(O)<0&&O.set(-O.x,-O.y,-O.z,-O.w),e.targetBone.quaternion.copy(O),e.targetBone.updateMatrixWorld(!0),e.times.push(n),e.values.push(O.x,O.y,O.z,O.w),e.previous??(e.previous=new i),e.previous.copy(O)}return R.stopAllAction(),R.uncacheRoot(t),new e(c.name,c.duration,b.map(e=>new a(`.bones[${e.targetBone.name}].quaternion`,e.times,e.values)))}(y,R,r.sourceRig,r.targetRig,r.retargeter,r.clip,v),O=F(r.targetRig,r.targetRig.retargetRootBoneId);return null!=O&&function(e,n,t,o,r,a,s,l,d){const p=e.tracks.find(e=>e instanceof c&&z(e.name,t)),g=F(r,r.pelvisBoneId),m=F(a,a.pelvisBoneId),f=null==g||g===t?void 0:e.tracks.find(e=>e instanceof c&&z(e.name,g));if(null==p&&null==f)return;const h=k(r),w=k(a),b=s.rootSettings.scaleTranslation&&h>0?w/h*s.rootSettings.scaleMultiplier:s.rootSettings.scaleMultiplier,y=Math.max(60,s.bakeSettings.framesPerSecond),I=Math.max(2,Math.ceil(e.duration*y)+1),x=new Float32Array(I),R=p?.createInterpolant(),v=null==R?null:Float32Array.from(R.evaluate(0)),M=f?.createInterpolant();A(l,r,P(r,s.sourcePoseId)),A(d,a,P(a,s.targetPoseId));const B=l.skeleton.getBoneByName(t),S=d.skeleton.getBoneByName(o),$=B?.parent?.getWorldQuaternion(new i)??new i,O=(S?.parent?.getWorldQuaternion(new i)??new i).invert(),q=null==g?void 0:l.skeleton.getBoneByName(g),C=null==m?void 0:d.skeleton.getBoneByName(m),N=q?.parent?.getWorldQuaternion(new i)??new i,W=(C?.parent?.getWorldQuaternion(new i)??new i).invert(),T=P(a,s.targetPoseId)?.rootOffset??[0,0,0],Q=a.bones.find(e=>e.name===o),E=(Q?.position??[0,0,0]).map((e,n)=>e+T[n]),j=null==m?void 0:a.bones.find(e=>e.name===m),D=m===o?E:j?.position??[0,0,0],L=null!=p||null!=f&&m===o?new Float32Array(3*I):null,_=null!=f&&null!=m&&m!==o?new Float32Array(3*I):null,U=new u,G=new u,H=new u,V=new u,Y=(e,n,t)=>{G.copy(e).applyQuaternion(n),H.set(0,0,0);for(let e=0;e<3;e++)if(s.rootSettings.translationAxes[e]){const n=s.rootSettings.translationAxisMap?.[e]??e+1,t=Math.max(0,Math.min(2,Math.abs(n)-1));H.setComponent(e,G.getComponent(t)*Math.sign(n||1))}return V.copy(H).applyQuaternion(t).multiplyScalar(b)};for(let n=0;n<I;n++){const t=Math.min(e.duration,n/y);if(x[n]=t,null!=L&&(L.set(E,3*n),null!=R&&null!=v)){const e=R.evaluate(t);U.set(e[0]-v[0],e[1]-v[1],e[2]-v[2]);const o=Y(U,$,O);L[3*n]+=o.x,L[3*n+1]+=o.y,L[3*n+2]+=o.z}if(null!=M&&null!=q&&null!=m){const e=M.evaluate(t);U.set(e[0]-q.position.x,e[1]-q.position.y,e[2]-q.position.z);const r=m===o,i=Y(U,N,r?O:W),a=r?L:_;null!=a&&(r||a.set(D,3*n),a[3*n]+=i.x,a[3*n+1]+=i.y,a[3*n+2]+=i.z)}}const Z=new Set([null==L?null:o,null==_?null:m].filter(e=>null!=e));n.tracks=n.tracks.filter(e=>!(e instanceof c&&[...Z].some(n=>z(e.name,n)))),null!=L&&n.tracks.push(new c(`.bones[${o}].position`,x,L));null!=_&&null!=m&&n.tracks.push(new c(`.bones[${m}].position`,x,_))}(r.clip,$,f,O,r.sourceRig,r.targetRig,r.retargeter,y,R),$.name=r.clip.name,$.optimize(),$}export function getAnimationRigIdFromObject(e){if(null==e)return;let n=e.userData?.animationRigId;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRigId)}),n}export function getAnimationRigDataFromObject(e){if(null==e)return;let n=e.userData?.animationRig;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRig)}),n}export function getAnimationRigChainBoneNames(e,n){if(null==e)return[];const t=e.chains.find(e=>e.role===n);return null==t?[]:v(e,t).map(e=>e.name)}export function getAnimationClipBoneNames(e){const n=new Set;for(const t of e.tracks){const e=t.name.match(/\.bones\[([^\]]+)\]\./);if(null!=e?.[1]){n.add(e[1]);continue}const o=t.name.lastIndexOf(".");o>0&&n.add(t.name.slice(0,o))}return[...n]}export function isAnimationClipCompatibleWithRig(e,n){const t=new Set(n.bones.map(e=>e.name));return getAnimationClipBoneNames(e).some(e=>t.has(e))}export function getAnimationClipRigId(e){return null==e?void 0:Q.get(e)}export function setAnimationClipRigId(e,n){null==n?Q.delete(e):Q.set(e,n)}export function findGeneratedAnimationOutput(e,n,t){for(const o of e){const r=o.animationRetargeter;if("animationRetargeter"===o.type&&r?.targetRigId===t&&null!=r.generatedOutputs[n]){const t=r.generatedOutputs[n];return e.find(e=>e.id===t)}}}export function resolveAnimationClipAssetForTarget(e,n,t){if(null==t||e.anim?.rigId===t)return e;if(null==e.anim?.rigId){const n=`${e.id}|${t}`;return p.has(n)||(p.add(n),console.warn(`Animation clip "${e.name}" (${e.id}) has no rig assigned, while the target uses rig ${t}. Playing the legacy source clip without rig compatibility validation.`)),e}const o=findGeneratedAnimationOutput(n,e.id,t);if(null==o)throw new Error(`Animation clip "${e.name}" (${e.id}) targets rig ${e.anim?.rigId??"unassigned"}, but the bound sequence actor uses rig ${t}. Generate this source/target output in an Animation Retargeter before playback.`);if(o.anim?.rigId!==t)throw new Error(`Generated animation clip "${o.name}" (${o.id}) is indexed for rig ${t}, but its clip metadata targets ${o.anim?.rigId??"no rig"}. Regenerate the output.`);return o}const p=new Set;function g(e,n){const o=new Map(n.bones.map((e,n)=>[e,n])),a=new Set(n.bones.filter(e=>function(e,n,o){const r=e.parent;if(!(r instanceof t&&r.name===e.name&&o.has(r)))return!1;if(e.position.lengthSq()>1e-12||Math.abs(e.quaternion.x)>1e-6||Math.abs(e.quaternion.y)>1e-6||Math.abs(e.quaternion.z)>1e-6||Math.abs(Math.abs(e.quaternion.w)-1)>1e-6||e.scale.distanceTo(new u(1,1,1))>1e-6)return!1;const i=n.boneInverses[o.get(e)],a=n.boneInverses[o.get(r)];return null!=i&&null!=a&&(s=i,l=a,s.elements.every((e,n)=>Math.abs(e-l.elements[n])<=1e-6));var s,l}(e,n,o))),s=n.bones.filter(e=>!a.has(e)),l=new Map(s.map((e,n)=>[e,n])),c=[];for(let e=0;e<s.length;e++){const a=s[e],d=o.get(a)??e;let p=a.parent;for(;p instanceof t&&!l.has(p);)p=p.parent;const g=p instanceof t?l.get(p)??-1:-1,m=a.name||`bone_${e}`,f=g<0?m:`${c[g].id}/${m}`,h=new u,w=new i,b=new u;a.matrix.decompose(h,w,b),c.push({id:f,name:m,parentIndex:g,position:h.toArray(),quaternion:w.toArray(),scale:b.toArray(),inverseBindMatrix:(n.boneInverses[d]??new r).toArray()})}const d=T(c.map(e=>[e.name,e.parentIndex])),p=T(c.map(e=>[e.name,e.parentIndex,...W(e.position),...W(e.quaternion),...W(e.scale),...W(e.inverseBindMatrix)])),g=function(e){const n=[{role:"spine",start:["spine"],end:["chest","spine2","spine_02","spine3"]},{role:"neck",start:["neck"],end:["head"]},{role:"leftArm",side:"left",start:["upperarm","arm"],end:["hand","wrist"]},{role:"rightArm",side:"right",start:["upperarm","arm"],end:["hand","wrist"]},{role:"leftLeg",side:"left",start:["upleg","thigh","upperleg"],end:["foot","ankle"]},{role:"rightLeg",side:"right",start:["upleg","thigh","upperleg"],end:["foot","ankle"]}],t=[];for(const o of n){const n=o.side?q(e,o.side,o.start):O(e,o.start),r=o.side?q(e,o.side,o.end):O(e,o.end);null!=n&&null!=r&&t.push({id:o.role,name:N(o.role),role:o.role,startBoneId:n.id,endBoneId:r.id})}return t}(c),m=O(c,["root","armature"]),f=O(c,["hips","hip","pelvis"]),h=q(c,"left",["hand","wrist"]),w=q(c,"right",["hand","wrist"]);return{version:1,basisPreset:"auto",basisYawDegrees:0,skinnedMeshName:e?.name||void 0,bones:c,topologyFingerprint:d,bindPoseFingerprint:p,retargetRootBoneId:m?.id??f?.id??c[0]?.id,pelvisBoneId:f?.id,leftHandBoneId:h?.id,rightHandBoneId:w?.id,chains:g,poses:[{id:"default",name:"Default",rotationOffsets:{}}],defaultPoseId:"default"}}function m(e){const n=new Set(e.bones);return e.bones.filter(e=>e.parent instanceof t&&!n.has(e.parent)).length}function f(e){return[...new Set(e.bones.map(e=>e.name))].sort().join("\n")}function h(e,n,t){const o={};for(const r of t.chainMappings){if(!1===r.enabled)continue;const t=e.chains.find(e=>e.id===r.sourceChainId),i=n.chains.find(e=>e.id===r.targetChainId);if(null==t||null==i)continue;const a=v(e,t),s=v(n,i);if(0!==a.length&&0!==s.length)for(let e=0;e<s.length;e++){const n=1===s.length?0:e/(s.length-1),t=Math.round(n*(a.length-1));o[s[e].name]=a[t].name}}return w(o,e,n,"retargetRootBoneId"),w(o,e,n,"pelvisBoneId"),w(o,e,n,"leftHandBoneId"),w(o,e,n,"rightHandBoneId"),b(o,e,n,"leftHandBoneId"),b(o,e,n,"rightHandBoneId"),o}function w(e,n,t,o){const r=F(n,n[o]),i=F(t,t[o]);null!=r&&null!=i&&(e[i]=r)}function b(e,n,t,o){const r=n.bones.findIndex(e=>e.id===n[o]),i=t.bones.findIndex(e=>e.id===t[o]);if(r<0||i<0)return;const a=new Map;for(const e of y(n,r)){const n=I(e.name);null!=n&&a.set(n,e)}for(const n of y(t,i)){const t=I(n.name),o=null==t?null:a.get(t);null!=o&&(e[n.name]=o.name)}}function y(e,n){return e.bones.filter((t,o)=>{let r=e.bones[o].parentIndex;for(;r>=0;){if(r===n)return!0;r=e.bones[r].parentIndex}return!1})}function I(e){const n=e.toLowerCase();if(n.includes("base"))return null;const t=["thumb","index","middle","ring","pinky"].find(e=>n.includes(e));if(null==t)return null;const o=n.slice(n.indexOf(t)+t.length),r=o.match(/\d+/)?.[0];return null==r?null:`${t}:${Number(r)}`}function x(e,n){const t=[],o=[],a=[];for(let s=0;s<e.bones.length;s++){const l=e.bones[s],c=(new i).fromArray(l.quaternion),d=n[l.id];null!=d&&c.multiply((new i).fromArray(d)).normalize();const p=(new r).compose((new u).fromArray(l.position),c,(new u).fromArray(l.scale));l.parentIndex>=0&&p.premultiply(t[l.parentIndex]),t.push(p),o.push((new u).setFromMatrixPosition(p)),a.push((new i).setFromRotationMatrix(p))}return{worldPositions:o,worldQuaternions:a}}function R(e,n){const t=x(e,n),o=resolveAnimationRigBasisRotation(e);for(const e of t.worldPositions)e.applyQuaternion(o);for(const e of t.worldQuaternions)e.premultiply(o);return t}function v(e,n){const t=e.bones.findIndex(e=>e.id===n.startBoneId),o=e.bones.findIndex(e=>e.id===n.endBoneId);if(t<0||o<0)return[];const r=[];let i=o;for(;i>=0;){if(r.push(e.bones[i]),i===t)return r.reverse();i=e.bones[i].parentIndex}return[]}function A(e,n,t){M(e,n),B(e,n,t),e.updateMatrixWorld(!0)}function M(e,n){const t=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const e of n.bones){const n=t.get(e.name);null!=n&&(n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale))}}function B(e,n,t){if(null==t)return;const o=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const[e,r]of Object.entries(t.rotationOffsets)){const t=n.bones.find(n=>n.id===e),a=null==t?void 0:o.get(t.name);null!=a&&a.quaternion.multiply((new i).fromArray(r)).normalize()}const r=F(n,n.retargetRootBoneId),a=null==r?void 0:o.get(r);null!=a&&null!=t.rootOffset&&a.position.add((new u).fromArray(t.rootOffset))}function k(e){const n=e.bones.map(()=>new r),t=e.bones.map(()=>new u);for(let o=0;o<e.bones.length;o++){const r=e.bones[o];n[o].compose((new u).fromArray(r.position),(new i).fromArray(r.quaternion),(new u).fromArray(r.scale)),r.parentIndex>=0&&n[o].premultiply(n[r.parentIndex]),t[o].setFromMatrixPosition(n[o])}const o=e.bones.findIndex(n=>n.id===e.pelvisBoneId),a=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),s=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);if(o>=0&&a>=0&&s.length>0){const e=t[o].distanceTo(t[a]),n=Math.max(...s.map(e=>t[o].distanceTo(t[e])));if(e+n>1e-4)return e+n}let l=0;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++)l=Math.max(l,t[e].distanceTo(t[n]));return Math.max(1e-4,l)}function P(e,n){return e.poses.find(e=>e.id===n)}function F(e,n){return null==n?void 0:e.bones.find(e=>e.id===n)?.name}function S(e,n){const t=[];if(e.traverse(e=>{$(e)&&t.push(e)}),null==n)return t[0];const o=null==n.skinnedMeshName?void 0:t.find(e=>e.name===n.skinnedMeshName);if(null!=o)return o;const r=t.map(e=>({candidate:e,rig:g(e,e.skeleton)}));return r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint&&e.rig.bindPoseFingerprint===n.bindPoseFingerprint)?.candidate??r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint)?.candidate??t[0]}function $(e){return e instanceof l||!0===e.isSkinnedMesh}function O(e,n){return e.find(e=>n.some(n=>C(e.name)===C(n)))??e.find(e=>n.some(n=>C(e.name).includes(C(n))))}function q(e,n,t){const o="left"===n?["left","_l",".l"]:["right","_r",".r"];return e.find(e=>{const n=e.name.toLowerCase(),r=C(n);return o.some(e=>n.includes(e))&&t.some(e=>r.includes(C(e)))})}function C(e){return e.toLowerCase().replace(/^mixamorig[:_]?/,"").replace(/^bip0*1[_:]?/,"").replace(/[^a-z0-9]/g,"")}function N(e){return e.replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,e=>e.toUpperCase())}function W(e){return e.map(e=>Math.round(1e5*e)/1e5)}function T(e){const n=JSON.stringify(e);let t=2166136261;for(let e=0;e<n.length;e++)t^=n.charCodeAt(e),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function z(e,n){return e===`${n}.position`||e===`.bones[${n}].position`||e.endsWith(`[${n}].position`)}const Q=new WeakMap;/*
|
|
1
|
+
import{AnimationClip as e,AnimationMixer as n,Bone as t,LoopOnce as o,Matrix4 as r,Quaternion as i,QuaternionKeyframeTrack as a,Skeleton as s,SkinnedMesh as l,Vector3 as u,VectorKeyframeTrack as c}from"three";import*as d from"three/addons/utils/SkeletonUtils.js";export const ANIMATION_RETARGET_GENERATOR_VERSION=9;export function resolveAnimationRigBasisRotation(e){const n=e.basisPreset??"yUp";let t;t="custom"===n&&null!=e.basisRotation?(new i).fromArray(e.basisRotation).normalize():"yUp"===n?new i:"unrealZUp"===n?(new i).setFromAxisAngle(new u(1,0,0),-Math.PI/2):detectAnimationRigBasisRotation(e);const o=(e.basisYawDegrees??0)*Math.PI/180;return(new i).setFromAxisAngle(new u(0,1,0),o).multiply(t).normalize()}export function detectAnimationRigBasisRotation(e){const n=R(e,{}),t=e.bones.findIndex(n=>n.id===e.pelvisBoneId),o=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),r=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);let a=new u;if(o>=0&&r.length>0){const e=r.reduce((e,t)=>e.add(n.worldPositions[t]),new u).multiplyScalar(1/r.length);a.copy(n.worldPositions[o]).sub(e)}else t>=0&&o>=0&&a.copy(n.worldPositions[o]).sub(n.worldPositions[t]);if(a.lengthSq()<1e-8)return new i;a.normalize();const s=[new u(Math.sign(a.x)||1,0,0),new u(0,Math.sign(a.y)||1,0),new u(0,0,Math.sign(a.z)||1)].sort((e,n)=>Math.abs(n.dot(a))-Math.abs(e.dot(a)))[0];return(new i).setFromUnitVectors(s,new u(0,1,0))}export function extractAnimationRigs(e){const n=[],o=new Set,r=new Set;e.updateMatrixWorld(!0),e.traverse(e=>{if(O(e)){for(const n of e.skeleton.bones)r.add(n);o.has(e.skeleton)||(o.add(e.skeleton),n.push({name:e.name,mesh:e,skeleton:e.skeleton}))}}),e.traverse(e=>{if(!(e instanceof t)||e.parent instanceof t)return;const o=[];e.traverse(e=>{e instanceof t&&!r.has(e)&&o.push(e)}),0!==o.length&&n.push({name:e.name,skeleton:new s(o)})});const i=new Map;for(const e of n){const n=f(e.skeleton),t=m(e.skeleton);i.set(n,Math.min(i.get(n)??Number.POSITIVE_INFINITY,t))}const a=[],l=[],u=[];for(const{name:e,mesh:t,skeleton:o}of n){const n=m(o);if(n>(i.get(f(o))??n))continue;const r=g(t,o),s=a.findIndex(e=>e.topologyFingerprint===r.topologyFingerprint&&e.bindPoseFingerprint===r.bindPoseFingerprint);s>=0?n<u[s]&&(a[s]=r,l[s]=e,u[s]=n):(a.push(r),l.push(e),u.push(n))}return{rigs:a,skinnedMeshNames:l}}export function areAnimationRigsCompatible(e,n){return e.topologyFingerprint===n.topologyFingerprint&&e.bindPoseFingerprint===n.bindPoseFingerprint}export function validateAnimationRig(e){const n=[],t=new Set(e.bones.map(e=>e.id)),o=new Map;for(const n of e.bones)o.set(n.name,(o.get(n.name)??0)+1);const r=[...o].filter(([,e])=>e>1).map(([e])=>e);r.length>0&&n.push({severity:"error",code:"duplicate-bone-names",message:`Bone names must be unique for animation tracks. Duplicates: ${r.join(", ")}`});for(const o of e.chains)t.has(o.startBoneId)&&t.has(o.endBoneId)?0===v(e,o).length&&n.push({severity:"error",code:"invalid-chain-hierarchy",message:`Chain "${o.name}" does not follow a parent-to-child hierarchy.`}):n.push({severity:"error",code:"invalid-chain-bone",message:`Chain "${o.name}" references a missing start or end bone.`});return null!=e.retargetRootBoneId&&t.has(e.retargetRootBoneId)||n.push({severity:"error",code:"missing-retarget-root",message:"Select a valid retarget root bone."}),null!=e.pelvisBoneId&&t.has(e.pelvisBoneId)||n.push({severity:"warning",code:"missing-pelvis",message:"Select a pelvis bone for reliable root-motion and height scaling."}),n}export function validateAnimationRetargeter(e,n,t){const o=[...validateAnimationRig(n).map(e=>({...e,message:`Source rig: ${e.message}`})),...validateAnimationRig(t).map(e=>({...e,message:`Target rig: ${e.message}`}))];e.sourceRigFingerprint?.topology===n.topologyFingerprint&&e.sourceRigFingerprint?.bindPose===n.bindPoseFingerprint||o.push({severity:"error",code:"source-rig-changed",message:"The source rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."}),e.targetRigFingerprint?.topology===t.topologyFingerprint&&e.targetRigFingerprint?.bindPose===t.bindPoseFingerprint||o.push({severity:"error",code:"target-rig-changed",message:"The target rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."});for(const r of e.chainMappings)!1!==r.enabled&&(n.chains.some(e=>e.id===r.sourceChainId)||o.push({severity:"error",code:"missing-source-chain",message:`Mapped source chain "${r.sourceChainId}" no longer exists.`}),t.chains.some(e=>e.id===r.targetChainId)||o.push({severity:"error",code:"missing-target-chain",message:`Mapped target chain "${r.targetChainId}" no longer exists.`}));return o}export function createDefaultAnimationRetargeter(e,n,t,o){const r=new Map(o.chains.map(e=>[e.role,e])),i=t.chains.flatMap(e=>{const n=r.get(e.role);return null==n?[]:[{sourceChainId:e.id,targetChainId:n.id,enabled:!0,rotationMode:"interpolated",translationMode:"root"===e.role?"scaled":"none"}]});return{version:1,solverVersion:9,sourceRigId:e,targetRigId:n,sourceRigFingerprint:{topology:t.topologyFingerprint,bindPose:t.bindPoseFingerprint},targetRigFingerprint:{topology:o.topologyFingerprint,bindPose:o.bindPoseFingerprint},sourcePoseId:t.defaultPoseId,targetPoseId:o.defaultPoseId,chainMappings:i,rootSettings:{scaleTranslation:!0,translationAxes:[!0,!0,!0],translationAxisMap:[1,2,3],scaleMultiplier:1},bakeSettings:{framesPerSecond:60},generatedOutputs:{}}}export function createAutoAlignedRetargetPose(e,n,t,o="auto-aligned",r="Auto Aligned"){const a=P(e,t.sourcePoseId),s=P(n,t.targetPoseId),l={...s?.rotationOffsets??{}},u=x(e,a?.rotationOffsets??{}),c=h(e,n,t),d=new Map(e.bones.map((e,n)=>[e.name,n]));new Map(n.bones.map((e,n)=>[e.name,n]));let p=x(n,l);for(let e=0;e<n.bones.length;e++){const t=n.bones[e],o=c[t.name],r=null==o?null:d.get(o);if(null==r)continue;const a=n.bones.map((e,n)=>({bone:e,index:n})).filter(n=>n.bone.parentIndex===e&&null!=c[n.bone.name]);if(1!==a.length)continue;const s=a[0],g=c[s.bone.name],m=null==g?null:d.get(g);if(null==m)continue;const f=u.worldPositions[m].clone().sub(u.worldPositions[r]),h=p.worldPositions[s.index].clone().sub(p.worldPositions[e]);if(f.lengthSq()<1e-8||h.lengthSq()<1e-8)continue;f.normalize(),h.normalize();const w=(new i).setFromUnitVectors(h,f).multiply(p.worldQuaternions[e]),b=p.parentWorldQuaternions[e].clone().invert().multiply(w);l[t.id]=(new i).fromArray(t.quaternion).invert().multiply(b).normalize().toArray(),p=x(n,l)}return{id:o,name:r,rotationOffsets:l,rootOffset:null==s?.rootOffset?void 0:[...s.rootOffset]}}export function bakeRetargetedAnimationClip(r){const p=validateAnimationRetargeter(r.retargeter,r.sourceRig,r.targetRig).filter(e=>"error"===e.severity);if(p.length>0)throw new Error(p.map(e=>e.message).join(" "));const g=S(r.sourceObject,r.sourceRig);if(null==S(r.targetObject,r.targetRig))throw new Error("The target model does not contain a skinned mesh.");r.sourceObject.updateMatrixWorld(!0);const m=F(r.sourceRig,r.sourceRig.retargetRootBoneId)??g?.skeleton.bones[0]?.name??r.sourceRig.bones.find(e=>e.parentIndex<0)?.name;if(null==m)throw new Error("The source rig has no retarget root.");const f=g?.skeleton.getBoneByName(m)??function(e,n,o){const r=[];if(e.traverse(e=>{e instanceof t&&e.name===o&&r.push(e)}),r.length<=1)return r[0];const i=new Set(n.bones.map(e=>e.name));return r.sort((e,n)=>$(n,i)-$(e,i))[0]}(r.sourceObject,r.sourceRig,m),w=f?.parent?.getWorldQuaternion(new i)??new i,b=function(e){const n=new l;n.name="RetargetSourceRig";const o=e.bones.map(e=>{const n=new t;return n.name=e.name,n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale),n});for(let t=0;t<o.length;t++){const r=e.bones[t].parentIndex;r>=0?o[r].add(o[t]):n.add(o[t])}return n.bind(new s(o)),n}(r.sourceRig),y=b,I=d.clone(r.targetObject);y.quaternion.copy(resolveAnimationRigBasisRotation(r.sourceRig)).multiply(w),I.quaternion.premultiply(resolveAnimationRigBasisRotation(r.targetRig)),y.updateMatrixWorld(!0),I.updateMatrixWorld(!0);const R=S(I,r.targetRig);if(null==R)throw new Error("Failed to clone the target skeleton.");A(b,r.sourceRig,P(r.sourceRig,r.retargeter.sourcePoseId)),A(R,r.targetRig,P(r.targetRig,r.retargeter.targetPoseId));const x=h(r.sourceRig,r.targetRig,r.retargeter),v=function(t,r,s,l,u,c,d){const p=P(s,u.sourcePoseId),g=P(l,u.targetPoseId),m=new Map(t.skeleton.bones.map(e=>[e.name,e]));A(t,s,p),A(r,l,g);const f=new Map;for(const e of t.skeleton.bones)f.set(e.name,e.getWorldQuaternion(new i));const h=new Map,w=new Map;for(const e of r.skeleton.bones)h.set(e.name,e.getWorldQuaternion(new i)),w.set(e.name,{position:e.position.clone(),quaternion:e.quaternion.clone(),scale:e.scale.clone()});const b=r.skeleton.bones.flatMap(e=>{const n=d[e.name],t=null==n?null:m.get(n),o=null==n?null:f.get(n),r=h.get(e.name);return null==t||null==o||null==r?[]:[{targetBone:e,sourceBone:t,sourceReference:o,targetReference:r,times:[],values:[],previous:null}]}),y=Math.max(60,u.bakeSettings.framesPerSecond),I=Math.max(1,Math.ceil(c.duration*y)),R=I+1,x=new n(t),v=x.clipAction(c);v.setLoop(o,1),v.clampWhenFinished=!0,v.play();const k=new i,F=new i,S=new i,$=new i,O=new i;for(let e=0;e<R;e++){const n=c.duration*e/I;M(t,s),x.setTime(n),B(t,s,p),t.updateMatrixWorld(!0);for(const e of r.skeleton.bones){const n=w.get(e.name);null!=n&&(e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.scale.copy(n.scale))}r.updateMatrixWorld(!0);for(const e of b)e.sourceBone.getWorldQuaternion(F),k.copy(F).multiply($.copy(e.sourceReference).invert()),S.copy(k).multiply(e.targetReference),null!=e.targetBone.parent?(e.targetBone.parent.getWorldQuaternion($).invert(),O.copy($).multiply(S)):O.copy(S),O.normalize(),null!=e.previous&&e.previous.dot(O)<0&&O.set(-O.x,-O.y,-O.z,-O.w),e.targetBone.quaternion.copy(O),e.targetBone.updateMatrixWorld(!0),e.times.push(n),e.values.push(O.x,O.y,O.z,O.w),e.previous??(e.previous=new i),e.previous.copy(O)}return x.stopAllAction(),x.uncacheRoot(t),new e(c.name,c.duration,b.map(e=>new a(`.bones[${e.targetBone.name}].quaternion`,e.times,e.values)))}(b,R,r.sourceRig,r.targetRig,r.retargeter,r.clip,x),O=F(r.targetRig,r.targetRig.retargetRootBoneId);return null!=O&&function(e,n,t,o,r,a,s,l,d){const p=e.tracks.find(e=>e instanceof c&&Q(e.name,t)),g=F(r,r.pelvisBoneId),m=F(a,a.pelvisBoneId),f=null==g||g===t?void 0:e.tracks.find(e=>e instanceof c&&Q(e.name,g));if(null==p&&null==f)return;const h=k(r),w=k(a),b=s.rootSettings.scaleTranslation&&h>0?w/h*s.rootSettings.scaleMultiplier:s.rootSettings.scaleMultiplier,y=Math.max(60,s.bakeSettings.framesPerSecond),I=Math.max(2,Math.ceil(e.duration*y)+1),R=new Float32Array(I),x=p?.createInterpolant(),v=null==x?null:Float32Array.from(x.evaluate(0)),M=f?.createInterpolant();A(l,r,P(r,s.sourcePoseId)),A(d,a,P(a,s.targetPoseId));const B=l.skeleton.getBoneByName(t),S=d.skeleton.getBoneByName(o),$=B?.parent?.getWorldQuaternion(new i)??new i,O=(S?.parent?.getWorldQuaternion(new i)??new i).invert(),q=null==g?void 0:l.skeleton.getBoneByName(g),C=null==m?void 0:d.skeleton.getBoneByName(m),W=q?.parent?.getWorldQuaternion(new i)??new i,N=(C?.parent?.getWorldQuaternion(new i)??new i).invert(),z=P(a,s.targetPoseId)?.rootOffset??[0,0,0],T=a.bones.find(e=>e.name===o),j=(T?.position??[0,0,0]).map((e,n)=>e+z[n]),E=null==m?void 0:a.bones.find(e=>e.name===m),D=m===o?j:E?.position??[0,0,0],L=null!=p||null!=f&&m===o?new Float32Array(3*I):null,_=null!=f&&null!=m&&m!==o?new Float32Array(3*I):null,U=new u,G=new u,H=new u,V=new u,Y=(e,n,t)=>{G.copy(e).applyQuaternion(n),H.set(0,0,0);for(let e=0;e<3;e++)if(s.rootSettings.translationAxes[e]){const n=s.rootSettings.translationAxisMap?.[e]??e+1,t=Math.max(0,Math.min(2,Math.abs(n)-1));H.setComponent(e,G.getComponent(t)*Math.sign(n||1))}return V.copy(H).applyQuaternion(t).multiplyScalar(b)};for(let n=0;n<I;n++){const t=Math.min(e.duration,n/y);if(R[n]=t,null!=L&&(L.set(j,3*n),null!=x&&null!=v)){const e=x.evaluate(t);U.set(e[0]-v[0],e[1]-v[1],e[2]-v[2]);const o=Y(U,$,O);L[3*n]+=o.x,L[3*n+1]+=o.y,L[3*n+2]+=o.z}if(null!=M&&null!=q&&null!=m){const e=M.evaluate(t);U.set(e[0]-q.position.x,e[1]-q.position.y,e[2]-q.position.z);const r=m===o,i=Y(U,W,r?O:N),a=r?L:_;null!=a&&(r||a.set(D,3*n),a[3*n]+=i.x,a[3*n+1]+=i.y,a[3*n+2]+=i.z)}}const Z=new Set([null==L?null:o,null==_?null:m].filter(e=>null!=e));n.tracks=n.tracks.filter(e=>!(e instanceof c&&[...Z].some(n=>Q(e.name,n)))),null!=L&&n.tracks.push(new c(`.bones[${o}].position`,R,L));null!=_&&null!=m&&n.tracks.push(new c(`.bones[${m}].position`,R,_))}(r.clip,v,m,O,r.sourceRig,r.targetRig,r.retargeter,b,R),v.name=r.clip.name,v.optimize(),v}export function getAnimationRigIdFromObject(e){if(null==e)return;let n=e.userData?.animationRigId;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRigId)}),n}export function getAnimationRigDataFromObject(e){if(null==e)return;let n=e.userData?.animationRig;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRig)}),n}export function getAnimationRigChainBoneNames(e,n){if(null==e)return[];const t=e.chains.find(e=>e.role===n);return null==t?[]:v(e,t).map(e=>e.name)}export function getAnimationClipBoneNames(e){const n=new Set;for(const t of e.tracks){const e=t.name.match(/\.bones\[([^\]]+)\]\./);if(null!=e?.[1]){n.add(e[1]);continue}const o=t.name.lastIndexOf(".");o>0&&n.add(t.name.slice(0,o))}return[...n]}export function isAnimationClipCompatibleWithRig(e,n){const t=new Set(n.bones.map(e=>e.name));return getAnimationClipBoneNames(e).some(e=>t.has(e))}export function getAnimationClipRigId(e){return null==e?void 0:j.get(e)}export function setAnimationClipRigId(e,n){null==n?j.delete(e):j.set(e,n)}export function findGeneratedAnimationOutput(e,n,t){for(const o of e){const r=o.animationRetargeter;if("animationRetargeter"===o.type&&r?.targetRigId===t&&null!=r.generatedOutputs[n]){const t=r.generatedOutputs[n];return e.find(e=>e.id===t)}}}export function resolveAnimationClipAssetForTarget(e,n,t){if(null==t||e.anim?.rigId===t)return e;if(null==e.anim?.rigId){const n=`${e.id}|${t}`;return p.has(n)||(p.add(n),console.warn(`Animation clip "${e.name}" (${e.id}) has no rig assigned, while the target uses rig ${t}. Playing the legacy source clip without rig compatibility validation.`)),e}const o=findGeneratedAnimationOutput(n,e.id,t);if(null==o)throw new Error(`Animation clip "${e.name}" (${e.id}) targets rig ${e.anim?.rigId??"unassigned"}, but the bound sequence actor uses rig ${t}. Generate this source/target output in an Animation Retargeter before playback.`);if(o.anim?.rigId!==t)throw new Error(`Generated animation clip "${o.name}" (${o.id}) is indexed for rig ${t}, but its clip metadata targets ${o.anim?.rigId??"no rig"}. Regenerate the output.`);return o}const p=new Set;function g(e,n){const o=new Map(n.bones.map((e,n)=>[e,n])),a=new Set(n.bones.filter(e=>function(e,n,o){const r=e.parent;if(!(r instanceof t&&r.name===e.name&&o.has(r)))return!1;if(e.position.lengthSq()>1e-12||Math.abs(e.quaternion.x)>1e-6||Math.abs(e.quaternion.y)>1e-6||Math.abs(e.quaternion.z)>1e-6||Math.abs(Math.abs(e.quaternion.w)-1)>1e-6||e.scale.distanceTo(new u(1,1,1))>1e-6)return!1;const i=n.boneInverses[o.get(e)],a=n.boneInverses[o.get(r)];return null!=i&&null!=a&&(s=i,l=a,s.elements.every((e,n)=>Math.abs(e-l.elements[n])<=1e-6));var s,l}(e,n,o))),s=n.bones.filter(e=>!a.has(e)),l=new Map(s.map((e,n)=>[e,n])),c=[];for(let e=0;e<s.length;e++){const a=s[e],d=o.get(a)??e;let p=a.parent;for(;p instanceof t&&!l.has(p);)p=p.parent;const g=p instanceof t?l.get(p)??-1:-1,m=a.name||`bone_${e}`,f=g<0?m:`${c[g].id}/${m}`,h=new u,w=new i,b=new u;a.matrix.decompose(h,w,b),c.push({id:f,name:m,parentIndex:g,position:h.toArray(),quaternion:w.toArray(),scale:b.toArray(),inverseBindMatrix:(n.boneInverses[d]??new r).toArray()})}const d=T(c.map(e=>[e.name,e.parentIndex])),p=T(c.map(e=>[e.name,e.parentIndex,...z(e.position),...z(e.quaternion),...z(e.scale),...z(e.inverseBindMatrix)])),g=function(e){const n=[{role:"spine",start:["spine"],end:["chest","spine2","spine_02","spine3"]},{role:"neck",start:["neck"],end:["head"]},{role:"leftArm",side:"left",start:["upperarm","arm"],end:["hand","wrist"]},{role:"rightArm",side:"right",start:["upperarm","arm"],end:["hand","wrist"]},{role:"leftLeg",side:"left",start:["upleg","thigh","upperleg"],end:["foot","ankle"]},{role:"rightLeg",side:"right",start:["upleg","thigh","upperleg"],end:["foot","ankle"]}],t=[];for(const o of n){const n=o.side?C(e,o.side,o.start):q(e,o.start),r=o.side?C(e,o.side,o.end):q(e,o.end);null!=n&&null!=r&&t.push({id:o.role,name:N(o.role),role:o.role,startBoneId:n.id,endBoneId:r.id})}return t}(c),m=q(c,["root","armature"]),f=q(c,["hips","hip","pelvis"]),h=C(c,"left",["hand","wrist"]),w=C(c,"right",["hand","wrist"]);return{version:1,basisPreset:"auto",basisYawDegrees:0,skinnedMeshName:e?.name||void 0,bones:c,topologyFingerprint:d,bindPoseFingerprint:p,retargetRootBoneId:m?.id??f?.id??c[0]?.id,pelvisBoneId:f?.id,leftHandBoneId:h?.id,rightHandBoneId:w?.id,chains:g,poses:[{id:"default",name:"Default",rotationOffsets:{}}],defaultPoseId:"default"}}function m(e){const n=new Set(e.bones);return e.bones.filter(e=>e.parent instanceof t&&!n.has(e.parent)).length}function f(e){return[...new Set(e.bones.map(e=>e.name))].sort().join("\n")}function h(e,n,t){const o={};for(const r of t.chainMappings){if(!1===r.enabled)continue;const t=e.chains.find(e=>e.id===r.sourceChainId),i=n.chains.find(e=>e.id===r.targetChainId);if(null==t||null==i)continue;const a=v(e,t),s=v(n,i);if(0!==a.length&&0!==s.length)for(let e=0;e<s.length;e++){const n=1===s.length?0:e/(s.length-1),t=Math.round(n*(a.length-1));o[s[e].name]=a[t].name}}return w(o,e,n,"retargetRootBoneId"),w(o,e,n,"pelvisBoneId"),w(o,e,n,"leftHandBoneId"),w(o,e,n,"rightHandBoneId"),b(o,e,n,"leftHandBoneId"),b(o,e,n,"rightHandBoneId"),o}function w(e,n,t,o){const r=F(n,n[o]),i=F(t,t[o]);null!=r&&null!=i&&(e[i]=r)}function b(e,n,t,o){const r=n.bones.findIndex(e=>e.id===n[o]),i=t.bones.findIndex(e=>e.id===t[o]);if(r<0||i<0)return;const a=new Map;for(const e of y(n,r)){const n=I(e.name);null!=n&&a.set(n,e)}for(const n of y(t,i)){const t=I(n.name),o=null==t?null:a.get(t);null!=o&&(e[n.name]=o.name)}}function y(e,n){return e.bones.filter((t,o)=>{let r=e.bones[o].parentIndex;for(;r>=0;){if(r===n)return!0;r=e.bones[r].parentIndex}return!1})}function I(e){const n=e.toLowerCase();if(n.includes("base"))return null;const t=["thumb","index","middle","ring","pinky"].find(e=>n.includes(e));if(null==t)return null;const o=n.slice(n.indexOf(t)+t.length),r=o.match(/\d+/)?.[0];return null==r?null:`${t}:${Number(r)}`}function R(e,n){const t=[],o=[],a=[],s=[];for(let l=0;l<e.bones.length;l++){const c=e.bones[l],d=(new i).fromArray(c.quaternion),p=d.clone(),g=n[c.id];null!=g&&p.multiply((new i).fromArray(g)).normalize();const m=(new r).compose((new u).fromArray(c.position),p,(new u).fromArray(c.scale));let f;if(c.parentIndex>=0)f=t[c.parentIndex],m.premultiply(f);else{const e=(new r).compose((new u).fromArray(c.position),d,(new u).fromArray(c.scale));f=(new r).fromArray(c.inverseBindMatrix).invert().multiply(e.invert()),m.premultiply(f)}t.push(m),o.push((new u).setFromMatrixPosition(m)),a.push((new i).setFromRotationMatrix(m)),s.push((new i).setFromRotationMatrix(f))}return{worldPositions:o,worldQuaternions:a,parentWorldQuaternions:s}}function x(e,n){const t=R(e,n),o=resolveAnimationRigBasisRotation(e);for(const e of t.worldPositions)e.applyQuaternion(o);for(const e of t.worldQuaternions)e.premultiply(o);for(const e of t.parentWorldQuaternions)e.premultiply(o);return t}function v(e,n){const t=e.bones.findIndex(e=>e.id===n.startBoneId),o=e.bones.findIndex(e=>e.id===n.endBoneId);if(t<0||o<0)return[];const r=[];let i=o;for(;i>=0;){if(r.push(e.bones[i]),i===t)return r.reverse();i=e.bones[i].parentIndex}return[]}function A(e,n,t){M(e,n),B(e,n,t),e.updateMatrixWorld(!0)}function M(e,n){const t=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const e of n.bones){const n=t.get(e.name);null!=n&&(n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale))}}function B(e,n,t){if(null==t)return;const o=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const[e,r]of Object.entries(t.rotationOffsets)){const t=n.bones.find(n=>n.id===e),a=null==t?void 0:o.get(t.name);null!=a&&a.quaternion.multiply((new i).fromArray(r)).normalize()}const r=F(n,n.retargetRootBoneId),a=null==r?void 0:o.get(r);null!=a&&null!=t.rootOffset&&a.position.add((new u).fromArray(t.rootOffset))}function k(e){const n=e.bones.map(()=>new r),t=e.bones.map(()=>new u);for(let o=0;o<e.bones.length;o++){const r=e.bones[o];n[o].compose((new u).fromArray(r.position),(new i).fromArray(r.quaternion),(new u).fromArray(r.scale)),r.parentIndex>=0&&n[o].premultiply(n[r.parentIndex]),t[o].setFromMatrixPosition(n[o])}const o=e.bones.findIndex(n=>n.id===e.pelvisBoneId),a=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),s=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);if(o>=0&&a>=0&&s.length>0){const e=t[o].distanceTo(t[a]),n=Math.max(...s.map(e=>t[o].distanceTo(t[e])));if(e+n>1e-4)return e+n}let l=0;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++)l=Math.max(l,t[e].distanceTo(t[n]));return Math.max(1e-4,l)}function P(e,n){return e.poses.find(e=>e.id===n)}function F(e,n){return null==n?void 0:e.bones.find(e=>e.id===n)?.name}function S(e,n){const t=[];if(e.traverse(e=>{O(e)&&t.push(e)}),null==n)return t[0];const o=null==n.skinnedMeshName?void 0:t.find(e=>e.name===n.skinnedMeshName);if(null!=o)return o;const r=t.map(e=>({candidate:e,rig:g(e,e.skeleton)}));return r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint&&e.rig.bindPoseFingerprint===n.bindPoseFingerprint)?.candidate??r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint)?.candidate??t[0]}function $(e,n){let o=0;return e.traverse(e=>{e instanceof t&&n.has(e.name)&&o++}),o}function O(e){return e instanceof l||!0===e.isSkinnedMesh}function q(e,n){return e.find(e=>n.some(n=>W(e.name)===W(n)))??e.find(e=>n.some(n=>W(e.name).includes(W(n))))}function C(e,n,t){const o="left"===n?["left","_l",".l"]:["right","_r",".r"];return e.find(e=>{const n=e.name.toLowerCase(),r=W(n);return o.some(e=>n.includes(e))&&t.some(e=>r.includes(W(e)))})}function W(e){return e.toLowerCase().replace(/^mixamorig[:_]?/,"").replace(/^bip0*1[_:]?/,"").replace(/[^a-z0-9]/g,"")}function N(e){return e.replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,e=>e.toUpperCase())}function z(e){return e.map(e=>Math.round(1e5*e)/1e5)}function T(e){const n=JSON.stringify(e);let t=2166136261;for(let e=0;e<n.length;e++)t^=n.charCodeAt(e),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function Q(e,n){return e===`${n}.position`||e===`.bones[${n}].position`||e.endsWith(`[${n}].position`)}const j=new WeakMap;/*
|
|
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 e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as s}from"./actors/factory.js";import{World as n}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as r}from"./services/render.js";import{RenderingView as i}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as m}from"./actors/internal/container-map.js";import{InputService as l}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as h}from"../scene/asset-resource-loader.js";import{AssetLoader as u}from"./services/asset-loader.js";import{polyfillClient as f}from"./polyfill.js";import{Subject as g}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{Scene as b}from"three";import{ShaderProvider as j}from"./services/shader-provider.js";import{SceneDataService as S}from"../scene/scene-data-service.js";import{NetMode as y}from"./net/net-session.js";import{AssetsProvider as x}from"../scene/assets-provider.js";export function initiateGame(g,I){if(f(),0!=I.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(r);const E=e.of("default"),R=new HologyRuntime(E),G=new s(E,{inEditor:!1});var P;G.classes=I.actors,e.set(s,G),P=I.element,Object.assign(P.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const D=new i(I.element,{enableXR:!0===I.xr?.enabled,maxPixelRatio:I.rendering?.maxPixelRatio,resolutionScale:I.rendering?.resolutionScale,dynamicResolution:I.rendering?.dynamicResolution,upscaling:I.rendering?.upscaling,msaa:I.rendering?.msaa,fpsCap:I.rendering?.fpsCap,depthPrepass:{enabled:!0===I.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==I?.rendering?.bloom?.enabled},reflection:{enabled:!1!==I?.rendering?.reflection?.enabled},shadows:{cascadeUpdateIntervals:[22,40,60,120]}});D.renderer.shadowMap.enabled=I.rendering?.shadows?.enabled??!0,D.renderer.shadowMap.autoUpdate=I.rendering?.shadows?.autoUpdate??!0,D.renderer.debug.checkShaderErrors=!1,e.set(i,D);const M=new r(D);e.set(r,M);const z=new v,A=new p(z),O=new h;O.setDataDir(I.dataDir),O.initKtx2(D.renderer);const C=Object.entries(I.shaders).map(([e,t])=>({name:e,type:t})),H=Object.entries(I.actors).map(([e,t])=>({name:e,type:t})),N={...d,...I.components??{}},T=Object.entries(N).map(([e,t])=>({name:e,type:t})),U=new j(C);e.set(j,U);const k=new u(O,A,C);e.set(x,A),e.set(h,O),e.set(u,k);const F=new b,W=new o(F,new S,A,O,D,C,H,G,T);W.inEditor=!1,W.netMode=I.multi?.session?.mode??y.none,e.set(o,W);const _=e.get(n);return e.set(n,_),_.materializer=W,(async()=>{const s=e.get(a);if(await s.start(),R.isShutdown)return;if(await z.preloadData(),R.isShutdown)return;if(_.scene=F,null!=I.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=E.get(e);t.session=I.multi.session,t.start(),R.shutdownStarted.subscribe(()=>t.stop())}const{scene:n,actors:o,materializer:r}=await t(D,I.sceneName,I.dataDir,I.shaders,I.actors,N,G,z,A,O,{detailTier:I.detailTier,nodeMode:I.multi?.session?.mode??y.none});_.scene=n,s.scene=_.scene;for(const e of F.children)_.scene.add(e);if(R.isShutdown)return void D.stop();e.import([c]);for(const e of o)_.addActor(e);s.addFromScene(n),await _.startSceneEventGraphs(r),console.log("Start compile shaders"),console.time("compile shaders"),await D.compileAsync(),console.timeEnd("compile shaders"),console.log("Finished compile shaders. Programs: ",D.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),D.initTextures(),console.timeEnd("init scene textures");const i=E.get(l);D.loop(e=>{i.update(e)}),R.status=5,R.shutdownStarted.subscribe(()=>{O.disposeAll()}),m.value=E,E.remove(g),E.set({id:g,type:g});const d=E.get(g);m.value=null,R.gameInstance=d,E.get(w).start(),d instanceof GameInstance&&await d.onStart(),R._resolver(!0)})(),R}export class GameInstance{onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new g,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(n)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(l).stop();const t=this.containerInstance.get(i);t?.stop();const s=this.getWorld();s.stopSceneEventGraphs();const n=this.containerInstance.get(r);n.setMuted(!0),n.dispose();for(const e of[...s.actors])s.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
|
|
1
|
+
import e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as s}from"./actors/factory.js";import{World as n}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as r}from"./services/render.js";import{RenderingView as i}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as m}from"./actors/internal/container-map.js";import{InputService as l}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as h}from"../scene/asset-resource-loader.js";import{AssetLoader as u}from"./services/asset-loader.js";import{polyfillClient as f}from"./polyfill.js";import{Subject as g}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{Scene as b}from"three";import{ShaderProvider as j}from"./services/shader-provider.js";import{SceneDataService as S}from"../scene/scene-data-service.js";import{NetMode as y}from"./net/net-session.js";import{AssetsProvider as x}from"../scene/assets-provider.js";export function initiateGame(g,I){if(f(),0!=I.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(r);const E=e.of("default"),R=new HologyRuntime(E),G=new s(E,{inEditor:!1});var P;G.classes=I.actors,e.set(s,G),P=I.element,Object.assign(P.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const D=new i(I.element,{enableXR:!0===I.xr?.enabled,maxPixelRatio:I.rendering?.maxPixelRatio,resolutionScale:I.rendering?.resolutionScale,dynamicResolution:I.rendering?.dynamicResolution,upscaling:I.rendering?.upscaling,msaa:I.rendering?.msaa,fpsCap:I.rendering?.fpsCap,depthPrepass:{enabled:!0===I.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==I?.rendering?.bloom?.enabled},reflection:{enabled:!1!==I?.rendering?.reflection?.enabled},shadows:{cascadeUpdateIntervals:[22,40,60,120]}});D.renderer.shadowMap.enabled=I.rendering?.shadows?.enabled??!0,D.renderer.shadowMap.autoUpdate=I.rendering?.shadows?.autoUpdate??!0,D.renderer.debug.checkShaderErrors=!1,e.set(i,D);const M=new r(D);e.set(r,M);const z=new v,A=new p(z),O=new h;O.setDataDir(I.dataDir),O.initKtx2(D.renderer);const C=Object.entries(I.shaders).map(([e,t])=>({name:e,type:t})),H=Object.entries(I.actors).map(([e,t])=>({name:e,type:t})),N={...d,...I.components??{}},T=Object.entries(N).map(([e,t])=>({name:e,type:t})),U=new j(C);e.set(j,U);const k=new u(O,A,C);e.set(x,A),e.set(h,O),e.set(u,k);const F=new b,W=new o(F,new S,A,O,D,C,H,G,T);W.inEditor=!1,W.netMode=I.multi?.session?.mode??y.none,e.set(o,W);const _=e.get(n);return e.set(n,_),_.materializer=W,(async()=>{const s=e.get(a);if(await s.start(),R.isShutdown)return;if(await z.preloadData(),R.isShutdown)return;if(_.scene=F,null!=I.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=E.get(e);t.session=I.multi.session,t.start(),R.shutdownStarted.subscribe(()=>t.stop())}const{scene:n,actors:o,materializer:r}=await t(D,I.sceneName,I.dataDir,I.shaders,I.actors,N,G,z,A,O,{detailTier:I.detailTier,nodeMode:I.multi?.session?.mode??y.none});_.scene=n,s.scene=_.scene;for(const e of F.children)_.scene.add(e);if(R.isShutdown)return void D.stop();e.import([c]);for(const e of o)_.addActor(e);s.addFromScene(n),await _.startSceneEventGraphs(r),console.log("Start compile shaders"),console.time("compile shaders"),await D.compileAsync(),console.timeEnd("compile shaders"),console.log("Finished compile shaders. Programs: ",D.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),D.initTextures(),console.timeEnd("init scene textures");const i=E.get(l);D.loop(e=>{i.update(e)}),R.status=5,R.shutdownStarted.subscribe(()=>{O.disposeAll()}),m.value=E,E.remove(g),E.set({id:g,type:g});const d=E.get(g);m.value=null,R.gameInstance=d,E.get(w).start(),d instanceof GameInstance&&await d.onStart(),R._resolver(!0)})(),R}export class GameInstance{onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new g,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(n)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(l).stop();const t=this.containerInstance.get(i);t?.stop();const s=this.getWorld();s.stopSceneEventGraphs();const n=this.containerInstance.get(r);n.setMuted(!0),n.dispose();for(const e of[...s.actors])s.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose();const c=this.containerInstance.get(x);c instanceof p&&c.dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
|
|
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{__decorate as t}from"tslib";import{Service as e}from"typedi";import{BaseActor as r}from"../actors/actor.js";import{ActorFactory as s}from"../actors/factory.js";import{Group as
|
|
1
|
+
import{__decorate as t}from"tslib";import{Service as e}from"typedi";import{BaseActor as r}from"../actors/actor.js";import{ActorFactory as s}from"../actors/factory.js";import{Group as i,Vector3 as n}from"three";import{ActorComponent as o}from"../../gameplay/actors/component.js";import{Subject as a}from"rxjs";import{RenderingView as c}from"../../rendering.js";import{randomUUID as h}from"../../utils/uuid";import{PrefabInstance as p}from"../../scene/objects/prefab";import{PhysicsSystem as l}from"./physics/physics-system.js";import{inject as d}from"../../gameplay/inject.js";import{isComponentEnabledInEnvironment as m}from"../actors/internal/component-init.js";import{NetRole as v}from"../net/service/net-actor-role.js";import{BasePlayerController as f}from"../actors/controller/actor-controller.js";import{EventGraphInstance as y}from"../event-graph/runtime.js";import{ViewController as w}from"./render.js";import{AssetsProvider as u}from"../../scene/assets-provider.js";import{WorldEventGraphAssetRuntime as b}from"../event-graph/runtime-assets.js";import{hasExecutableEventGraphDocument as E}from"../event-graph/model.js";const A=new n;class g{constructor(t){this.view=t}get direction(){return this.view.csm.lightDirection}set intensity(t){this.view.csm.lightIntensity=t,this.view.csm.lights.forEach(t=>t.intensity=this.view.csm.lightIntensity)}get intensity(){return this.view.csm.lightIntensity}get position(){return 0==this.view.csm.lights.length?A:this.view.csm.lights[0].position}}let G=class{constructor(){this.actorFactory=d(s),this.view=d(c),this.viewController=d(w),this.physics=d(l),this.assetsProvider=d(u),this.eventGraphAssets=new b(this,this.assetsProvider),this.actors=[],this.actorAdded=new a,this.actorRemoved=new a,this.directionalLight=new g(this.view),this.sceneEventGraphs=new Map,this.sceneEventGraphSubscriptions=[]}async spawnActor(t,e,r,s){if(null==t)throw new Error("Cannot spawn actor with null type");if("prefab"in t){const i=t.prefab,n=await this.spawnPrefab(i,e,r),o=n.mainActor;if(null==o)throw new Error(`Prefab has no main actor or there was an error when spwaning it. Prefab: ${JSON.stringify(i)}`);return o.disposed.subscribe(()=>{const t=n.actors.findIndex(t=>t===o);t>=0&&n.actors.splice(t,1),this.removePrefab(n)}),null!=s?.owner&&(o.owner=s.owner),o}const i=await this.actorFactory.create(t,e,r);return null!=s?.owner&&(i.owner=s.owner),this.addActor(i,e,r),i}async spawnActorWithNetInfo(t,e,r,s,i,n){const o=await this.actorFactory.create(t,i,n,!0),a=null!=s&&0!==s?this.actors.find(t=>t.__netid===s):null;return o.__netid=e,o.netRole=r,o.owner=a,o instanceof f&&(o.isLocallyControlled=r===v.autonomousProxy),this.actorFactory.initActor(o),this.addActor(o,i,n),o}async spawnLocalPlayerController(t,e,r){const s=await this.actorFactory.create(t,e,r,!0);return s.isLocallyControlled=!0,this.actorFactory.initActor(s),this.addActor(s,e,r),s}spawnActorSync(t,e,r){if(null==t)throw new Error("Cannot spawn actor with null type");const s=this.actorFactory.createSync(t,e,r);return this.addActor(s,e,r),s}addActor(t,e,r){e&&t.object.position.copy(e),r&&t.object.rotation.copy(r),null==t.object.parent&&this.scene.add(t.object),this.actors.push(t),j(t,t=>t.onBeginPlay(),this.actorFactory.inEditor),this.actorAdded.next(t)}removeActor(t){for(const[e,r]of[...this.sceneEventGraphs])r.binding.mainActor===t&&this.deactivateSceneEventGraph(e);j(t,t=>t.onEndPlay(),this.actorFactory.inEditor);const e=this.actors.indexOf(t);e>=0&&this.actors.splice(e,1),t.object.removeFromParent(),t.disposed.next(!0),this.actorRemoved.next(t),this.physics.removeActor(t)}findActorByType(t,e){return this.actors.find(r=>r instanceof t&&(null==e||r.object.name==e))}findActorsByType(t,e){return this.actors.filter(r=>r instanceof t&&(null==e||r.object.name==e))}resolveSceneActor(t){return this.materializer?.resolveSceneActor(t)}async startSceneEventGraphs(t){this.stopSceneEventGraphs(),this.sceneEventGraphSubscriptions.push(t.prefabEventGraphAdded$.subscribe(t=>{this.activateSceneEventGraph(t).catch(e=>{console.error(`Failed to start scene prefab event graph ${JSON.stringify(t.id)}`,e)})}),t.prefabEventGraphRemoved$.subscribe(t=>{this.deactivateSceneEventGraph(t.id);for(const e of t.actors)this.actors.includes(e)&&this.removeActor(e)}));for(const e of t.prefabEventGraphInstances)await this.activateSceneEventGraph(e)}stopSceneEventGraphs(){for(const t of this.sceneEventGraphSubscriptions)t.unsubscribe();this.sceneEventGraphSubscriptions.length=0;for(const t of[...this.sceneEventGraphs.keys()])this.deactivateSceneEventGraph(t)}async activateSceneEventGraph(t){if(this.sceneEventGraphs.has(t.id))return;for(const e of t.actors)this.actors.includes(e)||this.addActor(e);const e=new y(t.graph,{world:this,actorsById:t.actorsById,mainActor:t.mainActor,updates:this.viewController.onUpdate(),timer:this.viewController,physics:this.physics,assets:this.eventGraphAssets});this.sceneEventGraphs.set(t.id,{binding:t,runtime:e});try{await e.beginPlay()}catch(r){throw this.sceneEventGraphs.delete(t.id),e.endPlay(),r}}deactivateSceneEventGraph(t){const e=this.sceneEventGraphs.get(t);null!=e&&(this.sceneEventGraphs.delete(t),e.runtime.endPlay())}async spawnPrefab(t,e,r){if(null==this.materializer)return console.error("Internal error: Materializer is missing on World"),null;const s=new p,n=new i;null!=e&&n.position.copy(e),null!=r&&n.rotation.copy(r),this.materializer.setScene(this.scene),this.materializer.inEditor=this.actorFactory.inEditor;const o=null!=t.asset.id?await(this.assetsProvider?.getAsset(t.asset.id))??t.asset:t.asset,{object:a,actors:c,actorsById:l,mainActor:d,instanceId:m}=await this.materializer.createFromPrefabAsset(o,{sceneObjectChain:["r-"+h()],runtimeSpawn:!0},n,void 0,!1);s.object=a,s.actors=c,s.mainActor=d,s.__materializerInstanceId=m,this.scene.attach(a),c.forEach(t=>{this.addActor(t)}),this.physics.addFromScene(a);const v=o.prefab?.eventGraph;if(!this.actorFactory.inEditor&&E(v)){s.eventGraph=new y(v,{world:this,actorsById:l,mainActor:d,updates:this.viewController.onUpdate(),timer:this.viewController,physics:this.physics,assets:this.eventGraphAssets});try{await s.eventGraph.beginPlay()}catch(t){throw this.removePrefab(s),t}}return s}removePrefab(t){if(t.destroyed)return;t.destroyed=!0,t.eventGraph?.endPlay(),t.eventGraph=void 0,null!=t.__materializerInstanceId&&(this.materializer.unregisterLivePrefabInstance?.(t.__materializerInstanceId),t.__materializerInstanceId=void 0);t.actors.splice(0).forEach(t=>this.removeActor(t)),t.object?.removeFromParent(),this.physics.removeRemoved(t.object)}};G=t([e()],G);export{G as World};function j(t,e,s=!1,i=new WeakSet){if(!i.has(t))return i.add(t),e(t),t instanceof r&&t.attachedComponents.forEach(t=>{m(t,s)&&j(t,e,s,i)}),Object.entries(t).filter(([t,e])=>e instanceof o&&m(e,s)).forEach(([t,r])=>{j(r,e,s,i)})}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -378,6 +378,7 @@ export declare class SceneMaterializer {
|
|
|
378
378
|
get prefabEventGraphInstances(): readonly MaterializedPrefabEventGraph[];
|
|
379
379
|
private editorActorParamSnapshot;
|
|
380
380
|
private editorAttachedActorComponents;
|
|
381
|
+
private readonly livePrefabInstances;
|
|
381
382
|
resolveSceneActor(sceneObjectId: SceneObjectId): BaseActor | undefined;
|
|
382
383
|
private originalFog;
|
|
383
384
|
private assets;
|
|
@@ -466,8 +467,13 @@ export declare class SceneMaterializer {
|
|
|
466
467
|
private update;
|
|
467
468
|
materializeAndInitActor(source: SceneObject, parent?: THREE.Object3D<THREE.Object3DEventMap, Event>): Promise<THREE.Object3D<THREE.Object3DEventMap, Event>>;
|
|
468
469
|
private tryApplyLiveActorParameterUpdate;
|
|
470
|
+
private tryApplyLiveActorSettingsUpdate;
|
|
471
|
+
private applyLiveActorSettingsUpdate;
|
|
472
|
+
private applyLivePrefabParameterUpdate;
|
|
473
|
+
private applyLiveNestedPrefabOverrideUpdates;
|
|
474
|
+
private rememberLivePrefabActorSettings;
|
|
469
475
|
private tryApplyLiveParameterUpdate;
|
|
470
|
-
private
|
|
476
|
+
private applyLiveInnerParameterUpdates;
|
|
471
477
|
private resolveActorComponent;
|
|
472
478
|
private findParent;
|
|
473
479
|
private fixFogColor;
|
|
@@ -544,6 +550,7 @@ export declare class SceneMaterializer {
|
|
|
544
550
|
actors: BaseActor[];
|
|
545
551
|
actorsById: Map<string, BaseActor>;
|
|
546
552
|
mainActor: BaseActor | null;
|
|
553
|
+
instanceId: string;
|
|
547
554
|
}>;
|
|
548
555
|
private createParticleSystem;
|
|
549
556
|
private createLight;
|