@hology/core 0.0.214 → 0.0.216
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/config/project-config.d.ts +1 -0
- package/dist/effects/sequence/sequence-action.d.ts +4 -0
- package/dist/effects/sequence/sequence-actor.js +1 -1
- package/dist/effects/sequence/sequence-animation-retiming.d.ts +2 -1
- package/dist/effects/sequence/sequence-animation-retiming.js +1 -1
- package/dist/effects/sequence/sequence-data.d.ts +6 -0
- package/dist/effects/sequence/sequence-data.js +1 -1
- package/dist/effects/sequence/sequence-player.d.ts +11 -0
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/vfx-collision-behaviour.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 +3 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +22 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-slide.d.ts +7 -0
- package/dist/gameplay/actors/builtin/components/character/character-slide.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/modes.d.ts +2 -1
- package/dist/gameplay/actors/builtin/components/character/modes.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts +3 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/camera/third-person-camera-component.d.ts +1 -0
- package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
- package/dist/gameplay/ai/behavior-tree/move.js +1 -1
- package/dist/gameplay/ai/dynamic-tiled-navmesh.d.ts +20 -2
- package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
- package/dist/gameplay/animation/animation-action.d.ts +3 -0
- package/dist/gameplay/animation/animation-action.js +4 -0
- package/dist/gameplay/services/physics/physics-system.d.ts +56 -3
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +10 -0
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/collision/collision-shape.d.ts +1 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/builtin/unlit-shader.js +1 -1
- package/dist/shader/decal-shader.d.ts +2 -2
- package/dist/shader/decal-shader.js +1 -1
- package/dist/shader/shader.d.ts +2 -1
- package/dist/shader/shader.js +1 -1
- package/dist/shader/sprite-shader.d.ts +2 -2
- package/dist/shader/sprite-shader.js +1 -1
- package/dist/shader/trail-shader.d.ts +2 -2
- package/dist/shader/trail-shader.js +1 -1
- package/dist/test/asset-resource-loader-texture-array.test.d.ts +2 -0
- package/dist/test/asset-resource-loader-texture-array.test.js +4 -0
- package/dist/test/character-animation-transition.test.d.ts +2 -0
- package/dist/test/character-animation-transition.test.js +4 -0
- package/dist/test/character-slide.test.d.ts +2 -0
- package/dist/test/character-slide.test.js +4 -0
- package/dist/test/navmesh-worker-pool.test.d.ts +2 -0
- package/dist/test/navmesh-worker-pool.test.js +4 -0
- package/dist/test/net-character-movement.test.js +1 -1
- package/dist/test/sequence-animation-retiming.test.js +1 -1
- package/dist/test/sequence-root-motion-axis-mask.test.d.ts +2 -0
- package/dist/test/sequence-root-motion-axis-mask.test.js +4 -0
- package/package.json +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import{ActorComponent as o,Component as i}from"../component.js";import{Vector3 as s,MathUtils as n,PerspectiveCamera as h,Object3D as r}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as c,RestrictedRotationInput as d}from"../../input/index.js";import{PhysicsSystem as m}from"../../services/physics/physics-system.js";import{Parameter as p}from"../../../shader/parameter.js";import{World as l}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as f}from"@hology/nebula";const v=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let k=class extends o{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(m),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.5,this.far=500,this.viewAngle=v?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new h(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new d(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new c(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(l),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default")},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&this.canvas.requestPointerLock&&(this.canvas.requestPointerLock({unadjustedMovement:!0}),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t),this.collision&&this.checkForCollision(t);let e=this.zoomInput.value,o=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=n.lerp(this.smoothedRotX,o,s),this.smoothedRotY=n.lerp(this.smoothedRotY,i,s),o=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=n.lerp(this.smoothZoom,e,.4*s),e=this.smoothZoom}else this.smoothedRotX=o,this.smoothedRotY=i;const s=n.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*e,this.minDistance)),h=Math.cos(o)*s,r=this.fixedBehind?0:i;this.offset.x=Math.sin(-r)*h,this.offset.y=Math.sin(o)*s+
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import{ActorComponent as o,Component as i}from"../component.js";import{Vector3 as s,MathUtils as n,PerspectiveCamera as h,Object3D as r}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as c,RestrictedRotationInput as d}from"../../input/index.js";import{PhysicsSystem as m}from"../../services/physics/physics-system.js";import{Parameter as p}from"../../../shader/parameter.js";import{World as l}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as f}from"@hology/nebula";const v=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let k=class extends o{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(m),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.5,this.far=500,this.viewAngle=v?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new h(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetY=2,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new d(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new c(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(l),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default")},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&this.canvas.requestPointerLock&&(this.canvas.requestPointerLock({unadjustedMovement:!0}),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t),this.collision&&this.checkForCollision(t);let e=this.zoomInput.value,o=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=n.lerp(this.smoothedRotX,o,s),this.smoothedRotY=n.lerp(this.smoothedRotY,i,s),o=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=n.lerp(this.smoothZoom,e,.4*s),e=this.smoothZoom}else this.smoothedRotX=o,this.smoothedRotY=i;const s=n.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*e,this.minDistance)),h=Math.cos(o)*s,r=this.fixedBehind?0:i;this.offset.x=Math.sin(-r)*h,this.offset.y=Math.sin(o)*s+this.offsetY,this.offset.z=Math.cos(-r)*-h,this.fixedBehind&&this.offset.add(this.lookAtOffset),this.updateCameraPosition(t)}checkForCollision(t){const e=this.getLookAtPosition(),o=this.camera.getWorldPosition(w),i=A.subVectors(o,e),s=i.length();if(s<.001)return;i.divideScalar(s);const h=this.physicsSystem.sphereCast(e,this.collisionSphereRadius,i,this.distance,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2});if(h.hasHit){const e=Math.max(this.minDistance,h.distance-.05);e<this.restrictedDistance?this.restrictedDistance=e:this.restrictedDistance=n.lerp(this.restrictedDistance,e,n.clamp(this.bounceBackSpeed*t,0,1))}else this.restrictedDistance=n.lerp(this.restrictedDistance,this.distance,n.clamp(this.bounceBackSpeed*t,0,1))}getLookAtPosition(){const t=y;return t.set(0,0,0),t.y=this.height,this.fixedBehind&&t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(t){this.actor.object.updateWorldMatrix(!0,!1),this.fixedBehind?(L.position.set(this.offset.x,this.offset.y,this.offset.z),L.rotation.set(0,0,0),L.scale.set(1,1,1),L.applyMatrix4(this.actor.object.matrix)):L.position.copy(this.actor.position).add(this.offset);const e=f.easeInOutCubic(1-this.blendDurationLeft);if(this.blendDurationLeft>0){const t=this.getLookAtPosition();this.prevLookAt.lerp(t,e),this.camera.lookAt(this.prevLookAt),this.camera.position.lerp(L.position,e),this.smoothedLookAt.copy(this.prevLookAt),this.previousTargetLookAt.copy(t),this.hasSmoothedLookAt=!0}else{const e=this.getLookAtPosition();if(this.smoothCamera){const o=1-Math.exp(-this.smoothSpeed*t),i=Math.max(0,this.teleportSnapDistance);!this.hasSmoothedLookAt||this.previousTargetLookAt.distanceToSquared(e)>i*i?this.smoothedLookAt.copy(e):this.smoothedLookAt.lerp(e,o)}else this.smoothedLookAt.copy(e);this.previousTargetLookAt.copy(e),this.hasSmoothedLookAt=!0,g.subVectors(L.position,e),this.camera.position.copy(this.smoothedLookAt).add(g),this.camera.lookAt(this.smoothedLookAt),this.prevLookAt.copy(this.smoothedLookAt)}}};t([p(),e("design:type",Number)],k.prototype,"near",void 0),t([p(),e("design:type",Number)],k.prototype,"far",void 0),t([p(),e("design:type",Number)],k.prototype,"viewAngle",void 0),t([p(),e("design:type",Boolean)],k.prototype,"collision",void 0),t([p(),e("design:type",Number)],k.prototype,"collisionSphereRadius",void 0),t([p(),e("design:type",Boolean)],k.prototype,"smoothCamera",void 0),t([p(),e("design:type",Number)],k.prototype,"smoothSpeed",void 0),t([p(),e("design:type",Number)],k.prototype,"teleportSnapDistance",void 0),k=t([i(),e("design:paramtypes",[])],k);export{k as ThirdPersonCameraComponent};const L=new r,y=new s,g=new s,A=new s,w=(new s,new s);export class ThirdPartyCameraComponent extends k{}/*
|
|
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{Vector3 as t}from"three";import{LeafNode as e,NodeState as o}from"./bt";
|
|
1
|
+
import{Vector3 as t}from"three";import{LeafNode as e,NodeState as o}from"./bt";export class CharacterMoveToNode extends e{constructor(t,e){super(),this.navigation=t,this.movement=e,this.distanceFrom=.5}tick(t){const e=this.movement.actor.object.position,i=null!=this.target?this.target():null;if(null==i)return this.movement.directionInput.vector.set(0,0),o.FAILURE;if(e.distanceTo(i)<this.distanceFrom)return this.movement.directionInput.vector.set(0,0),o.SUCCESS;const{success:r,path:s}=this.navigation.findPath(e,i);if(!r||s.length<2)return o.FAILURE;const c=s[1],a=n.subVectors(c,e);return a.y=0,a.normalize(),this.movement.rotationInput.rotation.y=Math.atan2(a.x,a.z),this.movement.directionInput.togglePositiveY(!0),o.RUNNING}}const n=new t;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NavMesh, RecastConfig, Vector3Tuple } from 'recast-navigation';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
import { BuildTileMeshProps } from './build-tile.js';
|
|
3
4
|
import { Subject } from 'rxjs';
|
|
4
5
|
export type DynamicTiledNavMeshProps = {
|
|
5
6
|
navMeshBounds: THREE.Box3;
|
|
@@ -8,6 +9,23 @@ export type DynamicTiledNavMeshProps = {
|
|
|
8
9
|
workers: number;
|
|
9
10
|
cacheId: string;
|
|
10
11
|
};
|
|
12
|
+
export declare const MAX_NAV_MESH_WORKERS = 4;
|
|
13
|
+
type NavMeshWorkerResult = {
|
|
14
|
+
tileX: number;
|
|
15
|
+
tileY: number;
|
|
16
|
+
navMeshData: Uint8Array;
|
|
17
|
+
};
|
|
18
|
+
export declare class NavMeshWorkerPool {
|
|
19
|
+
private workerFactory;
|
|
20
|
+
private slots;
|
|
21
|
+
private queue;
|
|
22
|
+
private workerLimit;
|
|
23
|
+
constructor(workerFactory?: () => Worker);
|
|
24
|
+
schedule(owner: object, data: BuildTileMeshProps, transfer: Transferable[] | undefined, onResult: (event: MessageEvent<NavMeshWorkerResult>) => void, requestedWorkers: number): void;
|
|
25
|
+
cancel(owner: object): void;
|
|
26
|
+
private drain;
|
|
27
|
+
private createSlot;
|
|
28
|
+
}
|
|
11
29
|
export declare class DynamicTiledNavMesh {
|
|
12
30
|
navMesh: NavMesh;
|
|
13
31
|
navMeshVersion: number;
|
|
@@ -20,9 +38,8 @@ export declare class DynamicTiledNavMesh {
|
|
|
20
38
|
tileHeight: number;
|
|
21
39
|
tcs: number;
|
|
22
40
|
recastConfig: RecastConfig;
|
|
23
|
-
workers: InstanceType<any>[];
|
|
24
|
-
workerRoundRobin: number;
|
|
25
41
|
private cacheId;
|
|
42
|
+
private workerLimit;
|
|
26
43
|
constructor(props: DynamicTiledNavMeshProps);
|
|
27
44
|
private onResult;
|
|
28
45
|
buildTile(positions: Float32Array, indices: Uint32Array, [tileX, tileY]: [x: number, y: number], useTileCache?: boolean): Promise<unknown>;
|
|
@@ -31,4 +48,5 @@ export declare class DynamicTiledNavMesh {
|
|
|
31
48
|
getTilesForBounds(bounds: THREE.Box3): [x: number, y: number][];
|
|
32
49
|
destroy(): void;
|
|
33
50
|
}
|
|
51
|
+
export {};
|
|
34
52
|
//# sourceMappingURL=dynamic-tiled-navmesh.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{NavMesh as t,NavMeshParams as
|
|
1
|
+
import{NavMesh as t,NavMeshParams as e,Raw as s,UnsignedCharArray as i,recastConfigDefaults as o,statusToReadableString as n}from"recast-navigation";import{buildConfig as r,buildTile as a}from"./build-tile.js";import{Subject as h}from"rxjs";import{hasWorkerBuilder as l,createWorker as c}from"../../worker/index.js";import{hasSharedArrayBufferSupport as d}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export class NavMeshWorkerPool{constructor(t=c){this.workerFactory=t,this.slots=[],this.queue=[],this.workerLimit=0}schedule(t,e,s,i,o){this.workerLimit=Math.max(this.workerLimit,Math.min(4,Math.max(1,o))),this.queue.push({owner:t,data:e,transfer:s,onResult:i,cancelled:!1}),this.drain()}cancel(t){this.queue=this.queue.filter(e=>e.owner!==t);for(const e of this.slots)e.job?.owner===t&&(e.job.cancelled=!0)}drain(){for(;this.queue.length>0;){let t=this.slots.find(t=>null==t.job);if(null==t){if(this.slots.length>=this.workerLimit)return;t=this.createSlot(),this.slots.push(t)}const e=this.queue.shift();t.job=e,t.worker.postMessage(e.data,e.transfer)}}createSlot(){const t={worker:this.workerFactory()};return t.worker.onmessage=e=>{const s=t.job;t.job=void 0;try{null==s||s.cancelled||s.onResult(e)}finally{this.drain()}},t.worker.onerror=e=>{t.job=void 0,t.worker.terminate();const s=this.slots.indexOf(t);s>=0&&this.slots.splice(s,1),console.error("Navmesh worker failed",e),this.drain()},t}}const u=new NavMeshWorkerPool;export class DynamicTiledNavMesh{constructor(s){this.navMeshVersion=0,this.onNavMeshUpdate=new h;const i=s.navMeshBounds.min,n=s.navMeshBounds.max,a=[i.toArray(),n.toArray()],l=s.navMeshBounds.min;this.navMeshBoundsMin=i,this.navMeshBoundsMax=n,this.navMeshBounds=a,this.navMeshOrigin=l,this.cacheId=s.cacheId,this.workerLimit=Math.min(4,Math.max(0,s.workers));const c={...o,...s.recastConfig};this.recastConfig=c;const d=new t,{tileWidth:u,tileHeight:M,tcs:f,maxPolysPerTile:m}=r({recastConfig:c,navMeshBounds:a});this.tileWidth=u,this.tileHeight=M,this.tcs=f;const v=e.create({orig:l,tileWidth:c.tileSize*c.cs,tileHeight:c.tileSize*c.cs,maxTiles:s.maxTiles,maxPolys:m});d.initTiled(v),this.navMesh=d}onResult(t){const{tileX:e,tileY:o,navMeshData:r}=t.data,a=new i;a.copy(r),this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0));const h=this.navMesh.addTile(a,s.Module.DT_TILE_FREE_DATA,0);s.Detour.statusFailed(h.status)&&(console.error(s.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${n(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[s,i],o=!0){const n=d&&t.buffer instanceof window.SharedArrayBuffer,r=n?t:new Float32Array(t),h=n?e:new Uint32Array(e),c={tileX:s,tileY:i,tileBoundsMin:[this.navMeshBoundsMin.x+s*this.tcs,this.navMeshBoundsMin.y,this.navMeshBoundsMin.z+i*this.tcs],tileBoundsMax:[this.navMeshBoundsMax.x+(s+1)*this.tcs,this.navMeshBoundsMax.y,this.navMeshBoundsMax.z+(i+1)*this.tcs],recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:r,indices:h};return this.workerLimit>0&&l()?(u.schedule(this,c,n?void 0:[r.buffer,h.buffer],t=>this.onResult(t),this.workerLimit),Promise.resolve()):new Promise(t=>{requestIdleCallback(()=>{const e=this.cacheId+JSON.stringify({tileX:c.tileX,tileY:c.tileY});if(o){const s=localStorage.getItem(e);if(null!=s){const e=f(s);return this.onResult({data:{tileX:c.tileX,tileY:c.tileY,navMeshData:e}}),void t({})}}else localStorage.removeItem(e);const s=a(c);if(!s.success||!s.data)return;const i=s.data.toTypedArray();localStorage.setItem(e,M(i)),this.onResult({data:{tileX:c.tileX,tileY:c.tileY,navMeshData:i}}),t(s)})})}buildAllTiles(t,e){const{tileWidth:s,tileHeight:i}=this;for(let o=0;o<i;o++)for(let i=0;i<s;i++)this.buildTile(t,e,[i,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){const e=this.getTileForWorldPosition(t.min),s=this.getTileForWorldPosition(t.max),i=[];for(let t=e[1];t<=s[1];t++)for(let o=e[0];o<=s[0];o++)i.push([o,t]);return i}destroy(){u.cancel(this),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}const M=function(t){return btoa(String.fromCharCode(...t))},f=function(t){if(!t)return null;const e=atob(t),s=e.length,i=new Uint8Array(s);for(let t=0;t<s;t++)i[t]=e.charCodeAt(t);return i};/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -2,7 +2,7 @@ import * as RAPIER from "@dimforge/rapier3d-simd-compat";
|
|
|
2
2
|
import { Observable, Subject } from "rxjs";
|
|
3
3
|
import * as THREE from "three";
|
|
4
4
|
import { ColorRepresentation, Object3D, Quaternion, Vector3 } from "three";
|
|
5
|
-
import { CollisionShape } from '../../../
|
|
5
|
+
import { CollisionShape } from '../../../scene/collision/collision-shape.js';
|
|
6
6
|
import { AbstractType, Type } from '../../../utils/type.js';
|
|
7
7
|
import { BaseActor } from '../../actors/actor.js';
|
|
8
8
|
import { ViewController } from '../render.js';
|
|
@@ -35,6 +35,11 @@ export declare class RayTestResult {
|
|
|
35
35
|
hitNormal: Vector3;
|
|
36
36
|
}
|
|
37
37
|
export interface RayTestOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Whether to draw the ray while physics debug rendering is enabled.
|
|
40
|
+
* @default true
|
|
41
|
+
*/
|
|
42
|
+
debug?: boolean;
|
|
38
43
|
debugColor?: ColorRepresentation;
|
|
39
44
|
debugLifetime?: number;
|
|
40
45
|
collisionFilter?: InteractionGroups;
|
|
@@ -73,6 +78,26 @@ export declare enum PhysicsBodyType {
|
|
|
73
78
|
kinematic = 4,
|
|
74
79
|
kinematicVelocityBased = 8
|
|
75
80
|
}
|
|
81
|
+
export type PhysicsJointDescriptor = {
|
|
82
|
+
type: 'fixed';
|
|
83
|
+
anchor1: Vector3;
|
|
84
|
+
frame1: Quaternion;
|
|
85
|
+
anchor2: Vector3;
|
|
86
|
+
frame2: Quaternion;
|
|
87
|
+
contactsEnabled?: boolean;
|
|
88
|
+
} | {
|
|
89
|
+
type: 'spherical';
|
|
90
|
+
anchor1: Vector3;
|
|
91
|
+
anchor2: Vector3;
|
|
92
|
+
contactsEnabled?: boolean;
|
|
93
|
+
} | {
|
|
94
|
+
type: 'revolute';
|
|
95
|
+
anchor1: Vector3;
|
|
96
|
+
anchor2: Vector3;
|
|
97
|
+
axis: Vector3;
|
|
98
|
+
limits?: readonly [number, number];
|
|
99
|
+
contactsEnabled?: boolean;
|
|
100
|
+
};
|
|
76
101
|
/**
|
|
77
102
|
* A physics system implementation using the Rapier physics engine.
|
|
78
103
|
* Handles rigid body physics, collisions, and physics-based character movement.
|
|
@@ -89,6 +114,8 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
89
114
|
private eventQueue;
|
|
90
115
|
private fixedupdateSub;
|
|
91
116
|
private collisionSub;
|
|
117
|
+
private rayDebugArrowPool;
|
|
118
|
+
private activeRayDebugArrows;
|
|
92
119
|
private readonly collisionEvents;
|
|
93
120
|
readonly beforeStep: Subject<number>;
|
|
94
121
|
readonly afterStep: Subject<number>;
|
|
@@ -129,7 +156,11 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
129
156
|
*/
|
|
130
157
|
findActorsInRadius<T = BaseActor>(position: Vector3, radius: number, actorType?: Type<T>): T[];
|
|
131
158
|
private debugMesh;
|
|
159
|
+
private staticDebugMesh;
|
|
160
|
+
private staticDebugNeedsUpdate;
|
|
161
|
+
private invalidateStaticDebug;
|
|
132
162
|
private createDebugMesh;
|
|
163
|
+
private updateDebugMesh;
|
|
133
164
|
/**
|
|
134
165
|
* Initializes and starts the physics system.
|
|
135
166
|
* @returns A promise that resolves when the physics system is ready
|
|
@@ -184,6 +215,9 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
184
215
|
* @returns The result of the raycast test
|
|
185
216
|
*/
|
|
186
217
|
rayTest(from: Vector3, to: Vector3, result?: RayTestResult, options?: RayTestOptions): RayTestResult;
|
|
218
|
+
private drawRayDebugArrow;
|
|
219
|
+
private releaseExpiredRayDebugArrows;
|
|
220
|
+
private clearRayDebugArrows;
|
|
187
221
|
/**
|
|
188
222
|
* Sets the gravity vector for the physics world.
|
|
189
223
|
* @param x - Gravity force along X axis
|
|
@@ -274,6 +308,11 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
274
308
|
mass?: number;
|
|
275
309
|
userData?: any;
|
|
276
310
|
}): PhysicsBody;
|
|
311
|
+
/**
|
|
312
|
+
* Creates an impulse joint between two generic physics bodies.
|
|
313
|
+
* Joint anchors, axes, and frames are expressed in the local spaces of the bodies.
|
|
314
|
+
*/
|
|
315
|
+
createJoint(body1: PhysicsBody, body2: PhysicsBody, descriptor: PhysicsJointDescriptor): PhysicsJoint;
|
|
277
316
|
/**
|
|
278
317
|
* Computes the corrected movement vector for a collider using a kinematic character controller.
|
|
279
318
|
* This function uses the provided character controller to calculate the actual movement that can be performed
|
|
@@ -661,6 +700,7 @@ type ColliderCollisionEvent = {
|
|
|
661
700
|
actor: BaseActor;
|
|
662
701
|
};
|
|
663
702
|
export declare class PhysicsCollider {
|
|
703
|
+
private readonly invalidateStaticDebug?;
|
|
664
704
|
readonly disposed: Subject<true>;
|
|
665
705
|
readonly onBeginOverlapActor: Subject<ColliderCollisionEvent>;
|
|
666
706
|
readonly onEndOverlapActor: Subject<ColliderCollisionEvent>;
|
|
@@ -668,7 +708,7 @@ export declare class PhysicsCollider {
|
|
|
668
708
|
/** @internal */
|
|
669
709
|
collider: RAPIER.Collider,
|
|
670
710
|
/** @internal */
|
|
671
|
-
world: RAPIER.World);
|
|
711
|
+
world: RAPIER.World, invalidateStaticDebug?: () => void);
|
|
672
712
|
dispose(): void;
|
|
673
713
|
set mass(mass: number);
|
|
674
714
|
get mass(): number;
|
|
@@ -686,7 +726,8 @@ export declare class PhysicsCollider {
|
|
|
686
726
|
get enabled(): boolean;
|
|
687
727
|
}
|
|
688
728
|
export declare class PhysicsBody {
|
|
689
|
-
|
|
729
|
+
private readonly invalidateStaticDebug?;
|
|
730
|
+
constructor(body: RAPIER.RigidBody, world: RAPIER.World, invalidateStaticDebug?: () => void);
|
|
690
731
|
dispose(): void;
|
|
691
732
|
setEnabled(enabled: boolean): void;
|
|
692
733
|
isEnabled(): boolean;
|
|
@@ -698,6 +739,8 @@ export declare class PhysicsBody {
|
|
|
698
739
|
setLinearVelocity(vel: Vector3): void;
|
|
699
740
|
getAngularVelocity(target: Vector3): Vector3;
|
|
700
741
|
setAngularVelocity(vel: Vector3): void;
|
|
742
|
+
setLinearDamping(damping: number): void;
|
|
743
|
+
setAngularDamping(damping: number): void;
|
|
701
744
|
applyImpulse(impulse: Vector3, wakeUp?: boolean): void;
|
|
702
745
|
applyTorqueImpulse(torque: Vector3, wakeUp?: boolean): void;
|
|
703
746
|
setNextKinematicPosition(pos: Vector3): void;
|
|
@@ -718,4 +761,14 @@ export declare class PhysicsBody {
|
|
|
718
761
|
sleep(): void;
|
|
719
762
|
wakeUp(): void;
|
|
720
763
|
}
|
|
764
|
+
export declare class PhysicsJoint {
|
|
765
|
+
constructor(
|
|
766
|
+
/** @internal */
|
|
767
|
+
joint: RAPIER.ImpulseJoint,
|
|
768
|
+
/** @internal */
|
|
769
|
+
world: RAPIER.World);
|
|
770
|
+
dispose(): void;
|
|
771
|
+
setContactsEnabled(enabled: boolean): void;
|
|
772
|
+
get contactsEnabled(): boolean;
|
|
773
|
+
}
|
|
721
774
|
//# sourceMappingURL=physics-system.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-simd-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-simd-compat";import{BehaviorSubject as o,distinctUntilChanged as n,filter as r,map as a,Subject as l,takeUntil as c}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as p,Group as y,LineSegments as g,Matrix4 as m,Object3D as f,Quaternion as w,Raycaster as x,Scene as b,Vector3 as B}from"three";import*as v from"three/examples/jsm/utils/BufferGeometryUtils.js";import{Service as C}from"typedi";import{ActorComponent as S,Component as A}from"../../../gameplay/actors/component.js";import{inject as R}from"../../../gameplay/inject.js";import{BoxCollisionShape as z,CapsuleCollisionShape as D,ConeCollisionShape as T,ConvexPolyhedronCollisionShape as M,CylinderCollisionShape as E,PhysicalShapeMesh as P,PlaneCollisionShape as _,SphereCollisionShape as F,toInstancedCollisionShape as W,TrimeshCollisionShape as I}from"../../../index.js";import{AssetMeshInstance as j}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as V}from"../../../scene/landscape/landscape.js";import{calculateEffectiveScale as k}from"../../../utils/three/traverse.js";import{ViewController as N}from"../render.js";import{World as L}from"../world.js";import{AbstractPhysicsSystem as O}from"./abstract-physics-system.js";import{NetRole as G}from"../../net/index.js";export{ActorComponent,attach,Attach,Component}from"../../actors/component.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.hitNormal=new B}}export class ShapeCastResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.normal=new B}reset(){this.actor=void 0,this.hasHit=!1,this.distance=0,this.hitPoint.set(0,0,0),this.normal.set(0,0,0)}}ShapeCastResult.shared=new ShapeCastResult;export var PhysicsBodyType;!function(t){t[t.dynamic=1]="dynamic",t[t.static=2]="static",t[t.kinematic=4]="kinematic",t[t.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));const K=new B,U=new B,H=new w,q=new w,Q=new w,X=[];let $=class extends O{set showDebug(t){this.shouldRenderDebug=t,this.debugMesh&&(this.debugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(){super(),this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.colliders=new Map,this.collisionEvents=new l,this.beforeStep=new l,this.afterStep=new l,this.shouldRenderDebug=!1,this.viewController=R(N),this.shapeCacheBox=new Map,this.shapeCacheBall=new Map,this._raycaster=new x,this._reusableResult=new RayTestResult,this._raytestDiff=new B,this._raytestDirection=new B,this.controlledActors=new Set,this._isStopped=!1,this.ready=this.setup()}getBallShape(t){let e=this.shapeCacheBall.get(t);return null==e&&(e=new this.rapier.Ball(t),this.shapeCacheBall.set(t,e)),e}getBoxShape(t,e,i){const s=t+1e6*e+1e12*i;let o=this.shapeCacheBox.get(s);return null==o&&(o=new this.rapier.Cuboid(t,e,i),this.shapeCacheBox.set(s,o)),o}hasBoxIntersection(t){const e=t.getCenter(K),i=t.getSize(U),s=this.getBoxShape(i.x/2,i.y/2,i.z/2);return null!=this.world.intersectionWithShape(e,H,s)}hasSphereIntersection(t){const e=this.getBallShape(t.radius);return null!=this.world.intersectionWithShape(t.center,H,e)}findActorsInRadius(t,e,i){const s=this.getBallShape(e),o=[];for(const[e,n]of this.bodyActors)if(n instanceof i||null==i)for(let i=0,r=e.numColliders();i<r;i++){e.collider(i).intersectsShape(s,t,H)&&o.push(n)}return o}createDebugMesh(){return new g(new p,new d.LineBasicMaterial({color:255}))}async start(){return await this.ready,this.handleTick(),this.handleCollisionEvents(),this.ready}handleCollisionEvents(){this.collisionSub=this.collisionEvents.subscribe(t=>{const e=this.colliders.get(t.handle1);if(null==e)return;const i=this.world.getCollider(t.handle2);if(null==i||null==i.parent())return;const s=this.bodyActors.get(i.parent());null!=s&&(t.started?e.onBeginOverlapActor.next({actor:s}):e.onEndOverlapActor.next({actor:s}))})}renderDebug(){if(null==this.scene)return;null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.scene?.add(this.debugMesh));const t=this.world.debugRender().vertices,e=this.debugMesh.geometry,i=e.getAttribute("position");null==i||(i.array.length,t.length);{const i=new u(t,3);i.setUsage(d.DynamicDrawUsage),e.setAttribute("position",i)}e.setDrawRange(0,t.length/3)}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await dt(),this.eventQueue=new this.rapier.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe(t=>{this._isStopped||(t=Math.min(.1,t),this.beforeStep.next(t),this.updatePhysics(t),this.showDebug&&this.renderDebug(),this.world.bodies.forEach(t=>{if(t.isFixed())return;let e,i=this.staticMeshes.get(t);if(null==i&&(e=this.bodyActors.get(t),null!=e)){if(e.netRole===G.simulatedProxy)return;i=e.object}null!=i&&i.parent instanceof b&&(pt(i.position,t.translation()),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(t)?.id))&&yt(i.quaternion,t.rotation()),i.matrixWorldNeedsUpdate=!0)}),this.afterStep.next(t))})}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){this._isStopped||(this.world.timestep=t,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents((t,e,i)=>{this.collisionEvents.next({handle1:t,handle2:e,started:i}),this.collisionEvents.next({handle1:e,handle2:t,started:i})}))}rayTestFromCamera(t,e,i){this._raycaster.setFromCamera(rt,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(t).add(s);return this.rayTest(s,o,e,i)}rayTest(t,e,i,s){null==i&&(i=this._reusableResult);const o=this._raytestDiff,n=this._raytestDirection;if(o.subVectors(e,t),n.copy(o).normalize(),0===n.length())return console.warn("Ray test called with to and from being equal"),i;null==bt&&(bt=new this.rapier.Ray(new this.rapier.Vector3(0,0,0),new this.rapier.Vector3(0,1,0))),ht(bt.origin,t),ht(bt.dir,n);const r=o.length(),a=this.world.castRayAndGetNormal(bt,r,!1,void 0,s?.collisionFilter,void 0,null!=s?.excludeActor?this.actorBodies.get(s.excludeActor.id):void 0,s?.excludeTriggers?t=>!t.isSensor():void 0);if(i.hasHit=null!=a,i.hasHit){const e=bt.pointAt(a.timeOfImpact);if(i._internal=a,pt(i.hitNormal,a.normal),pt(i.hitPoint,e),i.distance=mt.subVectors(i.hitPoint,t).length(),!1!==s?.resolveActor){const t=this.world.bodies.getAll().find(t=>function(t,e){for(let i=0,s=t.numColliders();i<s;i++){const s=t.collider(i);if(e(s))return s}}(t,t=>t===a.collider));i.actor=null!=t?this.bodyActors.get(t):null}}if(this.showDebug){let e;X.length>0?(e=X.pop(),e.setDirection(n),e.position.copy(t),e.setLength(r,.2,.1),e.setColor(s?.debugColor??255)):e=new h(n,t,r,s?.debugColor??255),this.scene?.add(e),setTimeout(()=>{this.scene?.remove(e),X.push(e)},s?.debugLifetime??200)}return i}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return tt.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(t){this.addRecursively(t);for(const t of this.staticBodies.values())gt(t,t=>t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS))}addRecursively(t){if(this.removeSceneObject(t),!function(t){if(null!=t.userData?.src){const e=t.userData?.src;return"actor"===e.type}return!1}(t))if(t instanceof P&&null!=t.collisionShape){const e=this.createStaticBody(t,[t.collisionShape],t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else if(t instanceof j){const e=!1!==t.userData?.src?.collisionDetection;if(t.children[0]&&(t.children[0].instanceMatrix&&e||t.children[0].isBatchedMesh))this.createForInstancedMesh(t.children[0],t.collisionShapes);else if(e&&t.children.length>0){const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}}else t instanceof V?this.addLandscapeGroup(t):(t instanceof y||t instanceof b)&&t.children.forEach(t=>this.addRecursively(t))}createForInstancedMesh(t,e){const i=new m;if(t instanceof d.BatchedMesh){const e=t._instanceInfo??t._drawInfo,s=new Map;for(let o=0;o<e.length;o++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[o])continue;const e=t.userData.collisionShapes;let n=e?.[o];if(null==n&&null==e&&t.parent instanceof j&&(n=t.parent.collisionShapes),null==n)continue;let r=s.get(n);null==r&&(r=this.instancedShapeReset(n),s.set(n,r));const a=new f;a.matrix.identity(),t.getMatrixAt(o,i),a.applyMatrix4(i);this.createStaticBody(a,r)}}else{const s=this.instancedShapeReset(e);for(let e=0;e<t.count;e++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[e])continue;const o=new f;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*e),o.applyMatrix4(i);this.createStaticBody(o,s)}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>W(t))}getCharacterController(t){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i,o=null){const n=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const r=n.collider(0);e.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,o,wt);const a=e.computedMovement();return pt(ft,a),ft}setActorCapsuleCollider(t,e,i,s){const o=this.actorBodies.get(t.id),n=o?.collider(0);if(null==o||null==n)return!1;const r=t.object?.getWorldScale(xt)??it,a=Math.max(0,e*Math.abs(r.y)),l=Math.max(.001,i*Math.max(Math.abs(r.x),Math.abs(r.z)));return n.setHalfHeight(a/2),n.setRadius(l),nt.set(0,s,0).multiply(r),ht(st,nt),n.setTranslationWrtParent(st),o.recomputeMassPropertiesFromColliders(),!0}hasActorCapsuleIntersection(t,e,i,o,n,r=null){const a=this.actorBodies.get(t.id),l=t.object?.getWorldScale(xt)??it,c=Math.max(0,i*Math.abs(l.y)),d=Math.max(.001,o*Math.max(Math.abs(l.x),Math.abs(l.z))),h=new this.rapier.Capsule(c/2,d),u=t.object?.getWorldQuaternion(Q)??H;nt.set(0,n,0).multiply(l).applyQuaternion(u).add(e);return null!=this.world.intersectionWithShape(nt,u,h,s.EXCLUDE_SENSORS,r??void 0,void 0,a,wt)}createCollider(t,e){const i=this.addShape(e?.body,t),s=new PhysicsCollider(i,this.world);return this.colliders.set(i.handle,s),s.disposed.subscribe(()=>{this.colliders.delete(i.handle)}),s}createBody(t=PhysicsBodyType.dynamic,e={}){const i=(()=>{switch(t){case PhysicsBodyType.dynamic:return this.rapier.RigidBodyDesc.dynamic();case PhysicsBodyType.static:return this.rapier.RigidBodyDesc.fixed();case PhysicsBodyType.kinematic:return this.rapier.RigidBodyDesc.kinematicPositionBased();case PhysicsBodyType.kinematicVelocityBased:return this.rapier.RigidBodyDesc.kinematicVelocityBased();default:return this.rapier.RigidBodyDesc.dynamic()}})();e.position&&i.setTranslation(e.position.x,e.position.y,e.position.z),e.rotation&&i.setRotation({x:e.rotation.x,y:e.rotation.y,z:e.rotation.z,w:e.rotation.w}),"boolean"==typeof e.canSleep&&i.setCanSleep(e.canSleep),"boolean"==typeof e.ccdEnabled&&i.setCcdEnabled(e.ccdEnabled),"number"==typeof e.gravityScale&&i.setGravityScale(e.gravityScale),"number"==typeof e.mass&&i.setAdditionalMass(e.mass),void 0!==e.userData&&(i.userData=e.userData);const s=this.world.createRigidBody(i);return new PhysicsBody(s,this.world)}getCharacterComputedMovement(t,e,i,o=null){const n=t.collider;e.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,o,wt);const r=e.computedMovement();return pt(ft,r),ft}setNextKinematicTranslation(t,e){const i=this.actorBodies.get(t.id),s=i.translation();s.x+=e.x,s.y+=e.y,s.z+=e.z,i?.setNextKinematicTranslation(s)}setNextKinematicPosition(t,e){this.actorBodies.get(t.id).setNextKinematicTranslation(e)}setNextKinematicRotation(t,e){this.actorBodies.get(t.id).setNextKinematicRotation(e)}setNextKinematicTransform(t){!function(t,e){const i=e.getWorldPosition(Y),s=e.getWorldQuaternion(Z);t.setNextKinematicTranslation(at(i)),t.setNextKinematicRotation(lt(s))}(this.actorBodies.get(t.id),t.object)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.setAngvel(st,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.setLinvel(st,!0)}getLinearVelocity(t,e=new B){const i=this.actorBodies.get(t.id).linvel();return e.x=i.x,e.y=i.y,e.z=i.z,e}getAngularVelocity(t,e=new B){const i=this.actorBodies.get(t.id).angvel();return e.x=i.x,e.y=i.y,e.z=i.z,e}setLinearDamping(t,e){const i=this.actorBodies.get(t.id);i?.setLinearDamping(e)}getLienarDamping(t){const e=this.actorBodies.get(t.id);return e?.linearDamping()??0}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}getAngularDamping(t){const e=this.actorBodies.get(t.id);e?.angularDamping()}setPosition(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(at(e),!1)}getPosition(t,e=new B){const i=this.actorBodies.get(t.id);i&&pt(e,i.translation())}setRotation(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(lt(e),!1)}getRotation(t,e=new w){const i=this.actorBodies.get(t.id);i&&yt(e,i.rotation())}lockTranslations(t,e){const i=this.actorBodies.get(t.id);i?.lockTranslations(e,!1)}lockRotations(t,e){const i=this.actorBodies.get(t.id);i?.lockRotations(e,!1)}setEnabledTranslations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledTranslations(e,i,s,!1)}setEnabledRotations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledRotations(e,i,s,!1)}addLandscapeGroup(t){const e=t.userData.src,s=e.landscape.heightMaps;for(const n of t.sections){this.staticBodies.has(n)&&this.world.removeRigidBody(this.staticBodies.get(n));var o=n.getWorldPosition(new B);if(e.landscape.holes&&e.landscape.holes.some(t=>t.m===n.name&&0!==t.w[0])){const t=n.geometry.clone(),i=n.scale,s=n.geometry.getAttribute("hole"),r=new Float32Array(t.getAttribute("position").array);for(let t=0;t<r.length;t+=3)r[t]*=i.x,r[t+1]*=i.y,r[t+2]*=i.z;const a=t.index;for(let t=0;t<a.count;t+=3){const e=s.getX(a.getX(t)),i=s.getX(a.getY(t)),o=s.getX(a.getZ(t));(e>.5||i>.5||o>.5)&&(a.setX(t,0),a.setY(t,0),a.setZ(t,0))}const l=this.rapier.ColliderDesc.trimesh(r,new Uint32Array(t.getIndex().array));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);ht(e,o),t.setTranslation(e,!1),this.world.createCollider(l,t),this.staticBodies.set(n,t)}continue}const t=e.landscape.options.density+1,r=e.landscape.options.sectionSize,a=new Array(t);for(let e=0;e<t;e++)a[e]=new Array(t).fill(0);const l=s.find(t=>t.x===n.x&&t.y==n.y);if(null!=l)for(const e of l.points){if(null==a[e.i%t])continue;const i=t-1-Math.floor(e.i/t);i in a[e.i%t]?a[e.i%t][i]=e.y/r:console.warn("wrong index",{points:a,point:e,i:e.i%t,k:i,heightMap:l})}const c=e.landscape.options.density,d=a.flatMap(t=>t.reverse()),h=i.ColliderDesc.heightfield(c,c,new Float32Array(d),new this.rapier.Vector3(r,r,r));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);ht(e,o),t.setTranslation(e,!1),this.world.createCollider(h,t),this.staticBodies.set(n,t)}}}setEnabled(t,e){const i=this.actorBodies.get(t.id);i?.setEnabled(e)}addActor(t,e,i={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const s=t.object;let o;switch(i.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:o=this.rapier.RigidBodyDesc.dynamic(),o.mass=i.mass??1;break;case PhysicsBodyType.kinematic:o=this.rapier.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:o=this.rapier.RigidBodyDesc.kinematicVelocityBased();break;default:o=i.isTrigger?this.rapier.RigidBodyDesc.kinematicVelocityBased():this.rapier.RigidBodyDesc.fixed()}const n=this.world.createRigidBody(o);n.enableCcd(1==i.continousCollisionDetection);for(const t of e)this.addShape(n,t,s);return gt(n,t=>{null!=i.isTrigger&&(t.setSensor(i.isTrigger),t.setActiveCollisionTypes(this.rapier.ActiveCollisionTypes.ALL),t.setActiveEvents(this.rapier.ActiveEvents.COLLISION_EVENTS)),null!=i.friction&&t.setFriction(i.friction),null!=i.density&&t.setDensity(i.density),null!=i.mass&&t.setMass(i.mass),null!=i.restitution&&t.setRestitution(i.restitution)}),J(n,s),!0===i.ignoreForNavMesh&&(n.userData={ignoreForNavMesh:!0}),this.actorBodies.set(t.id,n),this.bodyActors.set(n,t),new PhysicsBody(n,this.world)}applyTorque(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.addTorque(st,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.applyTorqueImpulse(st,!0)}resetForces(t){const e=this.actorBodies.get(t.id);e?.resetForces(!1)}resetTorques(t){const e=this.actorBodies.get(t.id);e?.resetTorques(!1)}applyForce(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.addForce(st,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);st.x=e.x,st.y=e.y,st.z=e.z,i?.applyImpulse(st,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);ht(st,e),null==i?s?.addForce(st,!0):(ht(ot,i),s?.addForceAtPoint(st,ot,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);ht(st,e),null==i?s.applyImpulse(st,!0):(ht(ot,i),s.applyImpulseAtPoint(st,ot,!0))}applyRadiusImpulse(t,e,s){this.world.bodies.forEach(o=>{if(o.collider(0)?.isSensor())return;if(o.bodyType()!==i.RigidBodyType.Dynamic)return;const n=nt;pt(n,o.translation());const r=n.clone().sub(t);if(r.length()>e)return;const a=r.clone().normalize().multiplyScalar(s);st.x=a.x,st.y=a.y,st.z=a.z,o.applyImpulse(st,!0)})}removeActor(t){if(null==t)return;this.controlledActors.delete(t.id);const e=this.actorBodies.get(t.id);null!=e&&(this.bodyActors.delete(e),this.world.removeRigidBody(e)),this.actorBodies.delete(t.id)}removeRemoved(t){if(null==t)return;const e=new Set;t.traverse(t=>{e.add(t.uuid)});for(const[t,i]of this.staticBodies.entries())e.has(t.uuid)&&this.world.getRigidBody(i.handle)&&(this.staticBodies.delete(t),this.world.removeRigidBody(i))}removeSceneObject(t){if(t instanceof V){for(const e of t.sections)this.removeSceneObject(e);return}let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&this.world.removeRigidBody(e),this.staticBodies.delete(t)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(({started:t})=>t===i),a(({handle1:t,handle2:e,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(t)?.parent()),a2:this.bodyActors.get(this.world.getCollider(e)?.parent()),started:i})),r(({a1:i,a2:s})=>null!=i&&null!=s&&i.id===t.id&&e(i,s)),a(({a2:t})=>t))}onBeginContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onEndContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>!t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onHasContactChanged(t){const e=new Set,i=new o(!1);return this.onBeginContact(t).subscribe(t=>{e.add(t),i.next(e.size>0)}),this.onEndContact(t).subscribe(t=>{e.delete(t),i.next(e.size>0)}),i.pipe(n())}onBeginOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!0)}onEndOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!1)}onBeginOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!0)}onEndOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!1)}onBeginOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!0)}onEndOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!1)}onCollisionWithActor(t,e){return this.onBeginOverlapWithActor(t,e)}onCollisionWithActorType(t,e){return this.onBeginOverlapWithActorType(t,e)}updateActorTransform(t){const e=this.actorBodies.get(t.id);null!=e&&J(e,t.object)}flushModifiedBodyPositionsToColliders(){this.world.propagateModifiedBodyPositionsToColliders()}setupWorld(){const t=new this.rapier.World({x:0,y:-9.81,z:0});this.world=t}sphereCast(t,e,i,s,o=ShapeCastResult.shared,n){o.reset();const r=this.getBallShape(e);this.shapeCacheBall.get;const a={x:t.x,y:t.y,z:t.z},l={x:i.x,y:i.y,z:i.z},c=n?.excludeActor?this.actorBodies.get(n.excludeActor.id):null,d=this.world.castShape(a,{x:0,y:0,z:0,w:1},l,r,.01,s,!0,null,n?.collisionFilter??void 0,null,c,n?.excludeTriggers?t=>!t.isSensor():void 0);if(null!=d){pt(o.hitPoint,d.witness1),o.normal.set(d.normal1.x,d.normal1.y,d.normal1.z),o.distance=d.time_of_impact,o.hasHit=!0;const t=d.collider.parent();if(t){const e=this.bodyActors.get(t);e&&(o.actor=e)}}return o}castActorShape(t,e,i,s=ShapeCastResult.shared,o=void 0){s.reset();const n=this.actorBodies.get(t.id);if(n&&n.numColliders()>0){for(let t=0;t<n.numColliders();t++){const r=n.collider(t);let a=r.shape,l=r.translation(),c=r.rotation(),d=e,h=i;const u=this.world.castShape(l,c,d,a,.01,h,!0,null,o,null,n,void 0);if(null!=u){u.collider;const t=r;return pt(s.hitPoint,u.witness1),vt(t.rotation(),u.normal1,s.normal,q),s.distance=u.time_of_impact,s.actor=this.bodyActors.get(u.collider.parent()),s.hasHit=!0,s}}return s}return console.warn("Actor is not added to the physics system"),s}stop(){if(!this._isStopped){this._isStopped=!0,this.bodyActors.clear(),this.actorBodies.clear(),this.staticBodies.clear(),this.staticMeshes.clear(),this.colliders.clear(),this.fixedupdateSub?.unsubscribe(),this.collisionSub?.unsubscribe(),this.world?.bodies.forEach(t=>this.world.removeRigidBody(t));try{this.world?.free(),this.world=void 0}catch(t){console.warn("Error while freeing physics world",t)}X.length=0}}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed();o.setSleeping(!0);const n=this.world.createRigidBody(o);let r=0;for(const i of e){if(r>128){console.warn("Too many collision shapes for object",t);break}if(r++,null==i){console.warn("Collision shape is missing for object",t);continue}const o=this.addShape(n,i,t);null!=o&&(null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/e.length),null!=s?.restitution&&o.setRestitution(s.restitution))}return J(n,t),n.userData=t.uuid,n.sleep(),n}addShape(t=void 0,e,i){const s=i?.getWorldScale(xt)??it,o=this.createShape(e,s);if(null==o)return void console.error("Failed to create physics shape. This can happen if the geometry is degenerate or zero-scaled.",{shapeInfo:e,object:i});this.applyShapeSettings(o,e);const n=e.offset.clone().multiply(s);ht(o.translation,n);const r=(new w).setFromEuler(e.rotation);ut(o.rotation,r),null!=t&&t.numColliders()>128&&console.warn(`Rigid body has many colliders (${t.numColliders()}). Consider using a Trimesh if this is static geometry.`,t);try{return this.world.createCollider(o,t)}catch(t){return void console.error("Failed to create collider",t)}}applyShapeSettings(t,e){null!=e.collisionGroup&&t.setCollisionGroups(e.collisionGroup),t.friction=e.friction??.1,null!=e.restitution&&(t.restitution=e.restitution),null!=e.density&&(t.density=e.density,t.massPropsMode=i.MassPropsMode.Density),null!=e.mass&&(t.mass=e.mass,t.massPropsMode=i.MassPropsMode.Mass)}createShape(t,e){if(t instanceof z)return this.rapier.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof D){return this.rapier.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof I){const i=null!=t.geometry.getIndex()?t.geometry:v.mergeVertices(t.geometry),s=extractFloat32Array(i.getAttribute("position"));for(let t=0;t<s.length;t+=3)s[t]*=e.x,s[t+1]*=e.y,s[t+2]*=e.z;const o=i.getIndex();return null==o?(console.error("Trimesh collision shape is missing an index buffer.",t),null):this.rapier.ColliderDesc.trimesh(s,new Uint32Array(o.array))}if(t instanceof M){let i,s;t.mesh instanceof d.Mesh?i=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?i=t.mesh:console.log("Unknownd shape",{shapeInfo:t}),t.mesh instanceof d.Mesh&&(s=k(t.mesh));const o=`${i.uuid}|${s?.x??1},${s?.y??1},${s?.z??1}|${e.x},${e.y},${e.z}`,n=et.get(o);if(void 0!==n)return n;const r=extractFloat32Array(i.getAttribute("position"));if(null!=s)for(let t=0;t<r.length;t+=3)r[t]*=s.x,r[t+1]*=s.y,r[t+2]*=s.z;for(let t=0;t<r.length;t+=3)r[t]*=e.x,r[t+1]*=e.y,r[t+2]*=e.z;const a=this.rapier.ColliderDesc.convexHull(r);return null==a&&console.error("Failed to compute convex hull. Points may be coplanar or too few.",{count:r.length/3}),et.set(o,a),a}if(t instanceof F){const i=2*e.x-e.y-e.z;return Math.abs(i)>.01?this.createShape(new M(new d.SphereGeometry(t.radius).scale(e.x,e.y,e.z)),new B(1,1,1)):this.rapier.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z))}return t instanceof E?this.rapier.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof T?this.rapier.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof _?this.rapier.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.001):(console.error("Unsupported shape",t),this.rapier.ColliderDesc.cuboid(1,1,1))}createCharacterCollision(){return new this.rapier.CharacterCollision}};$=t([C(),e("design:paramtypes",[])],$);export{$ as PhysicsSystem};const Y=new B,Z=new d.Quaternion;function J(t,e){const i=e.getWorldPosition(Y),s=e.getWorldQuaternion(Z);t.setTranslation(at(i),!1),t.setRotation(lt(s),!1)}const tt=new B,et=new Map,it=new B(1,1,1),st=new i.Vector3(0,0,0),ot=new i.Vector3(0,0,0),nt=new B,rt=new d.Vector2;function at(t){return ht(st,t),st}function lt(t){return ut(q,t),q}let ct=null;const dt=async()=>(null==ct&&(ct=(async()=>{let t=await import("@dimforge/rapier3d-simd-compat");return await t.init(),t})()),ct);function ht(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function ut(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function pt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function yt(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function gt(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const mt=new B,ft=new B,wt=t=>!t.isSensor(),xt=new B;let bt,Bt=class extends S{constructor(){super(...arguments),this._active=!0,this.physics=R($),this.world=R(L)}set active(t){this._active=t,t?(this.world.scene.remove(this.actor.object),this.physics.setEnabled(this.actor,t)):(this.world.scene.add(this.actor.object),this.physics.setEnabled(this.actor,t))}get active(){return this._active}};Bt=t([A()],Bt);export function extractFloat32Array(t){const e=t.itemSize,i=t.count,s=new Float32Array(i*e);for(let o=0;o<i;o++)for(let i=0;i<e;i++)s[o*e+i]=t.getComponent(o,i);return s}function vt(t,e,i,s){return s.set(t.x,t.y,t.z,t.w),i.set(e.x,e.y,e.z),i.applyQuaternion(s),i}export class PhysicsCollider{constructor(t,e){this.collider=t,this.world=e,this.disposed=new l,this.onBeginOverlapActor=new l,this.onEndOverlapActor=new l}dispose(){this.world.removeCollider(this.collider,!1),this.disposed.next(!0),this.disposed.complete(),this.onBeginOverlapActor.complete(),this.onEndOverlapActor.complete()}set mass(t){this.collider.setMass(t)}get mass(){return this.collider.mass()}set friction(t){this.collider.setFriction(t)}get friction(){return this.collider.friction()}set restitution(t){this.collider.setRestitution(t)}get restitution(){return this.collider.restitution()}set density(t){this.collider.setDensity(t)}get density(){return this.collider.density()}set isTrigger(t){this.collider.setSensor(t)}get isTrigger(){return this.collider.isSensor()}set collisionGroups(t){this.collider.setCollisionGroups(t)}get collisionGroups(){return this.collider.collisionGroups()}set enabled(t){this.collider.setEnabled(t)}get enabled(){return this.collider.isEnabled()}}export class PhysicsBody{constructor(t,e){this.body=t,this.world=e}dispose(){this.world.removeRigidBody(this.body)}setEnabled(t){this.body.setEnabled(t)}isEnabled(){return this.body.isEnabled()}getPosition(t){const e=this.body.translation();return t.set(e.x,e.y,e.z),t}setPosition(t){this.body.setTranslation({x:t.x,y:t.y,z:t.z},!0)}getRotation(t){const e=this.body.rotation();return t.set(e.x,e.y,e.z,e.w),t}setRotation(t){this.body.setRotation({x:t.x,y:t.y,z:t.z,w:t.w},!0)}getLinearVelocity(t){const e=this.body.linvel();return t.set(e.x,e.y,e.z),t}setLinearVelocity(t){this.body.setLinvel({x:t.x,y:t.y,z:t.z},!0)}getAngularVelocity(t){const e=this.body.angvel();return t.set(e.x,e.y,e.z),t}setAngularVelocity(t){this.body.setAngvel({x:t.x,y:t.y,z:t.z},!0)}applyImpulse(t,e=!0){this.body.applyImpulse({x:t.x,y:t.y,z:t.z},e)}applyTorqueImpulse(t,e=!0){this.body.applyTorqueImpulse({x:t.x,y:t.y,z:t.z},e)}setNextKinematicPosition(t){this.body.setNextKinematicTranslation(t)}setNextKinematicRotation(t){this.body.setNextKinematicRotation(t)}setType(t){this.body.setBodyType(function(t){switch(t){case PhysicsBodyType.dynamic:return i.RigidBodyType.Dynamic;case PhysicsBodyType.static:return i.RigidBodyType.Fixed;case PhysicsBodyType.kinematic:return i.RigidBodyType.KinematicPositionBased;case PhysicsBodyType.kinematicVelocityBased:return i.RigidBodyType.KinematicVelocityBased}}(t),t!==PhysicsBodyType.static)}setGravityScale(t){this.body.setGravityScale(t,!1)}getGravityScale(){return this.body.gravityScale()}isDynamic(){return this.body.isDynamic()}isKinematic(){return this.body.isKinematic()}isStatic(){return this.body.isFixed()}sleep(){this.body.sleep()}wakeUp(){this.body.wakeUp()}}/*
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-simd-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-simd-compat";import{BehaviorSubject as o,distinctUntilChanged as r,filter as n,map as a,Subject as l,takeUntil as c}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as p,Group as y,LineSegments as g,Matrix4 as m,Object3D as b,Quaternion as f,Raycaster as w,Scene as x,Vector3 as v}from"three";import*as D from"three/examples/jsm/utils/BufferGeometryUtils.js";import{Service as B}from"typedi";import{ActorComponent as S,Component as A}from"../../../gameplay/actors/component.js";import{inject as C}from"../../../gameplay/inject.js";import{BoxCollisionShape as R,CapsuleCollisionShape as M,ConeCollisionShape as E,ConvexPolyhedronCollisionShape as z,CylinderCollisionShape as T,PhysicalShapeMesh as P,PlaneCollisionShape as F,SphereCollisionShape as _,toInstancedCollisionShape as I,TrimeshCollisionShape as j}from"../../../scene/collision/collision-shape.js";import{AssetMeshInstance as W}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as N}from"../../../scene/landscape/landscape.js";import{calculateEffectiveScale as k}from"../../../utils/three/traverse.js";import{ViewController as V}from"../render.js";import{World as L}from"../world.js";import{AbstractPhysicsSystem as O}from"./abstract-physics-system.js";import{NetRole as U}from"../../net/index.js";export{ActorComponent,attach,Attach,Component}from"../../actors/component.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.hitNormal=new v}}export class ShapeCastResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.normal=new v}reset(){this.actor=void 0,this.hasHit=!1,this.distance=0,this.hitPoint.set(0,0,0),this.normal.set(0,0,0)}}ShapeCastResult.shared=new ShapeCastResult;export var PhysicsBodyType;!function(t){t[t.dynamic=1]="dynamic",t[t.static=2]="static",t[t.kinematic=4]="kinematic",t[t.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));const G=new v,K=new v,H=new f,X=new f,q=new f;let Q=class extends O{set showDebug(t){this.shouldRenderDebug=t,t||this.clearRayDebugArrows(),this.debugMesh&&(this.debugMesh.visible=t),this.staticDebugMesh&&(this.staticDebugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(){super(),this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.colliders=new Map,this.rayDebugArrowPool=[],this.activeRayDebugArrows=[],this.collisionEvents=new l,this.beforeStep=new l,this.afterStep=new l,this.shouldRenderDebug=!1,this.viewController=C(V),this.shapeCacheBox=new Map,this.shapeCacheBall=new Map,this.staticDebugNeedsUpdate=!0,this.invalidateStaticDebug=()=>{this.staticDebugNeedsUpdate=!0},this._raycaster=new w,this._reusableResult=new RayTestResult,this._raytestDiff=new v,this._raytestDirection=new v,this.controlledActors=new Set,this._isStopped=!1,this.ready=this.setup()}getBallShape(t){let e=this.shapeCacheBall.get(t);return null==e&&(e=new this.rapier.Ball(t),this.shapeCacheBall.set(t,e)),e}getBoxShape(t,e,i){const s=t+1e6*e+1e12*i;let o=this.shapeCacheBox.get(s);return null==o&&(o=new this.rapier.Cuboid(t,e,i),this.shapeCacheBox.set(s,o)),o}hasBoxIntersection(t){const e=t.getCenter(G),i=t.getSize(K),s=this.getBoxShape(i.x/2,i.y/2,i.z/2);return null!=this.world.intersectionWithShape(e,H,s)}hasSphereIntersection(t){const e=this.getBallShape(t.radius);return null!=this.world.intersectionWithShape(t.center,H,e)}findActorsInRadius(t,e,i){const s=this.getBallShape(e),o=[];for(const[e,r]of this.bodyActors)if(r instanceof i||null==i)for(let i=0,n=e.numColliders();i<n;i++){e.collider(i).intersectsShape(s,t,H)&&o.push(r)}return o}createDebugMesh(){const t=new g(new p,new d.LineBasicMaterial({color:255}));return t.frustumCulled=!1,t}updateDebugMesh(t,e){const i=t.geometry,s=i.getAttribute("position");if(null==s||s.array.length<e.length){null!=s&&i.dispose();const t=new Float32Array(e.length);t.set(e);const o=new u(t,3);o.setUsage(d.DynamicDrawUsage),i.setAttribute("position",o)}else e.length>0&&(s.array.set(e),s.clearUpdateRanges(),s.addUpdateRange(0,e.length),s.needsUpdate=!0);i.setDrawRange(0,e.length/3)}async start(){return await this.ready,this.handleTick(),this.handleCollisionEvents(),this.ready}handleCollisionEvents(){this.collisionSub=this.collisionEvents.subscribe(t=>{const e=this.colliders.get(t.handle1);if(null==e)return;const i=this.world.getCollider(t.handle2);if(null==i||null==i.parent())return;const s=this.bodyActors.get(i.parent());null!=s&&(t.started?e.onBeginOverlapActor.next({actor:s}):e.onEndOverlapActor.next({actor:s}))})}renderDebug(){if(null==this.scene)return;if(null==this.staticDebugMesh&&(this.staticDebugMesh=this.createDebugMesh(),this.staticDebugMesh.visible=this.shouldRenderDebug,this.staticDebugMesh.raycast=function(){},this.scene.add(this.staticDebugMesh)),null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.scene.add(this.debugMesh)),this.staticDebugNeedsUpdate){const t=this.world.debugRender(s.ONLY_FIXED);this.updateDebugMesh(this.staticDebugMesh,t.vertices),this.staticDebugNeedsUpdate=!1}const t=this.world.debugRender(s.EXCLUDE_FIXED);this.updateDebugMesh(this.debugMesh,t.vertices)}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await ct(),this.eventQueue=new this.rapier.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe(t=>{this._isStopped||(t=Math.min(.1,t),this.beforeStep.next(t),this.updatePhysics(t),this.showDebug&&this.renderDebug(),this.releaseExpiredRayDebugArrows(),this.world.bodies.forEach(t=>{if(t.isFixed())return;let e,i=this.staticMeshes.get(t);if(null==i&&(e=this.bodyActors.get(t),null!=e)){if(e.netRole===U.simulatedProxy)return;i=e.object}null!=i&&i.parent instanceof x&&(ut(i.position,t.translation()),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(t)?.id))&&pt(i.quaternion,t.rotation()),i.matrixWorldNeedsUpdate=!0)}),this.afterStep.next(t))})}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){this._isStopped||(this.world.timestep=t,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents((t,e,i)=>{this.collisionEvents.next({handle1:t,handle2:e,started:i}),this.collisionEvents.next({handle1:e,handle2:t,started:i})}))}rayTestFromCamera(t,e,i){this._raycaster.setFromCamera(rt,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(t).add(s);return this.rayTest(s,o,e,i)}rayTest(t,e,i,s){null==i&&(i=this._reusableResult);const o=this._raytestDiff,r=this._raytestDirection;o.subVectors(e,t);const n=o.length();if(0===n)return console.warn("Ray test called with to and from being equal"),i;r.copy(o).multiplyScalar(1/n),null==ft&&(ft=new this.rapier.Ray(new this.rapier.Vector3(0,0,0),new this.rapier.Vector3(0,1,0))),dt(ft.origin,t),dt(ft.dir,r);const a=this.world.castRayAndGetNormal(ft,n,!1,void 0,s?.collisionFilter,void 0,null!=s?.excludeActor?this.actorBodies.get(s.excludeActor.id):void 0,s?.excludeTriggers?mt:void 0);if(i.hasHit=null!=a,i.actor=void 0,i.hasHit&&(i._internal=a,ut(i.hitNormal,a.normal),i.hitPoint.copy(t).addScaledVector(r,a.timeOfImpact),i.distance=a.timeOfImpact,!1!==s?.resolveActor)){const t=a.collider.parent();i.actor=null!=t?this.bodyActors.get(t):null}return this.showDebug&&!1!==s?.debug&&null!=this.scene&&this.drawRayDebugArrow(r,t,n,s?.debugColor,s?.debugLifetime),i}drawRayDebugArrow(t,e,i,s=255,o=200){let r=this.rayDebugArrowPool.pop();null==r?r=new h(t,e,i,s,.2,.1):(r.setDirection(t),r.position.copy(e),r.setLength(i,.2,.1),r.setColor(s)),r.userData.physicsRayDebugExpiresAt=performance.now()+o,this.activeRayDebugArrows.push(r),this.scene.add(r)}releaseExpiredRayDebugArrows(){if(0===this.activeRayDebugArrows.length)return;const t=performance.now();let e=0;for(let i=0;i<this.activeRayDebugArrows.length;i++){const s=this.activeRayDebugArrows[i];s.userData.physicsRayDebugExpiresAt<=t?(s.removeFromParent(),this.rayDebugArrowPool.push(s)):this.activeRayDebugArrows[e++]=s}this.activeRayDebugArrows.length=e}clearRayDebugArrows(){for(const t of this.activeRayDebugArrows)t.removeFromParent(),this.rayDebugArrowPool.push(t);this.activeRayDebugArrows.length=0}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return Z.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(t){this.addRecursively(t);for(const t of this.staticBodies.values())yt(t,t=>t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS))}addRecursively(t){if(this.removeSceneObject(t),!function(t){if(null!=t.userData?.src){const e=t.userData?.src;return"actor"===e.type}return!1}(t))if(t instanceof P&&null!=t.collisionShape){const e=this.createStaticBody(t,[t.collisionShape],t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else if(t instanceof W){const e=!1!==t.userData?.src?.collisionDetection;if(t.children[0]&&(t.children[0].instanceMatrix&&e||t.children[0].isBatchedMesh))this.createForInstancedMesh(t.children[0],t.collisionShapes);else if(e&&t.children.length>0){const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}}else t instanceof N?this.addLandscapeGroup(t):(t instanceof y||t instanceof x)&&t.children.forEach(t=>this.addRecursively(t))}createForInstancedMesh(t,e){const i=new m;if(t instanceof d.BatchedMesh){const e=t._instanceInfo??t._drawInfo,s=new Map,o=t.userData.collisionMatrices;for(let r=0;r<e.length;r++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[r])continue;const e=t.userData.collisionShapes;let n=e?.[r];if(null==n&&null==e&&t.parent instanceof W&&(n=t.parent.collisionShapes),null==n)continue;const a=o?.[r];let l=n;null==a&&(l=s.get(n),null==l&&(l=this.instancedShapeReset(n),s.set(n,l)));const c=new b;c.matrix.identity(),null!=a?i.copy(a):t.getMatrixAt(r,i),c.applyMatrix4(i);this.createStaticBody(c,l)}}else{const s=this.instancedShapeReset(e);for(let e=0;e<t.count;e++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[e])continue;const o=new b;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*e),o.applyMatrix4(i);this.createStaticBody(o,s)}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>I(t))}getCharacterController(t){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i,o=null){const r=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const n=r.collider(0);e.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,o,mt);const a=e.computedMovement();return ut(gt,a),gt}setActorCapsuleCollider(t,e,i,s){const o=this.actorBodies.get(t.id),r=o?.collider(0);if(null==o||null==r)return!1;const n=t.object?.getWorldScale(bt)??et,a=Math.max(0,e*Math.abs(n.y)),l=Math.max(.001,i*Math.max(Math.abs(n.x),Math.abs(n.z)));return r.setHalfHeight(a/2),r.setRadius(l),ot.set(0,s,0).multiply(n),dt(it,ot),r.setTranslationWrtParent(it),o.recomputeMassPropertiesFromColliders(),o.isFixed()&&this.invalidateStaticDebug(),!0}hasActorCapsuleIntersection(t,e,i,o,r,n=null){const a=this.actorBodies.get(t.id),l=t.object?.getWorldScale(bt)??et,c=Math.max(0,i*Math.abs(l.y)),d=Math.max(.001,o*Math.max(Math.abs(l.x),Math.abs(l.z))),h=new this.rapier.Capsule(c/2,d),u=t.object?.getWorldQuaternion(q)??H;ot.set(0,r,0).multiply(l).applyQuaternion(u).add(e);return null!=this.world.intersectionWithShape(ot,u,h,s.EXCLUDE_SENSORS,n??void 0,void 0,a,mt)}createCollider(t,e){const i=this.addShape(e?.body,t),s=new PhysicsCollider(i,this.world,this.invalidateStaticDebug);return this.colliders.set(i.handle,s),(null==e||e.body.isFixed())&&this.invalidateStaticDebug(),s.disposed.subscribe(()=>{this.colliders.delete(i.handle)}),s}createBody(t=PhysicsBodyType.dynamic,e={}){const i=(()=>{switch(t){case PhysicsBodyType.dynamic:return this.rapier.RigidBodyDesc.dynamic();case PhysicsBodyType.static:return this.rapier.RigidBodyDesc.fixed();case PhysicsBodyType.kinematic:return this.rapier.RigidBodyDesc.kinematicPositionBased();case PhysicsBodyType.kinematicVelocityBased:return this.rapier.RigidBodyDesc.kinematicVelocityBased();default:return this.rapier.RigidBodyDesc.dynamic()}})();e.position&&i.setTranslation(e.position.x,e.position.y,e.position.z),e.rotation&&i.setRotation({x:e.rotation.x,y:e.rotation.y,z:e.rotation.z,w:e.rotation.w}),"boolean"==typeof e.canSleep&&i.setCanSleep(e.canSleep),"boolean"==typeof e.ccdEnabled&&i.setCcdEnabled(e.ccdEnabled),"number"==typeof e.gravityScale&&i.setGravityScale(e.gravityScale),"number"==typeof e.mass&&i.setAdditionalMass(e.mass),void 0!==e.userData&&(i.userData=e.userData);const s=this.world.createRigidBody(i);return s.isFixed()&&this.invalidateStaticDebug(),new PhysicsBody(s,this.world,this.invalidateStaticDebug)}createJoint(t,e,i){let s,o;switch(i.type){case"fixed":s=this.rapier.JointData.fixed(i.anchor1,i.frame1,i.anchor2,i.frame2);break;case"spherical":s=this.rapier.JointData.spherical(i.anchor1,i.anchor2);break;case"revolute":s=this.rapier.JointData.revolute(i.anchor1,i.anchor2,i.axis),null!=i.limits&&(o=i.limits)}const r=this.world.createImpulseJoint(s,t.body,e.body,!0);if(null!=o){r.setLimits(o[0],o[1])}return r.setContactsEnabled(i.contactsEnabled??!1),new PhysicsJoint(r,this.world)}getCharacterComputedMovement(t,e,i,o=null){const r=t.collider;e.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,o,mt);const n=e.computedMovement();return ut(gt,n),gt}setNextKinematicTranslation(t,e){const i=this.actorBodies.get(t.id),s=i.translation();s.x+=e.x,s.y+=e.y,s.z+=e.z,i?.setNextKinematicTranslation(s)}setNextKinematicPosition(t,e){this.actorBodies.get(t.id).setNextKinematicTranslation(e)}setNextKinematicRotation(t,e){this.actorBodies.get(t.id).setNextKinematicRotation(e)}setNextKinematicTransform(t){!function(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setNextKinematicTranslation(nt(i)),t.setNextKinematicRotation(at(s))}(this.actorBodies.get(t.id),t.object)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setAngvel(it,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setLinvel(it,!0)}getLinearVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.linvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}getAngularVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.angvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}setLinearDamping(t,e){const i=this.actorBodies.get(t.id);i?.setLinearDamping(e)}getLienarDamping(t){const e=this.actorBodies.get(t.id);return e?.linearDamping()??0}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}getAngularDamping(t){const e=this.actorBodies.get(t.id);e?.angularDamping()}setPosition(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(nt(e),!1)}getPosition(t,e=new v){const i=this.actorBodies.get(t.id);i&&ut(e,i.translation())}setRotation(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(at(e),!1)}getRotation(t,e=new f){const i=this.actorBodies.get(t.id);i&&pt(e,i.rotation())}lockTranslations(t,e){const i=this.actorBodies.get(t.id);i?.lockTranslations(e,!1)}lockRotations(t,e){const i=this.actorBodies.get(t.id);i?.lockRotations(e,!1)}setEnabledTranslations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledTranslations(e,i,s,!1)}setEnabledRotations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledRotations(e,i,s,!1)}addLandscapeGroup(t){this.invalidateStaticDebug();const e=t.userData.src,s=e.landscape.heightMaps;for(const r of t.sections){this.staticBodies.has(r)&&this.world.removeRigidBody(this.staticBodies.get(r));var o=r.getWorldPosition(new v);if(e.landscape.holes&&e.landscape.holes.some(t=>t.m===r.name&&0!==t.w[0])){const t=r.geometry.clone(),i=r.scale,s=r.geometry.getAttribute("hole"),n=new Float32Array(t.getAttribute("position").array);for(let t=0;t<n.length;t+=3)n[t]*=i.x,n[t+1]*=i.y,n[t+2]*=i.z;const a=t.index;for(let t=0;t<a.count;t+=3){const e=s.getX(a.getX(t)),i=s.getX(a.getY(t)),o=s.getX(a.getZ(t));(e>.5||i>.5||o>.5)&&(a.setX(t,0),a.setY(t,0),a.setZ(t,0))}const l=this.rapier.ColliderDesc.trimesh(n,new Uint32Array(t.getIndex().array));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);dt(e,o),t.setTranslation(e,!1),this.world.createCollider(l,t),this.staticBodies.set(r,t)}continue}const t=e.landscape.options.density+1,n=e.landscape.options.sectionSize,a=new Array(t);for(let e=0;e<t;e++)a[e]=new Array(t).fill(0);const l=s.find(t=>t.x===r.x&&t.y==r.y);if(null!=l)for(const e of l.points){if(null==a[e.i%t])continue;const i=t-1-Math.floor(e.i/t);i in a[e.i%t]?a[e.i%t][i]=e.y/n:console.warn("wrong index",{points:a,point:e,i:e.i%t,k:i,heightMap:l})}const c=e.landscape.options.density,d=a.flatMap(t=>t.reverse()),h=i.ColliderDesc.heightfield(c,c,new Float32Array(d),new this.rapier.Vector3(n,n,n));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);dt(e,o),t.setTranslation(e,!1),this.world.createCollider(h,t),this.staticBodies.set(r,t)}}}setEnabled(t,e){const i=this.actorBodies.get(t.id);i?.setEnabled(e),i?.isFixed()&&this.invalidateStaticDebug()}addActor(t,e,i={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const s=t.object;let o;switch(i.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:o=this.rapier.RigidBodyDesc.dynamic(),o.mass=i.mass??1;break;case PhysicsBodyType.kinematic:o=this.rapier.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:o=this.rapier.RigidBodyDesc.kinematicVelocityBased();break;default:o=i.isTrigger?this.rapier.RigidBodyDesc.kinematicVelocityBased():this.rapier.RigidBodyDesc.fixed()}const r=this.world.createRigidBody(o);r.enableCcd(1==i.continousCollisionDetection);for(const t of e)this.addShape(r,t,s);return yt(r,t=>{null!=i.isTrigger&&(t.setSensor(i.isTrigger),t.setActiveCollisionTypes(this.rapier.ActiveCollisionTypes.ALL),t.setActiveEvents(this.rapier.ActiveEvents.COLLISION_EVENTS)),null!=i.friction&&t.setFriction(i.friction),null!=i.density&&t.setDensity(i.density),null!=i.mass&&t.setMass(i.mass),null!=i.restitution&&t.setRestitution(i.restitution)}),Y(r,s),!0===i.ignoreForNavMesh&&(r.userData={ignoreForNavMesh:!0}),this.actorBodies.set(t.id,r),this.bodyActors.set(r,t),r.isFixed()&&this.invalidateStaticDebug(),new PhysicsBody(r,this.world,this.invalidateStaticDebug)}applyTorque(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addTorque(it,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyTorqueImpulse(it,!0)}resetForces(t){const e=this.actorBodies.get(t.id);e?.resetForces(!1)}resetTorques(t){const e=this.actorBodies.get(t.id);e?.resetTorques(!1)}applyForce(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addForce(it,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyImpulse(it,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);dt(it,e),null==i?s?.addForce(it,!0):(dt(st,i),s?.addForceAtPoint(it,st,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);dt(it,e),null==i?s.applyImpulse(it,!0):(dt(st,i),s.applyImpulseAtPoint(it,st,!0))}applyRadiusImpulse(t,e,s){this.world.bodies.forEach(o=>{if(o.collider(0)?.isSensor())return;if(o.bodyType()!==i.RigidBodyType.Dynamic)return;const r=ot;ut(r,o.translation());const n=r.clone().sub(t);if(n.length()>e)return;const a=n.clone().normalize().multiplyScalar(s);it.x=a.x,it.y=a.y,it.z=a.z,o.applyImpulse(it,!0)})}removeActor(t){if(null==t)return;this.controlledActors.delete(t.id);const e=this.actorBodies.get(t.id);null!=e&&(e.isFixed()&&this.invalidateStaticDebug(),this.bodyActors.delete(e),this.world.removeRigidBody(e)),this.actorBodies.delete(t.id)}removeRemoved(t){if(null==t)return;const e=new Set;t.traverse(t=>{e.add(t.uuid)});for(const[t,i]of this.staticBodies.entries())e.has(t.uuid)&&this.world.getRigidBody(i.handle)&&(this.invalidateStaticDebug(),this.staticBodies.delete(t),this.world.removeRigidBody(i))}removeSceneObject(t){if(t instanceof N){for(const e of t.sections)this.removeSceneObject(e);return}let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&(this.invalidateStaticDebug(),this.world.removeRigidBody(e)),this.staticBodies.delete(t)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),n(({started:t})=>t===i),a(({handle1:t,handle2:e,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(t)?.parent()),a2:this.bodyActors.get(this.world.getCollider(e)?.parent()),started:i})),n(({a1:i,a2:s})=>null!=i&&null!=s&&i.id===t.id&&e(i,s)),a(({a2:t})=>t))}onBeginContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),n(t=>t.started),n(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onEndContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),n(t=>!t.started),n(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onHasContactChanged(t){const e=new Set,i=new o(!1);return this.onBeginContact(t).subscribe(t=>{e.add(t),i.next(e.size>0)}),this.onEndContact(t).subscribe(t=>{e.delete(t),i.next(e.size>0)}),i.pipe(r())}onBeginOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!0)}onEndOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!1)}onBeginOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!0)}onEndOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!1)}onBeginOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!0)}onEndOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!1)}onCollisionWithActor(t,e){return this.onBeginOverlapWithActor(t,e)}onCollisionWithActorType(t,e){return this.onBeginOverlapWithActorType(t,e)}updateActorTransform(t){const e=this.actorBodies.get(t.id);null!=e&&(Y(e,t.object),e.isFixed()&&this.invalidateStaticDebug())}flushModifiedBodyPositionsToColliders(){this.world.propagateModifiedBodyPositionsToColliders()}setupWorld(){const t=new this.rapier.World({x:0,y:-9.81,z:0});this.world=t,this.invalidateStaticDebug()}sphereCast(t,e,i,s,o=ShapeCastResult.shared,r){o.reset();const n=this.getBallShape(e);this.shapeCacheBall.get;const a={x:t.x,y:t.y,z:t.z},l={x:i.x,y:i.y,z:i.z},c=r?.excludeActor?this.actorBodies.get(r.excludeActor.id):null,d=this.world.castShape(a,{x:0,y:0,z:0,w:1},l,n,.01,s,!0,null,r?.collisionFilter??void 0,null,c,r?.excludeTriggers?t=>!t.isSensor():void 0);if(null!=d){ut(o.hitPoint,d.witness1),o.normal.set(d.normal1.x,d.normal1.y,d.normal1.z),o.distance=d.time_of_impact,o.hasHit=!0;const t=d.collider.parent();if(t){const e=this.bodyActors.get(t);e&&(o.actor=e)}}return o}castActorShape(t,e,i,s=ShapeCastResult.shared,o=void 0){s.reset();const r=this.actorBodies.get(t.id);if(r&&r.numColliders()>0){for(let t=0;t<r.numColliders();t++){const n=r.collider(t);let a=n.shape,l=n.translation(),c=n.rotation(),d=e,h=i;const u=this.world.castShape(l,c,d,a,.01,h,!0,null,o,null,r,void 0);if(null!=u){u.collider;const t=n;return ut(s.hitPoint,u.witness1),xt(t.rotation(),u.normal1,s.normal,X),s.distance=u.time_of_impact,s.actor=this.bodyActors.get(u.collider.parent()),s.hasHit=!0,s}}return s}return console.warn("Actor is not added to the physics system"),s}stop(){if(!this._isStopped){this._isStopped=!0,this.bodyActors.clear(),this.actorBodies.clear(),this.staticBodies.clear(),this.staticMeshes.clear(),this.colliders.clear(),this.fixedupdateSub?.unsubscribe(),this.collisionSub?.unsubscribe(),this.world?.bodies.forEach(t=>this.world.removeRigidBody(t));try{this.world?.free(),this.world=void 0}catch(t){console.warn("Error while freeing physics world",t)}this.clearRayDebugArrows();for(const t of this.rayDebugArrowPool)t.dispose();this.rayDebugArrowPool.length=0}}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed();o.setSleeping(!0);const r=this.world.createRigidBody(o);let n=0;for(const i of e){if(n>128){console.warn("Too many collision shapes for object",t);break}if(n++,null==i){console.warn("Collision shape is missing for object",t);continue}const o=this.addShape(r,i,t);null!=o&&(null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/e.length),null!=s?.restitution&&o.setRestitution(s.restitution))}return Y(r,t),r.userData=t.uuid,r.sleep(),r.isFixed()&&this.invalidateStaticDebug(),r}addShape(t=void 0,e,i){const s=i?.getWorldScale(bt)??et,o=this.createShape(e,s);if(null==o)return void console.error("Failed to create physics shape. This can happen if the geometry is degenerate or zero-scaled.",{shapeInfo:e,object:i});this.applyShapeSettings(o,e);const r=e.offset.clone().multiply(s);dt(o.translation,r);const n=(new f).setFromEuler(e.rotation);ht(o.rotation,n),null!=t&&t.numColliders()>128&&console.warn(`Rigid body has many colliders (${t.numColliders()}). Consider using a Trimesh if this is static geometry.`,t);try{return this.world.createCollider(o,t)}catch(t){return void console.error("Failed to create collider",t)}}applyShapeSettings(t,e){null!=e.collisionGroup&&t.setCollisionGroups(e.collisionGroup),t.friction=e.friction??.1,null!=e.restitution&&(t.restitution=e.restitution),null!=e.density&&(t.density=e.density,t.massPropsMode=i.MassPropsMode.Density),null!=e.mass&&(t.mass=e.mass,t.massPropsMode=i.MassPropsMode.Mass)}createShape(t,e){if(t instanceof R)return this.rapier.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof M){return this.rapier.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof j){const i=null!=t.geometry.getIndex()?t.geometry:D.mergeVertices(t.geometry),s=extractFloat32Array(i.getAttribute("position"));for(let t=0;t<s.length;t+=3)s[t]*=e.x,s[t+1]*=e.y,s[t+2]*=e.z;const o=i.getIndex();return null==o?(console.error("Trimesh collision shape is missing an index buffer.",t),null):this.rapier.ColliderDesc.trimesh(s,new Uint32Array(o.array))}if(t instanceof z){let i,s;t.mesh instanceof d.Mesh?i=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?i=t.mesh:console.log("Unknownd shape",{shapeInfo:t}),t.mesh instanceof d.Mesh&&(s=k(t.mesh));const o=`${i.uuid}|${s?.x??1},${s?.y??1},${s?.z??1}|${e.x},${e.y},${e.z}`,r=tt.get(o);if(void 0!==r)return r;const n=extractFloat32Array(i.getAttribute("position"));if(null!=s)for(let t=0;t<n.length;t+=3)n[t]*=s.x,n[t+1]*=s.y,n[t+2]*=s.z;for(let t=0;t<n.length;t+=3)n[t]*=e.x,n[t+1]*=e.y,n[t+2]*=e.z;const a=this.rapier.ColliderDesc.convexHull(n);return null==a&&console.error("Failed to compute convex hull. Points may be coplanar or too few.",{count:n.length/3}),tt.set(o,a),a}if(t instanceof _){const i=2*e.x-e.y-e.z;return Math.abs(i)>.01?this.createShape(new z(new d.SphereGeometry(t.radius).scale(e.x,e.y,e.z)),new v(1,1,1)):this.rapier.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z))}return t instanceof T?this.rapier.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof E?this.rapier.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof F?this.rapier.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.001):(console.error("Unsupported shape",t),this.rapier.ColliderDesc.cuboid(1,1,1))}createCharacterCollision(){return new this.rapier.CharacterCollision}};Q=t([B(),e("design:paramtypes",[])],Q);export{Q as PhysicsSystem};const J=new v,$=new d.Quaternion;function Y(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setTranslation(nt(i),!1),t.setRotation(at(s),!1)}const Z=new v,tt=new Map,et=new v(1,1,1),it=new i.Vector3(0,0,0),st=new i.Vector3(0,0,0),ot=new v,rt=new d.Vector2;function nt(t){return dt(it,t),it}function at(t){return ht(X,t),X}let lt=null;const ct=async()=>(null==lt&&(lt=(async()=>{let t=await import("@dimforge/rapier3d-simd-compat");return await t.init(),t})()),lt);function dt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function ht(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function ut(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function pt(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function yt(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const gt=new v,mt=t=>!t.isSensor(),bt=new v;let ft,wt=class extends S{constructor(){super(...arguments),this._active=!0,this.physics=C(Q),this.world=C(L)}set active(t){this._active=t,t?(this.world.scene.remove(this.actor.object),this.physics.setEnabled(this.actor,t)):(this.world.scene.add(this.actor.object),this.physics.setEnabled(this.actor,t))}get active(){return this._active}};wt=t([A()],wt);export function extractFloat32Array(t){const e=t.itemSize,i=t.count,s=new Float32Array(i*e);for(let o=0;o<i;o++)for(let i=0;i<e;i++)s[o*e+i]=t.getComponent(o,i);return s}function xt(t,e,i,s){return s.set(t.x,t.y,t.z,t.w),i.set(e.x,e.y,e.z),i.applyQuaternion(s),i}export class PhysicsCollider{constructor(t,e,i){this.collider=t,this.world=e,this.invalidateStaticDebug=i,this.disposed=new l,this.onBeginOverlapActor=new l,this.onEndOverlapActor=new l}dispose(){const t=this.collider.parent();(null==t||t.isFixed())&&this.invalidateStaticDebug?.(),this.world.removeCollider(this.collider,!1),this.disposed.next(!0),this.disposed.complete(),this.onBeginOverlapActor.complete(),this.onEndOverlapActor.complete()}set mass(t){this.collider.setMass(t)}get mass(){return this.collider.mass()}set friction(t){this.collider.setFriction(t)}get friction(){return this.collider.friction()}set restitution(t){this.collider.setRestitution(t)}get restitution(){return this.collider.restitution()}set density(t){this.collider.setDensity(t)}get density(){return this.collider.density()}set isTrigger(t){this.collider.setSensor(t)}get isTrigger(){return this.collider.isSensor()}set collisionGroups(t){this.collider.setCollisionGroups(t)}get collisionGroups(){return this.collider.collisionGroups()}set enabled(t){this.collider.setEnabled(t);const e=this.collider.parent();(null==e||e.isFixed())&&this.invalidateStaticDebug?.()}get enabled(){return this.collider.isEnabled()}}export class PhysicsBody{constructor(t,e,i){this.invalidateStaticDebug=i,this.body=t,this.world=e}dispose(){this.body.isFixed()&&this.invalidateStaticDebug?.(),this.world.removeRigidBody(this.body)}setEnabled(t){this.body.setEnabled(t),this.body.isFixed()&&this.invalidateStaticDebug?.()}isEnabled(){return this.body.isEnabled()}getPosition(t){const e=this.body.translation();return t.set(e.x,e.y,e.z),t}setPosition(t){this.body.setTranslation({x:t.x,y:t.y,z:t.z},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getRotation(t){const e=this.body.rotation();return t.set(e.x,e.y,e.z,e.w),t}setRotation(t){this.body.setRotation({x:t.x,y:t.y,z:t.z,w:t.w},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getLinearVelocity(t){const e=this.body.linvel();return t.set(e.x,e.y,e.z),t}setLinearVelocity(t){this.body.setLinvel({x:t.x,y:t.y,z:t.z},!0)}getAngularVelocity(t){const e=this.body.angvel();return t.set(e.x,e.y,e.z),t}setAngularVelocity(t){this.body.setAngvel({x:t.x,y:t.y,z:t.z},!0)}setLinearDamping(t){this.body.setLinearDamping(t)}setAngularDamping(t){this.body.setAngularDamping(t)}applyImpulse(t,e=!0){this.body.applyImpulse({x:t.x,y:t.y,z:t.z},e)}applyTorqueImpulse(t,e=!0){this.body.applyTorqueImpulse({x:t.x,y:t.y,z:t.z},e)}setNextKinematicPosition(t){this.body.setNextKinematicTranslation(t)}setNextKinematicRotation(t){this.body.setNextKinematicRotation(t)}setType(t){const e=this.body.isFixed();this.body.setBodyType(function(t){switch(t){case PhysicsBodyType.dynamic:return i.RigidBodyType.Dynamic;case PhysicsBodyType.static:return i.RigidBodyType.Fixed;case PhysicsBodyType.kinematic:return i.RigidBodyType.KinematicPositionBased;case PhysicsBodyType.kinematicVelocityBased:return i.RigidBodyType.KinematicVelocityBased}}(t),t!==PhysicsBodyType.static),(e||this.body.isFixed())&&this.invalidateStaticDebug?.()}setGravityScale(t){this.body.setGravityScale(t,!1)}getGravityScale(){return this.body.gravityScale()}isDynamic(){return this.body.isDynamic()}isKinematic(){return this.body.isKinematic()}isStatic(){return this.body.isFixed()}sleep(){this.body.sleep()}wakeUp(){this.body.wakeUp()}}export class PhysicsJoint{constructor(t,e){this.joint=t,this.world=e}dispose(){this.joint.isValid()&&this.world.removeImpulseJoint(this.joint,!0)}setContactsEnabled(t){this.joint.setContactsEnabled(t)}get contactsEnabled(){return this.joint.contactsEnabled()}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -37,6 +37,7 @@ export declare class AssetResourceLoader {
|
|
|
37
37
|
private getUri;
|
|
38
38
|
private _texturePromises;
|
|
39
39
|
private _arrayTexturesByFileKey;
|
|
40
|
+
private _arrayTexturePromisesByFileKey;
|
|
40
41
|
private _arrayTextureSettingsByFileKey;
|
|
41
42
|
private _animationPromises;
|
|
42
43
|
private _animationCache;
|
|
@@ -51,6 +52,7 @@ export declare class AssetResourceLoader {
|
|
|
51
52
|
texture: Texture | null;
|
|
52
53
|
layerIndex: number | null;
|
|
53
54
|
}>;
|
|
55
|
+
private loadTextureArray;
|
|
54
56
|
private applyTextureArraySettings;
|
|
55
57
|
private _getTextureLoader;
|
|
56
58
|
clearCache(asset: Asset): void;
|
|
@@ -132,5 +134,13 @@ export type GetMeshOptions = {
|
|
|
132
134
|
* Resolver for material assets. Defaults to the global provider on the AssetResourceLoader if not provided.
|
|
133
135
|
*/
|
|
134
136
|
materialResolver?: (materialId: AssetId) => Promise<Material>;
|
|
137
|
+
/**
|
|
138
|
+
* Whether to clone the cached scene before returning it. Set to false for read-only
|
|
139
|
+
* inspection (e.g. rig extraction, validation, tooltips) to avoid the expensive deep-copy
|
|
140
|
+
* of the full Object3D hierarchy. The returned scene must NOT be mutated or added to a
|
|
141
|
+
* live scene graph when clone is false.
|
|
142
|
+
* @default true
|
|
143
|
+
*/
|
|
144
|
+
clone?: boolean;
|
|
135
145
|
};
|
|
136
146
|
//# sourceMappingURL=asset-resource-loader.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{AudioLoader as e,BufferGeometry as t,Euler as r,Group as a,LoadingManager as s,Mesh as i,Object3D as n,Texture as o,TextureLoader as l,Vector3 as c}from"three";import{MTLLoader as h,OBJLoader as u,LUTCubeLoader as m}from"three-stdlib";import{cloneMesh as p}from"../utils/mesh.js";import{pathJoin as d}from"../utils/files.js";import{Subject as f,firstValueFrom as y}from"rxjs";import{BoxCollisionShape as g,CapsuleCollisionShape as w,CollisionShapeSource as x,CylinderCollisionShape as M,SphereCollisionShape as A}from"./collision/collision-shape.js";import{importCollisionShapes as b,isCollisionMesh as _}from"./collision/collision-shape-import.js";import*as S from"three";import{iterateMaterials as L}from"../utils/materials.js";import{applyMaterial as T,getConvertedFbxToGlbAssignedMaterialTextureFlipY as v}from"./materializer.js";import{BufferGeometryUtils as C,DRACOLoader as R,EXRLoader as P,FBXLoader as K,GLTFLoader as I,KTX2Loader as k,TGALoader as B,UltraHDRLoader as D}from"three/examples/jsm/Addons.js";import{disposeScene as F}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as W,setAnimationClipRigId as j}from"../gameplay/animation/retarget.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new S.DataTexture(e,1,1,S.RGBAFormat);t.needsUpdate=!0})();const U=new R;U.setDecoderConfig({type:"js"}),U.setDecoderPath("/assets/draco/");const E=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new I(this.loadingManager).setDRACOLoader(U),this.fbxLoader=new K(this.loadingManager),this.objLoader=new u(this.loadingManager),this.textureLoader=new l(this.loadingManager),this.tgaLoader=new B(this.loadingManager),this.exrLoader=new P(this.loadingManager),this.cubeLoader=new m(this.loadingManager),this.hdrLoader=new D(this.loadingManager),this.ktx2Loader=new k(this.loadingManager),this._textureLoader=new S.ImageBitmapLoader(this.loadingManager),this.audioLoader=new e(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new f,this.ready=y(this.makeReady),this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}initKtx2(e){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.detectSupport(e),this.ktx2Loader.setWorkerLimit(6)}setDataDir(e){this.basePath=d(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){const t=function(e){return G.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?d(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(d("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=O(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==Y(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=Y(e.texture?.wrapS)):t.wrapT!==Y(e.texture?.wrapT)&&(t.wrapT=Y(e.texture?.wrapT),t.needsUpdate=!0)}const r=V(N(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{await this._getTextureLoader(e.fileKey).loadAsync(this.getUri(e.fileKey)).then(t=>(t.texture3D?t=t.texture3D:(t.wrapS=Y(e.texture?.wrapS),t.wrapT=Y(e.texture?.wrapT),t.flipY=O(t,e),t.colorSpace=V(N(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};if(this._arrayTexturesByFileKey.has(t))this.applyTextureArraySettings(t,this._arrayTexturesByFileKey.get(t),e);else{const r=this._getTextureLoader(t);let a=await r.loadAsync(this.getUri(t));a instanceof o||(a=a.texture3D),this.applyTextureArraySettings(t,a,e),this._arrayTexturesByFileKey.set(t,a),this._retrievedTextures.push(a)}return{texture:this._arrayTexturesByFileKey.get(t),layerIndex:r}}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:Y(e.texture?.wrapS),wrapT:Y(e.texture?.wrapT)}}(r),s=this._arrayTextureSettingsByFileKey.get(e);if(null!=s&&(n=a,(i=s).wrapS!==n.wrapS||i.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var i,n;null==s&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),z(e.fileKey)),null!=e.materialLib&&z(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new a,animations:[]};if(!E.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new a,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new a,animations:[]}}const s=this.cache.get(r).scene,n=this.computeCollisionShapes(e,s);!0===t?.mergeGeomtries&&this.optimizeDrawGroups(s);const o=p(s),l=this.cache.get(r).animations;o.traverse(e=>{e instanceof i&&e.material instanceof Array&&(e.material=e.material.slice())});const c=new AssetMeshInstance;c.add(o),c.collisionShapes=n,c.animations=l,c.userData.assetId=e.id;const h=e.mesh?.animationRigId??e.anim?.rigId;if(c.userData.animationRigId=h,o.userData.animationRigId=h,null!=h&&null!=this.animationRigProvider){const e=await this.animationRigProvider(h);c.userData.animationRig=e,o.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&c.quaternion.copy(W(e))}const u=e.receiveShadow??!1,m=e.castShadow??!1;if(o.traverse(e=>{e.castShadow=m,e.receiveShadow=u}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&c.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await T(c,t,r,void 0,{textureFlipY:v(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:c,animations:l}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const t=e.anim.clip,r=e.fileKey+"|"+t;if(this._animationCache.has(r))return this._animationCache.get(r);if(this._animationPromises.has(r))return this._animationPromises.get(r);const a=(async()=>{try{const a=await this.getMesh(e),s=a.animations.find(e=>e.name===t);return null!=s&&(j(s,e.anim?.rigId),this._animationCache.set(r,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(r),1e3)}})();return this._animationPromises.set(r,a),a}computeCollisionShapes(e,t){if(!0!==e.collisionDetection)return[];const r=e.id+"|"+(e.mesh?.collisions?.shapeType??"")+"|"+(e.mesh?.rescale??1)+"|"+JSON.stringify(e.mesh?.colliders??[]);if(!this.collisionShapeCache.has(r)){const a=e.mesh?.colliders??[],s=a.length>0?createAuthoredCollisionShapes(a,e.mesh?.rescale):b(t,e);this.collisionShapeCache.set(r,s)}return this.collisionShapeCache.get(r)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(r=>(r.scene.traverse(e=>{e instanceof i&&e.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(Z):e.material=Z(t)}(e),_(e)?e.visible=!1:e instanceof i&&e.geometry instanceof t&&(e.geometry.hasAttribute("normal")||e.geometry.computeVertexNormals())}),this._retrievedMeshes.push(r.scene),r.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{J.test(e.name)&&(r=!0)}),!r)return t;const a=[],s=[t];for(;s.length>0;){const e=s.shift(),t=e.name.match(J);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}s.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,r.scene),function(e){const t=q;q.length=0,e.traverse(e=>{(e instanceof S.Camera||e instanceof S.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(r.scene),r.scene.userData.assetId=e.id,r))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const r=[];e.traverse(e=>{e instanceof i&&!(e instanceof S.SkinnedMesh)&&e.geometry instanceof t&&Array.isArray(e.material)&&!_(e)&&r.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:t,geometry:a,materialArray:s,parent:n}of r){t.removeFromParent();for(let r=0;r<s.length;r++){const o=s[r],l=a.groups.filter(e=>e.materialIndex===r);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&C.mergeGroups(c);const h=new i(c,o);h.copy(t,!1),h.geometry=c,h.material=o,n?n.add(h):e.add(h)}a.dispose()}let a=!0,s=0,n=0;if(e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!_(e)){s++;const t=Object.keys(e.geometry.attributes).length;t!==n&&0!==n&&(a=!1),n=t}else(e instanceof S.SkinnedMesh||e instanceof S.Bone)&&(a=!1)}),s>1&&a){const r=new Map;e.traverse(a=>{if(a instanceof i&&a.geometry instanceof t&&!_(a)){if(Array.isArray(a.material))return;a.updateWorldMatrix(!0,!0);const t=a.material?.uuid||"default";r.has(t)||r.set(t,{material:a.material,geometries:[],objects:[]});const s=r.get(t),i=e.matrixWorld.clone().invert().multiply(a.matrixWorld);s.geometries.push(a.geometry.clone().applyMatrix4(i)),s.objects.push(a)}});for(const e of r.values())for(const t of e.objects)t.removeFromParent();for(const t of r.values()){let r;r=1===t.geometries.length?t.geometries[0]:C.mergeGeometries(t.geometries,!0),r.groups.length>1&&C.mergeGroups(r),e.add(new i(r,t.material))}}e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!_(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&C.mergeGroups(t)}})}extractGeometryGroups(e,r){const a=e.index;if(!a){const a=new t;let s=0;for(const e of r)s+=e.count;if(0===s)return a;for(const t in e.attributes){const i=e.attributes[t],n=i.itemSize,o=i.array,l=new(0,o.constructor)(s*n);let c=0;for(const e of r){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new S.BufferAttribute(l,n,i.normalized);a.setAttribute(t,h)}return a.groups=[{start:0,count:s,materialIndex:0}],a}const s=[];for(const e of r)for(let t=0;t<e.count;t++){const r=a.getX(e.start+t);s.push(r)}if(0===s.length)return new t;const i=new Map,n=[];let o=0;for(const e of s)i.has(e)||(i.set(e,o),o++),n.push(i.get(e));if(0===n.length||0===i.size)return new t;const l=new t;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,s=r.array,n=new(0,s.constructor)(i.size*a);for(const[e,t]of i)for(let r=0;r<a;r++)n[t*a+r]=s[e*a+r];const o=new S.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new S.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(e=>({scene:e.scene,animations:e.animations}));case"fbx":return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new h;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>($(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>F(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const G=new Map;function z(e){G.set(e,(G.get(e)??0)+1)}function $(e){if(e instanceof i)for(const t of L(e.material))t instanceof S.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach($)}export class AssetMeshInstance extends n{}export function createAuthoredCollisionShapes(e,t=1){const a=null!=t&&0!==t?1/t:1;return e.map(e=>{let t;switch(e.type){case"box":t=new g((new c).fromArray(e.size).multiplyScalar(a));break;case"sphere":t=new A(e.radius*a);break;case"capsule":t=new w(e.length*a,e.radius*a);break;case"cylinder":t=new M(e.radius*a,e.radius*a,e.height*a,16,new r)}return t.source=x.custom,t.offset.fromArray(e.position??[0,0,0]).multiplyScalar(a),t.rotation.fromArray(e.rotation??[0,0,0,"XYZ"]),t})}export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function Y(e){switch(e){case"clamp":return S.ClampToEdgeWrapping;case"repeat":return S.RepeatWrapping;case"mirror":return S.MirroredRepeatWrapping}return S.RepeatWrapping}function O(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function N(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(X.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function V(e){return"linear"===e?S.LinearSRGBColorSpace:S.SRGBColorSpace}const X=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new S.Matrix4;const q=[];const J=/_LOD(\d+)/;function Z(e){let t=e instanceof S.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof S.MeshLambertMaterial||e instanceof S.MeshPhongMaterial||e instanceof S.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new S.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return e}/*
|
|
1
|
+
import{AudioLoader as e,BufferGeometry as t,Euler as r,Group as a,LoadingManager as s,Mesh as i,Object3D as n,Texture as o,TextureLoader as l,Vector3 as c}from"three";import{MTLLoader as h,OBJLoader as u,LUTCubeLoader as m}from"three-stdlib";import{cloneMesh as p}from"../utils/mesh.js";import{pathJoin as d}from"../utils/files.js";import{Subject as f,firstValueFrom as y}from"rxjs";import{BoxCollisionShape as g,CapsuleCollisionShape as w,CollisionShapeSource as x,CylinderCollisionShape as M,SphereCollisionShape as A}from"./collision/collision-shape.js";import{importCollisionShapes as b,isCollisionMesh as _}from"./collision/collision-shape-import.js";import*as L from"three";import{iterateMaterials as S}from"../utils/materials.js";import{applyMaterial as T,getConvertedFbxToGlbAssignedMaterialTextureFlipY as v}from"./materializer.js";import{BufferGeometryUtils as C,DRACOLoader as R,EXRLoader as P,FBXLoader as K,GLTFLoader as B,KTX2Loader as I,TGALoader as k,UltraHDRLoader as D}from"three/examples/jsm/Addons.js";import{disposeScene as F}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as W,setAnimationClipRigId as j}from"../gameplay/animation/retarget.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new L.DataTexture(e,1,1,L.RGBAFormat);t.needsUpdate=!0})();const U=new R;U.setDecoderConfig({type:"js"}),U.setDecoderPath("/assets/draco/");const E=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new B(this.loadingManager).setDRACOLoader(U),this.fbxLoader=new K(this.loadingManager),this.objLoader=new u(this.loadingManager),this.textureLoader=new l(this.loadingManager),this.tgaLoader=new k(this.loadingManager),this.exrLoader=new P(this.loadingManager),this.cubeLoader=new m(this.loadingManager),this.hdrLoader=new D(this.loadingManager),this.ktx2Loader=new I(this.loadingManager),this._textureLoader=new L.ImageBitmapLoader(this.loadingManager),this.audioLoader=new e(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new f,this.ready=y(this.makeReady),this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTexturePromisesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}initKtx2(e){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.detectSupport(e),this.ktx2Loader.setWorkerLimit(6)}setDataDir(e){this.basePath=d(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){const t=function(e){return G.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?d(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(d("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=O(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==Y(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=Y(e.texture?.wrapS)):t.wrapT!==Y(e.texture?.wrapT)&&(t.wrapT=Y(e.texture?.wrapT),t.needsUpdate=!0)}const r=V(N(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{await this._getTextureLoader(e.fileKey).loadAsync(this.getUri(e.fileKey)).then(t=>(t.texture3D?t=t.texture3D:(t.wrapS=Y(e.texture?.wrapS),t.wrapT=Y(e.texture?.wrapT),t.flipY=O(t,e),t.colorSpace=V(N(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};let a=this._arrayTexturesByFileKey.get(t);if(null==a){let e=this._arrayTexturePromisesByFileKey.get(t);null==e&&(e=this.loadTextureArray(t).finally(()=>{this._arrayTexturePromisesByFileKey.delete(t)}),this._arrayTexturePromisesByFileKey.set(t,e)),a=await e}return this.applyTextureArraySettings(t,a,e),{texture:a,layerIndex:r}}async loadTextureArray(e){const t=this._getTextureLoader(e);let r=await t.loadAsync(this.getUri(e));return r instanceof o||(r=r.texture3D),this._arrayTexturesByFileKey.set(e,r),this._retrievedTextures.push(r),r}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:Y(e.texture?.wrapS),wrapT:Y(e.texture?.wrapT)}}(r),s=this._arrayTextureSettingsByFileKey.get(e);if(null!=s&&(n=a,(i=s).wrapS!==n.wrapS||i.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var i,n;null==s&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),z(e.fileKey)),null!=e.materialLib&&z(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new a,animations:[]};if(!E.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new a,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new a,animations:[]}}const s=this.cache.get(r),n=s.scene,o=s.animations;if(!1===t?.clone)return{scene:n,animations:o};const l=this.computeCollisionShapes(e,n);!0===t?.mergeGeomtries&&this.optimizeDrawGroups(n);const c=p(n);c.traverse(e=>{e instanceof i&&e.material instanceof Array&&(e.material=e.material.slice())});const h=new AssetMeshInstance;h.add(c),h.collisionShapes=l,h.animations=o,h.userData.assetId=e.id;const u=e.mesh?.animationRigId??e.anim?.rigId;if(h.userData.animationRigId=u,c.userData.animationRigId=u,null!=u&&null!=this.animationRigProvider){const e=await this.animationRigProvider(u);h.userData.animationRig=e,c.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&h.quaternion.copy(W(e))}const m=e.receiveShadow??!1,d=e.castShadow??!1;if(c.traverse(e=>{e.castShadow=d,e.receiveShadow=m}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&h.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await T(h,t,r,void 0,{textureFlipY:v(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:h,animations:o}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const t=e.anim.clip,r=e.fileKey+"|"+t;if(this._animationCache.has(r))return this._animationCache.get(r);if(this._animationPromises.has(r))return this._animationPromises.get(r);const a=(async()=>{try{const a=await this.getMesh(e),s=a.animations.find(e=>e.name===t);return null!=s&&(j(s,e.anim?.rigId),this._animationCache.set(r,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(r),1e3)}})();return this._animationPromises.set(r,a),a}computeCollisionShapes(e,t){if(!0!==e.collisionDetection)return[];const r=e.id+"|"+(e.mesh?.collisions?.shapeType??"")+"|"+(e.mesh?.rescale??1)+"|"+JSON.stringify(e.mesh?.colliders??[]);if(!this.collisionShapeCache.has(r)){const a=e.mesh?.colliders??[],s=a.length>0?createAuthoredCollisionShapes(a,e.mesh?.rescale):b(t,e);this.collisionShapeCache.set(r,s)}return this.collisionShapeCache.get(r)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(r=>(r.scene.traverse(e=>{e instanceof i&&e.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(Z):e.material=Z(t)}(e),_(e)?e.visible=!1:e instanceof i&&e.geometry instanceof t&&(e.geometry.hasAttribute("normal")||e.geometry.computeVertexNormals())}),this._retrievedMeshes.push(r.scene),r.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{J.test(e.name)&&(r=!0)}),!r)return t;const a=[],s=[t];for(;s.length>0;){const e=s.shift(),t=e.name.match(J);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}s.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,r.scene),function(e){const t=q;q.length=0,e.traverse(e=>{(e instanceof L.Camera||e instanceof L.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(r.scene),r.scene.userData.assetId=e.id,r))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const r=[];e.traverse(e=>{e instanceof i&&!(e instanceof L.SkinnedMesh)&&e.geometry instanceof t&&Array.isArray(e.material)&&!_(e)&&r.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:t,geometry:a,materialArray:s,parent:n}of r){t.removeFromParent();for(let r=0;r<s.length;r++){const o=s[r],l=a.groups.filter(e=>e.materialIndex===r);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&C.mergeGroups(c);const h=new i(c,o);h.copy(t,!1),h.geometry=c,h.material=o,n?n.add(h):e.add(h)}a.dispose()}let a=!0,s=0,n=0;if(e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!_(e)){s++;const t=Object.keys(e.geometry.attributes).length;t!==n&&0!==n&&(a=!1),n=t}else(e instanceof L.SkinnedMesh||e instanceof L.Bone)&&(a=!1)}),s>1&&a){const r=new Map;e.traverse(a=>{if(a instanceof i&&a.geometry instanceof t&&!_(a)){if(Array.isArray(a.material))return;a.updateWorldMatrix(!0,!0);const t=a.material?.uuid||"default";r.has(t)||r.set(t,{material:a.material,geometries:[],objects:[]});const s=r.get(t),i=e.matrixWorld.clone().invert().multiply(a.matrixWorld);s.geometries.push(a.geometry.clone().applyMatrix4(i)),s.objects.push(a)}});for(const e of r.values())for(const t of e.objects)t.removeFromParent();for(const t of r.values()){let r;r=1===t.geometries.length?t.geometries[0]:C.mergeGeometries(t.geometries,!0),r.groups.length>1&&C.mergeGroups(r),e.add(new i(r,t.material))}}e.traverse(e=>{if(e instanceof i&&e.geometry instanceof t&&!_(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&C.mergeGroups(t)}})}extractGeometryGroups(e,r){const a=e.index;if(!a){const a=new t;let s=0;for(const e of r)s+=e.count;if(0===s)return a;for(const t in e.attributes){const i=e.attributes[t],n=i.itemSize,o=i.array,l=new(0,o.constructor)(s*n);let c=0;for(const e of r){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new L.BufferAttribute(l,n,i.normalized);a.setAttribute(t,h)}return a.groups=[{start:0,count:s,materialIndex:0}],a}const s=[];for(const e of r)for(let t=0;t<e.count;t++){const r=a.getX(e.start+t);s.push(r)}if(0===s.length)return new t;const i=new Map,n=[];let o=0;for(const e of s)i.has(e)||(i.set(e,o),o++),n.push(i.get(e));if(0===n.length||0===i.size)return new t;const l=new t;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,s=r.array,n=new(0,s.constructor)(i.size*a);for(const[e,t]of i)for(let r=0;r<a;r++)n[t*a+r]=s[e*a+r];const o=new L.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new L.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(e=>({scene:e.scene,animations:e.animations}));case"fbx":return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new h;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>($(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>F(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const G=new Map;function z(e){G.set(e,(G.get(e)??0)+1)}function $(e){if(e instanceof i)for(const t of S(e.material))t instanceof L.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach($)}export class AssetMeshInstance extends n{}export function createAuthoredCollisionShapes(e,t=1){const a=null!=t&&0!==t?1/t:1;return e.map(e=>{let t;switch(e.type){case"box":t=new g((new c).fromArray(e.size).multiplyScalar(a));break;case"sphere":t=new A(e.radius*a);break;case"capsule":t=new w(e.length*a,e.radius*a);break;case"cylinder":t=new M(e.radius*a,e.radius*a,e.height*a,16,new r)}return t.source=x.custom,t.offset.fromArray(e.position??[0,0,0]).multiplyScalar(a),t.rotation.fromArray(e.rotation??[0,0,0,"XYZ"]),t})}export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function Y(e){switch(e){case"clamp":return L.ClampToEdgeWrapping;case"repeat":return L.RepeatWrapping;case"mirror":return L.MirroredRepeatWrapping}return L.RepeatWrapping}function O(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function N(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(X.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function V(e){return"linear"===e?L.LinearSRGBColorSpace:L.SRGBColorSpace}const X=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new L.Matrix4;const q=[];const J=/_LOD(\d+)/;function Z(e){let t=e instanceof L.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof L.MeshLambertMaterial||e instanceof L.MeshPhongMaterial||e instanceof L.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new L.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return 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 { SceneObjectPhysicsSettings } from "../../scene/materializer.js";
|
|
1
|
+
import type { SceneObjectPhysicsSettings } from "../../scene/materializer.js";
|
|
2
2
|
import { BufferGeometry, Euler, Material, Mesh, Vector3 } from "three";
|
|
3
3
|
export declare enum CollisionShapeSource {
|
|
4
4
|
/**
|