@hology/core 0.0.42 → 0.0.43
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/effects/vfx/vfx-defs.d.ts +2 -2
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/index.d.ts +2 -0
- package/dist/gameplay/actors/builtin/index.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.d.ts +18 -0
- package/dist/gameplay/actors/builtin/navmesh-actor.js +5 -0
- package/dist/gameplay/ai/build-tile.d.ts +50 -0
- package/dist/gameplay/ai/build-tile.js +5 -0
- package/dist/gameplay/ai/dynamic-tiled-navmesh.d.ts +31 -0
- package/dist/gameplay/ai/dynamic-tiled-navmesh.js +5 -0
- package/dist/gameplay/ai/dynamic-tiled-navmesh.worker.d.ts +1 -0
- package/dist/gameplay/ai/dynamic-tiled-navmesh.worker.js +5 -0
- package/dist/gameplay/ai/index.d.ts +1 -0
- package/dist/gameplay/ai/index.js +5 -0
- package/dist/gameplay/ai/navigation.d.ts +19 -0
- package/dist/gameplay/ai/navigation.js +5 -0
- package/dist/gameplay/index.d.ts +1 -0
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +1 -0
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/scene/landscape/landscape-manager.js +1 -1
- package/dist/scene/materializer.d.ts +1 -0
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/objects/shapes.d.ts +1 -1
- package/package.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
@@ -203,8 +203,8 @@ declare const vfxBehaviours: {
|
|
203
203
|
};
|
204
204
|
export type LibraryVfxInitalizerType = keyof typeof vfxInitializsers;
|
205
205
|
export declare const VfxInitializserLibrary: Record<LibraryVfxInitalizerType, InitializerDefinition>;
|
206
|
-
export declare const VfxInitializserLibraryKeys: ("rotation" | "
|
206
|
+
export declare const VfxInitializserLibraryKeys: ("rotation" | "mass" | "scale" | "velocity" | "lifetime" | "positionPoint" | "positionBox" | "positionSphere" | "positionLine" | "randomDirection")[];
|
207
207
|
export type LibraryVfxBehaviourType = keyof typeof vfxBehaviours;
|
208
208
|
export declare const VfxBehaviourLibrary: Record<LibraryVfxBehaviourType, BehaviourDefinition>;
|
209
|
-
export declare const VfxBehaviourLibraryKeys: ("scale" | "
|
209
|
+
export declare const VfxBehaviourLibraryKeys: ("scale" | "force" | "gravity" | "randomDrift" | "rotate" | "changeColor" | "changeOpacity" | "vortex" | "moveTo" | "linearDamping")[];
|
210
210
|
export {};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{__decorate as t,__metadata as i}from"tslib";import{ActionInput as e,AxisInput as o,RotationInput as s}from"../../../../../gameplay/input/index.js";import{PhysicsSystem as n,RayTestResult as r}from"../../../../../gameplay/services/physics/physics-system.js";import{MathUtils as c,Vector3 as a}from"three";import{ActorComponent as l,Component as h}from"../../../component.js";import{CharacterMovementMode as p}from"./modes.js";import{CapsuleCollisionShape as m}from"../../../../../scene/collision/collision-shape.js";import{takeUntil as d}from"rxjs";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import{RootMotionClip as u}from"../../../../../gameplay/animation/root-motion.js";const g=new a,f=new a,S=1/30;let v=class extends l{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}constructor(t){super(),this.physicsSystem=t,this.directionInput=new o,this.jumpInput=new e,this.sprintInput=new e,this.rotationInput=new s,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=c.degToRad(70),this.maxSlopeClimbAngle=c.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.velocity=new a,this.mode=p.walking,this.isSprinting=!1,this.pressedJump=!1,this.rayTestResult=new r,this.resetRootMotion=!1;const i=this.cc=this.physicsSystem.getCharacterController(.1);i.enableSnapToGround(.1),i.enableAutostep(0,.1,!1)}onInit(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:y.kinematic,continousCollisionDetection:!0,friction:1}),this.rotationInput.rotation.copy(this.actor.rotation);let i=this.rotationInput.rotation.y;const e=new a,o=new a,s=new a,n=new a,r=new a,l=new a;let h=0,m=null;const v=new a,M=new a,x=new a,I=new a;this.physicsSystem.beforeStep.pipe(d(this.disposed)).subscribe((d=>{if(this.checkGrounded(d),null!=this.rootMotionAction){if(this.rootMotionAction.getClip()instanceof u){const t=this.rootMotionInterpolant;this.resetRootMotion&&(v.fromArray(t.evaluate(0)),this.resetRootMotion=!1),I.fromArray(t.evaluate(this.rootMotionAction.time)),M.subVectors(I,v),v.copy(I),this.rootMotionAction.getRoot().getWorldScale(x),M.multiply(x)}}d>S&&(d=S);const y=null!=this.rootMotionAction&&this.rootMotionAction.enabled&&0!=M.length();this.pressedJump=this.jumpInput.activated,this.isSprinting=this.sprintInput.activated&&this.directionInput.vertical>=0;let T=i-this.rotationInput.rotation.y;i=this.rotationInput.rotation.y,s.copy(this.actor.position),n.set(-this.directionInput.vector.x,0,this.directionInput.vector.y).normalize();const b=n.z<0?this.maxSpeedBackwards:this.isSprinting?this.maxSpeedSprint:this.maxSpeed;l.copy(n).applyAxisAngle(w,this.rotationInput.rotation.y),this.mode===p.walking?(0!==l.length()?(h=Math.min(b,h),h=c.lerp(h,b,4*d)):h=0,r.copy(l).multiplyScalar(h),this.pressedJump&&(this.mode=p.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),r.y=d*this.getEffectiveGravity()):this.mode===p.falling&&(this.pressedJump&&this.jumpInAir&&(this.mode=p.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),this.velocity.y+=d*this.getEffectiveGravity(),r.copy(this.velocity),r.add(l.clone().multiplyScalar(b*this.fallingMovementControl*d)),this.fallingReorientation&&r.applyAxisAngle(new a(0,1,0),-T)),o.copy(r).normalize(),e.copy(r),this.actor.rotation.y-=T,r.length(),y?(M.applyAxisAngle(w,this.actor.rotation.y),M.y+=d*this.getEffectiveGravity(),g.copy(M)):g.copy(r).multiplyScalar(d),this.isGrounded&&this.mode===p.walking&&(g.y=0),f.copy(this.physicsSystem.getActorComputedMovement(this.actor,t,g)),this.physicsSystem.setNextKinematicTranslation(this.actor,f);let j=function(t){if(t.numComputedCollisions()>0){const i=t.computedCollision(0);A.x=i.normal2.x,A.y=i.normal2.y,A.z=i.normal2.z;const e=A.angleTo(w);A.x=i.normal1.x,A.y=i.normal1.y,A.z=i.normal1.z;const o=A.angleTo(w);return!(e<100)&&o>t.minSlopeSlideAngle()}return!1}(t);y||this.isGrounded&&!j||this.mode!==p.falling&&(null==m?m=performance.now():performance.now()-m>100&&(this.mode=p.falling,this.velocity.copy(e))),this.isGrounded&&this.velocity.y<=0&&(this.mode,p.falling,this.mode=p.walking,this.velocity.y=0,m=null),this.mode,p.walking,this.horizontalSpeed=h}))}setRootMotionAction(t){const i=t?.getClip();if(i instanceof u){this.rootMotionAction=t,this.resetRootMotion=!0;const e=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(e)}}getWallDirection(t,i){const e=t.clone().negate().cross(w);return e.dot(i)<0?e.negate():e}moveTo(t){this.actor.position.copy(t),this.physicsSystem.updateActorTransform(this.actor)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}checkGrounded(t){const i=this.colliderHeight+2*this.colliderRadius;this.physicsSystem.rayTest(M.addVectors(this.actor.position,I.set(0,i/4,0)),x.addVectors(this.actor.position,T),this.rayTestResult,{excludeActor:this.actor})}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}createCollisionShape(){const t=new m(this.colliderHeight,this.colliderRadius);return t.offset.y=this.colliderRadius+this.colliderHeight/2,t}step(t){}performMovement(t){}};v=t([h({inEditor:!1}),i("design:paramtypes",[n])],v);export{v as CharacterMovementComponent};const w=new a(0,1,0),A=new a;const M=new a,x=new a,I=new a(0,1,0),T=new a(0,-.1,0);
|
1
|
+
import{__decorate as t,__metadata as i}from"tslib";import{ActionInput as e,AxisInput as o,RotationInput as s}from"../../../../../gameplay/input/index.js";import{PhysicsSystem as n,RayTestResult as r}from"../../../../../gameplay/services/physics/physics-system.js";import{MathUtils as c,Vector3 as a}from"three";import{ActorComponent as l,Component as h}from"../../../component.js";import{CharacterMovementMode as p}from"./modes.js";import{CapsuleCollisionShape as m}from"../../../../../scene/collision/collision-shape.js";import{takeUntil as d}from"rxjs";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import{RootMotionClip as u}from"../../../../../gameplay/animation/root-motion.js";const g=new a,f=new a,S=1/30;let v=class extends l{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}constructor(t){super(),this.physicsSystem=t,this.directionInput=new o,this.jumpInput=new e,this.sprintInput=new e,this.rotationInput=new s,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=c.degToRad(70),this.maxSlopeClimbAngle=c.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.velocity=new a,this.mode=p.walking,this.isSprinting=!1,this.pressedJump=!1,this.rayTestResult=new r,this.resetRootMotion=!1;const i=this.cc=this.physicsSystem.getCharacterController(.1);i.enableSnapToGround(.1),i.enableAutostep(0,.1,!1)}onInit(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:y.kinematic,continousCollisionDetection:!0,friction:1,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation);let i=this.rotationInput.rotation.y;const e=new a,o=new a,s=new a,n=new a,r=new a,l=new a;let h=0,m=null;const v=new a,M=new a,x=new a,I=new a;this.physicsSystem.beforeStep.pipe(d(this.disposed)).subscribe((d=>{if(this.checkGrounded(d),null!=this.rootMotionAction){if(this.rootMotionAction.getClip()instanceof u){const t=this.rootMotionInterpolant;this.resetRootMotion&&(v.fromArray(t.evaluate(0)),this.resetRootMotion=!1),I.fromArray(t.evaluate(this.rootMotionAction.time)),M.subVectors(I,v),v.copy(I),this.rootMotionAction.getRoot().getWorldScale(x),M.multiply(x)}}d>S&&(d=S);const y=null!=this.rootMotionAction&&this.rootMotionAction.enabled&&0!=M.length();this.pressedJump=this.jumpInput.activated,this.isSprinting=this.sprintInput.activated&&this.directionInput.vertical>=0;let T=i-this.rotationInput.rotation.y;i=this.rotationInput.rotation.y,s.copy(this.actor.position),n.set(-this.directionInput.vector.x,0,this.directionInput.vector.y).normalize();const b=n.z<0?this.maxSpeedBackwards:this.isSprinting?this.maxSpeedSprint:this.maxSpeed;l.copy(n).applyAxisAngle(w,this.rotationInput.rotation.y),this.mode===p.walking?(0!==l.length()?(h=Math.min(b,h),h=c.lerp(h,b,4*d)):h=0,r.copy(l).multiplyScalar(h),this.pressedJump&&(this.mode=p.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),r.y=d*this.getEffectiveGravity()):this.mode===p.falling&&(this.pressedJump&&this.jumpInAir&&(this.mode=p.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),this.velocity.y+=d*this.getEffectiveGravity(),r.copy(this.velocity),r.add(l.clone().multiplyScalar(b*this.fallingMovementControl*d)),this.fallingReorientation&&r.applyAxisAngle(new a(0,1,0),-T)),o.copy(r).normalize(),e.copy(r),this.actor.rotation.y-=T,r.length(),y?(M.applyAxisAngle(w,this.actor.rotation.y),M.y+=d*this.getEffectiveGravity(),g.copy(M)):g.copy(r).multiplyScalar(d),this.isGrounded&&this.mode===p.walking&&(g.y=0),f.copy(this.physicsSystem.getActorComputedMovement(this.actor,t,g)),this.physicsSystem.setNextKinematicTranslation(this.actor,f);let j=function(t){if(t.numComputedCollisions()>0){const i=t.computedCollision(0);A.x=i.normal2.x,A.y=i.normal2.y,A.z=i.normal2.z;const e=A.angleTo(w);A.x=i.normal1.x,A.y=i.normal1.y,A.z=i.normal1.z;const o=A.angleTo(w);return!(e<100)&&o>t.minSlopeSlideAngle()}return!1}(t);y||this.isGrounded&&!j||this.mode!==p.falling&&(null==m?m=performance.now():performance.now()-m>100&&(this.mode=p.falling,this.velocity.copy(e))),this.isGrounded&&this.velocity.y<=0&&(this.mode,p.falling,this.mode=p.walking,this.velocity.y=0,m=null),this.mode,p.walking,this.horizontalSpeed=h}))}setRootMotionAction(t){const i=t?.getClip();if(i instanceof u){this.rootMotionAction=t,this.resetRootMotion=!0;const e=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(e)}}getWallDirection(t,i){const e=t.clone().negate().cross(w);return e.dot(i)<0?e.negate():e}moveTo(t){this.actor.position.copy(t),this.physicsSystem.updateActorTransform(this.actor)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}checkGrounded(t){const i=this.colliderHeight+2*this.colliderRadius;this.physicsSystem.rayTest(M.addVectors(this.actor.position,I.set(0,i/4,0)),x.addVectors(this.actor.position,T),this.rayTestResult,{excludeActor:this.actor})}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}createCollisionShape(){const t=new m(this.colliderHeight,this.colliderRadius);return t.offset.y=this.colliderRadius+this.colliderHeight/2,t}step(t){}performMovement(t){}};v=t([h({inEditor:!1}),i("design:paramtypes",[n])],v);export{v as CharacterMovementComponent};const w=new a(0,1,0),A=new a;const M=new a,x=new a,I=new a(0,1,0),T=new a(0,-.1,0);
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { CameraActor } from './camera-actor.js';
|
2
|
+
import NavMeshActor from './navmesh-actor.js';
|
2
3
|
import { PositionalAudioActor } from './positional-audio-actor.js';
|
3
4
|
import { SpawnPoint } from './spawn-point.js';
|
4
5
|
import { TriggerVolume } from './trigger-volume.js';
|
@@ -7,5 +8,6 @@ declare const _default: {
|
|
7
8
|
SpawnPoint: typeof SpawnPoint;
|
8
9
|
TriggerVolume: typeof TriggerVolume;
|
9
10
|
PositionalAudio: typeof PositionalAudioActor;
|
11
|
+
NavMesh: typeof NavMeshActor;
|
10
12
|
};
|
11
13
|
export default _default;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{CameraActor as o}from"./camera-actor.js";import{PositionalAudioActor as
|
1
|
+
import{CameraActor as o}from"./camera-actor.js";import r from"./navmesh-actor.js";import{PositionalAudioActor as a}from"./positional-audio-actor.js";import{SpawnPoint as i}from"./spawn-point.js";import{TriggerVolume as m}from"./trigger-volume.js";export default{Camera:o,SpawnPoint:i,TriggerVolume:m,PositionalAudio:a,NavMesh:r};
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { BaseActor } from "../../";
|
2
|
+
import { NavMesh } from 'recast-navigation';
|
3
|
+
declare class NavMeshActor extends BaseActor {
|
4
|
+
private physics;
|
5
|
+
private view;
|
6
|
+
debug: boolean;
|
7
|
+
refreshMs: number;
|
8
|
+
tileSize: number;
|
9
|
+
cellSize: number;
|
10
|
+
walkableClimb: number;
|
11
|
+
walkableSlopeAngle: number;
|
12
|
+
walkableRadius: number;
|
13
|
+
walkableHeight: number;
|
14
|
+
navMesh: NavMesh;
|
15
|
+
onInit(): Promise<void>;
|
16
|
+
private init;
|
17
|
+
}
|
18
|
+
export default NavMeshActor;
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Ball as o,Capsule as i,Cone as n,ConvexPolyhedron as s,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as h,TriMesh as c}from"@dimforge/rapier3d-compat";import{Actor as p,BaseActor as d,Parameter as u,PhysicsSystem as w,ViewController as f,inject as m}from"../../";import{init as g}from"@recast-navigation/core";import{DebugDrawer as b,getPositionsAndIndices as y}from"recast-navigation/three";import*as v from"three";import{DynamicTiledNavMesh as x}from"../../ai/dynamic-tiled-navmesh";const M=new v.Box3(new v.Vector3(-5e3,-1e3,-5e4),new v.Vector3(7e4,3e4,4e4)),S=navigator.hardwareConcurrency??3;let B=class extends d{constructor(){super(...arguments),this.physics=m(w),this.view=m(f),this.debug=!0,this.refreshMs=1e3,this.tileSize=100,this.cellSize=.2,this.walkableClimb=1,this.walkableSlopeAngle=45,this.walkableRadius=.5,this.walkableHeight=1}async onInit(){await g(),this.init()}init(){const e={tileSize:this.tileSize,walkableClimb:this.walkableClimb,walkableSlopeAngle:this.walkableSlopeAngle,walkableRadius:this.walkableRadius,walkableHeight:this.walkableHeight,detailSampleDist:6,minRegionArea:8,mergeRegionArea:100,cs:this.cellSize,ch:this.cellSize},t=new x({navMeshBounds:M,recastConfig:e,maxTiles:1024,workers:S});this.navMesh=t.navMesh,this.object.position.set(0,0,0);const o=this.tileSize+10,i=performance.now(),n=new Map,s=new b,r=()=>{const e=this.view.getCamera().getWorldPosition(new v.Vector3),t=new v.Box3((new v.Vector3).copy(e).subScalar(o),(new v.Vector3).copy(e).addScalar(o)),i=[],s=this.physics.world.bodies,r=new v.Box3;for(const e of s.getAll())for(let o=0,s=e.numColliders();o<s;o++){const s=e.collider(o);if(s.isSensor()||null!=s.parent().userData&&!0===s.parent().userData.ignoreForNavMesh)continue;const a=n.get(s)?.mesh,l=a??z(s);if(C(s,l),null!=l){r.copy(l.geometry.boundingBox),r.min.add(l.position),r.max.add(l.position);const e=r.intersectsBox(t);n.set(s,{pos:s.translation(),mesh:l}),e&&i.push(l)}}return i},a=new v.Box3,l=new Map,h=new Map,c=setInterval((()=>{const e=new v.Box3,o=r();for(const t of o){const o=l.get(t);!0!==o?.equals(t.position)&&(null!=o&&e.expandByPoint(o),e.expandByObject(t),l.set(t,t.position.clone()))}const i=t.getTilesForBounds(e);if(0!=i.length){const n=[];for(const t of o)a.setFromObject(t),a.intersect(e)&&n.push(t);const[r,l]=y(n);Promise.all(i.map((e=>t.buildTile(r,l,e).then((()=>{const t=e[0]+","+e[1];h.set(t,(h.get(t)??0)+1)}))))).then((()=>{this.debug&&(s.clear(),s.drawNavMesh(t.navMesh))}))}}),this.refreshMs??1e4);this.disposed.subscribe((()=>clearInterval(c)));const p=t.navMesh;console.log("create with debug",this.debug),this.debug&&(s.clear(),s.drawNavMesh(p));const d=()=>{s.resize(window.innerWidth,window.innerHeight)};d(),window.addEventListener("resize",d),this.debug&&this.object.parent.add(s),this.disposed.subscribe((()=>{p?.destroy(),s.removeFromParent(),s.dispose(),window.removeEventListener("resize",d)}));const u=performance.now()-i;u>1e3&&console.warn(`NavMesh update took ${u} ms. Consider changing tileSize or other parameter that may affect performance`)}};e([u(),t("design:type",Boolean)],B.prototype,"debug",void 0),e([u(),t("design:type",Number)],B.prototype,"refreshMs",void 0),e([u(),t("design:type",Number)],B.prototype,"tileSize",void 0),e([u(),t("design:type",Number)],B.prototype,"cellSize",void 0),e([u(),t("design:type",Number)],B.prototype,"walkableClimb",void 0),e([u({range:[0,89]}),t("design:type",Number)],B.prototype,"walkableSlopeAngle",void 0),e([u(),t("design:type",Number)],B.prototype,"walkableRadius",void 0),e([u(),t("design:type",Number)],B.prototype,"walkableHeight",void 0),B=e([p()],B);export default B;function k(e){if(e.shape instanceof l)return function(e){const t=e.shape;if(t.type!==h.HeightField)throw new Error("The provided collider is not a height field.");let o=!1;const i=t,n=i.heights,s=i.nrows,r=i.ncols,a=i.scale.x,l=i.scale.z,c=i.scale.y,p=s+1,d=new v.PlaneGeometry(l,a,r,s);d.rotateX(-Math.PI/2);const u=d.attributes.position.array;let w=0;for(let e=0;e<p;e++)for(let t=0;t<p;t++)u[w+1]=n[t*p+e]*c,w+=3,0!=u[w+1]&&(o=!0);if(!o){const e=new v.PlaneGeometry(a,l,2,2);return e.rotateX(-Math.PI/2),e}return d}(e);if(e.shape instanceof o)return new v.SphereGeometry(e.shape.radius);if(e.shape instanceof r){const t=e.shape.halfExtents;return new v.BoxGeometry(2*t.x,2*t.y,2*t.z)}if(e.shape instanceof s||e.shape instanceof c){const t=e.shape.vertices,o=e.shape.indices,i=new v.BufferGeometry;return i.setAttribute("position",new v.Float32BufferAttribute(t,3)),null!=o&&i.setIndex(new v.Uint16BufferAttribute(o,1)),i}if(e.shape instanceof a){const t=e.shape.halfHeight,o=e.shape.radius;return new v.CylinderGeometry(o,o,2*t)}if(e.shape instanceof n){const t=e.shape.halfHeight,o=e.shape.radius;return new v.ConeGeometry(o,2*t)}if(e.shape instanceof i){const t=e.shape.halfHeight,o=e.shape.radius;return new v.CapsuleGeometry(o,2*t)}return console.warn("Unsupported shape",e.shape.type,e),null}function z(e){const t=k(e);if(null==t)return null;const o=new v.MeshBasicMaterial({wireframe:!1,color:16711680,side:v.DoubleSide}),i=new v.Mesh(t,o);return i.geometry.computeBoundingBox(),i}function C(e,t){const o=e.translation(),i=e.rotation();t.position.set(o.x,o.y,o.z),t.quaternion.set(i.x,i.y,i.z,i.w)}
|
2
|
+
/*
|
3
|
+
* Copyright (©) 2023. All rights reserved.
|
4
|
+
* See the LICENSE.md file for details.
|
5
|
+
*/
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { RecastBuildContext, RecastCompactHeightfield, RecastConfig, RecastContourSet, RecastHeightfield, UnsignedCharArray, Vector3Tuple } from '@recast-navigation/core';
|
2
|
+
type BuildConfigProps = {
|
3
|
+
recastConfig: RecastConfig;
|
4
|
+
navMeshBounds: [min: Vector3Tuple, max: Vector3Tuple];
|
5
|
+
};
|
6
|
+
export declare const buildConfig: ({ recastConfig, navMeshBounds: [navMeshBoundsMin, navMeshBoundsMax] }: BuildConfigProps) => {
|
7
|
+
config: import("@recast-navigation/wasm").default.rcConfig;
|
8
|
+
orig: {
|
9
|
+
x: number;
|
10
|
+
y: number;
|
11
|
+
z: number;
|
12
|
+
};
|
13
|
+
tileBits: number;
|
14
|
+
polyBits: number;
|
15
|
+
maxTiles: number;
|
16
|
+
maxPolysPerTile: number;
|
17
|
+
tcs: number;
|
18
|
+
tileWidth: number;
|
19
|
+
tileHeight: number;
|
20
|
+
};
|
21
|
+
export type TileIntermediates = {
|
22
|
+
tileX: number;
|
23
|
+
tileY: number;
|
24
|
+
heightfield?: RecastHeightfield;
|
25
|
+
compactHeightfield?: RecastCompactHeightfield;
|
26
|
+
contourSet?: RecastContourSet;
|
27
|
+
};
|
28
|
+
export type BuildTileMeshProps = {
|
29
|
+
positions: Float32Array;
|
30
|
+
indices: Uint32Array;
|
31
|
+
recastConfig: RecastConfig;
|
32
|
+
tileX: number;
|
33
|
+
tileY: number;
|
34
|
+
tileBoundsMin: Vector3Tuple;
|
35
|
+
tileBoundsMax: Vector3Tuple;
|
36
|
+
navMeshBounds: [Vector3Tuple, Vector3Tuple];
|
37
|
+
keepIntermediates: boolean;
|
38
|
+
};
|
39
|
+
export type BuildTileMeshResult = ({
|
40
|
+
success: true;
|
41
|
+
data?: UnsignedCharArray;
|
42
|
+
} | {
|
43
|
+
success: false;
|
44
|
+
error: string;
|
45
|
+
}) & {
|
46
|
+
tileIntermediates?: TileIntermediates;
|
47
|
+
buildContext: RecastBuildContext;
|
48
|
+
};
|
49
|
+
export declare const buildTile: ({ positions, indices, navMeshBounds, recastConfig, tileX, tileY, tileBoundsMin, tileBoundsMax, keepIntermediates, }: BuildTileMeshProps) => BuildTileMeshResult;
|
50
|
+
export {};
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import{NavMeshCreateParams as e,Raw as t,RecastBuildContext as i,TriangleAreasArray as l,TrianglesArray as o,VerticesArray as r,allocCompactHeightfield as a,allocContourSet as s,allocHeightfield as n,allocPolyMesh as d,allocPolyMeshDetail as c,buildCompactHeightfield as h,buildContours as g,buildDistanceField as m,buildPolyMesh as u,buildPolyMeshDetail as b,buildRegions as f,calcGridSize as S,cloneRcConfig as R,createHeightfield as w,createNavMeshData as p,createRcConfig as C,erodeWalkableArea as M,filterLedgeSpans as _,filterLowHangingWalkableObstacles as x,filterWalkableLowHeightSpans as A,freeCompactHeightfield as k,freeContourSet as y,freeHeightfield as z,markWalkableTriangles as E,rasterizeTriangles as v,vec3 as T}from"@recast-navigation/core";import{dtIlog2 as B,dtNextPow2 as O}from"@recast-navigation/generators";import*as P from"three";export const buildConfig=({recastConfig:e,navMeshBounds:[t,i]})=>{const l=C(e),o=S(t,i,l.cs);l.width=o.width,l.height=o.height,l.minRegionArea=l.minRegionArea*l.minRegionArea,l.mergeRegionArea=l.mergeRegionArea*l.mergeRegionArea,l.tileSize=Math.floor(l.tileSize),l.borderSize=l.walkableRadius+3,l.width=l.tileSize+2*l.borderSize,l.height=l.tileSize+2*l.borderSize,l.detailSampleDist=l.detailSampleDist<.9?0:l.cs*l.detailSampleDist,l.detailSampleMaxError=l.ch*l.detailSampleMaxError;const r=Math.floor(l.tileSize),a=Math.floor((o.width+r-1)/r),s=Math.floor((o.height+r-1)/r),n=l.tileSize*l.cs,d=T.fromArray(t);let c=Math.min(Math.floor(B(O(a*s))),14);c>14&&(c=14);const h=22-c;return{config:l,orig:d,tileBits:c,polyBits:h,maxTiles:1<<c,maxPolysPerTile:1<<h,tcs:n,tileWidth:a,tileHeight:s}};export const buildTile=({positions:S,indices:C,navMeshBounds:T,recastConfig:B,tileX:O,tileY:H,tileBoundsMin:L,tileBoundsMax:G,keepIntermediates:D})=>{const $=new i,F=S,V=C.length,W=new r;W.copy(F);const I=C,K=C.length/3;(new o).copy(I);const X={tileX:O,tileY:H},Y=()=>{D||(X.compactHeightfield&&k(X.compactHeightfield),X.heightfield&&z(X.heightfield),X.contourSet&&y(X.contourSet))},N=e=>($.log(t.Module.RC_LOG_ERROR,e),Y(),{success:!1,error:e,tileIntermediates:X,buildContext:$}),{config:U}=buildConfig({recastConfig:B,navMeshBounds:T}),j=R(U),q=[...L],J=[...G];q[0]-=j.borderSize*j.cs,q[2]-=j.borderSize*j.cs,J[0]+=j.borderSize*j.cs,J[2]+=j.borderSize*j.cs,j.set_bmin(0,q[0]),j.set_bmin(1,q[1]),j.set_bmin(2,q[2]),j.set_bmax(0,J[0]),j.set_bmax(1,J[1]),j.set_bmax(2,J[2]),$.resetTimers(),$.startTimer(t.Module.RC_TIMER_TOTAL),$.log(t.Module.RC_LOG_PROGRESS,`Building tile at x: ${O}, y: ${H}`),$.log(t.Module.RC_LOG_PROGRESS,` - ${U.width} x ${U.height} cells`),$.log(t.Module.RC_LOG_PROGRESS,` - ${V/1e3}fK verts, ${K/1e3}K tris`);const Q=n();if(X.heightfield=Q,!w($,Q,j.width,j.height,q,J,j.cs,j.ch))return N("Could not create heightfield");const Z=((e,t,i)=>{const l=[],o=new P.Vector3,r=new P.Vector3,a=new P.Vector3,s=new P.Triangle;for(let n=0;n<t.length;n+=3){const d=t[n],c=t[n+1],h=t[n+2];o.fromArray(e,3*d),r.fromArray(e,3*c),a.fromArray(e,3*h),s.set(o,r,a),s.intersectsBox(i)&&l.push(d,c,h)}return l})(S,C,new P.Box3(new P.Vector3(q[0],q[1],q[2]),new P.Vector3(J[0],J[1],J[2]))),ee=Z.length/3,te=new o;te.copy(Z);const ie=new l;ie.resize(ee),E($,j.walkableSlopeAngle,W,V,te,ee,ie);const le=v($,W,V,te,ie,ee,Q,j.walkableClimb);if(ie.destroy(),!le)return N("Could not rasterize triangles");x($,j.walkableClimb,Q),_($,j.walkableHeight,j.walkableClimb,Q),A($,j.walkableHeight,Q);const oe=a();if(X.compactHeightfield=oe,!h($,j.walkableHeight,j.walkableClimb,Q,oe))return N("Could not build compact heightfield");if(D||(z(X.heightfield),X.heightfield=void 0),!M($,j.walkableRadius,oe))return N("Could not erode walkable area");if(!m($,oe))return N("Failed to build distance field");if(!f($,oe,j.borderSize,j.minRegionArea,j.mergeRegionArea))return N("Failed to build regions");const re=s();if(X.contourSet=re,!g($,oe,j.maxSimplificationError,j.maxEdgeLen,re,t.Module.RC_CONTOUR_TESS_WALL_EDGES))return N("Failed to create contours");const ae=d();if(!u($,re,j.maxVertsPerPoly,ae))return N("Failed to triangulate contours");const se=c();if(!b($,ae,oe,j.detailSampleDist,j.detailSampleMaxError,se))return N("Failed to build detail mesh");D||(k(oe),X.compactHeightfield=void 0,y(re),X.contourSet=void 0);for(let e=0;e<ae.npolys();e++)ae.areas(e)==t.Recast.WALKABLE_AREA&&ae.setAreas(e,0),0==ae.areas(e)&&ae.setFlags(e,1);const ne=new e;ne.setPolyMeshCreateParams(ae),ne.setPolyMeshDetailCreateParams(se),ne.setWalkableHeight(j.walkableHeight),ne.setWalkableRadius(j.walkableRadius),ne.setWalkableClimb(j.walkableClimb),ne.setCellSize(j.cs),ne.setCellHeight(j.ch),ne.setBuildBvTree(!0),ne.setTileX(O),ne.setTileY(H);const de=p(ne);return de.success?($.log(t.Module.RC_LOG_PROGRESS,`>> Polymesh: ${ae.nverts()} vertices ${ae.npolys()} polygons`),Y(),{success:!0,data:de.navMeshData,tileIntermediates:X,buildContext:$}):N("Failed to create Detour navmesh data")};
|
2
|
+
/*
|
3
|
+
* Copyright (©) 2023. All rights reserved.
|
4
|
+
* See the LICENSE.md file for details.
|
5
|
+
*/
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { NavMesh, RecastConfig, Vector3Tuple } from 'recast-navigation';
|
2
|
+
import * as THREE from 'three';
|
3
|
+
import { Subject } from 'rxjs';
|
4
|
+
export type DynamicTiledNavMeshProps = {
|
5
|
+
navMeshBounds: THREE.Box3;
|
6
|
+
recastConfig: Partial<RecastConfig>;
|
7
|
+
maxTiles: number;
|
8
|
+
workers: number;
|
9
|
+
};
|
10
|
+
export declare class DynamicTiledNavMesh {
|
11
|
+
navMesh: NavMesh;
|
12
|
+
navMeshVersion: number;
|
13
|
+
onNavMeshUpdate: Subject<[version: number, tile: [x: number, y: number]]>;
|
14
|
+
navMeshBounds: [min: Vector3Tuple, max: Vector3Tuple];
|
15
|
+
navMeshBoundsMin: THREE.Vector3;
|
16
|
+
navMeshBoundsMax: THREE.Vector3;
|
17
|
+
navMeshOrigin: THREE.Vector3;
|
18
|
+
tileWidth: number;
|
19
|
+
tileHeight: number;
|
20
|
+
tcs: number;
|
21
|
+
recastConfig: RecastConfig;
|
22
|
+
workers: InstanceType<any>[];
|
23
|
+
workerRoundRobin: number;
|
24
|
+
constructor(props: DynamicTiledNavMeshProps);
|
25
|
+
private onResult;
|
26
|
+
buildTile(positions: Float32Array, indices: Uint32Array, [tileX, tileY]: [x: number, y: number]): Promise<unknown>;
|
27
|
+
buildAllTiles(positions: Float32Array, indices: Uint32Array): void;
|
28
|
+
getTileForWorldPosition(worldPosition: THREE.Vector3): [x: number, y: number];
|
29
|
+
getTilesForBounds(bounds: THREE.Box3): [x: number, y: number][];
|
30
|
+
destroy(): void;
|
31
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import{NavMesh as s,NavMeshParams as t,Raw as e,UnsignedCharArray as i,recastConfigDefaults as n,statusToReadableString as o}from"recast-navigation";import{buildConfig as a,buildTile as h}from"./build-tile.js";import{Subject as r}from"rxjs";export class DynamicTiledNavMesh{constructor(e){this.navMeshVersion=0,this.onNavMeshUpdate=new r,this.workerRoundRobin=0;const i=e.navMeshBounds.min,o=e.navMeshBounds.max,h=[i.toArray(),o.toArray()],l=e.navMeshBounds.min;this.navMeshBoundsMin=i,this.navMeshBoundsMax=o,this.navMeshBounds=h,this.navMeshOrigin=l;const d={...n,...e.recastConfig};this.recastConfig=d;const M=new s,{tileWidth:u,tileHeight:c,tcs:v,maxPolysPerTile:m}=a({recastConfig:d,navMeshBounds:h});this.tileWidth=u,this.tileHeight=c,this.tcs=v;const B=t.create({orig:l,tileWidth:d.tileSize*d.cs,tileHeight:d.tileSize*d.cs,maxTiles:e.maxTiles,maxPolys:m});M.initTiled(B),this.navMesh=M,this.workers=[]}onResult(s){const{tileX:t,tileY:n,navMeshData:a}=s.data,h=new i;h.copy(a),this.navMesh.removeTile(this.navMesh.getTileRefAt(t,n,0));const r=this.navMesh.addTile(h,e.Module.DT_TILE_FREE_DATA,0);e.Detour.statusFailed(r.status)&&(console.error(e.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${t}, ty: ${n},status: ${o(r.status)} (${r.status})`),h.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[t,n]])}buildTile(s,t,[e,i]){const n=new Float32Array(s),o=new Uint32Array(t),a={tileX:e,tileY:i,tileBoundsMin:[this.navMeshBoundsMin.x+e*this.tcs,this.navMeshBoundsMin.y,this.navMeshBoundsMin.z+i*this.tcs],tileBoundsMax:[this.navMeshBoundsMax.x+(e+1)*this.tcs,this.navMeshBoundsMax.y,this.navMeshBoundsMax.z+(i+1)*this.tcs],recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:n,indices:o};return this.workerRoundRobin=(this.workerRoundRobin+1)%this.workers.length,new Promise((s=>{requestIdleCallback((()=>{const t=h(a);if(!t.success||!t.data)return;const e=t.data.toTypedArray();this.onResult({data:{tileX:a.tileX,tileY:a.tileY,navMeshData:e}}),s(t)}))}))}buildAllTiles(s,t){const{tileWidth:e,tileHeight:i}=this;for(let n=0;n<i;n++)for(let i=0;i<e;i++)this.buildTile(s,t,[i,n])}getTileForWorldPosition(s){return[Math.floor((s.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((s.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(s){const t=this.getTileForWorldPosition(s.min),e=this.getTileForWorldPosition(s.max),i=[];for(let s=t[1];s<=e[1];s++)for(let n=t[0];n<=e[0];n++)i.push([n,s]);return i}destroy(){this.navMesh.destroy();for(const s of this.workers)s.terminate()}}
|
2
|
+
/*
|
3
|
+
* Copyright (©) 2023. All rights reserved.
|
4
|
+
* See the LICENSE.md file for details.
|
5
|
+
*/
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import{init as t}from"recast-navigation";import{buildTile as e}from"./build-tile.js";let s=!1;const a=[];self.onmessage=t=>{s?o(t.data):a.push(t.data)};const o=t=>{const s=e(t);if(!s.success||!s.data)return;const a=s.data.toTypedArray();s.data.destroy(),self.postMessage({tileX:t.tileX,tileY:t.tileY,navMeshData:a},[a.buffer])};t().then((()=>{s=!0;for(const t of a)o(t)}));
|
2
|
+
/*
|
3
|
+
* Copyright (©) 2023. All rights reserved.
|
4
|
+
* See the LICENSE.md file for details.
|
5
|
+
*/
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './navigation.js';
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Vector3 } from "three";
|
2
|
+
export declare class Navigation {
|
3
|
+
private navMeshActor;
|
4
|
+
private query?;
|
5
|
+
private world;
|
6
|
+
constructor();
|
7
|
+
/**
|
8
|
+
* Finds a path from a start point to an end point.
|
9
|
+
*/
|
10
|
+
findPath(start: Vector3, end: Vector3): {
|
11
|
+
success: boolean;
|
12
|
+
path: Vector3[];
|
13
|
+
};
|
14
|
+
/**
|
15
|
+
* Finds the closest point on the navmesh to a given position.
|
16
|
+
* Returns null if it can't be found or if nav mesh has not been generated
|
17
|
+
*/
|
18
|
+
findClosestPoint(position: Vector3): Vector3 | null;
|
19
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import{Service as s,World as n,inject as r}from"../";import o from"../actors/builtin/navmesh-actor";import{NavMeshQuery as i}from"recast-navigation";import{Vector3 as a}from"three";let c=class{constructor(){this.world=r(n);const t=this.world.actors.find((t=>t instanceof o));null!=t&&(this.navMeshActor=t,this.query=new i(t.navMesh)),this.world.actorAdded.subscribe((t=>{t instanceof o&&(this.navMeshActor=t,this.query=new i(t.navMesh))})),this.world.actorRemoved.subscribe((t=>{t instanceof o&&t.id===this.navMeshActor?.id&&(this.navMeshActor=null,this.query=null)}))}findPath(t,e){if(null==this.query)return console.warn("NavMesh has not been generated yet"),h;const{success:s,error:n,path:r}=this.query.computePath(t,e);return s?{success:!0,path:r.map((t=>new a(t.x,t.y,t.z)))}:(console.warn("Failed to generate path",n),h)}findClosestPoint(t){if(null==this.query)return console.warn("NavMesh has not been generated yet"),null;const{success:e,point:s}=this.query.findClosestPoint(t);return e?new a(s.x,s.y,s.z):null}};c=t([s(),e("design:paramtypes",[])],c);export{c as Navigation};const h={success:!1,path:[]};
|
2
|
+
/*
|
3
|
+
* Copyright (©) 2023. All rights reserved.
|
4
|
+
* See the LICENSE.md file for details.
|
5
|
+
*/
|
package/dist/gameplay/index.d.ts
CHANGED
package/dist/gameplay/index.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import"reflect-metadata";export{Container as DIContainer}from"typedi";export*from"./initiate.js";export*from"./inject.js";export{Service,Inject}from"typedi";export{ActorFactory}from"./actors/factory.js";export{Actor,BaseActor}from"./actors/actor.js";export{Component,ActorComponent,attach,Attach}from"./actors/component.js";export*from"./services/world.js";export*from"./services/render.js";export*from"./services/physics/physics-system.js";export*from"./animation/anim-sm.js";export*from"./animation/root-motion.js";export*from"./services/asset-loader.js";export*from"./services/pointer-events.js";export{VisualEffect}from"../effects/vfx/vfx-param.js";export*from"../shader/parameter.js";
|
1
|
+
import"reflect-metadata";export{Container as DIContainer}from"typedi";export*from"./initiate.js";export*from"./inject.js";export{Service,Inject}from"typedi";export{ActorFactory}from"./actors/factory.js";export{Actor,BaseActor}from"./actors/actor.js";export{Component,ActorComponent,attach,Attach}from"./actors/component.js";export*from"./services/world.js";export*from"./services/render.js";export*from"./services/physics/physics-system.js";export*from"./animation/anim-sm.js";export*from"./animation/root-motion.js";export*from"./services/asset-loader.js";export*from"./services/pointer-events.js";export{VisualEffect}from"../effects/vfx/vfx-param.js";export*from"../shader/parameter.js";export*from"./ai/index.js";
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-compat";import{BehaviorSubject as o,distinctUntilChanged as n,filter as r,map as a,Subject as c,takeUntil as l}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as y,Group as p,LineSegments as g,Matrix4 as m,MeshBasicMaterial as f,Object3D as w,Quaternion as v,Raycaster as x,Scene as B,Vector3 as b}from"three";import{Service as A}from"typedi";import{AssetMeshInstance as C}from"../../../scene/asset-resource-loader.js";import{BoxCollisionShape as D,CapsuleCollisionShape as z,ConeCollisionShape as T,ConvexPolyhedronCollisionShape as M,CylinderCollisionShape as R,PhysicalShapeMesh as E,PlaneCollisionShape as S,SphereCollisionShape as W,TrimeshCollisionShape as _}from"../../../index.js";import{LandscapeGroup as F}from"../../../scene/landscape/landscape.js";import{ViewController as V}from"../render.js";import{World as P}from"../world.js";import*as k from"three/examples/jsm/utils/BufferGeometryUtils.js";import{calculateEffectiveScale as I}from"../../../utils/three/traverse.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new b,this.hitNormal=new b}}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={}));let L=class{set showDebug(t){this.shouldRenderDebug=t,this.debugMesh&&(this.debugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(t,e){this.viewController=t,this.gameWorld=e,this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.collisionEvents=new c,this.beforeStep=new c,this.afterStep=new c,this.shouldRenderDebug=!1,this._raycaster=new x,this._reusableResult=new RayTestResult,this._raytestDiff=new b,this._raytestDirection=new b,this.controlledActors=new Set,this.ready=this.setup()}createDebugMesh(){return new g(new y,new f({color:255}))}async start(){return await this.ready,this.handleTick(),this.ready}renderDebug(){null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.gameWorld.scene.add(this.debugMesh));const t=this.world.debugRender();this.debugMesh.geometry.setAttribute("position",new u(t.vertices,3))}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await U(),this.eventQueue=new i.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe((t=>{t=Math.min(.1,t),this.beforeStep.next(t),this.updatePhysics(t),this.afterStep.next(t),this.showDebug&&this.renderDebug(),this.world.bodies.forEach((t=>{if(t.isFixed())return;const e=this.staticMeshes.get(t)??this.bodyActors.get(t)?.object;var i,s;null!=e&&(e.parent instanceof B&&(X(e.position,t.translation()),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(t)?.id))&&(i=e.quaternion,s=t.rotation(),i.x=s.x,i.y=s.y,i.z=s.z,i.w=s.w)))}))}))}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){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(H,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,s,o){null==s&&(s=this._reusableResult);const n=this._raytestDiff,r=this._raytestDirection;if(n.subVectors(e,t),r.copy(n).normalize(),0===r.length())return console.warn("Ray test called with to and from being equal"),s;const a=new i.Ray(t,r),c=n.length(),l=this.world.castRayAndGetNormal(a,c,!1,void 0,void 0,void 0,null!=o?.excludeActor?this.actorBodies.get(o.excludeActor.id):void 0);if(s.hasHit=null!=l,s.hasHit){const e=a.pointAt(l.toi);s._internal=l,X(s.hitNormal,l.normal),X(s.hitPoint,e),s.distance=Y.subVectors(s.hitPoint,t).length();const i=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===l.collider))));s.actor=null!=i?this.bodyActors.get(i):null}if(this.showDebug){const e=new h(r,t,c,o?.debugColor??255);this.gameWorld.scene.add(e),setTimeout((()=>this.gameWorld.scene.remove(e)),o?.debugLifetime??200)}return this._reusableResult}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return q.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())J(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 E&&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 C&&!1!==t.userData?.src?.collisionDetection)if(t.children[0]&&t.children[0].instanceMatrix)this.createForInstancedMesh(t.children[0],t.collisionShapes);else{const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else t instanceof F?this.addLandscapeGroup(t):(t instanceof p||t instanceof B)&&t.children.forEach((t=>this.addRecursively(t)))}createForInstancedMesh(t,e){const i=new m;for(let s=0;s<t.count;s++){const o=new w;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*s),o.applyMatrix4(i);this.createStaticBody(o,e)}}getCharacterController(t=.01){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i){const o=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const n=o.collider(0);e.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,null,$);const r=e.computedMovement();return X(Z,r),Z}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)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.setAngvel(G,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.setLinvel(G,!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)}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}createCharacterCollision(){return new i.CharacterCollision}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));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 c=s.find((t=>t.x===n.x&&t.y==n.y));if(null!=c)for(const e of c.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:c})}const l=e.landscape.options.density,d=a.flatMap((t=>t.reverse())),h=i.ColliderDesc.heightfield(l,l,new Float32Array(d),new i.Vector3(r,r,r));var o=n.getWorldPosition(new b);const u=this.world.createRigidBody(i.RigidBodyDesc.fixed()),y=new i.Vector3(0,0,0);K(y,o),u.setTranslation(y,!1),this.world.createCollider(h,u),this.staticBodies.set(n,u)}}addActor(t,e,s={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const o=t.object;let n;switch(s.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:n=i.RigidBodyDesc.dynamic(),n.mass=s.mass??1;break;case PhysicsBodyType.kinematic:n=i.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:n=i.RigidBodyDesc.kinematicVelocityBased();break;default:n=(s.isTrigger,i.RigidBodyDesc.kinematicVelocityBased())}const r=this.world.createRigidBody(n);r.enableCcd(1==s.continousCollisionDetection);for(const t of e)this.addShape(r,t,o);J(r,(t=>{null!=s.isTrigger&&(t.setSensor(s.isTrigger),t.setActiveCollisionTypes(i.ActiveCollisionTypes.ALL),t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)),null!=s.friction&&t.setFriction(s.friction),null!=s.density&&t.setDensity(s.density),null!=s.mass&&t.setMass(s.mass),null!=s.restitution&&t.setRestitution(s.restitution)})),N(r,o),this.actorBodies.set(t.id,r),this.bodyActors.set(r,t)}applyTorque(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.addTorque(G,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.applyTorqueImpulse(G,!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);G.x=e.x,G.y=e.y,G.z=e.z,i?.addForce(G,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.applyImpulse(G,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);K(G,e),null==i?s?.addForce(G,!0):(K(Q,i),s?.addForceAtPoint(G,Q,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);K(G,e),null==i?s.applyImpulse(G,!0):(K(Q,i),s.applyImpulseAtPoint(G,Q,!0))}removeActor(t){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)}removeSceneObject(t){let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&this.world.removeRigidBody(e)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(l(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(l(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(l(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())}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?N(e,t.object):console.warn("Actor has not been added to physics world",t)}setupWorld(){const t=new i.World({x:0,y:-9.81,z:0});this.world=t,t.maxVelocityIterations=4}getActorContacts(t,e){const s=this.actorBodies.get(t.id);if(s&&s.numColliders()>0){const o=s.collider(0);let n=o.shape,r=o.translation(),a=o.rotation(),c=e,l=.3;const d=this.world.castShape(r,a,c,n,l,!0,null,null,null,this.actorBodies.get(t.id),(t=>t.shape.type!=i.ShapeType.HeightField));if(null!=d){const t=new b,e=new b,i=new b;return X(t,d.witness2),X(e,d.witness1),X(i,d.normal1),i.negate(),[{ri:t,rj:e,ni:i}]}return[]}return console.warn("Actor is not added to the physics system"),[]}stop(){this.world?.bodies.forEach((t=>this.world.removeRigidBody(t))),this.world?.free(),this.fixedupdateSub?.unsubscribe()}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.kinematicPositionBased(),n=this.world.createRigidBody(o);for(const i of e){const o=this.addShape(n,i,t);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 N(n,t),n}addShape(t,e,i){const s=this.createShape(e,i.scale);s.friction=.1;const o=e.offset.clone().multiply(i.scale);var n,r;return K(s.translation,o),n=s.rotation,r=(new v).setFromEuler(e.rotation),n.x=r.x,n.y=r.y,n.z=r.z,n.w=r.w,this.world.createCollider(s,t)}createShape(t,e){if(t instanceof D)return i.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof z){return i.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof _){const e=null!=t.geometry.getIndex()?t.geometry:k.mergeVertices(t.geometry);return i.ColliderDesc.trimesh(new Float32Array(e.getAttribute("position").array),new Uint32Array(e.getIndex().array))}if(t instanceof M){let s;t.mesh instanceof d.Mesh?s=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?s=t.mesh:console.log("Unknownd shape",{shapeInfo:t});const o=new Float32Array(s.getAttribute("position").array);if(t.mesh instanceof d.Mesh){const e=I(t.mesh);for(let t=0;t<o.length;t+=3)o[t]*=e.x,o[t+1]*=e.y,o[t+2]*=e.z}for(let t=0;t<o.length;t+=3)o[t]*=e.x,o[t+1]*=e.y,o[t+2]*=e.z;return i.ColliderDesc.convexHull(o)}return t instanceof W?i.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z)):t instanceof R?i.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof T?i.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof S?i.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.01):(console.error("Unsupported shape",t),i.ColliderDesc.cuboid(1,1,1))}};L=t([A(),e("design:paramtypes",[V,P])],L);export{L as PhysicsSystem};const j=new b,O=new d.Quaternion;function N(t,e){const s=e.getWorldPosition(j),o=e.getWorldQuaternion(O);t.setTranslation(new i.Vector3(s.x,s.y,s.z),!1),t.setRotation(new i.Quaternion(o.x,o.y,o.z,o.w),!1)}const q=new b,G=new i.Vector3(0,0,0),Q=new i.Vector3(0,0,0),H=(new b,{x:0,y:0}),U=async()=>{let t=await import("@dimforge/rapier3d-compat");return await t.init(),t};function K(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function X(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function J(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const Y=new b,Z=new b,$=t=>!t.isSensor();
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-compat";import{BehaviorSubject as o,distinctUntilChanged as r,filter as n,map as a,Subject as c,takeUntil as l}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as y,Group as p,LineSegments as g,Matrix4 as m,MeshBasicMaterial as f,Object3D as w,Quaternion as v,Raycaster as x,Scene as B,Vector3 as b}from"three";import{Service as A}from"typedi";import{AssetMeshInstance as C}from"../../../scene/asset-resource-loader.js";import{BoxCollisionShape as D,CapsuleCollisionShape as z,ConeCollisionShape as M,ConvexPolyhedronCollisionShape as T,CylinderCollisionShape as R,PhysicalShapeMesh as S,PlaneCollisionShape as E,SphereCollisionShape as W,TrimeshCollisionShape as F}from"../../../index.js";import{LandscapeGroup as _}from"../../../scene/landscape/landscape.js";import{ViewController as V}from"../render.js";import{World as P}from"../world.js";import*as k from"three/examples/jsm/utils/BufferGeometryUtils.js";import{calculateEffectiveScale as I}from"../../../utils/three/traverse.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new b,this.hitNormal=new b}}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={}));let L=class{set showDebug(t){this.shouldRenderDebug=t,this.debugMesh&&(this.debugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(t,e){this.viewController=t,this.gameWorld=e,this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.collisionEvents=new c,this.beforeStep=new c,this.afterStep=new c,this.shouldRenderDebug=!1,this._raycaster=new x,this._reusableResult=new RayTestResult,this._raytestDiff=new b,this._raytestDirection=new b,this.controlledActors=new Set,this.ready=this.setup()}createDebugMesh(){return new g(new y,new f({color:255}))}async start(){return await this.ready,this.handleTick(),this.ready}renderDebug(){null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.gameWorld.scene.add(this.debugMesh));const t=this.world.debugRender();this.debugMesh.geometry.setAttribute("position",new u(t.vertices,3))}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await U(),this.eventQueue=new i.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe((t=>{t=Math.min(.1,t),this.beforeStep.next(t),this.updatePhysics(t),this.afterStep.next(t),this.showDebug&&this.renderDebug(),this.world.bodies.forEach((t=>{if(t.isFixed())return;const e=this.staticMeshes.get(t)??this.bodyActors.get(t)?.object;var i,s;null!=e&&(e.parent instanceof B&&(X(e.position,t.translation()),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(t)?.id))&&(i=e.quaternion,s=t.rotation(),i.x=s.x,i.y=s.y,i.z=s.z,i.w=s.w)))}))}))}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){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(H,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,s,o){null==s&&(s=this._reusableResult);const r=this._raytestDiff,n=this._raytestDirection;if(r.subVectors(e,t),n.copy(r).normalize(),0===n.length())return console.warn("Ray test called with to and from being equal"),s;const a=new i.Ray(t,n),c=r.length(),l=this.world.castRayAndGetNormal(a,c,!1,void 0,void 0,void 0,null!=o?.excludeActor?this.actorBodies.get(o.excludeActor.id):void 0);if(s.hasHit=null!=l,s.hasHit){const e=a.pointAt(l.toi);s._internal=l,X(s.hitNormal,l.normal),X(s.hitPoint,e),s.distance=Y.subVectors(s.hitPoint,t).length();const i=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===l.collider))));s.actor=null!=i?this.bodyActors.get(i):null}if(this.showDebug){const e=new h(n,t,c,o?.debugColor??255);this.gameWorld.scene.add(e),setTimeout((()=>this.gameWorld.scene.remove(e)),o?.debugLifetime??200)}return this._reusableResult}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return q.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())J(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 S&&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 C&&!1!==t.userData?.src?.collisionDetection)if(t.children[0]&&t.children[0].instanceMatrix)this.createForInstancedMesh(t.children[0],t.collisionShapes);else{const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else t instanceof _?this.addLandscapeGroup(t):(t instanceof p||t instanceof B)&&t.children.forEach((t=>this.addRecursively(t)))}createForInstancedMesh(t,e){const i=new m;for(let s=0;s<t.count;s++){const o=new w;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*s),o.applyMatrix4(i);this.createStaticBody(o,e)}}getCharacterController(t=.01){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i){const o=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const r=o.collider(0);e.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,null,$);const n=e.computedMovement();return X(Z,n),Z}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)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.setAngvel(G,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.setLinvel(G,!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)}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}createCharacterCollision(){return new i.CharacterCollision}addLandscapeGroup(t){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));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 c=s.find((t=>t.x===r.x&&t.y==r.y));if(null!=c)for(const e of c.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:c})}const l=e.landscape.options.density,d=a.flatMap((t=>t.reverse())),h=i.ColliderDesc.heightfield(l,l,new Float32Array(d),new i.Vector3(n,n,n));var o=r.getWorldPosition(new b);const u=this.world.createRigidBody(i.RigidBodyDesc.fixed()),y=new i.Vector3(0,0,0);K(y,o),u.setTranslation(y,!1),this.world.createCollider(h,u),this.staticBodies.set(r,u)}}addActor(t,e,s={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const o=t.object;let r;switch(s.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:r=i.RigidBodyDesc.dynamic(),r.mass=s.mass??1;break;case PhysicsBodyType.kinematic:r=i.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:r=i.RigidBodyDesc.kinematicVelocityBased();break;default:r=(s.isTrigger,i.RigidBodyDesc.kinematicVelocityBased())}const n=this.world.createRigidBody(r);n.enableCcd(1==s.continousCollisionDetection);for(const t of e)this.addShape(n,t,o);J(n,(t=>{null!=s.isTrigger&&(t.setSensor(s.isTrigger),t.setActiveCollisionTypes(i.ActiveCollisionTypes.ALL),t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)),null!=s.friction&&t.setFriction(s.friction),null!=s.density&&t.setDensity(s.density),null!=s.mass&&t.setMass(s.mass),null!=s.restitution&&t.setRestitution(s.restitution)})),O(n,o),!0===s.ignoreForNavMesh&&(n.userData={ignoreForNavMesh:!0}),this.actorBodies.set(t.id,n),this.bodyActors.set(n,t)}applyTorque(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.addTorque(G,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.applyTorqueImpulse(G,!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);G.x=e.x,G.y=e.y,G.z=e.z,i?.addForce(G,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);G.x=e.x,G.y=e.y,G.z=e.z,i?.applyImpulse(G,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);K(G,e),null==i?s?.addForce(G,!0):(K(Q,i),s?.addForceAtPoint(G,Q,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);K(G,e),null==i?s.applyImpulse(G,!0):(K(Q,i),s.applyImpulseAtPoint(G,Q,!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)}removeSceneObject(t){let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&this.world.removeRigidBody(e)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(l(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(l(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(l(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())}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?O(e,t.object):console.warn("Actor has not been added to physics world",t)}setupWorld(){const t=new i.World({x:0,y:-9.81,z:0});this.world=t,t.maxVelocityIterations=4}getActorContacts(t,e){const s=this.actorBodies.get(t.id);if(s&&s.numColliders()>0){const o=s.collider(0);let r=o.shape,n=o.translation(),a=o.rotation(),c=e,l=.3;const d=this.world.castShape(n,a,c,r,l,!0,null,null,null,this.actorBodies.get(t.id),(t=>t.shape.type!=i.ShapeType.HeightField));if(null!=d){const t=new b,e=new b,i=new b;return X(t,d.witness2),X(e,d.witness1),X(i,d.normal1),i.negate(),[{ri:t,rj:e,ni:i}]}return[]}return console.warn("Actor is not added to the physics system"),[]}stop(){this.world?.bodies.forEach((t=>this.world.removeRigidBody(t))),this.world?.free(),this.fixedupdateSub?.unsubscribe()}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.kinematicPositionBased(),r=this.world.createRigidBody(o);for(const i of e){const o=this.addShape(r,i,t);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 O(r,t),r}addShape(t,e,i){const s=i.getWorldScale(tt),o=this.createShape(e,s);o.friction=.1;const r=e.offset.clone().multiply(s);var n,a;return K(o.translation,r),n=o.rotation,a=(new v).setFromEuler(e.rotation),n.x=a.x,n.y=a.y,n.z=a.z,n.w=a.w,this.world.createCollider(o,t)}createShape(t,e){if(t instanceof D)return i.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof z){return i.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof F){const e=null!=t.geometry.getIndex()?t.geometry:k.mergeVertices(t.geometry);return i.ColliderDesc.trimesh(new Float32Array(e.getAttribute("position").array),new Uint32Array(e.getIndex().array))}if(t instanceof T){let s;t.mesh instanceof d.Mesh?s=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?s=t.mesh:console.log("Unknownd shape",{shapeInfo:t});const o=new Float32Array(s.getAttribute("position").array);if(t.mesh instanceof d.Mesh){const e=I(t.mesh);for(let t=0;t<o.length;t+=3)o[t]*=e.x,o[t+1]*=e.y,o[t+2]*=e.z}for(let t=0;t<o.length;t+=3)o[t]*=e.x,o[t+1]*=e.y,o[t+2]*=e.z;return i.ColliderDesc.convexHull(o)}return t instanceof W?i.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z)):t instanceof R?i.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof M?i.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof E?i.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.01):(console.error("Unsupported shape",t),i.ColliderDesc.cuboid(1,1,1))}};L=t([A(),e("design:paramtypes",[V,P])],L);export{L as PhysicsSystem};const j=new b,N=new d.Quaternion;function O(t,e){const s=e.getWorldPosition(j),o=e.getWorldQuaternion(N);t.setTranslation(new i.Vector3(s.x,s.y,s.z),!1),t.setRotation(new i.Quaternion(o.x,o.y,o.z,o.w),!1)}const q=new b,G=new i.Vector3(0,0,0),Q=new i.Vector3(0,0,0),H=(new b,{x:0,y:0}),U=async()=>{let t=await import("@dimforge/rapier3d-compat");return await t.init(),t};function K(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function X(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function J(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const Y=new b,Z=new b,$=t=>!t.isSensor(),tt=new b;
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{materialFromAsset as e}from"../../scene/materializer.js";import{Mesh as t,PlaneGeometry as s,Vector3 as n,InstancedMesh as a,Matrix4 as o,MeshLambertMaterial as i,Color as r,Vector2 as c,Triangle as l,Box3 as h,MathUtils as u,MeshStandardMaterial as f,ShaderMaterial as m,DoubleSide as d,PerspectiveCamera as p}from"three";import{indexBy as w}from"../../utils/collections.js";import{smoothNormalsCrossMeshes as y}from"./utils.js";import*as M from"three";import{defaultLandscapeMaterial as g,LandscapeMesh as x}from"./landscape.js";import{meanVectors3withWeight as S,clamp as b}from"../../utils/math.js";import{whenIdle as v}from"../../utils/async.js";import{Subject as A,debounceTime as z}from"rxjs";new n,new n;const P=new n,L=new n,j=new n;export class LandscapeManager{constructor(e,t,s,a,i,r,c){this.source=e,this.view=t,this.landscape=s,this.assetManagerService=a,this.assetService=i,this.shaders=r,this.applyMaterial=c,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new A,this.defaultLandscapeMaterial=g.clone(),this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new o,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new n,this._cameraPosition=new n,this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=g.name,this.defaultLandscapeMaterial.color=g.color,this.refreshRequests.pipe(z(500)).subscribe((e=>this.refreshScatter(e.origin,e.force,e.predicate)))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new s(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new f({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new n,new n);this.view.camera.getWorldPosition(t);const s=[];j.fromArray(this.source.position);const a=this.view.camera instanceof p?Math.min(this.view.camera.far,1e3):1e3,o=1.1*a,i=e.sections.y*e.sectionSize/-2,r=e.sections.x*e.sectionSize/-2;for(let n=0;n<e.sections.x;n++)if(P.x=r+n*e.sectionSize,!(Math.abs(t.x-P.x)>o))for(let c=0;c<e.sections.y;c++){P.z=i+c*e.sectionSize,L.copy(j).add(P);const l=L.distanceTo(t),h=`${n},${c}`,u=this.landscape.sections.find((e=>e.x===n&&e.y===c));if(l<=a){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,r,i,n,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>o&&this.landscape.remove(u)}y(s)}applyHeightMap(e,t,s,n=1){const a=Math.pow(s+1,2),o=e.getAttribute("position")
|
1
|
+
import{materialFromAsset as e}from"../../scene/materializer.js";import{Mesh as t,PlaneGeometry as s,Vector3 as n,InstancedMesh as a,Matrix4 as o,MeshLambertMaterial as i,Color as r,Vector2 as c,Triangle as l,Box3 as h,MathUtils as u,MeshStandardMaterial as f,ShaderMaterial as m,DoubleSide as d,PerspectiveCamera as p}from"three";import{indexBy as w}from"../../utils/collections.js";import{smoothNormalsCrossMeshes as y}from"./utils.js";import*as M from"three";import{defaultLandscapeMaterial as g,LandscapeMesh as x}from"./landscape.js";import{meanVectors3withWeight as S,clamp as b}from"../../utils/math.js";import{whenIdle as v}from"../../utils/async.js";import{Subject as A,debounceTime as z}from"rxjs";new n,new n;const P=new n,L=new n,j=new n;export class LandscapeManager{constructor(e,t,s,a,i,r,c){this.source=e,this.view=t,this.landscape=s,this.assetManagerService=a,this.assetService=i,this.shaders=r,this.applyMaterial=c,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new A,this.defaultLandscapeMaterial=g.clone(),this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new o,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new n,this._cameraPosition=new n,this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=g.name,this.defaultLandscapeMaterial.color=g.color,this.refreshRequests.pipe(z(500)).subscribe((e=>this.refreshScatter(e.origin,e.force,e.predicate)))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new s(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new f({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new n,new n);this.view.camera.getWorldPosition(t);const s=[];j.fromArray(this.source.position);const a=this.view.camera instanceof p?Math.min(this.view.camera.far,1e3):1e3,o=1.1*a,i=e.sections.y*e.sectionSize/-2,r=e.sections.x*e.sectionSize/-2;for(let n=0;n<e.sections.x;n++)if(P.x=r+n*e.sectionSize,!(Math.abs(t.x-P.x)>o))for(let c=0;c<e.sections.y;c++){P.z=i+c*e.sectionSize,L.copy(j).add(P);const l=L.distanceTo(t),h=`${n},${c}`,u=this.landscape.sections.find((e=>e.x===n&&e.y===c));if(l<=a){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,r,i,n,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>o&&this.landscape.remove(u)}y(s)}applyHeightMap(e,t,s,n=1){const a=Math.pow(s+1,2),o=e.getAttribute("position");if(1===n)for(const e of t.points)o.setY(e.i,e.y);else{const e=w(t.points??[],(e=>e.i));for(let t=0;t<o.count;t++){const s=B(t,o.count,a);let n=0;n=s%1==0?e.get(s)?.y??0:Math.floor(e.get(s)?.y),o.setY(t,n)}}o.needsUpdate=!0,e.computeVertexNormals()}deleteOldScatterMeshes(){const e=new Set;for(const[t,s]of this.source.grass?.layers.entries()??[])for(const[n,a]of s.meshes.entries()){const s=`${t}-${n}`;e.add(s)}for(const t of this.scatterMeshes.keys())if(!e.has(t)){this.scatterMeshes.get(t).forEach((e=>{e.parent?.remove(e),e.dispose()})),this.scatterMeshes.delete(t)}}queueRefreshScatter(e,t=!1,s=(()=>!0)){this.refreshRequests.next({origin:e,force:t,predicate:s})}async refreshScatter(o,c=!1,h=(()=>!0)){c&&this.scatterGeometryCache.clear(),this.deleteOldScatterMeshes();for(const[f,p]of this.source.grass?.layers.entries()??[])for(const[y,g]of p.meshes.entries()){const p=`${f}-${y}`;this.scatterMeshes.has(p)||this.scatterMeshes.set(p,new Map);const x=this.scatterMeshes.get(p),A=await this.assetService.getAsset(g.assetId),z=await this.assetManagerService.getMesh(A),P=[];if(z.scene.traverse((e=>{e instanceof t&&P.push(e)})),1!==P.length){console.log(z),console.warn("Dynamic grass only works for meshes with a single geometry.");continue}if(!(P[0]instanceof t)){console.warn("Only meshes can be used for dynamic grass. Found:",z.scene);continue}const L=P[0];let j=L.geometry;this.scatterGeometryCache.has(L.geometry.uuid)?j=this.scatterGeometryCache.get(L.geometry.uuid):(j=L.geometry.clone(),!0===g.normalsUp&&Y(j),this.scatterGeometryCache.set(L.geometry.uuid,j),null==j.userData.updatedMatrix&&(z.scene.updateMatrixWorld(),j.applyMatrix4(L.matrixWorld),j.userData.updatedMatrix=!0));const B=j.getIndex().count/3;if(B>400){console.warn(`The triangle count of ${A.name} is too big ${B}. Keep it below 400`);continue}const G=null!=A.materialAssignments&&A.materialAssignments.length>0?A.materialAssignments[0].materialId:null,R=null!=G&&"null"!==G?await e(await this.assetService.getAsset(G),null,this.assetService,this.assetManagerService,this.shaders,!1):null;let U=null!=R?R:L.material;U instanceof m&&(U.side=d);const W=u.degToRad(g.maxSlope??90),D=Math.cos(W),O=this.landscape.sections,E=O.filter(_(o,g.viewDistance)).filter((e=>!x.has(e.uuid)||c)).filter((e=>h(e)));O.filter($(o,2*g.viewDistance)).forEach((e=>{const t=x.get(e.uuid);t?.parent?.remove(t),x.delete(e.uuid)}));performance.now();const X=this.source.landscape.options,F=X.sectionSize,N=g.density??1??1,Z=X.density,K=F/Z,V=N,J=K/Math.sqrt(V),Q=Math.pow(Z,2),ee=J/K,te=Math.floor(Q*V),se=[0,0,0];for(const e of E)await v((async()=>{e.updateWorldMatrix(!0,!1);const t=this._matrix,o=new n,h=e.geometry.getAttribute("position"),u=e.geometry.getAttribute("normal"),m=(this.source.vertexMaterials??[]).filter((t=>t.m===e.name)),d=w(m,(e=>e.i));let p=x.get(e.uuid);if(null==p||p.count==te&&!c||(p.parent?.remove(p),x.delete(e.uuid),p=null),null==p){const e=new s(.15,.75).getAttribute("normal");for(let t=0;t<e.count;t++);new i({color:new r(3765785),side:M.DoubleSide});p=new a(j,U,te),p.raycast=()=>{},p.receiveShadow=!0}const y=new l(new n,new n,new n);let[v,A,z,P]=[new n,new n,new n,new n],[L,B,G]=[[],[],[]],[$,_,R]=[new n,new n,new n,new n];const W=new n,O=new n,Y=new n,E=new n,X=new l(new n,new n,new n),F=new l(new n,new n,new n),N=new l(new n,new n,new n),K=new l(new n,new n,new n);let J=0;e:for(let s=0;s<Q;s++){const n=Math.floor(s/Z);v.fromBufferAttribute(h,s+n),E.copy(v).applyMatrix4(e.matrixWorld),X.a.copy(v),X.b.fromBufferAttribute(h,s+1+n),X.c.fromBufferAttribute(h,s+Z+1+n),F.a.copy(X.b),F.b.copy(X.c),F.c.fromBufferAttribute(h,s+Z+2+n),N.a.fromBufferAttribute(u,s+n),N.b.fromBufferAttribute(u,s+1+n),N.c.fromBufferAttribute(u,s+Z+1+n),K.a.copy(N.b),K.b.copy(N.c),K.c.fromBufferAttribute(u,s+Z+2+n);const a=[];a[0]=d.get(s+n)?.w,a[1]=d.get(s+1+n)?.w,a[2]=d.get(s+Z+1+n)?.w,a[3]=d.get(s+Z+2+n)?.w;let i=0;for(let s=0;s<=1+ee;s+=ee)for(let n=0;n<=1+ee;n+=ee){if(J>te)break e;if(i++,i>V)continue e;1-s>n?(A=X.a,z=X.b,P=X.c,$=N.a,_=N.b,R=N.c,L=a[0],B=a[1],G=a[2]):(A=F.a,z=F.b,P=F.c,$=K.a,_=K.b,R=K.c,L=a[1],B=a[2],G=a[3]),y.a.copy(A),y.b.copy(z),y.c.copy(P),C(y),W.set(v.x,0,v.z),W.x=q(y.a.x,y.b.x),W.z=q(y.a.z,y.c.z),y.getBarycoord(W,o).toArray(se);if(k([L,B,G],se,.2)!==f-1)continue;const r=[A,z,P];S(r,se,O),S([$,_,R],se,Y);const c=r.map((e=>e.y)),l=Math.max(...c),h=Math.min(...c);if(O.y=b(O.y,h,l),null!=g.maxSlope&&g.maxSlope<90&&Y.y<D)continue;const u=O.applyMatrix4(e.matrixWorld);u.y+=q(g.offsetMin,g.offsetMax);const m=q(g.scaleMin,g.scaleMax);t.makeScale(1,1,1),t.setPosition(u),t.scale(T(m)),g.alignToNormal&&I(t,u,p.matrixWorld,Y),!1!==g.randomRotation&&H(t),p.setMatrixAt(J,t),J++}}p.instanceMatrix.count=J,t.makeScale(0,0,0);for(let e=J;e<te;e++)p.setMatrixAt(e,t);p.instanceMatrix.needsUpdate=!0,x.has(e.uuid)||this.landscape?.attach(p),x.set(e.uuid,p)}));performance.now()}}stop(){this.view.removeOnLoop(this.onLoopHandler)}update(){this.view.camera&&(this.view.camera.getWorldPosition(this._cameraPosition),this._cameraPosition.distanceTo(this._lastUpdatePosition)>10&&(this._lastUpdatePosition.copy(this._cameraPosition),this.refreshGeometry(),this.refreshScatter(this._cameraPosition)))}clear(){this.scatterMeshes.forEach((e=>e.forEach((e=>e.parent?.remove(e)))))}createLandscapeMesh(e,t,n,a,o,i){const r=new s(t.sectionSize,t.sectionSize,t.density,t.density);r.rotateX(Math.PI/-2);const c=this.defaultLandscapeMaterial,l=new x(r,c);l.position.x=n+o*t.sectionSize,l.position.z=a+i*t.sectionSize,l.receiveShadow=!0,l.castShadow=!1,l.userData.landscape={x:o,y:i},l.x=o,l.y=i,l.name=`${o},${i}`;const h=e.landscape.heightMaps.find((e=>e.x===o&&e.y===i));return null!=h&&this.applyHeightMap(r,h,t.density,1),r.computeBoundsTree(),l}}function B(e,t,s){const n=Math.sqrt(t),a=Math.floor(e/n)/(n-1),o=e%n/(n-1),i=Math.sqrt(s);return(s-1)*a-(i-1)*a+(i-1)*o}new Map,new c(0,0),new c(1,0),new c(0,1),new c(1,0),new c(0,1),new c(1,1),new n;const G=new h;function $(e,t){return function(s){return G.setFromObject(s).distanceToPoint(e)>t}}function _(e,t){return function(s){return G.setFromObject(s).distanceToPoint(e)<t}}function C(e){e.a.y=0,e.b.y=0,e.c.y=0}function k(e,t,s=.5){let n=-1,a=0;for(let o=0;o<e.length;o++)if(null!=e[o])for(let i=0;i<e[o].length;i++){const r=e[o][i]*t[o];r>s&&r>a&&(a=r,n=i)}return n}function q(e,t){let s=t-e,n=Math.random();return n*=s,n+=e,n}const R=new n;function T(e){return R.set(e,e,e)}new n;const U=new n,W=new n(0,1,0),D=(new o).makeRotationX(Math.PI/-2);function I(e,t,s,n){e.lookAt(U,n,W).multiply(D)}const O=new o;function H(e){e.multiply(O.makeRotationY(Math.random()*Math.PI/2))}function Y(e){const t=e.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0}
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -201,6 +201,7 @@ export declare class SceneMaterializer {
|
|
201
201
|
private editorActorParamSnapshot;
|
202
202
|
private originalFog;
|
203
203
|
constructor(scene: Scene, dataProvider: SceneDataProvider, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, renderingView: RenderingView, shaders: ShaderImpl[], actorTypes: ActorImpl[], actorProvider: ActorProvider);
|
204
|
+
private refreshMaterial;
|
204
205
|
get actorInstances(): BaseActor[];
|
205
206
|
private prefetchAssets;
|
206
207
|
init(): Promise<void>;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{Subject as e}from"rxjs";import*as t from"three";import{BoxGeometry as a,Color as s,Euler as r,Fog as i,FogExp2 as n,Group as o,Material as c,Mesh as l,MeshLambertMaterial as h,MeshPhongMaterial as m,MeshStandardMaterial as p,Object3D as d,PointLight as f,Quaternion as u,SphereGeometry as y,Texture as g,Vector2 as w,Vector3 as v,Vector4 as A}from"three";import S,{SpriteRenderer as b}from"three-nebula";import{bool as M,BooleanNode as j,float as x,FloatNode as I,NodeShaderMaterial as P,rgb as D,RgbNode as E,Texture2dLookupNode as V,textureSampler2d as N,vec2 as C,Vec2Node as F,vec3 as k,Vec3Node as z,vec4 as B}from"three-shader-graph";import O from"../gameplay/actors/builtin/index.js";import{extractShaderParameters as _}from"../shader/parameter.js";import{groupBy as T,ArrayMap as $}from"../utils/collections.js";import{filterChildrenShallow as L,filterSceneShallow as R}from"../utils/three/traverse.js";import{AssetMeshInstance as U}from"./asset-resource-loader.js";import{BoxCollisionShape as H,PhysicalShapeMesh as G}from"./collision/collision-shape.js";import{isCollisionMesh as J}from"./collision/collision-shape-import.js";import{initLandscape as X}from"./landscape/landscape.js";import{LandscapeManager as W}from"./landscape/landscape-manager.js";import{SectionGrid as Y,smoothNormalsCrossMeshes as q}from"./landscape/utils.js";import{createGrassMaterial as Z}from"./materials/grass.js";import{createGrassFoliageMaterial as K}from"./materials/grass-foliage.js";import{getMaterialAttribute as Q}from"./materials/utils/material-painting.js";import{createWaterMaterial as ee}from"./materials/water.js";import{SerializedParamType as te}from"./model.js";import{Matrix4 as ae}from"three";import{BaseActor as se}from"../gameplay/actors/actor.js";import{Sampler2DNode as re}from"../shader-nodes/index.js";import{StandardShader as ie}from"../shader/builtin/standard-shader.js";import{LambertShader as ne}from"../shader/builtin/lambert-shader.js";import{ShapeLibrary as oe,ShapeLibraryKeys as ce}from"./objects/shapes.js";import{ambientLightName as le,createSky as he,defaultSkyMaterial as me}from"./sky.js";import{ActorComponent as pe,PhysicsBodyType as de,withInjectionContext as fe}from"../gameplay/index.js";import{iterateMaterials as ue}from"../utils/materials.js";import{VfxActor as ye}from"../effects/vfx/vfx-actor.js";import{VisualEffect as ge}from"../effects/vfx/vfx-param.js";import{findFirstVisibleObject as we}from"../utils/three/traverse.js";const ve={};export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new SceneMaterializer(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}export class SceneMaterializer{constructor(t,a,s,r,i,n,o,c){this.scene=t,this.dataProvider=a,this.assetsService=s,this.assetManagerService=r,this.renderingView=i,this.shaders=n,this.actorTypes=o,this.actorProvider=c,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.inEditor=!0,this.updated$=new e,this.removed$=new e,this.error$=new e,this.editorActorParamSnapshot=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.originalFog=null,a.onUpdate((e=>this.update(e))),a.onRemove((e=>this.remove(e))),this.updateSubscription=s.onUpdate.subscribe((async e=>{"material"==e.type?((await this.assetsService.getAssets()).filter((t=>(t.materialAssignments??[]).some((t=>t.materialId===e.id)))).forEach((e=>{const t=this.findByAssetId(e.id);e.materialAssignments.forEach((e=>{t.forEach((t=>{const a=t.userData.src.materialAssignments;null!=a&&a.some((t=>t.color===e.color))||this.applyMaterial(t,e)}))}))})),R(this.scene,(t=>null!=t.userData.src&&(t.userData.src.materialAssignments??[]).some((t=>t.materialId===e.id))),(e=>null!=e.userData.src)).forEach((async e=>{this.deleteSceneObject(e.userData.src),this.materialize(e.userData.src)}))):"mesh"==e.type?this.findByAssetId(e.id).forEach((t=>{Ee(t.userData.src.materialAssignments,e.materialAssignments).forEach((e=>{this.applyMaterial(t,e)}))})):"prefab"===e.type&&this.findByAssetId(e.id).forEach((e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}))}))}get actorInstances(){return Array.from(this.materializedActors.values())}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter((e=>null!=e.assetId&&"asset_mesh"==e.type)).filter((e=>e.assetId))));await Promise.all(e.map((e=>this.assetsService.getAsset(e.assetId).then((e=>e&&this.assetManagerService.getMesh(e))))))}async init(){this.preInit(),Se.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map((e=>this.materialize(e)))),await this.initActorsPostInit()}initActorsPostInit(e=this.actorInstances){const t=e.map((async e=>{const t=e.object.userData.src;if("vfx"===t.type)return Promise.resolve();const a=await this.assetsService.getAsset(t.assetId),s={...a?.actor?.params??{},...t.actor?.params??{}};for(const a of t.actor.innerParams??[])await this.applyActorComponentParams(e,a.path.slice(),a.params);const r=await je(s,e.constructor,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders,this.actorProvider);Object.assign(e,r);try{return await this.actorProvider.initActor(e)}catch(e){console.error(`Failed to initiate actor (name="${t.name}", id=${t.id})`,e)}}));return Promise.all(t)}addVfxChildActors(e,t=e){for(const a of Object.keys(t))t[a]instanceof ge?null!=t[a].actor&&(console.log("add actor to world",t[a].actor),e.object.add(t[a].actor.object)):t[a]instanceof pe&&this.addVfxChildActors(e,t[a])}removeVfxChildActors(e,t=e){for(const a of Object.keys(t))if(t[a]instanceof ge){if(null!=t[a].actor){t[a].actor.onEndPlay(),console.log("remve actor from world",t[a].actor),e.object.remove(t[a].actor.object)}}else t[a]instanceof pe&&this.removeVfxChildActors(e,t[a])}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await je(a,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[r]&&await this.applyActorComponentParams(e[r],t,a)}canObjectBeInstanced(e){return e.physics?.type!==de.dynamic}async canAssetBeInstanced(e){if(!this._canBeInstancedCache.has(e.assetId)){const t=await this.createFromAsset(e);if(null==t)return!1;const a=[];t.traverse((e=>{!J(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=!0;this._canBeInstancedCache.set(e.assetId,s&&r)}return this._canBeInstancedCache.get(e.assetId)}preInit(){this.renderingView?.onLoop((()=>this.sky?.position.copy(this.renderingView.camera.position)))}async initWithInstancing(){this.preInit();const e=new $;for(const t of this.dataProvider.getObjects())await De(t,(async(t,a,s)=>{const r="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t)?t.assetId+JSON.stringify(t.materialAssignments??[]):"other";"other"!==r&&a&&a.children?.length>0&&a.children.splice(a.children.findIndex((e=>e.id===t.id)),1),"other"===r&&a||e.push(r,{...t,parentTransform:s})}));for(const[t,a]of e.entries())if("other"!==t&&a.length>0){const e=await this.createFromAsset(a[0]);if(null==e)continue;const t=await this.createInstancedMesh(a,e),s=new U;s.add(t),s.userData.src=a[0],e instanceof U&&(s.collisionShapes=e.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}else await Promise.all(a.map((e=>this.materialize(e))));await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=we(a,(e=>!J(e)&&null!=e.geometry)),i=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(a,Ee(e[0].materialAssignments,i.materialAssignments)),s.updateMatrix();const n=s.geometry.clone().applyMatrix4(s.matrix),o=new t.InstancedMesh(n,s.material.clone(),e.length);o.material.side=t.FrontSide;for(let a=0;a<e.length;a++){const s=(new t.Matrix4).compose((new v).fromArray(e[a].position),(new u).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new ae).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=i.castShadow??!0,o.receiveShadow=i.receiveShadow??!0,o}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("actor"==e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay(),this.removeVfxChildActors(t)):console.warn("Failed to remove actor",e)}const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter((t=>t.object.userData.src?.id===e.id)).forEach((e=>this.components.splice(this.components.indexOf(e,1)))),this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))})),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex((t=>t.source.id===e.id));if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return R(this.scene,(t=>t.userData.src?.assetId==e),(e=>null!=e.userData.src))}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter((e=>"null"!==e.materialId)).map((t=>this.applyMaterial(e,t))))}applyMaterial(e,a){const r=[];return e.traverse((async e=>{if(e instanceof l||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of ue(e.material))t.hasOwnProperty("color")&&r.push(e)})),Promise.all(r.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const r=e.material[t];if(null==r.color||!(r.color instanceof s))continue;const i="#"+r.color.getHexString(),n=r.name;if(i===a.color&&(r.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await this.assetsService.getAsset(a.materialId),r=e.material[t];s&&(e.material[t]=await materialFromAsset(s,this.renderingView,this.assetsService,this.assetManagerService,this.shaders),e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??i,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??n,this.inEditor&&this._originalMaterials.set(e.id+"#"+t,r))}}else{const t="#"+e.material.color.getHexString(),s=e.material.name;if(t===a.color&&(e.material.name===a.name||null==a.name)||e.userData.originalColor===a.color&&e.userData.originalName===a.name){const r=await this.assetsService.getAsset(a.materialId),i=e.material;r&&(e.material=await materialFromAsset(r,this.renderingView,this.assetsService,this.assetManagerService,this.shaders),e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,this.inEditor&&this._originalMaterials.set(e.id,i))}}})))}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof l)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material}))}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(O));R(this.scene,(e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type))).forEach((async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)}))}updateShaders(e){this.shaders=e;for(const[e,t]of Se.entries())t.userData.customShaderName&&Se.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),R(this.scene,(e=>!0)).forEach((e=>{e.traverse((e=>{if(e instanceof l){const t=e.material.userData?.customShaderName;if(null!=t){const t=function(e,t){if(t(e))return e;let a;return e.traverseAncestors((e=>{null==a&&t(e)&&(a=e)})),a}(e,(e=>null!=e.userData.src?.id))?.userData.src;null!=t&&this.update(t)}}}))}))}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);const t=this.sceneObjectMap.get(e.id);if(t){let r=!1;if(t.traverseAncestors((e=>{"_hology_transform_group"===e.name&&(r=!0)})),!r){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse((e=>{e instanceof l&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof l&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=await this.assetsService.getAsset(e.assetId);Ee(e.materialAssignments,a.materialAssignments).forEach((e=>this.applyMaterial(t,e)))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(r||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type)if("point"==e.light.type){const a=t;a.color=new s(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0)}else"directional"===e.light.type?this.applyDirectionalLight(e.light.directional):"ambient"===e.light.type&&this.applyDirectionalAmbientLight(t,e.light.ambient);else if("landscape"===e.shape)this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>!0))));else if("global_fog"===e.type){const t=(this.scene.fog instanceof n?"density":"linear")!==e.fog.type;this.scene.fog=Ie(e.fog),t&&(a=this.scene).traverse((e=>{if(e instanceof l){const t=e.material;t instanceof P&&(a.fog instanceof i?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof n&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}})),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.editorActorParamSnapshot.get(e.id);null!=t&&t===JSON.stringify(e.actor)||(console.log("Rematerializing actor because parameters changed"),this.remove(e),await this.materializeAndInitActor(e))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof G&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&Ae(t,e.castShadow,e.receiveShadow),e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a}async materializeAndInitActor(e,t=this.findParent(e)){console.log("materialize actor and init");const a=await this.materialize(e,t);return De(e,(async e=>{if("actor"===e.type){const t=this.materializedActors.get(e.id);null!=t?await this.initActorsPostInit([t]):console.error(`Something went wrong when creating actor ${e.id}`)}})),a}findParent(e){const t=this.dataProvider.getObjects().flatMap((t=>t.id===e.id?null:L(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?R(this.scene,(e=>e.userData?.src?.id===t.id),(e=>null!=e.userData?.src))[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new s(this.scene.fog.color).convertSRGBToLinear())}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof l&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=T(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof l){const t=Q(e,!1);if(null!=t){for(let e=0;e<t.array.length;e++)t.setX(e,0);t.needsUpdate=!0}}}));const s=new Set;for(const[e,r]of a.entries()){const a=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let i=!1;if(null==a)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const n=Q(a,!0);for(let e=0;e<n.array.length;e++)n.setX(e,0);for(const e of r)n.setX(e.i,e.w[0]),n.setY(e.i,e.w[1]),n.setZ(e.i,e.w[2]),i=!0;i&&s.add(e)}this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>s.has(e.name)))))}async materialize(e,t,s=!1){let r;switch(e.type){case"asset_mesh":r=await this.createFromAsset(e);break;case"shape_mesh":r=await this.createFromShape(e);break;case"light":r=await this.createLight(e);break;case"particles":r=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Ie(e.fog),this.fixFogColor(),r=new o;break;case"sky":this.sky=he(),this.updateSky(e),r=this.sky;break;case"actor":r=await this.createFromActor(e);break;case"group":r=new o;break;case"prefab":r=await this.createFromPrefabAsset(e);break;case"vfx":r=await this.createFromVfx(e);break;default:if(this.inEditor)throw new Error("unknown type "+e.type);console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version.`)}if(null!=r){if(e.name&&e.name.length>0&&(r.name=e.name),null!=e.position&&r.position.fromArray(e.position),null!=e.scale&&r.scale.fromArray(e.scale),null!=e.rotation&&r.rotation.fromArray(e.rotation),s||(r.userData.src=e),this.inEditor,this.inEditor){let e=null;r instanceof G&&(e=function(e){if(e instanceof H)return new l(new a(...e.offset.toArray()),Pe);return null}(r.collisionShape)),null!=e&&(e.layers.disable(0),e.layers.enable(18),e.scale.multiplyScalar(1.1),r.add(e))}return this.objectMap.set(r.uuid,e),this.sceneObjectMap.set(e.id,r),null==t?this.scene.add(r):t?.add(r),null!=e.children&&await Promise.all(e.children?.map((e=>this.materialize(e,r,s)))),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=me);const a=await this.assetsService.getAsset(e.sky.materialId),s=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);s.side=t.BackSide,null!=this.sky?this.sky.material=s:console.warn("No sky has been created")}async createComponent(e,t,a,s){const r=new ve[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e){const t=this.actorTypes.find((t=>t.name===e.actor?.type))?.type??O[e.actor?.type];if(null==t)return null;this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const a=await this.actorProvider.create(t,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!0);return this.materializedActors.set(e.id,a),a?.object}async createFromVfx(e){const t=await this.assetsService.getAsset(e.assetId);null==t&&console.error("Could not find asset",e);const a=await this.actorProvider.create(ye,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!1);return await a.fromAsset(t),a.play(),this.materializedActors.set(e.id,a),a?.object}cleanup(){this.materializedActors.clear()}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e);else{let r=new p({name:"Default",color:new s("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});const i=await this.createMeshByShape(e.shape,r,e.shapeParams);i.castShadow=e.castShadow??!0,i.receiveShadow=e.castShadow??!1,e.collisionDetection||(i.collisionShape=null),i.physics=e.physics,a=i,this._originalMaterials.set(a.id,i.material),a.traverse((e=>{}))}return t||((e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(a,e))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new o;const a=X(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new W(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,(t=>{(e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(t,e)))}));return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new Y(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach((e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()})),this.inEditor&&!a||setTimeout((()=>q(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&ce.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,oe[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,oe[e].collision(s)),new G(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:a}=await this.assetManagerService.getMesh(t);Ee(e.materialAssignments,t.materialAssignments).forEach((e=>this.applyMaterial(a,e)));const s=e.receiveShadow??!!t.receiveShadow??!0,r=e.castShadow??!!t.castShadow??!1;return a.receiveShadow=s,Ae(a,r,s),e.collisionDetection||(a.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(a.physics=e.physics),this.applyVertexMaterials(e,a),a.traverse((e=>{e instanceof l&&"computeBoundsTree"in e.geometry&&e.geometry.computeBoundsTree()})),a}async createFromPrefabAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);const a=new o;return t.prefab.objects.filter((e=>"global_fog"!==e.type)).forEach((e=>this.materialize(e,a,!0))),a}async createParticleSystem(e){const a=await this.assetsService.getAsset(e.assetId),s=new d;return await S.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new b(s,t);e.addRenderer(a),this.renderingView.onLoop((t=>e.update()))})),s}async createLight(e){if("point"===e.light.type){const t=new f(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=new y(.3,10,10),a=new p({color:new s(16771709)}),r=new l(e,a);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional),new o):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient),new o):void 0}applyDirectionalAmbientLight(e,t){const a=this.scene.children.find((e=>e.name===le));null!=a?(a.intensity=t.intensity,a.color.set(t.color),a.groundColor.set(t.color)):console.warn("Couldn't find ambient light")}applyDirectionalLight(e){for(const t of this.renderingView.csm.lights)t.intensity=e.intensity,t.color.set(e.color),t.castShadow=e.castShadow;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function Ae(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Se=new Map,be=new h({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const c=JSON.stringify(e.material);if(o&&Se.has(c))return Se.get(c);const l={opacity:e.material.params.opacity,map:null,emissive:e.material.params.emissive??null,metalness:e.material.params.metalness??0,flatShading:e.material.params.flatShading??!1,color:new s(e.material.params.color).convertSRGBToLinear(),transparent:null!=e.material.params.opacity&&e.material.params.opacity<1},h={};if(null!=e.material.params.map){const t=e.material.params.map,a=await r.getAsset(t);null!=a&&(l.map=await i.getTexture(a))}let p;switch(e.material.type){case"phong":p=new m({...l,...h});break;case"water":p=ee(l,a);break;case"grassFoliage":p=K({color:l.color,map:l.map},a);break;case"grass":p=Z({...l,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"lambert":case"shader":const t={standard:ie,lambert:ne}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await je(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{p=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),p=Me.get(e.material.shader)}p.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),p=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(p),o&&Se.set(c,p),p.side=e.material.side??p.side??t.FrontSide,p.transparent=(e.material.transparent??l.transparent??!1)||p.transparent,e.material.bloom&&(p.userData.hasBloom=!0),p}async function je(e,t,a,s,r,i,n,o){const c={};for(const[t,l]of Object.entries(e)){const e=await xe(l,a,s,r,i,n,o);null!=e&&(c[t]=e)}return c}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await xe(s,null,null,null);null!=e&&(t[a]=e)}return t}async function xe(e,t,a,i,n,o,c){if(te.String,null==e||null==e.value||""==e.value)return null;const l=e.value;switch(e.type){case te.Number:case te.FloatNode:let h="string"==typeof l?parseFloat(l):l;return e.type===te.FloatNode?x(h):h;case te.Texture:return await a.getTexture(await t.getAsset(l));case te.Sampler2DNode:return N(await a.getTexture(await t.getAsset(l)));case te.Boolean:return l;case te.BooleanNode:return M(l);case te.Vector2:case te.Vec2Node:if("object"==typeof l){const t=l instanceof Array?(new w).fromArray(l):new w(l.x,l.y);return e.type===te.Vec2Node?C(t):t}return null;case te.Vector3:case te.Vec3Node:if("object"==typeof l){const t=l instanceof Array?(new v).fromArray(l):new v(l.x,l.y,l.z);return e.type===te.Vec3Node?k(t):t}return null;case te.Color:case te.RgbNode:const m=new s(l).convertSRGBToLinear();return e.type===te.RgbNode?D(m):m;case te.String:return l;case te.BaseActor:const p=l;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(p);case te.Euler:const d=l;return(new r).fromArray(d);case te.Object3D:return(await a.getMesh(await t.getAsset(l))).scene;case te.Material:return await materialFromAsset(await t.getAsset(l),n,t,a,o);case te.AudioBuffer:return await a.getAudio(await t.getAsset(l));case te.VisualEffect:const f=await t.getAsset(l);if(null==c){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in f)return new ge(c,f);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Ie(e){return"linear"===e.type?new i(new s(e.color),e.near??100,e.far??1e3):"density"===e.type?new n(e.color,e.density):void console.warn("Invalid fog type",e)}const Pe=new p({color:4229780});async function De(e,a,s,i){null==i&&(i=(new ae).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){return t.compose((new v).fromArray(e.position),(new u).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>De(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?te.Number:t instanceof I||"function"==typeof e.prototype.isFloat?te.FloatNode:t instanceof g||e===g||e.isTexture?te.Texture:t instanceof re||e===V?te.Sampler2DNode:t instanceof Boolean||e===Boolean?te.Boolean:t instanceof j?te.BooleanNode:t instanceof s||e==s?te.Color:t instanceof E||"function"==typeof e.prototype.isRgb?te.RgbNode:t instanceof w||e==w?te.Vector2:t instanceof F||"function"==typeof e.prototype.isVec2?te.Vec2Node:t instanceof v||e==v?te.Vector3:t instanceof z||"function"==typeof e.prototype.isVec3?te.Vec3Node:t instanceof String||e===String?te.String:t instanceof se||e==se||e.prototype instanceof se||e.prototype==se?te.BaseActor:t instanceof r||e==r?te.Euler:t instanceof d||e==d?te.Object3D:t instanceof c||e==c?te.Material:t instanceof AudioBuffer||e==AudioBuffer?te.AudioBuffer:t instanceof ge||e==ge?te.VisualEffect:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map((e=>[e.name,{type:toSerializedParamType(e.type),value:t[e.name]?.value??a[e.name]??customParameterDefaultValueByType.get(toSerializedParamType(e.type))}])))}export function prepareCustomParamsFromType(e,t,a=null){const s=_(e);if(0===s.length)return{};let r;null!=a?fe(a,(()=>{r=a.get(e)})):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case w:return t instanceof w?t.toArray():void a();case v:return t instanceof v?t.toArray():void a();case A:return t instanceof A?t.toArray():void a();case s:return t instanceof s?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new s(t).getHexString():void a();case String:return t;case r:return t instanceof r?t.toArray():void a()}}function Ee(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter((e=>Ve(e.materialId))),(t??[]).filter((e=>Ve(e.materialId))),(e=>e.color+e.name))}function Ve(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[te.RgbNode,"#000000"],[te.Color,"#000000"],[te.Vector4,[0,0,0,0]],[te.Vec4Node,[0,0,0,0]],[te.Vector3,[0,0,0]],[te.Vec3Node,[0,0,0]],[te.Vector2,[0,0]],[te.Vec2Node,[0,0]],[te.Euler,[0,0,0,"XYZ"]]]);
|
1
|
+
import{Subject as e}from"rxjs";import*as t from"three";import{BoxGeometry as a,Color as s,Euler as r,Fog as i,FogExp2 as n,Group as o,Material as c,Mesh as l,MeshLambertMaterial as h,MeshPhongMaterial as m,MeshStandardMaterial as d,Object3D as p,PointLight as f,Quaternion as u,SphereGeometry as y,Texture as g,Vector2 as w,Vector3 as v,Vector4 as A}from"three";import S,{SpriteRenderer as b}from"three-nebula";import{bool as M,BooleanNode as j,float as x,FloatNode as I,NodeShaderMaterial as P,rgb as D,RgbNode as V,Texture2dLookupNode as E,textureSampler2d as N,vec2 as C,Vec2Node as F,vec3 as k,Vec3Node as z,vec4 as B}from"three-shader-graph";import O from"../gameplay/actors/builtin/index.js";import{extractShaderParameters as _}from"../shader/parameter.js";import{groupBy as T,ArrayMap as $}from"../utils/collections.js";import{filterChildrenShallow as L,filterSceneShallow as R}from"../utils/three/traverse.js";import{AssetMeshInstance as U}from"./asset-resource-loader.js";import{BoxCollisionShape as H,PhysicalShapeMesh as G}from"./collision/collision-shape.js";import{isCollisionMesh as J}from"./collision/collision-shape-import.js";import{initLandscape as W}from"./landscape/landscape.js";import{LandscapeManager as q}from"./landscape/landscape-manager.js";import{SectionGrid as X,smoothNormalsCrossMeshes as Y}from"./landscape/utils.js";import{createGrassMaterial as Z}from"./materials/grass.js";import{createGrassFoliageMaterial as Q}from"./materials/grass-foliage.js";import{getMaterialAttribute as K}from"./materials/utils/material-painting.js";import{createWaterMaterial as ee}from"./materials/water.js";import{SerializedParamType as te}from"./model.js";import{Matrix4 as ae}from"three";import{BaseActor as se}from"../gameplay/actors/actor.js";import{Sampler2DNode as re}from"../shader-nodes/index.js";import{StandardShader as ie}from"../shader/builtin/standard-shader.js";import{LambertShader as ne}from"../shader/builtin/lambert-shader.js";import{ShapeLibrary as oe,ShapeLibraryKeys as ce}from"./objects/shapes.js";import{ambientLightName as le,createSky as he,defaultSkyMaterial as me}from"./sky.js";import{ActorComponent as de,PhysicsBodyType as pe,withInjectionContext as fe}from"../gameplay/index.js";import{iterateMaterials as ue}from"../utils/materials.js";import{VfxActor as ye}from"../effects/vfx/vfx-actor.js";import{VisualEffect as ge}from"../effects/vfx/vfx-param.js";import{findFirstVisibleObject as we}from"../utils/three/traverse.js";const ve={};export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new SceneMaterializer(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}export class SceneMaterializer{constructor(a,s,r,i,n,o,c,l){this.scene=a,this.dataProvider=s,this.assetsService=r,this.assetManagerService=i,this.renderingView=n,this.shaders=o,this.actorTypes=c,this.actorProvider=l,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.inEditor=!0,this.updated$=new e,this.removed$=new e,this.error$=new e,this.editorActorParamSnapshot=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.originalFog=null,s.onUpdate((e=>this.update(e))),s.onRemove((e=>this.remove(e))),this.updateSubscription=r.onUpdate.subscribe((async e=>{"material"==e.type?a.traverse((a=>{if(a instanceof t.Mesh)if(Array.isArray(a.material))for(let t=0;t<a.material.length;t++)this.refreshMaterial(a,a.material[t],e,t);else this.refreshMaterial(a,a.material,e)})):"mesh"==e.type?(this.findByAssetId(e.id).forEach((t=>{Ve(t.userData.src.materialAssignments,e.materialAssignments).forEach((e=>{this.applyMaterial(t,e)}))})),this.landscapeManagers.forEach((t=>{t.source.grass.layers.some((t=>t.meshes.some((t=>t.assetId===e.id))))&&t.queueRefreshScatter(this.renderingView?.camera.position??new v,!0)}))):"prefab"===e.type&&this.findByAssetId(e.id).forEach((e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}))}))}async refreshMaterial(e,t,a,s){if(t?.userData?.assetId!==a.id)return;const r=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!0);r.userData=t.userData,s?e.material[s]=r:e.material=r}get actorInstances(){return Array.from(this.materializedActors.values())}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter((e=>null!=e.assetId&&"asset_mesh"==e.type)).filter((e=>e.assetId))));await Promise.all(e.map((e=>this.assetsService.getAsset(e.assetId).then((e=>e&&this.assetManagerService.getMesh(e))))))}async init(){this.preInit(),Se.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map((e=>this.materialize(e)))),await this.initActorsPostInit()}initActorsPostInit(e=this.actorInstances){const t=e.map((async e=>{const t=e.object.userData.src;if("vfx"===t.type)return Promise.resolve();const a=await this.assetsService.getAsset(t.assetId),s={...a?.actor?.params??{},...t.actor?.params??{}};for(const a of t.actor.innerParams??[])await this.applyActorComponentParams(e,a.path.slice(),a.params);const r=await je(s,e.constructor,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders,this.actorProvider);Object.assign(e,r);try{return await this.actorProvider.initActor(e)}catch(e){console.error(`Failed to initiate actor (name="${t.name}", id=${t.id})`,e)}}));return Promise.all(t)}addVfxChildActors(e,t=e){for(const a of Object.keys(t))t[a]instanceof ge?null!=t[a].actor&&(console.log("add actor to world",t[a].actor),e.object.add(t[a].actor.object)):t[a]instanceof de&&this.addVfxChildActors(e,t[a])}removeVfxChildActors(e,t=e){for(const a of Object.keys(t))if(t[a]instanceof ge){if(null!=t[a].actor){t[a].actor.onEndPlay(),console.log("remve actor from world",t[a].actor),e.object.remove(t[a].actor.object)}}else t[a]instanceof de&&this.removeVfxChildActors(e,t[a])}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await je(a,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[r]&&await this.applyActorComponentParams(e[r],t,a)}canObjectBeInstanced(e){return e.physics?.type!==pe.dynamic&&"sky"!==e.type&&"global_fog"!==e.type}async canAssetBeInstanced(e){if(!this._canBeInstancedCache.has(e.assetId)){const t=await this.createFromAsset(e);if(null==t)return!1;const a=[];t.traverse((e=>{!J(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=!0;this._canBeInstancedCache.set(e.assetId,s&&r)}return this._canBeInstancedCache.get(e.assetId)}preInit(){this.renderingView?.onLoop((()=>this.sky?.position.copy(this.renderingView.camera.position)))}async initWithInstancing(){this.preInit();const e=new $;for(const t of this.dataProvider.getObjects())await De(t,(async(t,a,s)=>{const r="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t)?t.assetId+JSON.stringify(t.materialAssignments??[]):"other";"other"!==r&&a&&a.children?.length>0&&a.children.splice(a.children.findIndex((e=>e.id===t.id)),1),"other"===r&&a||e.push(r,{...t,parentTransform:s})}));for(const[t,a]of e.entries())if("other"!==t&&a.length>0){const e=await this.createFromAsset(a[0]);if(null==e)continue;const t=await this.createInstancedMesh(a,e),s=new U;s.add(t),s.userData.src=a[0],e instanceof U&&(s.collisionShapes=e.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}else await Promise.all(a.map((e=>this.materialize(e))));await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=we(a,(e=>!J(e)&&null!=e.geometry)),i=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(a,Ve(e[0].materialAssignments,i.materialAssignments)),s.updateMatrix();const n=s.geometry.clone().applyMatrix4(s.matrix),o=new t.InstancedMesh(n,s.material.clone(),e.length);o.material.side=t.FrontSide;for(let a=0;a<e.length;a++){const s=(new t.Matrix4).compose((new v).fromArray(e[a].position),(new u).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new ae).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=i.castShadow??!0,o.receiveShadow=i.receiveShadow??!0,o}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("actor"==e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay(),this.removeVfxChildActors(t)):console.warn("Failed to remove actor",e)}const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter((t=>t.object.userData.src?.id===e.id)).forEach((e=>this.components.splice(this.components.indexOf(e,1)))),this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))})),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex((t=>t.source.id===e.id));if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return R(this.scene,(t=>t.userData.src?.assetId==e),(e=>null!=e.userData.src))}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter((e=>"null"!==e.materialId)).map((t=>this.applyMaterial(e,t))))}applyMaterial(e,a){const r=[];return e.traverse((async e=>{if(e instanceof l||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of ue(e.material))t.hasOwnProperty("color")&&r.push(e)})),Promise.all(r.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const r=e.material[t];if(null==r.color||!(r.color instanceof s))continue;const i="#"+r.color.getHexString(),n=r.name;if(i===a.color&&(r.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await this.assetsService.getAsset(a.materialId),r=e.material[t];s&&(e.material[t]=await materialFromAsset(s,this.renderingView,this.assetsService,this.assetManagerService,this.shaders),e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??i,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??n,this.inEditor&&this._originalMaterials.set(e.id+"#"+t,r))}}else{const t="#"+e.material.color.getHexString(),s=e.material.name;if(t===a.color&&(e.material.name===a.name||null==a.name)||e.userData.originalColor===a.color&&e.userData.originalName===a.name){const r=await this.assetsService.getAsset(a.materialId),i=e.material;r&&(e.material=await materialFromAsset(r,this.renderingView,this.assetsService,this.assetManagerService,this.shaders),e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,this.inEditor&&this._originalMaterials.set(e.id,i))}}})))}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof l)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material}))}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(O));R(this.scene,(e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type))).forEach((async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)}))}updateShaders(e){this.shaders=e;for(const[e,t]of Se.entries())t.userData.customShaderName&&Se.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),R(this.scene,(e=>!0)).forEach((e=>{e.traverse((async e=>{if(e instanceof l)if(Array.isArray(e.material))for(let t=0;t<e.material.length;t++){const a=e.material[t].userData?.customShaderName;if(null!=a){const a=await this.assetsService.getAsset(e.material[t].userData.assetId);this.refreshMaterial(e,e.material[t],a,t)}}else{const t=e.material.userData?.customShaderName;if(null!=t){const t=await this.assetsService.getAsset(e.material.userData.assetId);this.refreshMaterial(e,e.material,t)}}}))}))}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);const t=this.sceneObjectMap.get(e.id);if(t){let r=!1;if(t.traverseAncestors((e=>{"_hology_transform_group"===e.name&&(r=!0)})),!r){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse((e=>{e instanceof l&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof l&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=await this.assetsService.getAsset(e.assetId);Ve(e.materialAssignments,a.materialAssignments).forEach((e=>this.applyMaterial(t,e)))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(r||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type)if("point"==e.light.type){const a=t;a.color=new s(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0)}else"directional"===e.light.type?this.applyDirectionalLight(e.light.directional):"ambient"===e.light.type&&this.applyDirectionalAmbientLight(t,e.light.ambient);else if("landscape"===e.shape)this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>!0))));else if("global_fog"===e.type){const t=(this.scene.fog instanceof n?"density":"linear")!==e.fog.type;this.scene.fog=Ie(e.fog),t&&(a=this.scene).traverse((e=>{if(e instanceof l){const t=e.material;t instanceof P&&(a.fog instanceof i?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof n&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}})),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.editorActorParamSnapshot.get(e.id);null!=t&&t===JSON.stringify(e.actor)||(console.log("Rematerializing actor because parameters changed"),this.remove(e),await this.materializeAndInitActor(e))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof G&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&Ae(t,e.castShadow,e.receiveShadow),e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a}async materializeAndInitActor(e,t=this.findParent(e)){console.log("materialize actor and init");const a=await this.materialize(e,t);return De(e,(async e=>{if("actor"===e.type){const t=this.materializedActors.get(e.id);null!=t?await this.initActorsPostInit([t]):console.error(`Something went wrong when creating actor ${e.id}`)}})),a}findParent(e){const t=this.dataProvider.getObjects().flatMap((t=>t.id===e.id?null:L(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?R(this.scene,(e=>e.userData?.src?.id===t.id),(e=>null!=e.userData?.src))[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new s(this.scene.fog.color).convertSRGBToLinear())}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof l&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=T(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof l){const t=K(e,!1);if(null!=t){for(let e=0;e<t.array.length;e++)t.setX(e,0);t.needsUpdate=!0}}}));const s=new Set;for(const[e,r]of a.entries()){const a=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let i=!1;if(null==a)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const n=K(a,!0);for(let e=0;e<n.array.length;e++)n.setX(e,0);for(const e of r)n.setX(e.i,e.w[0]),n.setY(e.i,e.w[1]),n.setZ(e.i,e.w[2]),i=!0;i&&s.add(e)}this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>s.has(e.name)))))}async materialize(e,t,s=!1){let r;switch(e.type){case"asset_mesh":r=await this.createFromAsset(e);break;case"shape_mesh":r=await this.createFromShape(e);break;case"light":r=await this.createLight(e);break;case"particles":r=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Ie(e.fog),this.fixFogColor(),r=new o;break;case"sky":this.sky=he(),this.updateSky(e),r=this.sky;break;case"actor":r=await this.createFromActor(e);break;case"group":r=new o;break;case"prefab":r=await this.createFromPrefabAsset(e);break;case"vfx":r=await this.createFromVfx(e);break;default:if(this.inEditor)throw new Error("unknown type "+e.type);console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version.`)}if(null!=r){if(e.name&&e.name.length>0&&(r.name=e.name),null!=e.position&&r.position.fromArray(e.position),null!=e.scale&&r.scale.fromArray(e.scale),null!=e.rotation&&r.rotation.fromArray(e.rotation),s||(r.userData.src=e),this.inEditor,this.inEditor){let e=null;r instanceof G&&(e=function(e){if(e instanceof H)return new l(new a(...e.offset.toArray()),Pe);return null}(r.collisionShape)),null!=e&&(e.layers.disable(0),e.layers.enable(18),e.scale.multiplyScalar(1.1),r.add(e))}return this.objectMap.set(r.uuid,e),this.sceneObjectMap.set(e.id,r),e.physics?.type!==pe.dynamic||null==t||this.inEditor?null==t?this.scene.add(r):t?.add(r):(t.add(r),r.getWorldPosition(r.position),r.getWorldQuaternion(r.quaternion),r.getWorldScale(r.scale),this.scene?.attach(r)),null!=e.children&&await Promise.all(e.children?.map((e=>this.materialize(e,r,s)))),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=me);const a=await this.assetsService.getAsset(e.sky.materialId),s=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);s.side=t.BackSide,null!=this.sky?this.sky.material=s:console.warn("No sky has been created")}async createComponent(e,t,a,s){const r=new ve[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e){const t=this.actorTypes.find((t=>t.name===e.actor?.type))?.type??O[e.actor?.type];if(null==t)return null;this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const a=await this.actorProvider.create(t,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!0);return this.materializedActors.set(e.id,a),a?.object}async createFromVfx(e){const t=await this.assetsService.getAsset(e.assetId);null==t&&console.error("Could not find asset",e);const a=await this.actorProvider.create(ye,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!1);return await a.fromAsset(t),a.play(),this.materializedActors.set(e.id,a),a?.object}cleanup(){this.materializedActors.clear()}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e);else{let r=new d({name:"Default",color:new s("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});const i=await this.createMeshByShape(e.shape,r,e.shapeParams);i.castShadow=e.castShadow??!0,i.receiveShadow=e.castShadow??!1,e.collisionDetection||(i.collisionShape=null),i.physics=e.physics,a=i,this._originalMaterials.set(a.id,i.material),a.traverse((e=>{}))}return t||((e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(a,e))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new o;const a=W(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new q(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,(t=>{(e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(t,e)))}));return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new X(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach((e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()})),this.inEditor&&!a||setTimeout((()=>Y(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&ce.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,oe[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,oe[e].collision(s)),new G(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:a}=await this.assetManagerService.getMesh(t);Ve(e.materialAssignments,t.materialAssignments).forEach((e=>this.applyMaterial(a,e)));const s=e.receiveShadow??!!t.receiveShadow??!0,r=e.castShadow??!!t.castShadow??!1;return a.receiveShadow=s,Ae(a,r,s),e.collisionDetection||(a.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(a.physics=e.physics),this.applyVertexMaterials(e,a),a.traverse((e=>{e instanceof l&&"computeBoundsTree"in e.geometry&&e.geometry.computeBoundsTree()})),a}async createFromPrefabAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);const a=new o;return t.prefab.objects.filter((e=>"global_fog"!==e.type)).forEach((e=>this.materialize(e,a,!0))),a}async createParticleSystem(e){const a=await this.assetsService.getAsset(e.assetId),s=new p;return await S.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new b(s,t);e.addRenderer(a),this.renderingView.onLoop((t=>e.update()))})),s}async createLight(e){if("point"===e.light.type){const t=new f(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=new y(.3,10,10),a=new d({color:new s(16771709)}),r=new l(e,a);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional),new o):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient),new o):void 0}applyDirectionalAmbientLight(e,t){const a=this.scene.children.find((e=>e.name===le));null!=a?(a.intensity=t.intensity,a.color.set(t.color),a.groundColor.set(t.color)):console.warn("Couldn't find ambient light")}applyDirectionalLight(e){for(const t of this.renderingView.csm.lights)t.intensity=e.intensity,t.color.set(e.color),t.castShadow=e.castShadow;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function Ae(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Se=new Map,be=new h({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const c=JSON.stringify(e.material);if(o&&Se.has(c))return Se.get(c);const l={opacity:e.material.params.opacity,map:null,emissive:e.material.params.emissive??null,metalness:e.material.params.metalness??0,flatShading:e.material.params.flatShading??!1,color:new s(e.material.params.color).convertSRGBToLinear(),transparent:null!=e.material.params.opacity&&e.material.params.opacity<1},h={};if(null!=e.material.params.map){const t=e.material.params.map,a=await r.getAsset(t);null!=a&&(l.map=await i.getTexture(a))}let d;switch(e.material.type){case"phong":d=new m({...l,...h});break;case"water":d=ee(l,a);break;case"grassFoliage":d=Q({color:l.color,map:l.map},a);break;case"grass":d=Z({...l,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"lambert":case"shader":const t={standard:ie,lambert:ne}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await je(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{d=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),d=Me.get(e.material.shader)}d.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),d=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(d),o&&Se.set(c,d),d.side=e.material.side??d.side??t.FrontSide,d.transparent=(e.material.transparent??l.transparent??!1)||d.transparent,e.material.bloom&&(d.userData.hasBloom=!0),d.userData.assetId=e.id,d}async function je(e,t,a,s,r,i,n,o){const c={};for(const[t,l]of Object.entries(e)){const e=await xe(l,a,s,r,i,n,o);null!=e&&(c[t]=e)}return c}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await xe(s,null,null,null);null!=e&&(t[a]=e)}return t}async function xe(e,t,a,i,n,o,c){if(te.String,null==e||null==e.value||""==e.value)return null;const l=e.value;switch(e.type){case te.Number:case te.FloatNode:let h="string"==typeof l?parseFloat(l):l;return e.type===te.FloatNode?x(h):h;case te.Texture:return await a.getTexture(await t.getAsset(l));case te.Sampler2DNode:return N(await a.getTexture(await t.getAsset(l)));case te.Boolean:return l;case te.BooleanNode:return M(l);case te.Vector2:case te.Vec2Node:if("object"==typeof l){const t=l instanceof Array?(new w).fromArray(l):new w(l.x,l.y);return e.type===te.Vec2Node?C(t):t}return null;case te.Vector3:case te.Vec3Node:if("object"==typeof l){const t=l instanceof Array?(new v).fromArray(l):new v(l.x,l.y,l.z);return e.type===te.Vec3Node?k(t):t}return null;case te.Color:case te.RgbNode:const m=new s(l).convertSRGBToLinear();return e.type===te.RgbNode?D(m):m;case te.String:return l;case te.BaseActor:const d=l;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(d);case te.Euler:const p=l;return(new r).fromArray(p);case te.Object3D:return(await a.getMesh(await t.getAsset(l))).scene;case te.Material:return await materialFromAsset(await t.getAsset(l),n,t,a,o);case te.AudioBuffer:return await a.getAudio(await t.getAsset(l));case te.VisualEffect:const f=await t.getAsset(l);if(null==c){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in f)return new ge(c,f);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Ie(e){return"linear"===e.type?new i(new s(e.color),e.near??100,e.far??1e3):"density"===e.type?new n(e.color,e.density):void console.warn("Invalid fog type",e)}const Pe=new d({color:4229780});async function De(e,a,s,i){null==i&&(i=(new ae).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){return t.compose((new v).fromArray(e.position),(new u).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>De(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?te.Number:t instanceof I||"function"==typeof e.prototype.isFloat?te.FloatNode:t instanceof g||e===g||e.isTexture?te.Texture:t instanceof re||e===E?te.Sampler2DNode:t instanceof Boolean||e===Boolean?te.Boolean:t instanceof j?te.BooleanNode:t instanceof s||e==s?te.Color:t instanceof V||"function"==typeof e.prototype.isRgb?te.RgbNode:t instanceof w||e==w?te.Vector2:t instanceof F||"function"==typeof e.prototype.isVec2?te.Vec2Node:t instanceof v||e==v?te.Vector3:t instanceof z||"function"==typeof e.prototype.isVec3?te.Vec3Node:t instanceof String||e===String?te.String:t instanceof se||e==se||e.prototype instanceof se||e.prototype==se?te.BaseActor:t instanceof r||e==r?te.Euler:t instanceof p||e==p?te.Object3D:t instanceof c||e==c?te.Material:t instanceof AudioBuffer||e==AudioBuffer?te.AudioBuffer:t instanceof ge||e==ge?te.VisualEffect:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map((e=>[e.name,{type:toSerializedParamType(e.type),value:t[e.name]?.value??a[e.name]??customParameterDefaultValueByType.get(toSerializedParamType(e.type))}])))}export function prepareCustomParamsFromType(e,t,a=null){const s=_(e);if(0===s.length)return{};let r;null!=a?fe(a,(()=>{r=a.get(e)})):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case w:return t instanceof w?t.toArray():void a();case v:return t instanceof v?t.toArray():void a();case A:return t instanceof A?t.toArray():void a();case s:return t instanceof s?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new s(t).getHexString():void a();case String:return t;case r:return t instanceof r?t.toArray():void a()}}function Ve(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter((e=>Ee(e.materialId))),(t??[]).filter((e=>Ee(e.materialId))),(e=>e.color+e.name))}function Ee(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[te.RgbNode,"#000000"],[te.Color,"#000000"],[te.Vector4,[0,0,0,0]],[te.Vec4Node,[0,0,0,0]],[te.Vector3,[0,0,0]],[te.Vec3Node,[0,0,0]],[te.Vector2,[0,0]],[te.Vec2Node,[0,0]],[te.Euler,[0,0,0,"XYZ"]]]);
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|