@hology/core 0.0.211 → 0.0.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/initializsers.d.ts +8 -1
- package/dist/effects/vfx/initializsers.js +1 -1
- package/dist/effects/vfx/vfx-collision-behaviour.js +1 -1
- package/dist/effects/vfx/vfx-defs.d.ts +10 -1
- package/dist/effects/vfx/vfx-defs.js +1 -1
- package/dist/effects/vfx/vfx-renderers.d.ts +1 -0
- package/dist/effects/vfx/vfx-renderers.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +23 -1
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.d.ts +23 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-policy.d.ts +26 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-policy.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +145 -55
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts +125 -0
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/old-character-movement.d.ts +100 -0
- package/dist/gameplay/actors/builtin/components/character/old-character-movement.js +4 -0
- package/dist/gameplay/actors/builtin/components/index.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/index.js +1 -1
- package/dist/gameplay/actors/camera/third-person-camera-component.d.ts +3 -0
- package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
- package/dist/gameplay/actors/component.js +1 -1
- package/dist/gameplay/actors/controller/actor-controller.d.ts +16 -0
- package/dist/gameplay/actors/controller/actor-controller.js +4 -0
- package/dist/gameplay/actors/factory.d.ts +3 -0
- package/dist/gameplay/actors/factory.js +1 -1
- package/dist/gameplay/actors/index.d.ts +4 -0
- package/dist/gameplay/actors/index.js +1 -1
- package/dist/gameplay/actors/internal/component-init.js +1 -1
- package/dist/gameplay/ai/behavior-tree/move.d.ts +2 -2
- package/dist/gameplay/index.d.ts +3 -1
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.d.ts +4 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/net/browser/index.d.ts +147 -0
- package/dist/gameplay/net/browser/index.js +4 -0
- package/dist/gameplay/net/index.d.ts +7 -0
- package/dist/gameplay/net/index.js +4 -0
- package/dist/gameplay/net/net-connection.d.ts +25 -0
- package/dist/gameplay/net/net-connection.js +4 -0
- package/dist/gameplay/net/net-session.d.ts +70 -0
- package/dist/gameplay/net/net-session.js +4 -0
- package/dist/gameplay/net/service/net-actor-role.d.ts +12 -0
- package/dist/gameplay/net/service/net-actor-role.js +4 -0
- package/dist/gameplay/net/service/net-decorator.d.ts +29 -0
- package/dist/gameplay/net/service/net-decorator.js +4 -0
- package/dist/gameplay/net/service/net-serializer.d.ts +15 -0
- package/dist/gameplay/net/service/net-serializer.js +4 -0
- package/dist/gameplay/net/service/net-service.d.ts +171 -0
- package/dist/gameplay/net/service/net-service.js +4 -0
- package/dist/gameplay/net/service/net-utils.d.ts +8 -0
- package/dist/gameplay/net/service/net-utils.js +4 -0
- package/dist/gameplay/net/service/replication.d.ts +31 -0
- package/dist/gameplay/net/service/replication.js +4 -0
- package/dist/gameplay/net/service/rpc-decorator.d.ts +21 -0
- package/dist/gameplay/net/service/rpc-decorator.js +4 -0
- package/dist/gameplay/net/service/rpc.d.ts +35 -0
- package/dist/gameplay/net/service/rpc.js +4 -0
- package/dist/gameplay/services/asset-loader.d.ts +3 -2
- package/dist/gameplay/services/asset-loader.js +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +2 -1
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/world.d.ts +13 -2
- package/dist/gameplay/services/world.js +1 -1
- package/dist/rendering/color-pass.js +1 -1
- package/dist/rendering.d.ts +2 -0
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/batched-mesh-2.d.ts +9 -0
- package/dist/scene/batched-mesh-2.js +1 -1
- package/dist/scene/bootstrap.d.ts +2 -0
- package/dist/scene/bootstrap.js +1 -1
- package/dist/scene/materializer.d.ts +4 -0
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/storage/storage.d.ts +1 -1
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/builtin/toon-shader.js +1 -1
- package/dist/shader/builtin/unlit-shader.js +1 -1
- package/dist/shader/color-layer.js +1 -1
- package/dist/shader/parameter.d.ts +1 -1
- package/dist/shader/parameter.js +1 -1
- package/dist/shader-nodes/depth.js +1 -1
- package/dist/shader-nodes/scene-sample.js +1 -1
- package/dist/test/batched-mesh-2.test.d.ts +2 -0
- package/dist/test/batched-mesh-2.test.js +4 -0
- package/dist/test/browser-net-session.test.d.ts +2 -0
- package/dist/test/browser-net-session.test.js +4 -0
- package/dist/test/first-person-camera-component.test.js +1 -1
- package/dist/test/net-character-movement.test.d.ts +2 -0
- package/dist/test/net-character-movement.test.js +4 -0
- package/dist/test/net-property-snapshot.test.d.ts +2 -0
- package/dist/test/net-property-snapshot.test.js +4 -0
- package/dist/test/sequence-animation-retiming.test.js +1 -1
- package/dist/test/vfx-random-color-initializer.test.d.ts +2 -0
- package/dist/test/vfx-random-color-initializer.test.js +4 -0
- package/dist/test/world-prefab-spawn.test.d.ts +2 -0
- package/dist/test/world-prefab-spawn.test.js +4 -0
- package/dist/utils/three/placeholder-texture.d.ts +3 -0
- package/dist/utils/three/placeholder-texture.js +4 -0
- package/package.json +9 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as a}from"tslib";import{Color as t,MeshStandardMaterial as n,Texture as r,Vector2 as i}from"three";import{Shader as s}from"../shader.js";import{Parameter as o}from"../parameter.js";import*as p from"three";import{attributes as l,AttributeVec3Node as d,colorToNormal as h,ifDefApply as m,NodeShaderMaterial as u,normalize as v,Sampler2DNode as c,standardMaterial as y,UniformSampler2d as S,uniformFloat as g,uniformVec2 as f,uniformVec3 as M,varying as x,varyingAttributes as C,varyingTransformed as b,vec2 as w,UniformVec3Node as O,UniformFloatNode as R}from"three-shader-graph";import{parallaxOcclusionMapping as L}from"../../shader-nodes/pom.js";const T=new r,N=new i(1,1);export class StandardShader extends s{constructor(){super(...arguments),this.color=new t("#FFFFFF"),this.map=new S("map",T),this.opacity=1,this.alphaMap=new S("alphaMap",T),this.roughness=1,this.roughnessMap=new S("roughnessMap",T),this.metalness=0,this.metalnessMap=new S("metalnessMap",T),this.lightMap=new S("lightMap",T),this.aoMap=new S("aoMap",T),this.emissiveMap=new S("emissiveMap",T),this.normalMap=new S("normalMap",T),this.normalScale=new i(1,1),this.sheen=0,this.sheenColor=new t("#FFFFFF"),this.sheenColorMap=new S("sheenColorMap",T),this.sheenRoughness=.5,this.sheenRoughnessMap=new S("sheenRoughnessMap",T),this.anisotropyMap=new S("anisotropyMap",T),this.anisotropy=0,this.heightMap=new S("heightMap",T),this.vertexColor=!1,this.uvScale=N}build(){F(this.map,p.SRGBColorSpace),F(this.alphaMap,p.LinearSRGBColorSpace),F(this.roughnessMap,p.LinearSRGBColorSpace),F(this.metalnessMap,p.LinearSRGBColorSpace),F(this.aoMap,p.LinearSRGBColorSpace),F(this.emissiveMap,p.SRGBColorSpace),F(this.normalMap,p.LinearSRGBColorSpace),F(this.sheenColorMap,p.LinearSRGBColorSpace),F(this.sheenRoughnessMap,p.LinearSRGBColorSpace),F(this.anisotropyMap,p.LinearSRGBColorSpace);let e=!1;const a=f("uvScale",this.uvScale??N);let n=C.uv.multiply(a);B(this.heightMap)&&0!==(this.heightScale??.05)&&(n=L(n,this.heightMap,g("heightScale",this.heightScale??.05)));const r=x(new d("particleData"));let s=m("IS_PARTICLE",new R("opacity",this.opacity,void 0,!1),e=>e.multiply(r.x)),o=new O("color",(new p.Vector3).setFromColor(this.color),void 0,!1).rgb;if(B(this.map)){const e=this.map.sample(n);o=o.multiply(e.rgb),s=s.multiply(e.a)}B(this.alphaMap)&&(s=s.multiply(this.alphaMap.sample(n).r)),!0===this.vertexColor&&(o=o.multiply(x(l.color.rgb)));let c=null,S=null;B(this.aoMap)&&(S=g("aoMapIntensity",this.aoMapIntensity??1),c=this.aoMap.sample(n).r);let T=g("roughness",this.roughness??1);B(this.roughnessMap)&&(T=T.multiply(this.roughnessMap.sample(n).g),e=!0);let P=g("metalness",this.metalness??0);B(this.metalnessMap)&&(P=P.multiply(this.metalnessMap.sample(n).b),e=!0);let D=null;B(this.lightMap)&&(D=this.lightMap.sample(n).rgb.multiplyScalar(g("lightMapIntensity",this.lightMapIntensity??1)));let _=M("emissive",(new p.Vector3).setFromColor(this.emissive??new t(0))).rgb;B(this.emissiveMap)&&(_=_.multiply(this.emissiveMap.sample(n).rgb));const I=g("emissiveIntensity",this.emissiveIntensity??1);let E=b.normal;if(B(this.normalMap)){const e=g("normalScale",this.normalScale?.x??1);E=h(this.normalMap.sample(n),e)}let V=null,G=null;if((this.sheen??0)>0){const e=g("sheen",this.sheen??0);V=M("sheenColor",(new p.Vector3).setFromColor(this.sheenColor??new t(16777215))).rgb.multiplyScalar(e),B(this.sheenColorMap)&&(V=V.multiply(this.sheenColorMap.sample(n).rgb)),G=g("sheenRoughness",this.sheenRoughness??.5),B(this.sheenRoughnessMap)&&(G=G.multiply(this.sheenRoughnessMap.sample(n).a))}(this.roughness<1||this.metalness>0)&&(e=!0);let H=null,A=null;if((this.anisotropy??0)>0&&(H=g("anisotropy",this.anisotropy??0),A=f("anisotropyDirection",(U=this.anisotropyRotation??0,new i(Math.cos(U),Math.sin(U)))),B(this.anisotropyMap))){const e=this.anisotropyMap.sample(n),a=v(w(e.r,e.g).multiplyScalar(2).subtract(w(1,1)));A=w(A.x.multiply(a.x).subtract(A.y.multiply(a.y)),A.y.multiply(a.x).add(A.x.multiply(a.y))),H=H.multiply(e.b)}var U;const z=new u({color:y({color:o.rgba(s),roughness:T,metalness:P,ambientOcclusion:c,ambientOcclusionIntensity:S,emissive:_,emissiveIntensity:I,normal:E,bakedLight:D,sheenColor:V,sheenRoughness:G,anisotropy:H,anisotropyDirection:A,specular:e}),opacity:s,roughness:T,normal:E,emissive:_.multiplyScalar(I),envMap:this.envMap});return null!=this.envMap&&(z.uniforms.envMapIntensity={value:this.envMapIntensity??1}),z.vertexColors=!0===this.vertexColor,z}}function B(e){return null!=e&&(!(e instanceof S)||null!=e.value&&e.value!==T)}e([o(),a("design:type",t)],StandardShader.prototype,"color",void 0),e([o({label:"Color Map"}),a("design:type",c)],StandardShader.prototype,"map",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"opacity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"alphaMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"roughness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"roughnessMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"metalness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"metalnessMap",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"lightMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"lightMapIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"aoMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"aoMapIntensity",void 0),e([o(),a("design:type",t)],StandardShader.prototype,"emissive",void 0),e([o({range:[0,10]}),a("design:type",Number)],StandardShader.prototype,"emissiveIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"emissiveMap",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"normalMap",void 0),e([o(),a("design:type",i)],StandardShader.prototype,"normalScale",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheen",void 0),e([o(),a("design:type",t)],StandardShader.prototype,"sheenColor",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"sheenColorMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheenRoughness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"sheenRoughnessMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"anisotropyRotation",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"anisotropyMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"anisotropy",void 0),e([o(),a("design:type",r)],StandardShader.prototype,"envMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"envMapIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"heightMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"heightScale",void 0),e([o(),a("design:type",Boolean)],StandardShader.prototype,"vertexColor",void 0),e([o(),a("design:type",i)],StandardShader.prototype,"uvScale",void 0);export var ParallaxType;!function(e){e[e.none=0]="none",e[e.offset=1]="offset",e[e.pom=2]="pom"}(ParallaxType||(ParallaxType={}));export class ParallaxStandardMaterial extends n{constructor(e={}){super(e),e.heightMap&&(this.heightMap=e.heightMap),this.heightScale=e.heightScale??.05,this.parallaxType=e.parallaxType??ParallaxType.pom,this.minLayers=e.minLayers??10,this.maxLayers=e.maxLayers??32}onBeforeCompile(e){e.uniforms.heightMap={value:this.heightMap},e.uniforms.heightScale={value:this.heightScale},e.uniforms.minLayers={value:this.minLayers},e.uniforms.maxLayers={value:this.maxLayers},e.uniforms.parallaxType={value:this.parallaxType},e.vertexTangents=!0,e.vertexShader=e.vertexShader.replace("#include <uv_pars_vertex>","\n #include <uv_pars_vertex>\n "),e.vertexShader=e.vertexShader.replace("#include <begin_vertex>","\n #include <begin_vertex>\n "),e.fragmentShader=e.fragmentShader.replace("#include <uv_pars_fragment>","\n #include <uv_pars_fragment>\n uniform sampler2D heightMap;\n uniform float heightScale;\n uniform int minLayers;\n uniform int maxLayers;\n uniform int parallaxType;\n\n vec2 parallaxOffset(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 viewDirTS = -viewDir * tbn;\n\n float h = texture(heightMap, uv).r;\n return uv - (viewDirTS.xy / viewDirTS.z) * (h * heightScale);\n }\n\n vec2 parallaxOcclusion2(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 vv = -viewDir * tbn;\n\n float parallaxLimit = -length(vv.xy) / vv.z;\n parallaxLimit *= heightScale;\n\n vec2 vOffsetDir = normalize(vv.xy);\n vec2 vMaxOffset = vOffsetDir * parallaxLimit;\n\n float factor = pow(1.0 - abs(vv.z), 2.0);\n float nNumSamples = mix(float(minLayers), float(maxLayers), factor);\n float fStepSize = 1.0 / nNumSamples;\n\n float fCurrRayHeight = 1.0;\n vec2 vCurrOffset = vec2(0.0);\n vec2 vLastOffset = vec2(0.0);\n float fLastSampledHeight = 1.0;\n float fCurrSampledHeight = 1.0;\n\n for (int nCurrSample = 0; nCurrSample < 128; nCurrSample++) {\n if (float(nCurrSample) > nNumSamples) break;\n\n fCurrSampledHeight = texture2D(heightMap, uv + vCurrOffset).r;\n if (fCurrSampledHeight > fCurrRayHeight) {\n float delta1 = fCurrSampledHeight - fCurrRayHeight;\n float delta2 = (fCurrRayHeight + fStepSize) - fLastSampledHeight;\n float ratio = delta1 / (delta1 + delta2);\n vCurrOffset = ratio * vLastOffset + (1.0 - ratio) * vCurrOffset;\n break;\n } else {\n fCurrRayHeight -= fStepSize;\n vLastOffset = vCurrOffset;\n vCurrOffset += fStepSize * vMaxOffset;\n fLastSampledHeight = fCurrSampledHeight;\n }\n }\n\n return uv + vCurrOffset;\n }\n "),e.fragmentShader=e.fragmentShader.replace("#include <map_fragment>","\n vec3 pomViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n vec2 uvPOM = vMapUv ;\n if (parallaxType == 1) {\n uvPOM = parallaxOffset(vMapUv, pomViewDir, vNormal);\n } else if (parallaxType == 2) {\n uvPOM = parallaxOcclusion2(vMapUv, pomViewDir, vNormal);\n }\n\n vec4 texelColor = texture2D(map, uvPOM);\n diffuseColor *= texelColor;\n "),e.fragmentShader=e.fragmentShader.replace("#include <normal_fragment_maps>","\n #ifdef USE_NORMALMAP\n // RE-COMPUTE TBN for normal mapping consistency\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uvPOM);\n vec2 duv2 = dFdy(uvPOM);\n vec3 dp2perp = cross(dp2, vNormal);\n vec3 dp1perp = cross(vNormal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 localTBN = mat3(T * invmax, B * invmax, vNormal);\n\n vec3 mapN = texture2D(normalMap, uvPOM).xyz * 2.0 - 1.0;\n mapN.xy *= normalScale;\n normal = normalize( localTBN * mapN );\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <roughnessmap_fragment>","\n float roughnessFactor = roughness;\n #ifdef USE_ROUGHNESSMAP\n vec4 texelRoughness = texture2D( roughnessMap, uvPOM );\n // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n roughnessFactor *= texelRoughness.g;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <metalnesssmap_fragment>","\n float metalnessFactor = metalness;\n #ifdef USE_METALNESSMAP\n vec4 texelMetalness = texture2D( metalnessMap, uvPOM );\n // reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n metalnessFactor *= texelMetalness.b;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <aomap_fragment>","\n #ifdef USE_AOMAP\n\n // reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n float ambientOcclusion = ( texture2D( aoMap, uvPOM ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n reflectedLight.indirectDiffuse *= ambientOcclusion;\n\n #if defined( USE_CLEARCOAT ) \n clearcoatSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_SHEEN ) \n sheenSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_ENVMAP ) && defined( STANDARD )\n\n float dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\n reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\n #endif\n\n #endif\n "),this.userData.shader=e}clone(){const e=super.clone();return e.heightMap=this.heightMap,e.heightScale=this.heightScale,e.parallaxType=this.parallaxType,e.minLayers=this.minLayers,e.maxLayers=this.maxLayers,e}}export function applyTiling(e,a){if(null==e||null==a)return e;if(1===a.x&&1===a.y)return e;const t=e.clone();return t.repeat.copy(a),t.needsUpdate=!0,t}function F(e,a){null!=e&&(e instanceof r?e.colorSpace=a:e instanceof S&&null!=e.value&&(e.value.colorSpace=a))}/*
|
|
1
|
+
import{__decorate as e,__metadata as a}from"tslib";import{Color as t,MeshStandardMaterial as n,Texture as r,Vector2 as i}from"three";import{Shader as s}from"../shader.js";import{Parameter as o}from"../parameter.js";import*as p from"three";import{attributes as l,AttributeVec3Node as d,colorToNormal as h,ifDefApply as m,NodeShaderMaterial as u,normalize as v,Sampler2DNode as c,standardMaterial as y,UniformSampler2d as S,uniformFloat as g,uniformVec2 as f,uniformVec3 as M,varying as x,varyingAttributes as C,varyingTransformed as b,vec2 as w,UniformVec3Node as O,UniformFloatNode as R}from"three-shader-graph";import{parallaxOcclusionMapping as L}from"../../shader-nodes/pom.js";import{createPlaceholderTexture as T}from"../../utils/three/placeholder-texture.js";const N=T(),B=new i(1,1);export class StandardShader extends s{constructor(){super(...arguments),this.color=new t("#FFFFFF"),this.map=new S("map",N),this.opacity=1,this.alphaMap=new S("alphaMap",N),this.roughness=1,this.roughnessMap=new S("roughnessMap",N),this.metalness=0,this.metalnessMap=new S("metalnessMap",N),this.lightMap=new S("lightMap",N),this.aoMap=new S("aoMap",N),this.emissiveMap=new S("emissiveMap",N),this.normalMap=new S("normalMap",N),this.normalScale=new i(1,1),this.sheen=0,this.sheenColor=new t("#FFFFFF"),this.sheenColorMap=new S("sheenColorMap",N),this.sheenRoughness=.5,this.sheenRoughnessMap=new S("sheenRoughnessMap",N),this.anisotropyMap=new S("anisotropyMap",N),this.anisotropy=0,this.heightMap=new S("heightMap",N),this.vertexColor=!1,this.uvScale=B}build(){P(this.map,p.SRGBColorSpace),P(this.alphaMap,p.LinearSRGBColorSpace),P(this.roughnessMap,p.LinearSRGBColorSpace),P(this.metalnessMap,p.LinearSRGBColorSpace),P(this.aoMap,p.LinearSRGBColorSpace),P(this.emissiveMap,p.SRGBColorSpace),P(this.normalMap,p.LinearSRGBColorSpace),P(this.sheenColorMap,p.LinearSRGBColorSpace),P(this.sheenRoughnessMap,p.LinearSRGBColorSpace),P(this.anisotropyMap,p.LinearSRGBColorSpace);let e=!1;const a=f("uvScale",this.uvScale??B);let n=C.uv.multiply(a);F(this.heightMap)&&0!==(this.heightScale??.05)&&(n=L(n,this.heightMap,g("heightScale",this.heightScale??.05)));const r=x(new d("particleData"));let s=m("IS_PARTICLE",new R("opacity",this.opacity,void 0,!1),e=>e.multiply(r.x)),o=new O("color",(new p.Vector3).setFromColor(this.color),void 0,!1).rgb;if(F(this.map)){const e=this.map.sample(n);o=o.multiply(e.rgb),s=s.multiply(e.a)}F(this.alphaMap)&&(s=s.multiply(this.alphaMap.sample(n).r)),!0===this.vertexColor&&(o=o.multiply(x(l.color.rgb)));let c=null,S=null;F(this.aoMap)&&(S=g("aoMapIntensity",this.aoMapIntensity??1),c=this.aoMap.sample(n).r);let T=g("roughness",this.roughness??1);F(this.roughnessMap)&&(T=T.multiply(this.roughnessMap.sample(n).g),e=!0);let N=g("metalness",this.metalness??0);F(this.metalnessMap)&&(N=N.multiply(this.metalnessMap.sample(n).b),e=!0);let D=null;F(this.lightMap)&&(D=this.lightMap.sample(n).rgb.multiplyScalar(g("lightMapIntensity",this.lightMapIntensity??1)));let _=M("emissive",(new p.Vector3).setFromColor(this.emissive??new t(0))).rgb;F(this.emissiveMap)&&(_=_.multiply(this.emissiveMap.sample(n).rgb));const I=g("emissiveIntensity",this.emissiveIntensity??1);let E=b.normal;if(F(this.normalMap)){const e=g("normalScale",this.normalScale?.x??1);E=h(this.normalMap.sample(n),e)}let V=null,G=null;if((this.sheen??0)>0){const e=g("sheen",this.sheen??0);V=M("sheenColor",(new p.Vector3).setFromColor(this.sheenColor??new t(16777215))).rgb.multiplyScalar(e),F(this.sheenColorMap)&&(V=V.multiply(this.sheenColorMap.sample(n).rgb)),G=g("sheenRoughness",this.sheenRoughness??.5),F(this.sheenRoughnessMap)&&(G=G.multiply(this.sheenRoughnessMap.sample(n).a))}(this.roughness<1||this.metalness>0)&&(e=!0);let H=null,A=null;if((this.anisotropy??0)>0&&(H=g("anisotropy",this.anisotropy??0),A=f("anisotropyDirection",(U=this.anisotropyRotation??0,new i(Math.cos(U),Math.sin(U)))),F(this.anisotropyMap))){const e=this.anisotropyMap.sample(n),a=v(w(e.r,e.g).multiplyScalar(2).subtract(w(1,1)));A=w(A.x.multiply(a.x).subtract(A.y.multiply(a.y)),A.y.multiply(a.x).add(A.x.multiply(a.y))),H=H.multiply(e.b)}var U;const z=new u({color:y({color:o.rgba(s),roughness:T,metalness:N,ambientOcclusion:c,ambientOcclusionIntensity:S,emissive:_,emissiveIntensity:I,normal:E,bakedLight:D,sheenColor:V,sheenRoughness:G,anisotropy:H,anisotropyDirection:A,specular:e}),opacity:s,roughness:T,normal:E,emissive:_.multiplyScalar(I),envMap:this.envMap});return null!=this.envMap&&(z.uniforms.envMapIntensity={value:this.envMapIntensity??1}),z.vertexColors=!0===this.vertexColor,z}}function F(e){return null!=e&&(!(e instanceof S)||null!=e.value&&e.value!==N)}e([o(),a("design:type",t)],StandardShader.prototype,"color",void 0),e([o({label:"Color Map"}),a("design:type",c)],StandardShader.prototype,"map",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"opacity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"alphaMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"roughness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"roughnessMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"metalness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"metalnessMap",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"lightMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"lightMapIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"aoMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"aoMapIntensity",void 0),e([o(),a("design:type",t)],StandardShader.prototype,"emissive",void 0),e([o({range:[0,10]}),a("design:type",Number)],StandardShader.prototype,"emissiveIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"emissiveMap",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"normalMap",void 0),e([o(),a("design:type",i)],StandardShader.prototype,"normalScale",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheen",void 0),e([o(),a("design:type",t)],StandardShader.prototype,"sheenColor",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"sheenColorMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"sheenRoughness",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"sheenRoughnessMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"anisotropyRotation",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"anisotropyMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"anisotropy",void 0),e([o(),a("design:type",r)],StandardShader.prototype,"envMap",void 0),e([o({range:[0,1]}),a("design:type",Number)],StandardShader.prototype,"envMapIntensity",void 0),e([o(),a("design:type",c)],StandardShader.prototype,"heightMap",void 0),e([o(),a("design:type",Number)],StandardShader.prototype,"heightScale",void 0),e([o(),a("design:type",Boolean)],StandardShader.prototype,"vertexColor",void 0),e([o(),a("design:type",i)],StandardShader.prototype,"uvScale",void 0);export var ParallaxType;!function(e){e[e.none=0]="none",e[e.offset=1]="offset",e[e.pom=2]="pom"}(ParallaxType||(ParallaxType={}));export class ParallaxStandardMaterial extends n{constructor(e={}){super(e),e.heightMap&&(this.heightMap=e.heightMap),this.heightScale=e.heightScale??.05,this.parallaxType=e.parallaxType??ParallaxType.pom,this.minLayers=e.minLayers??10,this.maxLayers=e.maxLayers??32}onBeforeCompile(e){e.uniforms.heightMap={value:this.heightMap},e.uniforms.heightScale={value:this.heightScale},e.uniforms.minLayers={value:this.minLayers},e.uniforms.maxLayers={value:this.maxLayers},e.uniforms.parallaxType={value:this.parallaxType},e.vertexTangents=!0,e.vertexShader=e.vertexShader.replace("#include <uv_pars_vertex>","\n #include <uv_pars_vertex>\n "),e.vertexShader=e.vertexShader.replace("#include <begin_vertex>","\n #include <begin_vertex>\n "),e.fragmentShader=e.fragmentShader.replace("#include <uv_pars_fragment>","\n #include <uv_pars_fragment>\n uniform sampler2D heightMap;\n uniform float heightScale;\n uniform int minLayers;\n uniform int maxLayers;\n uniform int parallaxType;\n\n vec2 parallaxOffset(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 viewDirTS = -viewDir * tbn;\n\n float h = texture(heightMap, uv).r;\n return uv - (viewDirTS.xy / viewDirTS.z) * (h * heightScale);\n }\n\n vec2 parallaxOcclusion2(vec2 uv, vec3 viewDir, vec3 normal) {\n // Compute TBN in fragment shader using screen-space derivatives\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uv);\n vec2 duv2 = dFdy(uv);\n \n vec3 dp2perp = cross(dp2, normal);\n vec3 dp1perp = cross(normal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n \n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 tbn = mat3(T * invmax, B * invmax, normal);\n vec3 vv = -viewDir * tbn;\n\n float parallaxLimit = -length(vv.xy) / vv.z;\n parallaxLimit *= heightScale;\n\n vec2 vOffsetDir = normalize(vv.xy);\n vec2 vMaxOffset = vOffsetDir * parallaxLimit;\n\n float factor = pow(1.0 - abs(vv.z), 2.0);\n float nNumSamples = mix(float(minLayers), float(maxLayers), factor);\n float fStepSize = 1.0 / nNumSamples;\n\n float fCurrRayHeight = 1.0;\n vec2 vCurrOffset = vec2(0.0);\n vec2 vLastOffset = vec2(0.0);\n float fLastSampledHeight = 1.0;\n float fCurrSampledHeight = 1.0;\n\n for (int nCurrSample = 0; nCurrSample < 128; nCurrSample++) {\n if (float(nCurrSample) > nNumSamples) break;\n\n fCurrSampledHeight = texture2D(heightMap, uv + vCurrOffset).r;\n if (fCurrSampledHeight > fCurrRayHeight) {\n float delta1 = fCurrSampledHeight - fCurrRayHeight;\n float delta2 = (fCurrRayHeight + fStepSize) - fLastSampledHeight;\n float ratio = delta1 / (delta1 + delta2);\n vCurrOffset = ratio * vLastOffset + (1.0 - ratio) * vCurrOffset;\n break;\n } else {\n fCurrRayHeight -= fStepSize;\n vLastOffset = vCurrOffset;\n vCurrOffset += fStepSize * vMaxOffset;\n fLastSampledHeight = fCurrSampledHeight;\n }\n }\n\n return uv + vCurrOffset;\n }\n "),e.fragmentShader=e.fragmentShader.replace("#include <map_fragment>","\n vec3 pomViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n vec2 uvPOM = vMapUv ;\n if (parallaxType == 1) {\n uvPOM = parallaxOffset(vMapUv, pomViewDir, vNormal);\n } else if (parallaxType == 2) {\n uvPOM = parallaxOcclusion2(vMapUv, pomViewDir, vNormal);\n }\n\n vec4 texelColor = texture2D(map, uvPOM);\n diffuseColor *= texelColor;\n "),e.fragmentShader=e.fragmentShader.replace("#include <normal_fragment_maps>","\n #ifdef USE_NORMALMAP\n // RE-COMPUTE TBN for normal mapping consistency\n vec3 dp1 = dFdx(-vViewPosition);\n vec3 dp2 = dFdy(-vViewPosition);\n vec2 duv1 = dFdx(uvPOM);\n vec2 duv2 = dFdy(uvPOM);\n vec3 dp2perp = cross(dp2, vNormal);\n vec3 dp1perp = cross(vNormal, dp1);\n vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n float invmax = inversesqrt(max(dot(T,T), dot(B,B)));\n mat3 localTBN = mat3(T * invmax, B * invmax, vNormal);\n\n vec3 mapN = texture2D(normalMap, uvPOM).xyz * 2.0 - 1.0;\n mapN.xy *= normalScale;\n normal = normalize( localTBN * mapN );\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <roughnessmap_fragment>","\n float roughnessFactor = roughness;\n #ifdef USE_ROUGHNESSMAP\n vec4 texelRoughness = texture2D( roughnessMap, uvPOM );\n // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n roughnessFactor *= texelRoughness.g;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <metalnesssmap_fragment>","\n float metalnessFactor = metalness;\n #ifdef USE_METALNESSMAP\n vec4 texelMetalness = texture2D( metalnessMap, uvPOM );\n // reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n metalnessFactor *= texelMetalness.b;\n #endif\n "),e.fragmentShader=e.fragmentShader.replace("#include <aomap_fragment>","\n #ifdef USE_AOMAP\n\n // reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n float ambientOcclusion = ( texture2D( aoMap, uvPOM ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n reflectedLight.indirectDiffuse *= ambientOcclusion;\n\n #if defined( USE_CLEARCOAT ) \n clearcoatSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_SHEEN ) \n sheenSpecularIndirect *= ambientOcclusion;\n #endif\n\n #if defined( USE_ENVMAP ) && defined( STANDARD )\n\n float dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\n reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\n #endif\n\n #endif\n "),this.userData.shader=e}clone(){const e=super.clone();return e.heightMap=this.heightMap,e.heightScale=this.heightScale,e.parallaxType=this.parallaxType,e.minLayers=this.minLayers,e.maxLayers=this.maxLayers,e}}export function applyTiling(e,a){if(null==e||null==a)return e;if(1===a.x&&1===a.y)return e;const t=e.clone();return t.repeat.copy(a),t.needsUpdate=!0,t}function P(e,a){null!=e&&(e instanceof r?e.colorSpace=a:e instanceof S&&null!=e.value&&(e.value.colorSpace=a))}/*
|
|
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 e,__metadata as t}from"tslib";import{Color as o,DataTexture as i,RedFormat as s,
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Color as o,DataTexture as i,RedFormat as s,Vector2 as r}from"three";import{Parameter as a}from"../parameter.js";import{Shader as p}from"../shader.js";import*as n from"three";import{attributes as l,colorToNormal as h,NodeShaderMaterial as m,Sampler2DNode as y,toonMaterial as d,UniformSampler2d as g,uniformFloat as v,uniformVec3 as c,varying as u,varyingAttributes as S,varyingTransformed as M,vec2 as b}from"three-shader-graph";import{createPlaceholderTexture as T}from"../../utils/three/placeholder-texture.js";const w=T();export class ToonShader extends p{constructor(){super(...arguments),this.color=new o("#FFFFFF"),this.opacity=1,this.intensity=1,this.map=new g("map",w),this.lightSteps=[],this.lightMap=new g("lightMap",w),this.normalMap=new g("normalMap",w),this.normalScale=new r(1,1),this.aoMap=new g("aoMap",w),this.alphaMap=new g("alphaMap",w),this.emissiveMap=new g("emissiveMap",w),this.vertexColor=!1,this.uvScale=new r(1,1)}build(){let e;if(null!=this.lightSteps&&this.lightSteps.length>0){const t=new Uint8Array(this.lightSteps.length);for(let e=0;e<t.length;e++)t[e]=255*this.lightSteps[e];e=new i(t,t.length,1,s),e.needsUpdate=!0}const t=function(e,t){if(null==t||1===t.x&&1===t.y)return e;return e.multiply(b(t))}(S.uv,this.uvScale);let r=v("opacity",this.opacity),a=c("color",(new n.Vector3).setFromColor(this.color)).rgb.multiplyScalar(v("intensity",this.intensity));if(f(this.map)){const e=this.map.sample(t);a=a.multiply(e.rgb),r=r.multiply(e.a)}f(this.alphaMap)&&(r=r.multiply(this.alphaMap.sample(t).r)),!0===this.vertexColor&&(a=a.multiply(u(l.color.rgb)));let p=null;f(this.lightMap)&&(p=this.lightMap.sample(t).rgb.multiplyScalar(v("lightMapIntensity",this.lightMapIntensity??1)));let y=M.normal;f(this.normalMap)&&(y=h(this.normalMap.sample(t),v("normalScale",this.normalScale?.x??1)));let g=null;f(this.aoMap)&&(g=this.aoMap.sample(t).r);const T=v("aoMapIntensity",this.aoMapIntensity??1);let w=c("emissive",(new n.Vector3).setFromColor(this.emissive??new o(0))).rgb;f(this.emissiveMap)&&(w=w.multiply(this.emissiveMap.sample(t).rgb));const I=v("emissiveIntensity",this.emissiveIntensity??1),x=new m({color:d({color:a.rgba(r),gradientMap:e,bakedLight:p,normal:y,ambientOcclusion:g,ambientOcclusionIntensity:T,emissive:w,emissiveIntensity:I}),opacity:r,normal:y,emissive:w.multiplyScalar(I)});return x.vertexColors=!0===this.vertexColor,x}}function f(e){return null!=e&&(!(e instanceof g)||null!=e.value&&e.value!==w)}e([a(),t("design:type",o)],ToonShader.prototype,"color",void 0),e([a({range:[0,1]}),t("design:type",Number)],ToonShader.prototype,"opacity",void 0),e([a({range:[0,10]}),t("design:type",Number)],ToonShader.prototype,"intensity",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"map",void 0),e([a({type:Number,array:!0,range:[0,1]}),t("design:type",Array)],ToonShader.prototype,"lightSteps",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"lightMap",void 0),e([a(),t("design:type",Number)],ToonShader.prototype,"lightMapIntensity",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"normalMap",void 0),e([a(),t("design:type",r)],ToonShader.prototype,"normalScale",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"aoMap",void 0),e([a(),t("design:type",Number)],ToonShader.prototype,"aoMapIntensity",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"alphaMap",void 0),e([a(),t("design:type",o)],ToonShader.prototype,"emissive",void 0),e([a({range:[0,10]}),t("design:type",Number)],ToonShader.prototype,"emissiveIntensity",void 0),e([a(),t("design:type",y)],ToonShader.prototype,"emissiveMap",void 0),e([a(),t("design:type",Boolean)],ToonShader.prototype,"vertexColor",void 0),e([a(),t("design:type",r)],ToonShader.prototype,"uvScale",void 0);/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import{Color as i,Texture as o,Vector2 as p}from"three";import{Shader as
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import{Color as i,Texture as o,Vector2 as p}from"three";import{Shader as r}from"../shader.js";import{Parameter as a}from"../parameter.js";import{attributes as l,NodeShaderMaterial as n,rgba as s,Sampler2DNode as h,UniformSampler2d as y,uniformFloat as d,uniformVec3 as m,varying as u,varyingAttributes as c,vec2 as g}from"three-shader-graph";import*as v from"three";import{createPlaceholderTexture as M}from"../../utils/three/placeholder-texture.js";const S=M();export class UnlitShader extends r{constructor(){super(...arguments),this.color=new i("#FFFFFF"),this.opacity=1,this.intensity=1,this.map=new y("map",S),this.lightMap=new y("lightMap",S),this.aoMap=new y("aoMap",S),this.alphaMap=new y("alphaMap",S),this.vertexColor=!1,this.uvScale=new p(1,1)}build(){const t=function(t,e){if(null==e||1===e.x&&1===e.y)return t;return t.multiply(g(e))}(c.uv,this.uvScale);let e=d("opacity",this.opacity),i=m("color",(new v.Vector3).setFromColor(this.color)).rgb.multiplyScalar(d("intensity",this.intensity));if(f(this.map)){const o=this.map.sample(t);i=i.multiply(o.rgb),e=e.multiply(o.a)}if(f(this.alphaMap)&&(e=e.multiply(this.alphaMap.sample(t).r)),!0===this.vertexColor&&(i=i.multiply(u(l.color.rgb))),f(this.lightMap)&&(i=i.add(this.lightMap.sample(t).rgb.multiplyScalar(d("lightMapIntensity",this.lightMapIntensity??1)))),f(this.aoMap)){const e=this.aoMap.sample(t).r,o=d("aoMapIntensity",this.aoMapIntensity??1);i=i.multiplyScalar(e.subtract(1).multiply(o).add(1))}const o=new n({color:s(i,e),opacity:e,emissive:i,envMap:this.envMap});return o.vertexColors=!0===this.vertexColor,o}}function f(t){return null!=t&&(!(t instanceof y)||null!=t.value&&t.value!==S)}t([a(),e("design:type",i)],UnlitShader.prototype,"color",void 0),t([a({range:[0,1]}),e("design:type",Number)],UnlitShader.prototype,"opacity",void 0),t([a({range:[0,10]}),e("design:type",Number)],UnlitShader.prototype,"intensity",void 0),t([a(),e("design:type",h)],UnlitShader.prototype,"map",void 0),t([a(),e("design:type",h)],UnlitShader.prototype,"lightMap",void 0),t([a(),e("design:type",Number)],UnlitShader.prototype,"lightMapIntensity",void 0),t([a(),e("design:type",h)],UnlitShader.prototype,"aoMap",void 0),t([a(),e("design:type",Number)],UnlitShader.prototype,"aoMapIntensity",void 0),t([a(),e("design:type",h)],UnlitShader.prototype,"alphaMap",void 0),t([a(),e("design:type",o)],UnlitShader.prototype,"envMap",void 0),t([a(),e("design:type",Boolean)],UnlitShader.prototype,"vertexColor",void 0),t([a(),e("design:type",p)],UnlitShader.prototype,"uvScale",void 0);/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{Color as r,Texture as o,Vector2 as a}from"three";import{abs as s,attributes as i,float as l,FloatNode as p,max as n,min as y,mix as u,pow as d,rgba as h,SimplexNoiseNode as c,standardMaterial as g,step as L,textureSampler2d as m,varying as v,varyingAttributes as M,vec2 as x,colorToNormal as k,varyingTransformed as f,attributeVec2 as C}from"three-shader-graph";import{edgeDepthEffect as b,fresnelEffect as T,oneMinus as w,sceneColorSampler as S,screenUV as A,timeUniforms as V}from"../shader-nodes/index.js";import{SerializedParamType as F}from"../scene/model.js";import{Parameter as N}from"./parameter.js";export var ColorLayerType;!function(e){e.solid="solid",e.refraction="refraction",e.lighting="lighting",e.texture="texture",e.textureMask="textureMask",e.vertexMask="vertexMask",e.fresnelMask="fresnelMask",e.depthMask="depthMask",e.gradientMask="gradientMask"}(ColorLayerType||(ColorLayerType={}));export const defaultValueColorLayer={enabled:!0,type:ColorLayerType.solid,outputType:"rgba",opacity:1,blendMode:"normal",params:{color:{type:F.Color,value:"#FFFFFF"}}};export const defaultValueMaskLayer={enabled:!0,type:ColorLayerType.textureMask,outputType:"alpha",opacity:1,blendMode:"normal",params:{texture:{type:F.Texture,value:null},channel:{type:F.String,value:"red"}}};const z={normal:(e,t,r)=>u(e,t,r),add:(e,t,r)=>e.add(t.multiplyScalar(r)),multiply:(e,t,r)=>u(e,e.multiply(t),r),screen:(e,t,r)=>u(e,w(w(e).multiply(w(t))),r),overlay:(e,t,r)=>{const o=u(e.multiply(t).multiplyScalar(2),w(l(2).multiplyVec3(w(e)).multiply(w(t))),L(.5,e));return u(e,o.rgb,r)},difference:(e,t,r)=>u(e,s(e.subtract(t)),r),subtract:(e,t,r)=>u(e,e.subtract(t),r)};export const blendModes=Object.keys(z);const B={normal:(e,t,r)=>u(e,t,r),add:(e,t,r)=>e.add(t.multiply(r)),multiply:(e,t,r)=>u(e,e.multiply(t),r),max:(e,t,r)=>u(e,n(e,t),r),min:(e,t,r)=>u(e,y(e,t),r),difference:(e,t,r)=>u(e,s(e.subtract(t)),r),subtract:(e,t,r)=>u(e,e.subtract(t),r)};export const maskBlendModes=Object.keys(B);export class ColorLayer{constructor(){this.layers=[]}static get outputType(){return"rgba"}apply(e){const t=this.output();if(t instanceof p)return h(e.rgb,this.applyMask(e.a));{let a=t;if(null!=this.layers&&(a=this.layers.filter(e=>!1!==e.enabled).reduce((e,t)=>t.apply(e),t)),null==e)return a;const s=z[this.blendMode]??z.normal,i=a.a.multiply(this.opacity),l=s(e.rgb,a.rgb,i);let p=(r=e.a,(o=i).add(r.multiply(w(o))));return h(l,p)}var r,o}applyMask(e){const t=this.output();if(t instanceof p){let r=t;null!=this.layers&&(r=this.layers.filter(e=>!1!==e.enabled).reduce((e,t)=>t.applyMask(e),t));return(B[this.blendMode]??z.normal)(e,r,this.opacity)}return console.error("Can not use non-float layer for mask"),e}init(e,t){}static async decode(e,t){if(console.log("Decode value",e),!isColorLayerSerialized(e))return;const r=new layerTypes[e.type];return r.enabled=e.enabled,r.opacity=e.opacity??1,r.blendMode=e.blendMode,r}output(){return h("white")}}export class SolidColorLayer extends ColorLayer{constructor(){super(...arguments),this.color=new r("white"),this.layers=[]}output(){return h(this.color).multiplyScalar(1.3)}}e([N(),t("design:type",r)],SolidColorLayer.prototype,"color",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],SolidColorLayer.prototype,"layers",void 0);export class TextureColorLayer extends ColorLayer{constructor(){super(...arguments),this.texture=new o,this.scale=new a(1,1),this.scroll=new a(0,0),this.layers=[]}output(){let e=M.uv;return null!=this.scroll&&this.scroll.lengthSq()>0&&(e=e.add(x(this.scroll).multiplyScalar(V.elapsed))),e=e.multiply(x(this.scale??1)),m(this.texture).sample(e)}}e([N(),t("design:type",o)],TextureColorLayer.prototype,"texture",void 0),e([N(),t("design:type",a)],TextureColorLayer.prototype,"scale",void 0),e([N(),t("design:type",a)],TextureColorLayer.prototype,"scroll",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],TextureColorLayer.prototype,"layers",void 0);export class RefractionColorLayer extends ColorLayer{constructor(){super(...arguments),this.texture=new o,this.layers=[]}output(){return S.sample(A.addScalar(new c(M.uv).multiply(.2)))}}e([N(),t("design:type",o)],RefractionColorLayer.prototype,"texture",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],RefractionColorLayer.prototype,"layers",void 0);export class LightingColorLayer extends ColorLayer{constructor(){super(...arguments),this.roughness=1,this.metalness=0}apply(e){const t=M.uv,r=e?.a??l(1);let o=l(this.roughness);null!=this.roughnessMap&&(o=o.multiply(m(this.roughnessMap).sample(t).g));let a=l(this.metalness);null!=this.metalnessMap&&(a=a.multiply(m(this.metalnessMap).sample(t).b));let s=f.normal;null!=this.normalMap&&(s=k(m(this.normalMap).sample(t),this.normalScale));let i=null;null!=this.aoMap&&(i=m(this.aoMap).sample(t).r);let p=null;null!=this.lightMap&&(p=m(this.lightMap).sample(t).rgb);let n=h(this.emissive??"black",r);return null!=this.emissiveMap&&(n=n.multiply(m(this.emissiveMap).sample(t))),g({color:e,emissive:n,emissiveIntensity:l(this.emissiveIntensity??1),metalness:a,roughness:o,normal:s,ambientOcclusion:i,ambientOcclusionIntensity:l(this.aoMapIntensity??1),bakedLight:p?.multiplyScalar(this.lightMapIntensity??1)})}}e([N({range:[0,1]}),t("design:type",Number)],LightingColorLayer.prototype,"roughness",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"roughnessMap",void 0),e([N({range:[0,1]}),t("design:type",Number)],LightingColorLayer.prototype,"metalness",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"metalnessMap",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"lightMap",void 0),e([N(),t("design:type",Number)],LightingColorLayer.prototype,"lightMapIntensity",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"aoMap",void 0),e([N(),t("design:type",Number)],LightingColorLayer.prototype,"aoMapIntensity",void 0),e([N(),t("design:type",r)],LightingColorLayer.prototype,"emissive",void 0),e([N({range:[0,10]}),t("design:type",Number)],LightingColorLayer.prototype,"emissiveIntensity",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"emissiveMap",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"normalMap",void 0),e([N(),t("design:type",p)],LightingColorLayer.prototype,"normalScale",void 0);export class MaskLayer extends ColorLayer{constructor(){super(...arguments),this.power=1,this.invert=!1}static get outputType(){return"float"}output(){let e=this.outputAlpha();return this.invert&&(e=w(e)),null!=this.power&&1!==this.power&&(e=d(e,this.power)),e}outputAlpha(){throw"not implemented"}}const I=["red","green","blue","alpha"];export class TextureMaskLayer extends MaskLayer{constructor(){super(...arguments),this.texture=new o,this.channel="red",this.space="uv",this.flipU=!1,this.flipV=!1,this.scale=new a(1,1),this.scroll=new a(0,0),this.offsetLayers=[],this.offset=new a(1,0),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){let e=M.uv;switch(this.space??"uv"){case"uv":e=M.uv;break;case"uv1":e=v(C("uv1"));break;case"uv2":e=v(C("uv2"));break;case"uv3":e=v(C("uv3"));break;case"world xz":e=f.worldPosition.xz}if(this.flipU&&(e=x(w(e.x),e.y)),this.flipV&&(e=x(e.x,w(e.y))),null!=this.scroll&&this.scroll.lengthSq()>0&&(e=e.add(x(this.scroll).multiplyScalar(V.elapsed))),null!=this.offsetLayers&&this.offsetLayers.length>0&&null!=this.offset&&this.offset.lengthSq()>0){const t=this.offsetLayers.reduce((e,t)=>t.applyMask(e),l(0));e=e.add(x(this.offset).multiplyScalar(t))}e=e.multiply(x(this.scale??1));return j(m(this.texture).sample(e),this.channel)}}e([N(),t("design:type",o)],TextureMaskLayer.prototype,"texture",void 0),e([N({options:I.map(e=>({name:e,value:e}))}),t("design:type",String)],TextureMaskLayer.prototype,"channel",void 0),e([N({options:["uv","uv1","uv2","uv3","world xz"].map(e=>({name:e,value:e}))}),t("design:type",String)],TextureMaskLayer.prototype,"space",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"flipU",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"flipV",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"scale",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"scroll",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],TextureMaskLayer.prototype,"offsetLayers",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"offset",void 0),e([N(),t("design:type",Number)],TextureMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],TextureMaskLayer.prototype,"layers",void 0);export class VertexMaskLayer extends MaskLayer{constructor(){super(...arguments),this.channel="red",this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){const e=i.color;return v(j(e,this.channel))}}function j(e,t){switch(t??"red"){case"red":return e.r;case"green":return e.g;case"blue":return e.b;case"alpha":return e.a}}e([N({options:I.map(e=>({name:e,value:e}))}),t("design:type",String)],VertexMaskLayer.prototype,"channel",void 0),e([N(),t("design:type",Number)],VertexMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],VertexMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],VertexMaskLayer.prototype,"layers",void 0);export class GradientMaskLayer extends MaskLayer{constructor(){super(...arguments),this.direction="u",this.start=0,this.end=1,this.invert=!1,this.layers=[]}outputAlpha(){return u(l(this.start),l(this.end),function(e){switch(e??"u"){case"u":return M.uv.x;case"v":return M.uv.y;case"x":return M.position.x;case"y":return M.position.y;case"z":return M.position.z}}(this.direction))}}e([N({options:["u","v","x","y","z"].map(e=>({name:e,value:e}))}),t("design:type",String)],GradientMaskLayer.prototype,"direction",void 0),e([N(),t("design:type",Number)],GradientMaskLayer.prototype,"start",void 0),e([N(),t("design:type",Number)],GradientMaskLayer.prototype,"end",void 0),e([N(),t("design:type",Boolean)],GradientMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],GradientMaskLayer.prototype,"layers",void 0);export class FresnelMaskLayer extends MaskLayer{constructor(){super(...arguments),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){return v(T(1))}}e([N(),t("design:type",Number)],FresnelMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],FresnelMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],FresnelMaskLayer.prototype,"layers",void 0);export class DepthMaskLayer extends MaskLayer{constructor(){super(...arguments),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){return b(1)}}e([N(),t("design:type",Number)],DepthMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],DepthMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],DepthMaskLayer.prototype,"layers",void 0);export function isColorLayerSerialized(e){return"object"==typeof e&&null!==e&&"boolean"==typeof e.enabled&&"string"==typeof e.type&&e.outputType&&("object"==typeof e.params||void 0===e.params)}export const layerTypes={[ColorLayerType.solid]:SolidColorLayer,[ColorLayerType.texture]:TextureColorLayer,[ColorLayerType.refraction]:RefractionColorLayer,[ColorLayerType.lighting]:LightingColorLayer,[ColorLayerType.textureMask]:TextureMaskLayer,[ColorLayerType.vertexMask]:VertexMaskLayer,[ColorLayerType.fresnelMask]:FresnelMaskLayer,[ColorLayerType.depthMask]:DepthMaskLayer,[ColorLayerType.gradientMask]:GradientMaskLayer};/*
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Color as r,Texture as o,Vector2 as a}from"three";import{abs as s,attributes as i,float as l,FloatNode as p,max as y,min as n,mix as u,pow as d,rgba as h,SimplexNoiseNode as c,standardMaterial as g,step as L,textureSampler2d as m,varying as v,varyingAttributes as M,vec2 as x,colorToNormal as k,varyingTransformed as f,attributeVec2 as C}from"three-shader-graph";import{edgeDepthEffect as b,fresnelEffect as T,oneMinus as w,sceneColorSampler as S,screenUV as A,timeUniforms as V}from"../shader-nodes/index.js";import{SerializedParamType as F}from"../scene/model.js";import{Parameter as N}from"./parameter.js";import{createPlaceholderTexture as j}from"../utils/three/placeholder-texture.js";export var ColorLayerType;!function(e){e.solid="solid",e.refraction="refraction",e.lighting="lighting",e.texture="texture",e.textureMask="textureMask",e.vertexMask="vertexMask",e.fresnelMask="fresnelMask",e.depthMask="depthMask",e.gradientMask="gradientMask"}(ColorLayerType||(ColorLayerType={}));export const defaultValueColorLayer={enabled:!0,type:ColorLayerType.solid,outputType:"rgba",opacity:1,blendMode:"normal",params:{color:{type:F.Color,value:"#FFFFFF"}}};export const defaultValueMaskLayer={enabled:!0,type:ColorLayerType.textureMask,outputType:"alpha",opacity:1,blendMode:"normal",params:{texture:{type:F.Texture,value:null},channel:{type:F.String,value:"red"}}};const z={normal:(e,t,r)=>u(e,t,r),add:(e,t,r)=>e.add(t.multiplyScalar(r)),multiply:(e,t,r)=>u(e,e.multiply(t),r),screen:(e,t,r)=>u(e,w(w(e).multiply(w(t))),r),overlay:(e,t,r)=>{const o=u(e.multiply(t).multiplyScalar(2),w(l(2).multiplyVec3(w(e)).multiply(w(t))),L(.5,e));return u(e,o.rgb,r)},difference:(e,t,r)=>u(e,s(e.subtract(t)),r),subtract:(e,t,r)=>u(e,e.subtract(t),r)};export const blendModes=Object.keys(z);const B={normal:(e,t,r)=>u(e,t,r),add:(e,t,r)=>e.add(t.multiply(r)),multiply:(e,t,r)=>u(e,e.multiply(t),r),max:(e,t,r)=>u(e,y(e,t),r),min:(e,t,r)=>u(e,n(e,t),r),difference:(e,t,r)=>u(e,s(e.subtract(t)),r),subtract:(e,t,r)=>u(e,e.subtract(t),r)};export const maskBlendModes=Object.keys(B);export class ColorLayer{constructor(){this.layers=[]}static get outputType(){return"rgba"}apply(e){const t=this.output();if(t instanceof p)return h(e.rgb,this.applyMask(e.a));{let a=t;if(null!=this.layers&&(a=this.layers.filter(e=>!1!==e.enabled).reduce((e,t)=>t.apply(e),t)),null==e)return a;const s=z[this.blendMode]??z.normal,i=a.a.multiply(this.opacity),l=s(e.rgb,a.rgb,i);let p=(r=e.a,(o=i).add(r.multiply(w(o))));return h(l,p)}var r,o}applyMask(e){const t=this.output();if(t instanceof p){let r=t;null!=this.layers&&(r=this.layers.filter(e=>!1!==e.enabled).reduce((e,t)=>t.applyMask(e),t));return(B[this.blendMode]??z.normal)(e,r,this.opacity)}return console.error("Can not use non-float layer for mask"),e}init(e,t){}static async decode(e,t){if(console.log("Decode value",e),!isColorLayerSerialized(e))return;const r=new layerTypes[e.type];return r.enabled=e.enabled,r.opacity=e.opacity??1,r.blendMode=e.blendMode,r}output(){return h("white")}}export class SolidColorLayer extends ColorLayer{constructor(){super(...arguments),this.color=new r("white"),this.layers=[]}output(){return h(this.color).multiplyScalar(1.3)}}e([N(),t("design:type",r)],SolidColorLayer.prototype,"color",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],SolidColorLayer.prototype,"layers",void 0);export class TextureColorLayer extends ColorLayer{constructor(){super(...arguments),this.texture=j(),this.scale=new a(1,1),this.scroll=new a(0,0),this.layers=[]}output(){let e=M.uv;return null!=this.scroll&&this.scroll.lengthSq()>0&&(e=e.add(x(this.scroll).multiplyScalar(V.elapsed))),e=e.multiply(x(this.scale??1)),m(this.texture).sample(e)}}e([N(),t("design:type",o)],TextureColorLayer.prototype,"texture",void 0),e([N(),t("design:type",a)],TextureColorLayer.prototype,"scale",void 0),e([N(),t("design:type",a)],TextureColorLayer.prototype,"scroll",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],TextureColorLayer.prototype,"layers",void 0);export class RefractionColorLayer extends ColorLayer{constructor(){super(...arguments),this.texture=j(),this.layers=[]}output(){return S.sample(A.addScalar(new c(M.uv).multiply(.2)))}}e([N(),t("design:type",o)],RefractionColorLayer.prototype,"texture",void 0),e([N({type:ColorLayer,array:!0}),t("design:type",Array)],RefractionColorLayer.prototype,"layers",void 0);export class LightingColorLayer extends ColorLayer{constructor(){super(...arguments),this.roughness=1,this.metalness=0}apply(e){const t=M.uv,r=e?.a??l(1);let o=l(this.roughness);null!=this.roughnessMap&&(o=o.multiply(m(this.roughnessMap).sample(t).g));let a=l(this.metalness);null!=this.metalnessMap&&(a=a.multiply(m(this.metalnessMap).sample(t).b));let s=f.normal;null!=this.normalMap&&(s=k(m(this.normalMap).sample(t),this.normalScale));let i=null;null!=this.aoMap&&(i=m(this.aoMap).sample(t).r);let p=null;null!=this.lightMap&&(p=m(this.lightMap).sample(t).rgb);let y=h(this.emissive??"black",r);return null!=this.emissiveMap&&(y=y.multiply(m(this.emissiveMap).sample(t))),g({color:e,emissive:y,emissiveIntensity:l(this.emissiveIntensity??1),metalness:a,roughness:o,normal:s,ambientOcclusion:i,ambientOcclusionIntensity:l(this.aoMapIntensity??1),bakedLight:p?.multiplyScalar(this.lightMapIntensity??1)})}}e([N({range:[0,1]}),t("design:type",Number)],LightingColorLayer.prototype,"roughness",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"roughnessMap",void 0),e([N({range:[0,1]}),t("design:type",Number)],LightingColorLayer.prototype,"metalness",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"metalnessMap",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"lightMap",void 0),e([N(),t("design:type",Number)],LightingColorLayer.prototype,"lightMapIntensity",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"aoMap",void 0),e([N(),t("design:type",Number)],LightingColorLayer.prototype,"aoMapIntensity",void 0),e([N(),t("design:type",r)],LightingColorLayer.prototype,"emissive",void 0),e([N({range:[0,10]}),t("design:type",Number)],LightingColorLayer.prototype,"emissiveIntensity",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"emissiveMap",void 0),e([N(),t("design:type",o)],LightingColorLayer.prototype,"normalMap",void 0),e([N(),t("design:type",p)],LightingColorLayer.prototype,"normalScale",void 0);export class MaskLayer extends ColorLayer{constructor(){super(...arguments),this.power=1,this.invert=!1}static get outputType(){return"float"}output(){let e=this.outputAlpha();return this.invert&&(e=w(e)),null!=this.power&&1!==this.power&&(e=d(e,this.power)),e}outputAlpha(){throw"not implemented"}}const I=["red","green","blue","alpha"];export class TextureMaskLayer extends MaskLayer{constructor(){super(...arguments),this.texture=j(),this.channel="red",this.space="uv",this.flipU=!1,this.flipV=!1,this.scale=new a(1,1),this.scroll=new a(0,0),this.offsetLayers=[],this.offset=new a(1,0),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){let e=M.uv;switch(this.space??"uv"){case"uv":e=M.uv;break;case"uv1":e=v(C("uv1"));break;case"uv2":e=v(C("uv2"));break;case"uv3":e=v(C("uv3"));break;case"world xz":e=f.worldPosition.xz}if(this.flipU&&(e=x(w(e.x),e.y)),this.flipV&&(e=x(e.x,w(e.y))),null!=this.scroll&&this.scroll.lengthSq()>0&&(e=e.add(x(this.scroll).multiplyScalar(V.elapsed))),null!=this.offsetLayers&&this.offsetLayers.length>0&&null!=this.offset&&this.offset.lengthSq()>0){const t=this.offsetLayers.reduce((e,t)=>t.applyMask(e),l(0));e=e.add(x(this.offset).multiplyScalar(t))}e=e.multiply(x(this.scale??1));return G(m(this.texture).sample(e),this.channel)}}e([N(),t("design:type",o)],TextureMaskLayer.prototype,"texture",void 0),e([N({options:I.map(e=>({name:e,value:e}))}),t("design:type",String)],TextureMaskLayer.prototype,"channel",void 0),e([N({options:["uv","uv1","uv2","uv3","world xz"].map(e=>({name:e,value:e}))}),t("design:type",String)],TextureMaskLayer.prototype,"space",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"flipU",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"flipV",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"scale",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"scroll",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],TextureMaskLayer.prototype,"offsetLayers",void 0),e([N(),t("design:type",a)],TextureMaskLayer.prototype,"offset",void 0),e([N(),t("design:type",Number)],TextureMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],TextureMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],TextureMaskLayer.prototype,"layers",void 0);export class VertexMaskLayer extends MaskLayer{constructor(){super(...arguments),this.channel="red",this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){const e=i.color;return v(G(e,this.channel))}}function G(e,t){switch(t??"red"){case"red":return e.r;case"green":return e.g;case"blue":return e.b;case"alpha":return e.a}}e([N({options:I.map(e=>({name:e,value:e}))}),t("design:type",String)],VertexMaskLayer.prototype,"channel",void 0),e([N(),t("design:type",Number)],VertexMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],VertexMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],VertexMaskLayer.prototype,"layers",void 0);export class GradientMaskLayer extends MaskLayer{constructor(){super(...arguments),this.direction="u",this.start=0,this.end=1,this.invert=!1,this.layers=[]}outputAlpha(){return u(l(this.start),l(this.end),function(e){switch(e??"u"){case"u":return M.uv.x;case"v":return M.uv.y;case"x":return M.position.x;case"y":return M.position.y;case"z":return M.position.z}}(this.direction))}}e([N({options:["u","v","x","y","z"].map(e=>({name:e,value:e}))}),t("design:type",String)],GradientMaskLayer.prototype,"direction",void 0),e([N(),t("design:type",Number)],GradientMaskLayer.prototype,"start",void 0),e([N(),t("design:type",Number)],GradientMaskLayer.prototype,"end",void 0),e([N(),t("design:type",Boolean)],GradientMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],GradientMaskLayer.prototype,"layers",void 0);export class FresnelMaskLayer extends MaskLayer{constructor(){super(...arguments),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){return v(T(1))}}e([N(),t("design:type",Number)],FresnelMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],FresnelMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],FresnelMaskLayer.prototype,"layers",void 0);export class DepthMaskLayer extends MaskLayer{constructor(){super(...arguments),this.power=1,this.invert=!1,this.layers=[]}outputAlpha(){return b(1)}}e([N(),t("design:type",Number)],DepthMaskLayer.prototype,"power",void 0),e([N(),t("design:type",Boolean)],DepthMaskLayer.prototype,"invert",void 0),e([N({type:MaskLayer,array:!0}),t("design:type",Array)],DepthMaskLayer.prototype,"layers",void 0);export function isColorLayerSerialized(e){return"object"==typeof e&&null!==e&&"boolean"==typeof e.enabled&&"string"==typeof e.type&&e.outputType&&("object"==typeof e.params||void 0===e.params)}export const layerTypes={[ColorLayerType.solid]:SolidColorLayer,[ColorLayerType.texture]:TextureColorLayer,[ColorLayerType.refraction]:RefractionColorLayer,[ColorLayerType.lighting]:LightingColorLayer,[ColorLayerType.textureMask]:TextureMaskLayer,[ColorLayerType.vertexMask]:VertexMaskLayer,[ColorLayerType.fresnelMask]:FresnelMaskLayer,[ColorLayerType.depthMask]:DepthMaskLayer,[ColorLayerType.gradientMask]:GradientMaskLayer};/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -122,6 +122,6 @@ export declare function getDataAssetDefinitionId(type: ParameterType | undefined
|
|
|
122
122
|
export declare function getParameterDefinitionInfo(type: ParameterType | undefined | null): ParameterDefinitionInfo | undefined;
|
|
123
123
|
export declare function resolveParameterType(type: ParameterOptions['type']): ParameterType | undefined;
|
|
124
124
|
export declare function getDataAssetDefinitionInfo(type: ParameterType | undefined | null): DataAssetDefinitionInfo | undefined;
|
|
125
|
-
export declare function Parameter(options?: ParameterOptions):
|
|
125
|
+
export declare function Parameter(options?: ParameterOptions): any;
|
|
126
126
|
export declare function ParameterCategory(name: string): void;
|
|
127
127
|
//# sourceMappingURL=parameter.d.ts.map
|
package/dist/shader/parameter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"reflect-metadata";import{reflect as e,decorateProperty as t}from"@plumier/reflect";import{ArrayMap as n}from"../utils/collections.js";Symbol("format");const r=Symbol("parameterDefinition"),a=Symbol("dataAssetDefinition");export function shaderParameterUniformName(e){return`pu_${e}`}class i{constructor(e){this.options=e,this.isParameterDecorator=!0}}new Map;const o=new n,s=new Map,f=new Map,l=new WeakMap,p=new Map,u=new Map,c=new WeakMap;export function ParameterDefinition(e,t={}){return function(n){registerParameterDefinition(e??n.name,n,t)}}export function DataAssetDefinition(e,t={}){return function(n){registerDataAssetDefinition(e??n.name,n,t)}}export function registerParameterDefinition(e,t,n={}){if(null==e||""===e.trim())throw new Error("Parameter definition id must be a non-empty string");const a=s.get(e);null!=a&&a!==t&&console.warn(`Replacing parameter definition "${e}"`,{existing:a,type:t}),s.set(e,t),f.set(e,{id:e,type:t,...!0===n.abstract?{abstract:!0}:{}}),l.set(t,e),Reflect.defineMetadata(r,f.get(e),t)}export function getParameterDefinitionType(e){return s.get(e)}export function registerDataAssetDefinition(e,t,n={}){if(null==e||""===e.trim())throw new Error("Data asset definition id must be a non-empty string");const r=p.get(e);null!=r&&r!==t&&console.warn(`Replacing data asset definition "${e}"`,{existing:r,type:t}),p.set(e,t),u.set(e,{id:e,type:t,...!0===n.abstract?{abstract:!0}:{}}),c.set(t,e),Reflect.defineMetadata(a,u.get(e),t)}export function getDataAssetDefinitionType(e){return p.get(e)}export function getAssignableDataAssetDefinitions(e,t={}){if(null==e)return[];const n=getDataAssetDefinitionId(e);return Array.from(p.entries()).filter(([,t])=>isParameterDefinitionAssignableTo(t,e)).filter(([e])=>!0===t.includeAbstract||!isDataAssetDefinitionAbstract(e)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.id===n?-1:t.id===n?1:e.label.localeCompare(t.label))}export function getDataAssetDefinitions(e={}){return Array.from(p.entries()).filter(([t])=>!0===e.includeAbstract||!isDataAssetDefinitionAbstract(t)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.label.localeCompare(t.label))}export function getAssignableParameterDefinitions(e,t={}){if(null==e)return[];const n=getParameterDefinitionId(e);return Array.from(s.entries()).filter(([,t])=>isParameterDefinitionAssignableTo(t,e)).filter(([e])=>!0===t.includeAbstract||!isParameterDefinitionAbstract(e)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.id===n?-1:t.id===n?1:e.label.localeCompare(t.label))}export function isParameterDefinitionAssignableTo(e,t){return null!=e&&null!=t&&(e===t||e.prototype instanceof t)}export function isParameterDefinitionStructAssignableTo(e,t){return null!=e&&null!=t&&(e===t||isParameterDefinitionAssignableTo(getParameterDefinitionType(e),getParameterDefinitionType(t)))}export function isParameterDefinitionAbstract(e){if(null==e)return!1;const t="string"==typeof e?f.get(e):getParameterDefinitionInfo(e);return!0===t?.abstract}export function isDataAssetDefinitionAbstract(e){if(null==e)return!1;const t="string"==typeof e?u.get(e):getDataAssetDefinitionInfo(e);return!0===t?.abstract}export function getParameterDefinitionDisplayName(e){return("string"==typeof e?e:e.name).replace(/Definition$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[_-]+/g," ").trim().split(/\s+/).filter(e=>e.length>0).map(e=>e.length<=2&&e===e.toUpperCase()?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}export function getParameterDefinitionId(e){if(null!=e)return l.get(e)??Reflect.getMetadata(r,e)?.id}export function getDataAssetDefinitionId(e){if(null!=e)return c.get(e)??Reflect.getMetadata(a,e)?.id}export function getParameterDefinitionInfo(e){if(null==e)return;const t=getParameterDefinitionId(e);return null!=t?f.get(t)??Reflect.getMetadata(r,e)??{id:t,type:e}:void 0}export function resolveParameterType(e){if(null!=e)return"function"==typeof e&&null==e.prototype?e():e}function m(e,t){const{enum:n,...r}=e,a=n??t;if(null==a||r.options?.length>0)return r;const i=function(e){return Object.entries(e).filter(([e])=>!function(e){return""!==e.trim()&&String(Number(e))===e}(e)).map(([e,t])=>({name:getParameterDefinitionDisplayName(e),value:t}))}(a);return{...r,type:r.type??g(i),defaultValue:void 0!==r.defaultValue?r.defaultValue:i[0]?.value,options:i}}function g(e){const t=new Set(e.map(e=>typeof e.value));if(1===t.size)return t.has("number")?Number:t.has("string")?String:void 0}export function getDataAssetDefinitionInfo(e){if(null==e)return;const t=getDataAssetDefinitionId(e);return null!=t?u.get(t)??Reflect.getMetadata(a,e)??{id:t,type:e}:void 0}export function Parameter(e){return function(n,r,a){if(null!=n){o.push(n.constructor,{name:r,options:e??{}});try{t(new i(e))(n,r,a)}catch(e){console.warn("Failed to decorate method ",n,r,a)}}}}export function extractShaderParameters(e){if(null==e)return[];const t=o.get(e).map(({name:t,options:n})=>{const r=Reflect.getMetadata("parameter:enum",e.prototype,t),a=Reflect.getMetadata("parameter:array",e.prototype,t),i=Reflect.getMetadata("parameter:arrayElementType",e.prototype,t),o=Reflect.getMetadata("parameter:dataAssetOf",e.prototype,t),s=m(n,r),f=Reflect.getMetadata("design:type",e.prototype,t),l=!0===s.array||!0===a||f===Array,p=resolveParameterType(s.type)??(l?i:void 0)??f,u=Reflect.getMetadata("prefab:type",e.prototype,t);return s.prefabOf??(s.prefabOf=u),s.dataAssetOf??(s.dataAssetOf=o),s.array=l,{name:t,type:p,options:s,definition:getParameterDefinitionInfo(p)}});return[...extractShaderParameters(Object.getPrototypeOf(e)).filter(e=>t.every(t=>t.name!==e.name)),...t]}export function ParameterCategory(e){}/*
|
|
1
|
+
import"reflect-metadata";import{reflect as e,decorateProperty as t}from"@plumier/reflect";import{ArrayMap as n}from"../utils/collections.js";Symbol("format");const r=Symbol("parameterDefinition"),a=Symbol("dataAssetDefinition");export function shaderParameterUniformName(e){return`pu_${e}`}class i{constructor(e){this.options=e,this.isParameterDecorator=!0}}new Map;const o=new n,s=new Map,f=new Map,l=new WeakMap,p=new Map,u=new Map,c=new WeakMap;export function ParameterDefinition(e,t={}){return function(n){registerParameterDefinition(e??n.name,n,t)}}export function DataAssetDefinition(e,t={}){return function(n){registerDataAssetDefinition(e??n.name,n,t)}}export function registerParameterDefinition(e,t,n={}){if(null==e||""===e.trim())throw new Error("Parameter definition id must be a non-empty string");const a=s.get(e);null!=a&&a!==t&&console.warn(`Replacing parameter definition "${e}"`,{existing:a,type:t}),s.set(e,t),f.set(e,{id:e,type:t,...!0===n.abstract?{abstract:!0}:{}}),l.set(t,e),Reflect.defineMetadata(r,f.get(e),t)}export function getParameterDefinitionType(e){return s.get(e)}export function registerDataAssetDefinition(e,t,n={}){if(null==e||""===e.trim())throw new Error("Data asset definition id must be a non-empty string");const r=p.get(e);null!=r&&r!==t&&console.warn(`Replacing data asset definition "${e}"`,{existing:r,type:t}),p.set(e,t),u.set(e,{id:e,type:t,...!0===n.abstract?{abstract:!0}:{}}),c.set(t,e),Reflect.defineMetadata(a,u.get(e),t)}export function getDataAssetDefinitionType(e){return p.get(e)}export function getAssignableDataAssetDefinitions(e,t={}){if(null==e)return[];const n=getDataAssetDefinitionId(e);return Array.from(p.entries()).filter(([,t])=>isParameterDefinitionAssignableTo(t,e)).filter(([e])=>!0===t.includeAbstract||!isDataAssetDefinitionAbstract(e)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.id===n?-1:t.id===n?1:e.label.localeCompare(t.label))}export function getDataAssetDefinitions(e={}){return Array.from(p.entries()).filter(([t])=>!0===e.includeAbstract||!isDataAssetDefinitionAbstract(t)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.label.localeCompare(t.label))}export function getAssignableParameterDefinitions(e,t={}){if(null==e)return[];const n=getParameterDefinitionId(e);return Array.from(s.entries()).filter(([,t])=>isParameterDefinitionAssignableTo(t,e)).filter(([e])=>!0===t.includeAbstract||!isParameterDefinitionAbstract(e)).map(([e,t])=>({id:e,type:t,label:getParameterDefinitionDisplayName(t)})).sort((e,t)=>e.id===n?-1:t.id===n?1:e.label.localeCompare(t.label))}export function isParameterDefinitionAssignableTo(e,t){return null!=e&&null!=t&&(e===t||e.prototype instanceof t)}export function isParameterDefinitionStructAssignableTo(e,t){return null!=e&&null!=t&&(e===t||isParameterDefinitionAssignableTo(getParameterDefinitionType(e),getParameterDefinitionType(t)))}export function isParameterDefinitionAbstract(e){if(null==e)return!1;const t="string"==typeof e?f.get(e):getParameterDefinitionInfo(e);return!0===t?.abstract}export function isDataAssetDefinitionAbstract(e){if(null==e)return!1;const t="string"==typeof e?u.get(e):getDataAssetDefinitionInfo(e);return!0===t?.abstract}export function getParameterDefinitionDisplayName(e){return("string"==typeof e?e:e.name).replace(/Definition$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[_-]+/g," ").trim().split(/\s+/).filter(e=>e.length>0).map(e=>e.length<=2&&e===e.toUpperCase()?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}export function getParameterDefinitionId(e){if(null!=e)return l.get(e)??Reflect.getMetadata(r,e)?.id}export function getDataAssetDefinitionId(e){if(null!=e)return c.get(e)??Reflect.getMetadata(a,e)?.id}export function getParameterDefinitionInfo(e){if(null==e)return;const t=getParameterDefinitionId(e);return null!=t?f.get(t)??Reflect.getMetadata(r,e)??{id:t,type:e}:void 0}export function resolveParameterType(e){if(null!=e)return"function"==typeof e&&null==e.prototype?e():e}function m(e,t){const{enum:n,...r}=e,a=n??t;if(null==a||r.options?.length>0)return r;const i=function(e){return Object.entries(e).filter(([e])=>!function(e){return""!==e.trim()&&String(Number(e))===e}(e)).map(([e,t])=>({name:getParameterDefinitionDisplayName(e),value:t}))}(a);return{...r,type:r.type??g(i),defaultValue:void 0!==r.defaultValue?r.defaultValue:i[0]?.value,options:i}}function g(e){const t=new Set(e.map(e=>typeof e.value));if(1===t.size)return t.has("number")?Number:t.has("string")?String:void 0}export function getDataAssetDefinitionInfo(e){if(null==e)return;const t=getDataAssetDefinitionId(e);return null!=t?u.get(t)??Reflect.getMetadata(a,e)??{id:t,type:e}:void 0}export function Parameter(e){return function(n,r,a){if(a&&"object"==typeof a&&"field"===a.kind)return o.push(n,{name:r,options:e??{}}),a.addInitializer&&a.addInitializer(function(){}),Reflect.defineMetadata("isParameterDecorator",!0,n,r),void Reflect.defineMetadata("parameterOptions",e,n,r);if(null!=n){o.push(n.constructor,{name:r,options:e??{}});try{t(new i(e))(n,r,a)}catch(e){console.warn("Failed to decorate method ",n,r,a)}}}}export function extractShaderParameters(e){if(null==e)return[];const t=o.get(e).map(({name:t,options:n})=>{const r=Reflect.getMetadata("parameter:enum",e.prototype,t),a=Reflect.getMetadata("parameter:array",e.prototype,t),i=Reflect.getMetadata("parameter:arrayElementType",e.prototype,t),o=Reflect.getMetadata("parameter:dataAssetOf",e.prototype,t),s=m(n,r),f=Reflect.getMetadata("design:type",e.prototype,t),l=!0===s.array||!0===a||f===Array,p=resolveParameterType(s.type)??(l?i:void 0)??f,u=Reflect.getMetadata("prefab:type",e.prototype,t);return s.prefabOf??(s.prefabOf=u),s.dataAssetOf??(s.dataAssetOf=o),s.array=l,{name:t,type:p,options:s,definition:getParameterDefinitionInfo(p)}});return[...extractShaderParameters(Object.getPrototypeOf(e)).filter(e=>t.every(t=>t.name!==e.name)),...t]}export function ParameterCategory(e){}/*
|
|
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*as e from"three";import{Vector2 as t}from"three";import{cross as o,dot as r,float as n,FloatExpressionNode as
|
|
1
|
+
import*as e from"three";import{Vector2 as t}from"three";import{cross as o,dot as r,float as n,FloatExpressionNode as s,FloatNode as c,inverse as a,normalize as i,texture2d as p,transformed as l,uniformFloat as m,uniforms as h,uniformSampler2d as u,uniformVec2 as d,unpackRGBToNormal as x,varying as f,vec2 as y,Vec2ExpressionNode as _,vec4 as U,Vec4Node as g}from"three-shader-graph";import{createPlaceholderTexture as k}from"../utils/three/placeholder-texture.js";export function supportsDepthTextureExtension(e){return!0}export const depthUniformName="hology_depth_map";export const resolutionUniformName="hology_resolution";export const nearUniformName="hology_camera_near";export const farUniformName="hology_camera_far";export const sceneNormalUniformName="hology_scene_normal_map";export const depthSampler=u(depthUniformName,new e.DepthTexture(1,1));const $=m(nearUniformName,.5),N=m(farUniformName,500);class v extends c{compile(e){const t=e.variable();var o=e.get($),r=e.get(N);return{chunk:`\n float depth_${t} = 2.0 * ${o} * ${r} / (${r} + ${o} - (2.0 * ${e.get(this.depth)} - 1.0) * (${r} - ${o}));\n `,out:`depth_${t}`}}constructor(e){super(),this.depth=e}}function w(e){return new v(e)}new class extends g{constructor(){super(...arguments),this.k="31u50"}compile(e){return{pars:`\n const float UnpackDownscale_${this.k} = 255. / 256.; // 0..1 -> fraction (excluding 1)\n const vec4 PackFactors_${this.k} = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\n const vec4 UnpackFactors_${this.k} = vec4( UnpackDownscale_${this.k} / PackFactors_${this.k}.rgb, 1.0 / PackFactors_${this.k}.a );\n `,out:`UnpackFactors_${this.k}`}}};function V(e){return p(depthSampler,e).r}export function sampleSceneDepth(e){return V(e)}export function sampleSceneLinearEyeDepth(e){return w(V(e))}const D=f(h.projectionMatrix.multiplyVec(l.mvPosition).zw);export const highPrecisionEyeDepth=D.x.multiply(.5).divide(D.y).add(.5);const S=new s("gl_FragCoord.z");export const fragmentLinearEyeDepth=w(S);export const resolution=d("hology_resolution",new t(250,1e3));export const screenUV=new _("gl_FragCoord.xy").divide(resolution);export const linearEyeDepth=w(V(screenUV));const P=f(a(h.projectionMatrix)),b=f(a(h.viewMatrix));function F(e=screenUV){const t=V(e).multiply(2).subtract(1),o=e.multiplyScalar(2).subtractScalar(1),r=U(o.x,o.y,t,1),n=P.multiplyVec(r),s=n.xyz.divideScalar(n.w);return b.multiplyVec(U(s,1)).xyz}export const depthWorldPosition=F(screenUV);const E=n(1).divide(resolution.x),z=n(1).divide(resolution.y),j=F(screenUV.add(y(E,n(0)))),M=F(screenUV.add(y(n(0),z)));export const depthNormal=i(o(j.subtract(depthWorldPosition),M.subtract(depthWorldPosition)));export const sceneNormalSampler=u(sceneNormalUniformName,k(128,128,255));export const sceneNormal=x(sceneNormalSampler.sample(screenUV).rgb);/*
|
|
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{float as o,ifDefApply as e,uniformSampler2d as r,Vec3ExpressionNode as
|
|
1
|
+
import{float as o,ifDefApply as e,uniformSampler2d as r,Vec3ExpressionNode as p}from"three-shader-graph";import{screenUV as a}from"./depth.js";import{createPlaceholderTexture as t}from"../utils/three/placeholder-texture.js";export const sceneMapUniformName="hology_scene_map";export const sceneColorSampler=r("hology_scene_map",t());export function sampleSceneColor(o){return sceneColorSampler.sample(o)}export const fragCoord=new p("gl_FragCoord");export const aoMapUniformName="hology_ao_map";export const aoColorSampler=r("hology_ao_map",t());export function sampleScreenAO(r=a){return e("USE_SSAO_MAP",o(1),()=>aoColorSampler.sample(r).r)}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as t,expect as e,it as s}from"vitest";import{BoxGeometry as o,MeshBasicMaterial as a,PerspectiveCamera as n,Scene as d}from"three";import{BatchedMesh2 as r}from"../scene/batched-mesh-2.js";function i(){const t=new o,e=t.getAttribute("position").count,s=t.index?.count??e,n=new r(3,e,s,new a),d=n.addGeometry(t);return n.perObjectFrustumCulled=!1,n.sortObjects=!1,{mesh:n,instanceIds:[n.addInstance(d),n.addInstance(d),n.addInstance(d)]}}function c(t){const e=t._multiDrawCount,s=t._indirectTexture.image.data;return Array.from(s.slice(0,e))}t("BatchedMesh2",()=>{s("filters non-casting instances only while building the shadow draw list",()=>{const{mesh:t,instanceIds:s}=i(),o=new d,a=new n,r=t.material;t.setCastShadowAt(s[0],!1),t.setCastShadowAt(s[1],!0),t.setCastShadowAt(s[2],!1),t.receiveShadow=!1,t.onBeforeShadow({},o,a,a,t.geometry,r,null),e(t.receiveShadow).toBe(!1),e(t._multiDrawCount).toBe(1),e(c(t)).toEqual([s[1]]),e(s.map(e=>t.getVisibleAt(e))).toEqual([!0,!0,!0]),t.onBeforeRender({},o,a,t.geometry,r,null),e(t._multiDrawCount).toBe(3),e(c(t)).toEqual(s)}),s("keeps the object out of shadow passes when no instances cast shadows",()=>{const{mesh:t,instanceIds:s}=i();t.setCastShadowAt(s[0],!0),e(t.castShadow).toBe(!0),t.setCastShadowAt(s[0],!1),e(t.castShadow).toBe(!1),t.setCastShadowAt(s[1],!0),t.deleteInstance(s[1]),e(t.castShadow).toBe(!1)})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{afterEach as e,beforeEach as s,expect as t,test as a,vi as r}from"vitest";import{BrowserNetSession as n}from"../gameplay/net/browser/index.js";import{NetMode as o}from"../gameplay/net/net-session.js";class l{constructor(e){this.name=e,this.listeners=new Set,this.closed=!1;const s=l.channels.get(e)??new Set;s.add(this),l.channels.set(e,s)}postMessage(e){const s=l.channels.get(this.name);if(null!=s)for(const t of s)t===this||t.closed||t.dispatch({data:e})}addEventListener(e,s){"message"===e&&this.listeners.add(s)}removeEventListener(e,s){"message"===e&&this.listeners.delete(s)}close(){this.closed=!0,l.channels.get(this.name)?.delete(this)}dispatch(e){for(const s of this.listeners)"function"==typeof s?s.call(this,e):s.handleEvent(e)}static reset(){l.channels.clear()}}l.channels=new Map;let i=[];function c(e){return i.push(e),e}function d(e){return Array.from(new Uint8Array(e))}s(()=>{l.reset(),r.stubGlobal("BroadcastChannel",l),Object.defineProperty(window,"BroadcastChannel",{configurable:!0,writable:!0,value:l}),localStorage.clear()}),e(()=>{i.forEach(e=>e.disconnect()),i=[],localStorage.clear(),r.useRealTimers(),r.unstubAllGlobals()}),a("sends raw buffers over BroadcastChannel without using localStorage as a message queue",()=>{const e=c(new n(o.listenServer,"room",1,{heartbeatIntervalMs:0})),s=c(new n(o.client,"room",2,{heartbeatIntervalMs:0})),a=[];e.playerJoined.subscribe(e=>a.push(Number(e.id))),e.connect(),s.connect(),t(a).toEqual([2]),t(e.clients.map(e=>e.id)).toEqual([2]),t(s.server?.id).toBe(1),s.sendMessage(s.server,!0,Uint8Array.of(7,8,9).buffer),t(e.hasMessage()).toBe(1);const r=e.readMessage();t(r?.from.id).toBe(2),t(d(r.buffer)).toEqual([7,8,9]),t(e.hasMessage()).toBe(0);const l=JSON.parse(localStorage.getItem("net_session_room"));t(l.members.map(e=>e.connectionId)).toEqual([1,2]),t(l.messages).toBeUndefined()}),a("emits playerLeft when a member disconnects",()=>{const e=c(new n(o.listenServer,"leave-room",1,{heartbeatIntervalMs:0})),s=c(new n(o.client,"leave-room",2,{heartbeatIntervalMs:0})),a=[];e.playerLeft.subscribe(e=>a.push(Number(e.id))),e.connect(),s.connect(),s.disconnect(),t(a).toEqual([2]),t(e.clients).toEqual([])}),a("applies latency and packet loss to unreliable messages",()=>{r.useFakeTimers();const e=c(new n(o.listenServer,"sim-room",1,{heartbeatIntervalMs:0})),s=c(new n(o.client,"sim-room",2,{heartbeatIntervalMs:0,latencyMs:25,packetLoss:1}));e.connect(),s.connect(),s.sendMessage(s.server,!1,Uint8Array.of(1).buffer),r.advanceTimersByTime(100),t(e.hasMessage()).toBe(0),s.configureNetworkSimulation({packetLoss:0}),s.sendMessage(s.server,!1,Uint8Array.of(2).buffer),r.advanceTimersByTime(24),t(e.hasMessage()).toBe(0),r.advanceTimersByTime(1),t(e.hasMessage()).toBe(1),t(d(e.readMessage().buffer)).toEqual([2])}),a("keeps reliable messages ordered when jitter would otherwise reorder them",()=>{r.useFakeTimers();r.spyOn(Math,"random").mockReturnValueOnce(1).mockReturnValueOnce(0);const e=c(new n(o.listenServer,"ordered-room",1,{heartbeatIntervalMs:0})),s=c(new n(o.client,"ordered-room",2,{heartbeatIntervalMs:0,jitterMs:10}));e.connect(),s.connect(),s.sendMessage(s.server,!0,Uint8Array.of(1).buffer),s.sendMessage(s.server,!0,Uint8Array.of(2).buffer),r.advanceTimersByTime(10),t(e.hasMessage()).toBe(2),t(d(e.readMessage().buffer)).toEqual([1]),t(d(e.readMessage().buffer)).toEqual([2])});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"reflect-metadata";import{afterEach as e,expect as t,test as o,vi as n}from"vitest";n.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=("string"!=typeof t||!t.startsWith("is"))&&n.fn()),e[t]),set:(e,t,o)=>(e[t]=o,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),n.mock("../gameplay/services/render.js",()=>({ViewController:class{}})),n.mock("../gameplay/services/physics/physics-system.js",()=>({PhysicsSystem:class{},RayTestResult:class{}})),n.mock("../gameplay/services/world.js",()=>({World:class{}})),n.mock("@hology/nebula",()=>({ease:{easeInOutCubic:e=>e}}));import{Subject as a}from"rxjs";import{Container as i}from"typedi";import{Object3D as
|
|
1
|
+
import"reflect-metadata";import{afterEach as e,expect as t,test as o,vi as n}from"vitest";n.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=("string"!=typeof t||!t.startsWith("is"))&&n.fn()),e[t]),set:(e,t,o)=>(e[t]=o,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),n.mock("../gameplay/services/render.js",()=>({ViewController:class{}})),n.mock("../gameplay/services/physics/physics-system.js",()=>({PhysicsSystem:class{},RayTestResult:class{}})),n.mock("../gameplay/services/world.js",()=>({World:class{}})),n.mock("@hology/nebula",()=>({ease:{easeInOutCubic:e=>e}}));import{Subject as a}from"rxjs";import{Container as i}from"typedi";import{Object3D as s,Ray as r,Scene as c,Vector3 as p}from"three";import{BaseActor as m}from"../gameplay/actors/actor.js";import{FirstPersonCameraComponent as l}from"../gameplay/actors/camera/first-person-camera-component.js";import{ThirdPersonCameraComponent as d}from"../gameplay/actors/camera/third-person-camera-component.js";import{PhysicsSystem as y}from"../gameplay/services/physics/physics-system.js";import{ViewController as u}from"../gameplay/services/render.js";import{World as v}from"../gameplay/services/world.js";function f(e=new g){const t=h(),o=new l;return o.actor=e,{camera:o,actor:e,element:t}}function h(){const e=document.createElement("div"),t=document.createElement("canvas");return e.appendChild(t),Object.defineProperty(e,"clientWidth",{configurable:!0,value:1280}),Object.defineProperty(e,"clientHeight",{configurable:!0,value:720}),i.set(u,{htmlElement:e,setCamera:n.fn(),onUpdate:()=>new a,onLateUpdate:()=>new a}),i.set(v,{scene:new c}),i.set(y,{sphereCast:n.fn()}),e}function w(){Object.defineProperty(document.body,"requestPointerLock",{configurable:!0,value:n.fn()}),Object.defineProperty(document,"pointerLockElement",{configurable:!0,value:null})}function B(e,t){return e.mock.calls.filter(e=>e[0]===t).length}e(()=>{n.restoreAllMocks(),i.reset()}),o("first-person camera clamps pitch input",()=>{const{camera:e}=f();e.rotationInput.rotateX(Math.PI),t(e.rotationInput.rotation.x).toBeCloseTo(Math.PI/2-.01),e.rotationInput.rotateX(2*-Math.PI),t(e.rotationInput.rotation.x).toBeCloseTo(-Math.PI/2+.01)}),o("first-person camera follows actor eye offset",async()=>{const e=new g;e.position.set(1,2,3),e.rotation.y=Math.PI/2,e.object.updateMatrixWorld(!0);const{camera:o}=f(e);o.eyeHeight=1.5,o.offsetZ=.25,o.autoActivate=!1,await o.onInit(),o.updateCameraTransform(),t(o.camera.position.x).toBeCloseTo(1.25),t(o.camera.position.y).toBeCloseTo(3.5),t(o.camera.position.z).toBeCloseTo(3)}),o("first-person aim helpers write to caller-provided objects",async()=>{const e=new g;e.position.set(0,1,0);const{camera:o}=f(e);o.autoActivate=!1,await o.onInit();const n=new p,a=new p,i=new r;t(o.getAimOrigin(n)).toBe(n),t(o.getAimDirection(a)).toBe(a),t(o.getAimRay(i)).toBe(i),t(i.origin).toEqual(n),t(i.direction).toEqual(a),t(a.x).toBeCloseTo(0),t(a.y).toBeCloseTo(0),t(a.z).toBeCloseTo(1),t(a.length()).toBeCloseTo(1)}),o("first-person camera pitch input tilts aim downward when positive",async()=>{const{camera:e}=f();e.autoActivate=!1,await e.onInit(),e.rotationInput.rotateX(.25),e.updateCameraTransform();const o=e.getAimDirection(new p);t(o.y).toBeLessThan(0),t(o.z).toBeGreaterThan(0),t(o.length()).toBeCloseTo(1)}),o("first-person hidden objects restore their previous visibility",()=>{const{camera:e}=f(),o=new s,n=new s;n.visible=!1,e.hideObjects(o,n),t(o.visible).toBe(!1),t(n.visible).toBe(!1),e.restoreHiddenObjects(),t(o.visible).toBe(!0),t(n.visible).toBe(!1)}),o("first-person activation is idempotent",async()=>{const{camera:e,element:o}=f();e.autoActivate=!1,await e.onInit(),w();const a=n.spyOn(o,"addEventListener"),i=n.spyOn(o,"removeEventListener"),s=n.spyOn(document,"addEventListener"),r=n.spyOn(document,"removeEventListener");e.activate(),e.activate(),t(B(a,"pointerdown")).toBe(1),t(B(a,"keydown")).toBe(1),t(B(s,"pointerlockchange")).toBe(1),e.deactivate(),e.deactivate(),t(B(i,"pointerdown")).toBe(1),t(B(i,"keydown")).toBe(1),t(B(r,"pointerlockchange")).toBe(1)}),o("third-person activation remains idempotent",async()=>{const e=new g,o=h(),a=new d;a.actor=e,a.autoActivate=!1,await a.onInit(),w();const i=n.spyOn(o,"addEventListener"),s=n.spyOn(o,"removeEventListener"),r=n.spyOn(document,"addEventListener"),c=n.spyOn(document,"removeEventListener");a.activate(),a.activate(),t(B(i,"pointerdown")).toBe(1),t(B(i,"keydown")).toBe(1),t(B(r,"pointerlockchange")).toBe(1),a.deactivate(),a.deactivate(),t(B(s,"pointerdown")).toBe(1),t(B(s,"keydown")).toBe(1),t(B(c,"pointerlockchange")).toBe(1)}),o("third-person camera does not treat sustained fast movement as a teleport",async()=>{const e=new g;h();const o=new d;o.actor=e,o.autoActivate=!0,o.collision=!1,o.fixedBehind=!1,o.smoothCamera=!0,o.smoothSpeed=10,await o.onInit(),o.onLateUpdate(1/60);for(let t=0;t<12;t++)e.position.x+=.2,o.onLateUpdate(1/60);t(e.position.x-o.camera.position.x).toBeGreaterThan(.7)}),o("third-person camera still snaps after a target teleport",async()=>{const e=new g;h();const o=new d;o.actor=e,o.autoActivate=!0,o.collision=!1,o.fixedBehind=!1,o.smoothCamera=!0,o.teleportSnapDistance=5,await o.onInit(),o.onLateUpdate(1/60),e.position.x=10,o.onLateUpdate(1/60),t(o.camera.position.x).toBeCloseTo(10)});class g extends m{constructor(){super(),this.__isInitialised=!0}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{beforeAll as e,describe as t,expect as o,test as a}from"vitest";import{CharacterMovementMode as n}from"../gameplay/actors/builtin/components/character/modes.js";let r,c;function s(e={}){return{sequence:1,clientTime:.016,dt:.016,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0,...e}}function i(e={}){return{sequence:0,x:0,y:0,z:0,velocityX:0,velocityY:0,velocityZ:0,yaw:0,mode:n.walking,horizontalSpeed:0,...e}}function l(e){return{directionInput:{},jumpInput:{},sprintInput:{},rotationInput:{},setRootMotionAction(){},applyImpulse(){},...e}}e(async()=>{"undefined"!=typeof HTMLCanvasElement&&Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>({fillStyle:"",fillRect(){},clearRect(){},getImageData:()=>({data:new Uint8ClampedArray(4)}),putImageData(){},createImageData:()=>({data:new Uint8ClampedArray(4)}),setTransform(){},drawImage(){},save(){},restore(){},beginPath(){},moveTo(){},lineTo(){},closePath(){},stroke(){},translate(){},scale(){},rotate(){},arc(){},fill(){},measureText:()=>({width:0}),transform(){},rect(){},clip(){}})}),r=await import("../gameplay/actors/builtin/components/character/net-character-movement-protocol.js"),c=(await import("../gameplay/actors/builtin/components/character/character-movement-like.js")).getCharacterMovementLike}),t("net character movement packets",()=>{a("round trips batched saved moves",()=>{const e=[s({sequence:1,dt:.016,inputX:.25,inputY:1,yaw:.5,flags:3,clientX:1,clientY:2,clientZ:3}),s({sequence:2,dt:.033,inputX:-.5,inputY:.5,yaw:-1,flags:1,clientX:4,clientY:5,clientZ:6,rootMotionZ:.2})],t=r.decodeNetCharacterMoveBatch(r.encodeNetCharacterMoveBatch(e));o(t.ok).toBe(!0),t.ok&&(o(t.value.moves).toHaveLength(2),o(t.value.moves[0].sequence).toBe(1),o(t.value.moves[0].clientTime).toBeCloseTo(.016,3),o(t.value.moves[0].dt).toBeCloseTo(.016,3),o(t.value.moves[0].inputX).toBeCloseTo(.25,4),o(t.value.moves[1].rootMotionZ).toBeCloseTo(.2))}),a("round trips owner ack, correction, and simulated state packets",()=>{const e=i({sequence:42,x:10,y:2,z:-3,velocityX:1,yaw:1.25,mode:n.falling,horizontalSpeed:7}),t=r.decodeNetCharacterOwnerAck(r.encodeNetCharacterOwnerAck(42)),a=r.decodeNetCharacterOwnerCorrection(r.encodeNetCharacterOwnerCorrection(e)),c=r.decodeNetCharacterSimulatedState(r.encodeNetCharacterSimulatedState(e));o(t.ok&&t.value.sequence).toBe(42),o(a.ok&&a.value.snapshot.sequence).toBe(42),o(c.ok&&c.value.mode).toBe(n.falling),o(c.ok&&c.value.horizontalSpeed).toBeCloseTo(7)}),a("rejects malformed, unsupported version, and wrong-kind packets",()=>{const e=r.encodeNetCharacterMoveBatch([s({sequence:1})]),t=e.slice();t[0]=99;const a=e.slice();a[1]=99,o(r.decodeNetCharacterMoveBatch(new Uint8Array([1,1,0]))).toMatchObject({ok:!1,reason:"malformed"}),o(r.decodeNetCharacterMoveBatch(t)).toMatchObject({ok:!1,reason:"unsupported-version"}),o(r.decodeNetCharacterMoveBatch(a)).toMatchObject({ok:!1,reason:"wrong-kind"})})}),t("net character prediction helpers",()=>{a("combines adjacent equivalent saved moves by default",()=>{const e=new r.NetCharacterSavedMoveBuffer(4);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,clientZ:.1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,clientZ:.3}));const t=e.getMovesForSend(4);o(t).toHaveLength(1),o(t[0].sequence).toBe(2),o(t[0].dt).toBeCloseTo(.032),o(t[0].clientZ).toBeCloseTo(.3)}),a("keeps adjacent saved moves separate when combining is disabled",()=>{const e=new r.NetCharacterSavedMoveBuffer(4,-1);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,clientZ:.1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,clientZ:.3}));const t=e.getMovesForSend(4);o(t.map(e=>e.sequence)).toEqual([1,2]),o(t.map(e=>e.dt)).toEqual([.016,.016])}),a("preserves a sprint start move for server simulation and replay",()=>{const e=new r.NetCharacterSavedMoveBuffer(4),t=r.MOVE_FLAG_SPRINT|r.MOVE_FLAG_SPRINT_START;e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,flags:t})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,flags:r.MOVE_FLAG_SPRINT}));const a=r.encodeNetCharacterMoveBatch(e.getMovesForSend(4)),n=r.decodeNetCharacterMoveBatch(a);o(n.ok).toBe(!0),n.ok&&(o(n.value.moves.map(e=>e.sequence)).toEqual([1,2]),o(n.value.moves[0].flags).toBe(t))}),a("respects saved move max combined delta time",()=>{const e=new r.NetCharacterSavedMoveBuffer(4,.02);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1})),o(e.getMovesForSend(4).map(e=>e.sequence)).toEqual([1,2])}),a("does not combine a move after it has been selected for sending",()=>{const e=new r.NetCharacterSavedMoveBuffer(4,.1);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1})),o(e.getMovesForSend(4).map(e=>e.sequence)).toEqual([1]),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1}));const t=e.getMovesForSend(4);o(t.map(e=>e.sequence)).toEqual([1,2]),o(t.map(e=>e.dt)).toEqual([.016,.016])}),a("selects the oldest unacked move and newest moves for send packets",()=>{const e=new r.NetCharacterSavedMoveBuffer(8);for(let t=1;t<=5;t++)e.push(s({sequence:t,clientTime:.02*t,dt:.02,inputX:t%2==0?.25:-.25}));o(e.getMovesForSend(3).map(e=>e.sequence)).toEqual([1,4,5])}),a("replays saved moves with a deterministic simulator",()=>{const e=r.replayNetCharacterSavedMoves({x:0},[s({sequence:1,dt:.1,inputY:1}),s({sequence:2,dt:.2,inputY:1})],(e,t)=>({x:e.x+t.inputY*t.dt*10}));o(e.x).toBeCloseTo(3)}),a("validates move sequence, dt, and normalized input",()=>{o(r.validateNetCharacterMove(s({sequence:2,dt:.016}),1)).toBe(!0),o(r.validateNetCharacterMove(s({sequence:1,dt:.016}),1)).toBe(!1),o(r.validateNetCharacterMove(s({sequence:2,clientTime:0}),1)).toBe(!1),o(r.validateNetCharacterMove(s({sequence:2,dt:.5}),1,.1)).toBe(!1),o(r.validateNetCharacterMove(s({sequence:2,inputX:1,inputY:1}),1)).toBe(!1)}),a("derives server move dt from client timestamps",()=>{const e=r.createNetCharacterServerMoveTimingState();r.accrueNetCharacterServerMoveTime(e,.05);const t=r.consumeNetCharacterServerMoveTime(e,s({sequence:1,clientTime:.016}),{maxMoveDeltaTime:.1}),a=r.consumeNetCharacterServerMoveTime(e,s({sequence:2,clientTime:.05}),{maxMoveDeltaTime:.1});o(t).toBeCloseTo(.016),o(a).toBeCloseTo(.034),o(e.lastClientTime).toBeCloseTo(.05)}),a("clamps server move dt and rejects clients too far ahead of server time",()=>{const e=r.createNetCharacterServerMoveTimingState();r.accrueNetCharacterServerMoveTime(e,.02);const t=r.consumeNetCharacterServerMoveTime(e,s({sequence:1,clientTime:.5}),{maxMoveDeltaTime:.05,maxServerMoveDeltaTimeScalar:2,maxClientTimeAhead:.1}),a=r.consumeNetCharacterServerMoveTime(e,s({sequence:2,clientTime:.7}),{maxMoveDeltaTime:.05,maxServerMoveDeltaTimeScalar:2,maxClientTimeAhead:.01});o(t).toBeCloseTo(.1),o(a).toBe(-1)})}),t("net character simulated proxy smoothing",()=>{a("interpolates delayed snapshots",()=>{const e=new r.NetCharacterProxySmoother(.1,20),t=i();e.push(i({sequence:1,x:0}),0),e.push(i({sequence:2,x:10}),1),o(e.sample(.6,t)).toBe(!0),o(t.x).toBeCloseTo(5)}),a("snaps instead of interpolating large gaps",()=>{const e=new r.NetCharacterProxySmoother(0,1),t=i();e.push(i({sequence:1,x:0}),0),e.push(i({sequence:2,x:10}),1),o(e.sample(.5,t)).toBe(!0),o(t.x).toBe(10)})}),t("character movement compatibility",()=>{a("prefers the default movement component when present",()=>{const e=l({horizontalSpeed:2}),t=l({horizontalSpeed:5,isDefaultCharacterMovementComponent:!0});o(c({oldMovement:e,defaultMovement:t,attachedComponents:[]})).toBe(t)})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import"reflect-metadata";import{Subject as n}from"rxjs";import{Vector3 as r}from"three";import{expect as s,test as o,vi as c}from"vitest";c.mock("../gameplay/services/render.js",()=>({ViewController:class{}})),c.mock("../gameplay/services/world.js",()=>({World:class{}}));import{Actor as a,BaseActor as i}from"../gameplay/actors/actor.js";import{ActorComponent as l}from"../gameplay/actors/component.js";import{$actorComponents as p}from"../gameplay/actors/internal/component-init.js";import{NetMode as d}from"../gameplay/net/net-session.js";import{NetRole as u}from"../gameplay/net/service/net-actor-role.js";import{NetSerializer as w}from"../gameplay/net/service/net-serializer.js";import{NetService as _}from"../gameplay/net/service/net-service.js";import{ReplOn as R}from"../gameplay/net/service/replication.js";import{getRpcMethodId as y,registerRpcMethod as g,RunsOn as v}from"../gameplay/net/service/rpc.js";import{RunOnServer as m}from"../gameplay/net/service/rpc-decorator.js";const f=2,h=3,B=4,b=1,S=21,V=25,A=7,C=8;let P=class extends i{constructor(){super(...arguments),this.allValue=0,this.ownerValue=0,this.notOwnerValue=0,this.changingValue=0,this.allOnRepSawOwnerValue=-1,this.clientRpcCalls=[],this.serverRpcCalls=[],this.clientBinaryRpcCalls=[],this.serverBinaryRpcCalls=[],this.largeBinaryRpcByteLength=0,this.largeBinaryRpcLastByte=0}onRep_allValue(){this.allOnRepSawOwnerValue=this.ownerValue}clientRpc(e){this.clientRpcCalls.push(e)}serverRpc(e){this.serverRpcCalls.push(e)}clientBinaryRpc(e){this.clientBinaryRpcCalls.push(Array.from(e))}serverBinaryRpc(e){this.serverBinaryRpcCalls.push(Array.from(e))}largeBinaryRpc(e){this.largeBinaryRpcByteLength=e.byteLength,this.largeBinaryRpcLastByte=e[e.byteLength-1]}};P=e([a({replicate:!0})],P);class O extends l{constructor(){super(...arguments),this.componentValue="",this.binaryRpcCalls=[]}componentBinaryRpc(e){this.binaryRpcCalls.push(Array.from(e))}}g(P.prototype,"clientRpc"),g(P.prototype,"serverRpc"),g(P.prototype,"clientBinaryRpc"),g(P.prototype,"serverBinaryRpc"),g(P.prototype,"largeBinaryRpc"),g(O.prototype,"componentBinaryRpc");class I extends i{constructor(){super(...arguments),this.baseRpcCalls=[]}baseRpc(e){this.baseRpcCalls.push(e)}}class M extends I{constructor(){super(...arguments),this.derivedRpcCalls=[]}derivedRpc(e){this.derivedRpcCalls.push(e)}}g(I.prototype,"baseRpc"),g(M.prototype,"derivedRpc");class k extends i{inheritedRpc(){}}e([m(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],k.prototype,"inheritedRpc",null);class q extends k{derivedRpc(){}}function U(e,t,n={}){const r={actors:t,removeActor(e){const n=t.indexOf(e);n>=0&&t.splice(n,1)}},s=Object.create(w.prototype);s.world=r;const o=j(e,n.clients??[],n.server,n.sent??[]),c=Object.create(_.prototype);return c.session=o,c.world=r,c.serializer=s,c.actorConnection=new Map,c.actorPreSpawnMessageBuffer=new Map,c.actorRefMissingMessageQueue=new Map,c.netStartupActorSpawnQueue=new Map,c.spawningActorNetIds=new Set,c.shouldReplicateMap=new Map,c.replicatedActors=new Map,c.replicatedProperties=new Map,c.replicatedPropertyRegistry=new Map,c.nextNetId=1,c}function j(e,t,r,s){return{id:"test-session",mode:e,clients:t,server:r,reconnect(){},disconnect(){},sendMessage(e,t,n){s.push({receiver:e,reliable:t,buffer:n})},hasMessage:()=>0,readMessage:()=>null,playerJoined:new n,playerLeft:new n}}function L(e){return{id:e}}function x(e){const t=new ArrayBuffer(5),n=new DataView(t);return n.setUint8(0,A),n.setUint32(1,e,!0),t}function E(e){const t=new ArrayBuffer(5),n=new DataView(t);return n.setUint8(0,B),n.setUint32(1,e,!0),t}function z(e){return new DataView(e).getUint8(0)}function D(e){return new DataView(e).getUint8(5)}function Q(e){const t=new DataView(e);let n=0;const r=t.getUint8(n);n+=1;const s=t.getUint32(n,!0);n+=4;n+=1+t.getUint8(n),n+=12,n+=12;const o=t.getUint8(n);n+=1;return{messageType:r,actorId:s,netRole:o,ownerId:t.getUint32(n)}}e([m(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],q.prototype,"derivedRpc",null),o("property snapshots are sent after actorReady and respect replication targets",()=>{const e=L(1),t=L(2),n=L("server"),r=new P;r.__netid=10,r.allValue=11,r.ownerValue=22,r.notOwnerValue=33;const o=[],c=U(d.dedicatedServer,[r],{clients:[e,t],sent:o});c.setOwningConnection(r,e),c.registerReplicatedProperty(R.all,!0,r,"allValue",r),c.registerReplicatedProperty(R.owner,!0,r,"ownerValue",r),c.registerReplicatedProperty(R.notOwner,!0,r,"notOwnerValue",r),c.getPreSpawnMessageQueue(r,e),c.processActorReady(e,x(r.__netid));const a=new P;a.__netid=r.__netid;U(d.client,[a],{server:n}).processPropSnapshot(n,o[0].buffer),s(a.allValue).toBe(11),s(a.ownerValue).toBe(22),s(a.notOwnerValue).toBe(0),s(a.allOnRepSawOwnerValue).toBe(22),o.length=0,c.getPreSpawnMessageQueue(r,t),c.processActorReady(t,x(r.__netid));const i=new P;i.__netid=r.__netid;U(d.client,[i],{server:n}).processPropSnapshot(n,o[0].buffer),s(i.allValue).toBe(11),s(i.ownerValue).toBe(0),s(i.notOwnerValue).toBe(33)}),o("property updates queued during spawn are replaced by the latest snapshot value",()=>{const e=L(1),t=L("server"),n=new P;n.changingValue=1;const r=[],o=U(d.dedicatedServer,[n],{clients:[e],sent:r});o.setReplicate(n,!0),o.registerReplicatedProperty(R.all,!0,n,"changingValue",n),o.sendActorSpawn(n,[e]),r.length=0,n.changingValue=2,o.handlePropertySet(R.all,!0,n,"changingValue",n.changingValue),n.changingValue=3,o.handlePropertySet(R.all,!0,n,"changingValue",n.changingValue),s(r).toHaveLength(0),o.processActorReady(e,x(n.__netid)),s(r.map(e=>z(e.buffer))).toEqual([C]);const c=new P;c.__netid=n.__netid;U(d.client,[c],{server:t}).processPropSnapshot(t,r[0].buffer),s(c.changingValue).toBe(3)}),o("property snapshots include component properties",()=>{const e=L(1),t=L("server"),n=new P;n.__netid=20;const r=new O;r.actor=n,r.__netid=1,r.componentValue="server component",n[p]=[r];const o=[],c=U(d.dedicatedServer,[n],{clients:[e],sent:o});c.registerReplicatedProperty(R.all,!0,n,"componentValue",r,r),c.getPreSpawnMessageQueue(n,e),c.processActorReady(e,x(n.__netid));const a=new P;a.__netid=n.__netid;const i=new O;i.actor=a,i.__netid=r.__netid,a[p]=[i];U(d.client,[a],{server:t}).processPropSnapshot(t,o[0].buffer),s(i.componentValue).toBe("server component")}),o("property snapshots queue atomically when they reference a missing actor",()=>{const e=c.spyOn(console,"warn").mockImplementation(()=>{}),t=c.spyOn(console,"debug").mockImplementation(()=>{}),n=c.spyOn(console,"log").mockImplementation(()=>{}),r=L(1),o=L("server"),a=new P;a.__netid=30,a.allValue=44;const i=new P;i.__netid=31,a.referencedActor=i;const l=[],p=U(d.dedicatedServer,[a,i],{clients:[r],sent:l});p.registerReplicatedProperty(R.all,!0,a,"allValue",a),p.registerReplicatedProperty(R.all,!0,a,"referencedActor",a),p.getPreSpawnMessageQueue(a,r),p.processActorReady(r,x(a.__netid));const u=new P;u.__netid=a.__netid;const w=U(d.client,[u],{server:o});w.processPropSnapshot(o,l[0].buffer),s(u.allValue).toBe(0),s(u.referencedActor).toBeUndefined();const _=new P;_.__netid=i.__netid,w.world.actors.push(_),w.processQueuedActorMessages(_.__netid),s(u.allValue).toBe(44),s(u.referencedActor).toBe(_),e.mockRestore(),t.mockRestore(),n.mockRestore()}),o("live property replication applies server updates and ignores non-server messages",()=>{const e=L("server"),t=L(1),n=new P;n.__netid=40;const r=[],o=U(d.dedicatedServer,[n],{clients:[t],sent:r});o.setReplicate(n,!0),o.sendActorSpawn(n,[t]),o.processActorReady(t,x(n.__netid)),r.length=0,o.handlePropertySet(R.all,!0,n,"allValue",55),s(r).toHaveLength(1),s(z(r[0].buffer)).toBe(f);const a=new P;a.__netid=n.__netid,a.ownerValue=66;const i=U(d.client,[a],{server:e});i.processProp(e,r[0].buffer),s(a.allValue).toBe(55),s(a.allOnRepSawOwnerValue).toBe(66);const l=c.spyOn(console,"warn").mockImplementation(()=>{}),p=r[0].buffer;a.allValue=12,i.processProp(L("rogue"),p),s(a.allValue).toBe(12),l.mockRestore()}),o("server RPCs from clients require ownership and owner RPCs run on the owning client",()=>{const e=L(1),t=L(2),n=L("server"),r=new P;r.__netid=50;const o=U(d.dedicatedServer,[r],{clients:[e,t]});o.setReplicate(r,!0),o.replicatedActors.set(r,{spawnedAt:Date.now(),connections:[e,t]}),o.setOwningConnection(r,e);const a=new P;a.__netid=r.__netid;const i=[],l=U(d.client,[a],{server:n,sent:i});l.setReplicate(a,!0),l.sendRpc(v.server,!0,a,"serverRpc",[77]),s(D(i[0].buffer)).toBe(y(a,"serverRpc")),o.processRpc(e,i[0].buffer),s(r.serverRpcCalls).toEqual([77]);const p=new P;p.__netid=r.__netid;const u=[],w=U(d.client,[p],{server:n,sent:u});w.setReplicate(p,!0);const _=c.spyOn(console,"warn").mockImplementation(()=>{});w.sendRpc(v.server,!0,p,"serverRpc",[88]),o.processRpc(t,u[0].buffer),s(r.serverRpcCalls).toEqual([77]),_.mockRestore();const R=[];o.session=j(d.dedicatedServer,[e,t],void 0,R),o.sendRpc(v.client,!0,r,"clientRpc",[99]),s(R.map(e=>e.receiver.id)).toEqual([e.id]),s(z(R[0].buffer)).toBe(b),s(D(R[0].buffer)).toBe(y(r,"clientRpc")),l.processRpc(n,R[0].buffer),s(a.clientRpcCalls).toEqual([99])}),o("RPC method ids include inherited methods before derived registrations",()=>{const e=L(1),t=L("server"),n=new M;n.__netid=60;const r=U(d.dedicatedServer,[n],{clients:[e]});r.setReplicate(n,!0),r.setOwningConnection(n,e);const o=new M;o.__netid=n.__netid;const c=[],a=U(d.client,[o],{server:t,sent:c});a.setReplicate(o,!0),s(y(o,"baseRpc")).toBe(0),s(y(o,"derivedRpc")).toBe(1),a.sendRpc(v.server,!0,o,"baseRpc",[10]),a.sendRpc(v.server,!0,o,"derivedRpc",[20]),s(D(c[0].buffer)).toBe(0),s(D(c[1].buffer)).toBe(1),r.processRpc(e,c[0].buffer),r.processRpc(e,c[1].buffer),s(n.baseRpcCalls).toEqual([10]),s(n.derivedRpcCalls).toEqual([20])}),o("decorated inherited RPCs do not need to be redecorated on subclasses",()=>{const e=new q;s(y(e,"inheritedRpc")).toBe(0),s(y(e,"derivedRpc")).toBe(1)}),o("binary actor RPCs bypass NetSerializer from client to server",()=>{const e=L(1),t=L("server"),n=new P;n.__netid=80;const r=U(d.dedicatedServer,[n],{clients:[e]});r.setReplicate(n,!0),r.setOwningConnection(n,e);const o=new P;o.__netid=n.__netid;const a=[],i=U(d.client,[o],{server:t,sent:a});i.setReplicate(o,!0);const l=c.spyOn(i.serializer,"encode"),p=c.spyOn(r.serializer,"decode");i.sendRpc(v.server,!0,o,"serverBinaryRpc",[new Uint8Array([1,2,3])]),s(z(a[0].buffer)).toBe(S),s(l).not.toHaveBeenCalled(),r.processRpc(e,a[0].buffer),s(p).not.toHaveBeenCalled(),s(n.serverBinaryRpcCalls).toEqual([[1,2,3]]),l.mockRestore(),p.mockRestore()}),o("server to owner binary RPC preserves owner routing",()=>{const e=L(1),t=L(2),n=L("server"),r=new P;r.__netid=81;const o=[],c=U(d.dedicatedServer,[r],{clients:[e,t],sent:o});c.setReplicate(r,!0),c.replicatedActors.set(r,{spawnedAt:Date.now(),connections:[e,t]}),c.setOwningConnection(r,e);const a=new Uint8Array([9,8,7]);c.sendRpc(v.client,!0,r,"clientBinaryRpc",[new DataView(a.buffer)]),s(o.map(e=>e.receiver.id)).toEqual([e.id]),s(z(o[0].buffer)).toBe(S);const i=new P;i.__netid=r.__netid;U(d.client,[i],{server:n}).processRpc(n,o[0].buffer),s(i.clientBinaryRpcCalls).toEqual([[9,8,7]])}),o("component binary RPC resolves component id",()=>{const e=L(1),t=L("server"),n=new P;n.__netid=82;const r=new O;r.actor=n,r.__netid=4,n[p]=[r];const o=[],c=U(d.dedicatedServer,[n],{clients:[e],sent:o});c.setReplicate(n,!0),c.replicatedActors.set(n,{spawnedAt:Date.now(),connections:[e]}),c.sendRpc(v.all,!0,n,"componentBinaryRpc",[new Uint8Array([4,5,6])],r),s(z(o[0].buffer)).toBe(V);const a=new P;a.__netid=n.__netid;const i=new O;i.actor=a,i.__netid=r.__netid,a[p]=[i];U(d.client,[a],{server:t}).processRpc(t,o[0].buffer),s(i.binaryRpcCalls).toEqual([[4,5,6]])}),o("binary RPC payload length supports more than uint16",()=>{const e=L(1),t=L("server"),n=new P;n.__netid=83;const r=U(d.dedicatedServer,[n],{clients:[e]});r.setReplicate(n,!0),r.setOwningConnection(n,e);const o=new P;o.__netid=n.__netid;const c=[],a=U(d.client,[o],{server:t,sent:c});a.setReplicate(o,!0);const i=new Uint8Array(7e4);i[i.length-1]=231,a.sendRpc(v.server,!0,o,"largeBinaryRpc",[i]),s(z(c[0].buffer)).toBe(S),s(function(e){const t=new DataView(e);let n=6;return t.getUint32(n,!0)}(c[0].buffer)).toBe(i.length),r.processRpc(e,c[0].buffer),s(n.largeBinaryRpcByteLength).toBe(i.length),s(n.largeBinaryRpcLastByte).toBe(231)}),o("binary RPCs queue when the target actor is missing",()=>{const e=c.spyOn(console,"debug").mockImplementation(()=>{}),t=L(1),n=L("server"),r=new P;r.__netid=84;const o=[],a=U(d.dedicatedServer,[r],{clients:[t],sent:o});a.setReplicate(r,!0),a.replicatedActors.set(r,{spawnedAt:Date.now(),connections:[t]}),a.sendRpc(v.all,!0,r,"clientBinaryRpc",[new Uint8Array([8,4])]);const i=U(d.client,[],{server:n});i.processRpc(n,o[0].buffer);const l=new P;l.__netid=r.__netid,i.world.actors.push(l),i.processQueuedActorMessages(l.__netid),s(l.clientBinaryRpcCalls).toEqual([[8,4]]),e.mockRestore()}),o("actor spawn messages are personalized with owner role and owner actor id",()=>{const e=L(1),t=L(2),n=new P;n.__netid=90;const r=new P;r.owner=n;const o=[],c=U(d.dedicatedServer,[n,r],{clients:[e,t],sent:o});c.setOwningConnection(n,e),c.sendActorSpawn(r,[e,t]),s(o).toHaveLength(2);const a=Q(o[0].buffer),i=Q(o[1].buffer);s(a.messageType).toBe(h),s(a.actorId).toBe(r.__netid),s(a.netRole).toBe(u.autonomousProxy),s(a.ownerId).toBe(n.__netid),s(i.actorId).toBe(r.__netid),s(i.netRole).toBe(u.simulatedProxy),s(i.ownerId).toBe(n.__netid)}),o("startup actor spawn binds an existing materialized scene actor",async()=>{const e=c.spyOn(console,"log").mockImplementation(()=>{}),t=L(1),n=L("server"),r="level/chest",o=new P;o.__netSceneId=r;const a=[];U(d.dedicatedServer,[o],{clients:[t],sent:a}).sendActorSpawn(o,[t]);const i=new P;i.__netSceneId=r;const l=[],p=U(d.client,[i],{server:n,sent:l});await p.processSpawn(n,a[0].buffer),s(i.__netid).toBe(o.__netid),s(i.netRole).toBe(u.simulatedProxy),s(p.world.actors).toEqual([i]),s(l).toHaveLength(1),s(z(l[0].buffer)).toBe(A),s(new DataView(l[0].buffer).getUint32(1,!0)).toBe(o.__netid),e.mockRestore()}),o("startup actor spawn waits for the materialized scene actor",async()=>{const e=c.spyOn(console,"log").mockImplementation(()=>{}),t=L(1),n=L("server"),r="level/delayed-chest",o=new P;o.__netSceneId=r;const a=[];U(d.dedicatedServer,[o],{clients:[t],sent:a}).sendActorSpawn(o,[t]);const i=[],l=[],p=U(d.client,i,{server:n,sent:l});await p.processSpawn(n,a[0].buffer),s(l).toHaveLength(0),s(p.netStartupActorSpawnQueue.get(r)).toHaveLength(1);const w=new P;w.__netSceneId=r,i.push(w),p.processQueuedNetStartupActorSpawns(w),s(w.__netid).toBe(o.__netid),s(w.netRole).toBe(u.simulatedProxy),s(p.netStartupActorSpawnQueue.has(r)).toBe(!1),s(l).toHaveLength(1),s(z(l[0].buffer)).toBe(A),e.mockRestore()}),o("materialized scene actors get client-side initial roles",()=>{const e=new P;e.__netSceneId="level/replicated";const t=new I;t.__netSceneId="level/local-only";const n=U(d.client,[e,t]);n.configureMaterializedActorRole(e),n.configureMaterializedActorRole(t),s(e.netRole).toBe(u.simulatedProxy),s(t.netRole).toBe(u.none)}),o("remove actor messages only remove client actors when sent by the server",()=>{const e=L("server"),t=new P;t.__netid=60;const n=[t],r=U(d.client,n,{server:e}),o=c.spyOn(console,"warn").mockImplementation(()=>{});r.processRemoveActor(L("rogue"),E(t.__netid)),s(n).toContain(t),r.processRemoveActor(e,E(t.__netid)),s(n).not.toContain(t),o.mockRestore()}),o("net serializer preserves actor references and three vector values",()=>{const e=new P;e.__netid=70;const t={actors:[e]},n=Object.create(w.prototype);n.world=t;const o=n.encode({actor:e,position:new r(1,2,3),nested:{values:new Set([new r(4,5,6)])}}),c={error:!1,missingActorId:void 0,reset(){this.error=!1,this.missingActorId=void 0}},a=n.decode(o,c);s(a.actor).toBe(e),s(a.position).toBeInstanceOf(r),s(a.position.toArray()).toEqual([1,2,3]),s([...a.nested.values][0].toArray()).toEqual([4,5,6]),s(c.error).toBe(!1)});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{expect as t,test as o}from"vitest";import*as e from"three";import{BaseActor as i}from"../gameplay/actors/actor.js";import{CharacterAnimationComponent as n,
|
|
1
|
+
import{expect as t,test as o}from"vitest";import*as e from"three";import{BaseActor as i}from"../gameplay/actors/actor.js";import{CharacterAnimationComponent as n,OldCharacterMovementComponent as s}from"../gameplay/actors/index.js";import{RootMotionClip as r}from"../gameplay/animation/root-motion.js";import{createAnimationClipInstance as a,createAnimationSubTrack as c,evaluateAnimationClipOutputProgress as l,evaluateAnimationClipSourceProgress as m,normalizeAnimationClipRetiming as p,SequencePlayer as u,buildRetimedAnimationClip as d}from"../effects/sequence/index.js";function g(t){return Array.from(t).map(t=>Math.round(1e3*t)/1e3)}o("uniform retiming mapping stays linear",()=>{t(m(void 0,.25)).toBeCloseTo(.25),t(l(void 0,.75)).toBeCloseTo(.75),t(m({mode:"uniform",points:[]},.6)).toBeCloseTo(.6)}),o("impact retiming redistributes time around the impact marker",()=>{const o={mode:"impact",points:[{id:"impact",clipProgress:.35,sourceProgress:.55}]};t(m(o,.35)).toBeCloseTo(.55),t(l(o,.55)).toBeCloseTo(.35),t(m(o,.7)).toBeGreaterThan(.7)}),o("advanced retiming sanitization stays monotonic and bounded",()=>{const o=p({mode:"advanced",points:[{id:"a",clipProgress:.9,sourceProgress:.2},{id:"b",clipProgress:-4,sourceProgress:.8},{id:"c",clipProgress:.9,sourceProgress:2},{id:"d",clipProgress:.4,sourceProgress:.1}]});t(o.points).toHaveLength(3);for(let e=1;e<o.points.length;e++)t(o.points[e].clipProgress).toBeGreaterThan(o.points[e-1].clipProgress),t(o.points[e].sourceProgress).toBeGreaterThan(o.points[e-1].sourceProgress);t(o.points[0].clipProgress).toBeGreaterThan(0),t(o.points[o.points.length-1].sourceProgress).toBeLessThan(1)}),o("retimed clip baking preserves trim boundary poses and remaps track times to clip duration",()=>{const o=new e.AnimationClip("trim-test",2,[new e.NumberKeyframeTrack("weight",[0,1,2],[0,10,20])]),i=a("anim",0,1);i.clipStartOffset=.5,i.clipEndOffset=.25,i.retiming={mode:"advanced",points:[]};const n=d(o,i),s=n.tracks[0];t(n.duration).toBeCloseTo(1),t(g(s.times)).toEqual([0,.4,1]),t(g(s.values)).toEqual([5,10,17.5])}),o("root motion track baking stays aligned with the retimed visual clip",()=>{const o=new e.AnimationClip("root-motion-test",2,[new e.VectorKeyframeTrack("hips.position",[0,1,2],[0,0,0,1,0,0,2,0,0])]),i=a("anim",0,1);i.retiming={mode:"impact",points:[{id:"impact",clipProgress:.25,sourceProgress:.5}]};const n=d(o,i),s=n.tracks[0],c=r.fromClip(n,!1);t(g(s.times)).toEqual([0,.25,1]),t(g(c.motionTrack.times)).toEqual([0,.25,1]),t(g(c.motionTrack.values)).toEqual([0,0,0,1,0,0,2,0,0])}),o("sequence player keeps uniform clips on the existing playback path",()=>{const o=new u,i=c(),n=a("anim",0,1);n.playbackRate=1.75,n.clipStartOffset=.25,i.clips.push(n);const s=new e.AnimationClip("uniform-test",2,[new e.NumberKeyframeTrack("weight",[0,1,2],[0,1,2])]);o.animationClips.set("anim",s);const r=new e.Object3D,l={target:r,mixer:new e.AnimationMixer(r),activeActions:new Map};o.evaluateAnimationSubTrack(i,l,.1);const m=l.activeActions.get(`${i.id}-${n.id}`);t(m).toBeDefined(),t(m.getClip()).toBe(s),t(m.timeScale).toBeCloseTo(1.75),t(m.time).toBeCloseTo(.25)}),o("sequence player uses baked retimed clips and still wires root motion through the action",()=>{const o=new u,i=c(),n=a("anim",0,1.5);n.rootMotion=!0,n.playbackRate=2,n.retiming={mode:"impact",points:[{id:"impact",clipProgress:.3,sourceProgress:.55}]},i.clips.push(n);const s=new e.AnimationClip("retimed-root",2,[new e.VectorKeyframeTrack("hips.position",[0,1,2],[0,0,0,1,0,0,2,0,0]),new e.NumberKeyframeTrack("weight",[0,1,2],[0,1,2])]);o.animationClips.set("anim",s);const l=new h,m=new f(l.object),p=new A;l.charAnim=m,l.movement=p;const d={target:l,activeActions:new Map};o.evaluateAnimationSubTrack(i,d,.1);const g=d.activeActions.get(`${i.id}-${n.id}`);t(g).toBeDefined(),t(g.timeScale).toBeCloseTo(1),t(g.getClip()).toBeInstanceOf(r),t(g.getClip().duration).toBeCloseTo(1.5),t(p.lastRootMotionAction).toBe(g),t(o.retimedAnimationClips.size).toBe(1)});class h extends i{constructor(){super(...arguments),this.charAnim=null,this.movement=null}getComponent(t){return t===n?this.charAnim:t===s?this.movement:void 0}}class f{constructor(t){this.fullBodyAction=null,this.mixer=new e.AnimationMixer(t)}play(t,o={}){this.fullBodyAction=this.mixer.clipAction(t),this.fullBodyAction.setLoop(e.LoopOnce,1),this.fullBodyAction.clampWhenFinished=!0,this.fullBodyAction.timeScale=o.timeScale??1,null!=o.offset&&(this.fullBodyAction.time=o.offset),this.fullBodyAction.play()}beginExternalAnimationControl(t,o={}){return this.play(t,o),this.getFullBodyAction()}getFullBodyAction(){if(null==this.fullBodyAction)throw new Error("No full body action is active");return this.fullBodyAction}getMixer(){return this.mixer}beginExternalControl(){}endExternalControl(){}stopSequenceAnimation(){}}class A{constructor(){this.lastRootMotionAction=null}setRootMotionAction(t){this.lastRootMotionAction=t}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{expect as o,test as e,vi as r}from"vitest";import{Color as t}from"three";import{RandomColor as l}from"../effects/vfx/initializsers.js";e("random color initializer assigns particle color and enables renderer color use",()=>{const e=r.spyOn(Math,"random").mockReturnValue(.25);try{const e=new l(new t("#000000"),new t("#ffffff")),r={color:{r:0,g:0,b:0},useColor:!1};e.initialize(r),o(r.useColor).toBe(!0),o(r.color.r).toBeCloseTo(.25),o(r.color.g).toBeCloseTo(.25),o(r.color.b).toBeCloseTo(.25)}finally{e.mockRestore()}});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as e,expect as t,test as o,vi as n}from"vitest";import{Euler as s,Group as a,Scene as i,Vector3 as r}from"three";n.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=n.fn()),e[t]),set:(e,t,o)=>(e[t]=o,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),n.mock("../rendering.js",()=>({RenderingView:class{}})),n.mock("../gameplay/services/physics/physics-system.js",()=>({PhysicsSystem:class{}}));import{World as c}from"../gameplay/services/world.js";e("World.spawnPrefab",()=>{o("makes the requested transform available while prefab actors initialize",async()=>{const e=new i,o=new i,p=new a;p.position.set(1,0,0);const l=new a;let d,m=o;const y={inEditor:!0,setScene:n.fn(e=>{m=e}),createFromPrefabAsset:n.fn(async(e,t,o)=>(o.add(l),l.add(p),y.inEditor||m.attach(p),d=p.position.clone(),{object:l,actors:[],mainActor:null}))},f=Object.create(c.prototype);f.scene=e,f.materializer=y,f.actorFactory={inEditor:!1},f.physics={addFromScene:n.fn()};const w=new r(10,2,5),b=new s(0,Math.PI/2,0),h=new a,j=new a;h.position.copy(w),h.rotation.copy(b),j.position.set(1,0,0),h.add(j),h.updateWorldMatrix(!0,!0);const u=j.getWorldPosition(new r),g=await f.spawnPrefab({asset:{}},w,b);t(d).toEqual(u),t(y.setScene).toHaveBeenCalledWith(e),t(y.inEditor).toBe(!1),t(p.parent).toBe(e),t(g?.object.parent).toBe(e),t(g?.object.position).toEqual(w),t(g?.object.rotation.y).toBeCloseTo(b.y)})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{DataTexture as e,RGBAFormat as r}from"three";export function createPlaceholderTexture(t=255,n=255,o=255,a=255){const c=new e(new Uint8Array([t,n,o,a]),1,1,r);return c.needsUpdate=!0,c}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hology/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.212",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
"./gameplay/actors/actor": "./dist/gameplay/actors/actor.js",
|
|
46
46
|
"./gameplay/input": "./dist/gameplay/input/index.js",
|
|
47
47
|
"./gameplay/services/physics/physics-system": "./dist/gameplay/services/physics/physics-system.js",
|
|
48
|
+
"./gameplay/net": "./dist/gameplay/net/index.js",
|
|
49
|
+
"./gameplay/net/browser": "./dist/gameplay/net/browser/index.js",
|
|
48
50
|
"./effects/vfx/vfx-actor": "./dist/effects/vfx/vfx-actor.js",
|
|
49
51
|
"./effects/vfx/vfx-asset": "./dist/effects/vfx/vfx-asset.js",
|
|
50
52
|
"./effects/vfx/vfx-defs": "./dist/effects/vfx/vfx-defs.js",
|
|
@@ -147,6 +149,12 @@
|
|
|
147
149
|
"gameplay/services/physics/physics-system": [
|
|
148
150
|
"./dist/gameplay/services/physics/physics-system.d.ts"
|
|
149
151
|
],
|
|
152
|
+
"gameplay/net": [
|
|
153
|
+
"./dist/gameplay/net/index.d.ts"
|
|
154
|
+
],
|
|
155
|
+
"gameplay/net/browser": [
|
|
156
|
+
"./dist/gameplay/net/browser/index.d.ts"
|
|
157
|
+
],
|
|
150
158
|
"effects/vfx/vfx-actor": [
|
|
151
159
|
"./dist/effects/vfx/vfx-actor.d.ts"
|
|
152
160
|
],
|