@hology/core 0.0.62 → 0.0.64
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.d.ts +4 -0
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/camera/third-party-camera-component.d.ts +1 -0
- package/dist/gameplay/actors/camera/third-party-camera-component.js +1 -1
- package/dist/gameplay/ai/dynamic-tiled-navmesh.d.ts +3 -1
- package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
- package/dist/gameplay/ai/navigation.js +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +1 -1
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +9 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/collision/collision-shape.d.ts +1 -0
- package/dist/scene/materializer.js +1 -1
- package/package.json +4 -3
- package/tsconfig.tsbuildinfo +1 -1
@@ -25,6 +25,8 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
25
25
|
minSlopeSlideAngle: number;
|
26
26
|
maxSlopeClimbAngle: number;
|
27
27
|
applyImpulsesToDynamicBodies: boolean;
|
28
|
+
/** Collide with other characters */
|
29
|
+
characterCollision: boolean;
|
28
30
|
get autoStepMinWidth(): number;
|
29
31
|
set autoStepMinWidth(minWidth: number);
|
30
32
|
get autoStepDynamicObjects(): boolean;
|
@@ -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 a,Vector3 as c,ArrowHelper as l}from"three";import{ActorComponent as h,Component as p}from"../../../component.js";import{CharacterMovementMode as m}from"./modes.js";import{CapsuleCollisionShape as d}from"../../../../../scene/collision/collision-shape.js";import{takeUntil as u}from"rxjs";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import{RootMotionClip as
|
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 a,Vector3 as c,ArrowHelper as l}from"three";import{ActorComponent as h,Component as p}from"../../../component.js";import{CharacterMovementMode as m}from"./modes.js";import{CapsuleCollisionShape as d}from"../../../../../scene/collision/collision-shape.js";import{takeUntil as u}from"rxjs";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import g from"@dimforge/rapier3d-compat";import{RootMotionClip as f}from"../../../../../gameplay/animation/root-motion.js";import*as S from"three";const v=new c,w=new c,A=1/30,M=-131071;let x=class extends h{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()}set normalNudgeFactor(t){this.cc.setNormalNudgeFactor(t)}get normalNudgeFactor(){return this.cc.normalNudgeFactor()}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=a.degToRad(70),this.maxSlopeClimbAngle=a.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.characterCollision=!1,this.velocity=new c,this.mode=m.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:!1,friction:0,restitution:.5,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation);let i=this.rotationInput.rotation.y;const e=new c,o=new c,s=new c,n=new c,r=new c,l=new c;let h=0,p=null;const d=new c,g=new c,x=new c,T=new c,b=this.characterCollision?null:M;this.physicsSystem.beforeStep.pipe(u(this.disposed)).subscribe((u=>{if(this.checkGrounded(u),null!=this.rootMotionAction){if(this.rootMotionAction.getClip()instanceof f){const t=this.rootMotionInterpolant;this.resetRootMotion&&(d.fromArray(t.evaluate(0)),this.resetRootMotion=!1),T.fromArray(t.evaluate(this.rootMotionAction.time)),g.subVectors(T,d),d.copy(T),this.rootMotionAction.getRoot().getWorldScale(x),g.multiply(x)}}u>A&&(u=A);const y=null!=this.rootMotionAction&&this.rootMotionAction.enabled&&0!=g.length();this.pressedJump=this.jumpInput.activated,this.isSprinting=this.sprintInput.activated&&this.directionInput.vertical>=0;let M=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 j=n.z<0?this.maxSpeedBackwards:this.isSprinting?this.maxSpeedSprint:this.maxSpeed;if(l.copy(n).applyAxisAngle(I,this.rotationInput.rotation.y),this.mode===m.walking?(0!==l.length()?(h=Math.min(j,h),h=a.lerp(h,j,4*u)):h=0,r.copy(l).multiplyScalar(h),this.pressedJump&&(this.mode=m.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),r.y=.016*this.getEffectiveGravity()):this.mode===m.falling&&(this.pressedJump&&this.jumpInAir&&(this.mode=m.falling,this.velocity.copy(r),this.velocity.y=this.jumpVelocity),this.velocity.y+=u*this.getEffectiveGravity(),r.copy(this.velocity),r.add(l.clone().multiplyScalar(j*this.fallingMovementControl*u)),this.fallingReorientation&&r.applyAxisAngle(new c(0,1,0),-M)),o.copy(r).normalize(),e.copy(r),this.actor.rotation.y-=M,r.length(),y?(g.applyAxisAngle(I,this.actor.rotation.y),g.y+=u*this.getEffectiveGravity(),v.copy(g)):v.copy(r).multiplyScalar(u),this.isGrounded&&this.mode===m.walking&&(this.rayTestResult.distance>t.offset()||(v.y=0),this.physicsSystem.getActorComputedMovement(this.actor,t,v,b),t.computedCollision(0,R),null!=R&&null!=R.normal1)){const i=(new S.Vector3).copy(R.normal1);Math.acos(i.dot(I))>t.maxSlopeClimbAngle()&&(v.y=.016*this.getEffectiveGravity()*.5)}w.copy(this.physicsSystem.getActorComputedMovement(this.actor,t,v,b)),this.physicsSystem.setNextKinematicTranslation(this.actor,w);let G=function(t){if(t.numComputedCollisions()>0){const i=t.computedCollision(0);C.x=i.normal2.x,C.y=i.normal2.y,C.z=i.normal2.z;const e=C.angleTo(I);C.x=i.normal1.x,C.y=i.normal1.y,C.z=i.normal1.z;const o=C.angleTo(I);return!(e<100)&&o>t.minSlopeSlideAngle()}return!1}(t);y||this.isGrounded&&!G||this.mode!==m.falling&&(null==p?p=performance.now():performance.now()-p>100&&(this.mode=m.falling,this.velocity.copy(e))),this.isGrounded&&this.velocity.y<=0&&(this.mode,m.falling,this.mode=m.walking,this.velocity.y=0,p=null),this.mode,m.walking,this.horizontalSpeed=h}))}debugDirection(){const t=new l(v,this.actor.position,1,65280);this.actor.object.parent.add(t),setTimeout((()=>{t.removeFromParent()}),30);const i=new l(w,this.actor.position,1,16711680);this.actor.object.parent.add(i),setTimeout((()=>{i.removeFromParent()}),30)}setRootMotionAction(t){const i=t?.getClip();if(i instanceof f){this.rootMotionAction=t,this.resetRootMotion=!0;const e=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(e)}}getWallDirection(t,i){const e=t.clone().negate().cross(I);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){this.colliderHeight,this.colliderRadius;G.y=-.05,this.physicsSystem.rayTest(T.addVectors(this.actor.position,j.set(0,this.offset,0)),b.addVectors(this.actor.position,G),this.rayTestResult,{excludeActor:this.actor,excludeTriggers:!0})}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}createCollisionShape(){const t=new d(this.colliderHeight,this.colliderRadius);return t.offset.y=this.colliderRadius+this.colliderHeight/2+this.offset,t.collisionGroup=M,t}step(t){}performMovement(t){}};x=t([p({inEditor:!1}),i("design:paramtypes",[n])],x);export{x as CharacterMovementComponent};const I=new c(0,1,0),C=new c;const T=new c,b=new c,j=new c(0,1,0),G=new c(0,-.1,0),R=(new c(0,-1,0),new g.CharacterCollision);
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -1,8 +1,12 @@
|
|
1
1
|
import { BaseActor } from "../../";
|
2
2
|
import { NavMesh } from 'recast-navigation';
|
3
|
+
export type NavMeshLoader = {
|
4
|
+
save(): any;
|
5
|
+
};
|
3
6
|
declare class NavMeshActor extends BaseActor {
|
4
7
|
private physics;
|
5
8
|
private view;
|
9
|
+
private world;
|
6
10
|
debug: boolean;
|
7
11
|
refreshMs: number;
|
8
12
|
tileSize: number;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{Ball as o,Capsule as
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Ball as o,Capsule as s,Cone as n,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-compat";import{Actor as p,BaseActor as d,Parameter as u,PhysicsSystem as m,ViewController as f,World as g,inject as w}from"../../";import{init as b}from"@recast-navigation/core";import{DebugDrawer as y,getPositionsAndIndices as x}from"@recast-navigation/three";import*as v from"three";import{DynamicTiledNavMesh as B}from"../../ai/dynamic-tiled-navmesh";import{BufferGeometryUtils as M,ConvexHull as S}from"three/examples/jsm/Addons.js";const k=new v.Box3(new v.Vector3(-1e3,-200,-1e3),new v.Vector3(1e3,200,1e3));let z=!1,A=class extends d{constructor(){super(...arguments),this.physics=w(m),this.view=w(f),this.world=w(g),this.debug=!0,this.refreshMs=1e3,this.tileSize=16,this.cellSize=.2,this.walkableClimb=1,this.walkableSlopeAngle=45,this.walkableRadius=.5,this.walkableHeight=1}async onInit(){z||(await b(),z=!0),this.init()}init(){const e={tileSize:400,walkableClimb:this.walkableClimb,walkableSlopeAngle:45,walkableRadius:2,walkableHeight:5,detailSampleDist:1,minRegionArea:6,mergeRegionArea:400,cs:.2,ch:.2,maxSimplificationError:1.3,maxEdgeLen:200},t=(new v.Box3,new B({navMeshBounds:k,recastConfig:e,maxTiles:16384,workers:1,cacheId:"nav"+this.object.userData?.src?.id}));this.navMesh=t.navMesh,this.object.position.set(0,0,0);const o=this.tileSize*e.cs*2,s=performance.now(),n=new Map,i=new y;let r=t.navMesh;const a=()=>{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)),s=[],i=this.physics.world.bodies,r=new v.Box3;for(const e of i.getAll())for(let o=0,i=e.numColliders();o<i;o++){const i=(e.userData??e.handle)+","+o,a=e.collider(o);if(a.isSensor()||null!=a.parent().userData&&!0===a.parent().userData.ignoreForNavMesh)continue;const l=n.get(i)?.mesh;l||console.log("Not cached",a);const c=l??C(a);if(F(a,c),null!=c){r.copy(c.geometry.boundingBox),r.min.add(c.position),r.max.add(c.position);const e=r.intersectsBox(t)||!0;n.set(i,{pos:a.translation(),mesh:c}),e&&s.push(c)}}return s},l=new v.Box3,c=new Map,h=new Map;let p=!0;const d=setInterval((()=>{const e=new v.Box3,o=a();for(const t of o){const o=c.get(t);!0!==o?.equals(t.position)&&(null!=o&&e.expandByPoint(o),e.expandByObject(t),c.set(t,t.position.clone()))}const s=t.getTilesForBounds(e);if(0!=s.length){const n=[];for(const t of o)l.setFromObject(t),l.intersect(e)&&n.push(t);console.log("tiles to update ",s),console.log("intersecting meshes",n.length);const[r,a]=x(n),c=p;p=!1,Promise.all(s.map((e=>t.buildTile(r,a,e,c).then((()=>{const t=e[0]+","+e[1];h.set(t,(h.get(t)??0)+1),this.debug}))))).then((()=>{this.debug&&(i.clear(),i.drawNavMesh(t.navMesh))}))}}),this.refreshMs??1e4);this.disposed.subscribe((()=>clearInterval(d))),console.log("create with debug",this.debug),this.debug,this.debug&&this.object.parent.add(i),this.disposed.subscribe((()=>{r?.destroy(),i.removeFromParent(),i.dispose()}));const u=performance.now()-s;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)],A.prototype,"debug",void 0),e([u(),t("design:type",Number)],A.prototype,"refreshMs",void 0),e([u(),t("design:type",Number)],A.prototype,"tileSize",void 0),e([u(),t("design:type",Number)],A.prototype,"cellSize",void 0),e([u(),t("design:type",Number)],A.prototype,"walkableClimb",void 0),e([u({range:[0,89]}),t("design:type",Number)],A.prototype,"walkableSlopeAngle",void 0),e([u(),t("design:type",Number)],A.prototype,"walkableRadius",void 0),e([u(),t("design:type",Number)],A.prototype,"walkableHeight",void 0),A=e([p()],A);export default A;function N(e){if(e.shape instanceof l)return function(e){const t=e.shape;if(t.type!==c.HeightField)throw new Error("The provided collider is not a height field.");let o=!1;const s=t,n=s.heights,i=s.nrows,r=s.ncols,a=s.scale.x,l=s.scale.z,h=s.scale.y,p=i+1,d=new v.PlaneGeometry(l,a,r,i);d.rotateX(-Math.PI/2);const u=d.attributes.position.array;let m=0;for(let e=0;e<p;e++)for(let t=0;t<p;t++)u[m+1]=n[t*p+e]*h,m+=3,0!=u[m+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 i)return function(e){const t=[];for(let o=0;o<e.length;o+=3)t.push(new v.Vector3(e[o],e[o+1],e[o+2]));const o=(new S).setFromPoints(t),s=[];o.faces.forEach((e=>{const t=e.edge.head().point,o=e.edge.next.head().point,n=e.edge.next.next.head().point;s.push(t.x,t.y,t.z),s.push(o.x,o.y,o.z),s.push(n.x,n.y,n.z)}));const n=new v.BufferGeometry;return n.setAttribute("position",new v.Float32BufferAttribute(s,3)),n}(e.shape.vertices);if(e.shape instanceof h){const t=e.shape.vertices,o=e.shape.indices;let s=new v.BufferGeometry;return s.setAttribute("position",new v.Float32BufferAttribute(t,3)),null!=o?s.setIndex(new v.Uint16BufferAttribute(o,1)):s=M.mergeVertices(s),s.computeVertexNormals(),s}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 s){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 C(e){const t=N(e);if(null==t)return null;const o=new v.MeshBasicMaterial({wireframe:!1,color:16711680,side:v.FrontSide}),s=new v.Mesh(t,o);return s.geometry.computeBoundingBox(),s.geometry.scale(1.01,1.01,1.01),s}function F(e,t){const o=e.translation(),s=e.rotation();t.position.set(o.x,o.y,o.z),t.quaternion.set(s.x,s.y,s.z,s.w)}
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -28,6 +28,7 @@ export declare class ThirdPartyCameraComponent extends ActorComponent {
|
|
28
28
|
constructor(viewController: ViewController, physicsSystem: PhysicsSystem);
|
29
29
|
isMouseLocked: boolean;
|
30
30
|
onInit(): Promise<void>;
|
31
|
+
activate(): void;
|
31
32
|
onLateUpdate(deltaTime: number): void;
|
32
33
|
private get element();
|
33
34
|
private canvas;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{__decorate as t,__metadata as s}from"tslib";import{ActorComponent as e,Component as i,attach as o}from"../component.js";import{CameraComponent as n}from"./camera-component.js";import{Vector3 as a,MathUtils as h}from"three";import{ViewController as c}from"../../services/render.js";import{DecimalInput as r,RestrictedRotationInput as m}from"../../input/index.js";import{PhysicsSystem as d,RayTestResult as l}from"../../services/physics/physics-system.js";let u=class extends e{constructor(t,s){super(),this.viewController=t,this.physicsSystem=s,this.camera=o(n),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=5,this.collisionCheckRadius=.5,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new m(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new r(1,0,1),this.offset=new a,this.lookAtOffset=new a(this.offsetX,0,this.offsetZ),this.isMouseLocked=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{null!=document.pointerLockElement||null!=document.mozPointerLockElement||this.showCursor()}}async onInit(){this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.autoActivate&&this.viewController.setCamera(this.camera.instance);const t=this.element;null!=document.body.requestPointerLock&&(t.addEventListener("mousedown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.disposed.subscribe((()=>{t.removeEventListener("mousedown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1)})))}onLateUpdate(t){this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){"ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0||null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&(this.canvas.requestPointerLock(),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.checkForCollision(t);const s=h.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*this.zoomInput.value,this.minDistance)),e=Math.cos(this.rotationInput.rotation.x)*s;this.offset.x=Math.sin(this.rotationInput.rotation.y)*e,this.offset.y=Math.sin(this.rotationInput.rotation.x)*s+2,this.offset.z=Math.cos(this.rotationInput.rotation.y)*-e,this.offset.add(this.lookAtOffset),this.updateCameraPosition()}checkForCollision(t){const s=this.getLookAtPosition(),e=f;let i=!1,o=this.distance;const n=new l,a=this.camera.instance.getWorldPosition(w);for(let t=-1;t<=1;t++){const h=k.subVectors(a,s);e.copy(a).add(h.multiplyScalar(1.2)),e.x+=t*this.collisionCheckRadius,this.physicsSystem.rayTest(s,e,n,{debugLifetime:0,excludeActor:this.actor,excludeTriggers:!0}),n.hasHit&&n.distance<this.distance&&(o=Math.min(n.distance,o),i||=n.hasHit)}i||(this.restrictedDistance=h.lerp(this.restrictedDistance,this.distance,h.clamp(this.bounceBackSpeed*t,0,1)))}getLookAtPosition(){const t=p;return t.set(0,0,0),t.y=this.height,t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(){this.camera.instance.position.copy(this.offset);const t=this.getLookAtPosition();this.camera.instance.lookAt(t)}};u=t([i(),s("design:paramtypes",[c,d])],u);export{u as ThirdPartyCameraComponent};const p=new a,f=new a,k=(new a,new a),w=new a;
|
1
|
+
import{__decorate as t,__metadata as s}from"tslib";import{ActorComponent as e,Component as i,attach as o}from"../component.js";import{CameraComponent as n}from"./camera-component.js";import{Vector3 as a,MathUtils as h}from"three";import{ViewController as c}from"../../services/render.js";import{DecimalInput as r,RestrictedRotationInput as m}from"../../input/index.js";import{PhysicsSystem as d,RayTestResult as l}from"../../services/physics/physics-system.js";let u=class extends e{constructor(t,s){super(),this.viewController=t,this.physicsSystem=s,this.camera=o(n),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=5,this.collisionCheckRadius=.5,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new m(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new r(1,0,1),this.offset=new a,this.lookAtOffset=new a(this.offsetX,0,this.offsetZ),this.isMouseLocked=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{null!=document.pointerLockElement||null!=document.mozPointerLockElement||this.showCursor()}}async onInit(){this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.autoActivate&&this.activate()}activate(){this.viewController.setCamera(this.camera.instance);const t=this.element;null!=document.body.requestPointerLock&&(t.addEventListener("mousedown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.disposed.subscribe((()=>{t.removeEventListener("mousedown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1)})))}onLateUpdate(t){this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){"ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0||null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&(this.canvas.requestPointerLock(),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.checkForCollision(t);const s=h.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*this.zoomInput.value,this.minDistance)),e=Math.cos(this.rotationInput.rotation.x)*s;this.offset.x=Math.sin(this.rotationInput.rotation.y)*e,this.offset.y=Math.sin(this.rotationInput.rotation.x)*s+2,this.offset.z=Math.cos(this.rotationInput.rotation.y)*-e,this.offset.add(this.lookAtOffset),this.updateCameraPosition()}checkForCollision(t){const s=this.getLookAtPosition(),e=f;let i=!1,o=this.distance;const n=new l,a=this.camera.instance.getWorldPosition(w);for(let t=-1;t<=1;t++){const h=k.subVectors(a,s);e.copy(a).add(h.multiplyScalar(1.2)),e.x+=t*this.collisionCheckRadius,this.physicsSystem.rayTest(s,e,n,{debugLifetime:0,excludeActor:this.actor,excludeTriggers:!0}),n.hasHit&&n.distance<this.distance&&(o=Math.min(n.distance,o),i||=n.hasHit)}i||(this.restrictedDistance=h.lerp(this.restrictedDistance,this.distance,h.clamp(this.bounceBackSpeed*t,0,1)))}getLookAtPosition(){const t=p;return t.set(0,0,0),t.y=this.height,t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(){this.camera.instance.position.copy(this.offset);const t=this.getLookAtPosition();this.camera.instance.lookAt(t)}};u=t([i(),s("design:paramtypes",[c,d])],u);export{u as ThirdPartyCameraComponent};const p=new a,f=new a,k=(new a,new a),w=new a;
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -6,6 +6,7 @@ export type DynamicTiledNavMeshProps = {
|
|
6
6
|
recastConfig: Partial<RecastConfig>;
|
7
7
|
maxTiles: number;
|
8
8
|
workers: number;
|
9
|
+
cacheId: string;
|
9
10
|
};
|
10
11
|
export declare class DynamicTiledNavMesh {
|
11
12
|
navMesh: NavMesh;
|
@@ -21,9 +22,10 @@ export declare class DynamicTiledNavMesh {
|
|
21
22
|
recastConfig: RecastConfig;
|
22
23
|
workers: InstanceType<any>[];
|
23
24
|
workerRoundRobin: number;
|
25
|
+
private cacheId;
|
24
26
|
constructor(props: DynamicTiledNavMeshProps);
|
25
27
|
private onResult;
|
26
|
-
buildTile(positions: Float32Array, indices: Uint32Array, [tileX, tileY]: [x: number, y: number]): Promise<unknown>;
|
28
|
+
buildTile(positions: Float32Array, indices: Uint32Array, [tileX, tileY]: [x: number, y: number], useTileCache?: boolean): Promise<unknown>;
|
27
29
|
buildAllTiles(positions: Float32Array, indices: Uint32Array): void;
|
28
30
|
getTileForWorldPosition(worldPosition: THREE.Vector3): [x: number, y: number];
|
29
31
|
getTilesForBounds(bounds: THREE.Box3): [x: number, y: number][];
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{NavMesh as
|
1
|
+
import{NavMesh as t,NavMeshParams as s,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,this.cacheId=e.cacheId;const d={...n,...e.recastConfig};this.recastConfig=d;const c=new t,{tileWidth:u,tileHeight:M,tcs:v,maxPolysPerTile:f}=a({recastConfig:d,navMeshBounds:h});this.tileWidth=u,this.tileHeight=M,this.tcs=v;const m=s.create({orig:l,tileWidth:d.tileSize*d.cs,tileHeight:d.tileSize*d.ch,maxTiles:e.maxTiles,maxPolys:f});c.initTiled(m),this.navMesh=c,this.workers=[]}onResult(t){const{tileX:s,tileY:n,navMeshData:a}=t.data,h=new i;h.copy(a),this.navMesh.removeTile(this.navMesh.getTileRefAt(s,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: ${s}, ty: ${n},status: ${o(r.status)} (${r.status})`),h.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[s,n]])}buildTile(t,s,[e,i],n=!0){const o=new Float32Array(t),a=new Uint32Array(s),r={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:o,indices:a};return this.workerRoundRobin=(this.workerRoundRobin+1)%this.workers.length,new Promise((t=>{requestIdleCallback((()=>{const s=this.cacheId+JSON.stringify({tileX:r.tileX,tileY:r.tileY});if(n){const e=localStorage.getItem(s);if(null!=e){const s=d(e);return this.onResult({data:{tileX:r.tileX,tileY:r.tileY,navMeshData:s}}),void t({})}}else localStorage.removeItem(s);const e=h(r);if(!e.success||!e.data)return;const i=e.data.toTypedArray();localStorage.setItem(s,l(i)),this.onResult({data:{tileX:r.tileX,tileY:r.tileY,navMeshData:i}}),t(e)}))}))}buildAllTiles(t,s){const{tileWidth:e,tileHeight:i}=this;for(let n=0;n<i;n++)for(let i=0;i<e;i++)this.buildTile(t,s,[i,n])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){const s=this.getTileForWorldPosition(t.min),e=this.getTileForWorldPosition(t.max),i=[];for(let t=s[1];t<=e[1];t++)for(let n=s[0];n<=e[0];n++)i.push([n,t]);return i}destroy(){this.navMesh.destroy();for(const t of this.workers)t.terminate()}}const l=function(t){return btoa(String.fromCharCode(...t))},d=function(t){if(!t)return null;const s=atob(t),e=s.length,i=new Uint8Array(e);for(let t=0;t<e;t++)i[t]=s.charCodeAt(t);return i};
|
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{Service as s,World as n,inject as r}from"../";import o from"../actors/builtin/navmesh-actor";import{NavMeshQuery as
|
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{init as i,NavMeshQuery as a}from"recast-navigation";import{Vector3 as c}from"three";let h=class{constructor(){this.world=r(n),i().then((()=>{const t=this.world.actors.find((t=>t instanceof o));null!=t&&(this.navMeshActor=t,this.query=new a(t.navMesh)),this.world.actorAdded.subscribe((t=>{t instanceof o&&(this.navMeshActor=t,this.query=new a(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"),l;const{success:s,error:n,path:r}=this.query.computePath(t,e);return s?{success:!0,path:r.map((t=>new c(t.x,t.y,t.z)))}:(console.warn("Failed to generate path",n),l)}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 c(s.x,s.y,s.z):null}};h=t([s(),e("design:paramtypes",[])],h);export{h as Navigation};const l={success:!1,path:[]};
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -85,7 +85,7 @@ export declare class PhysicsSystem {
|
|
85
85
|
private createForInstancedMesh;
|
86
86
|
private readonly controlledActors;
|
87
87
|
getCharacterController(offset?: number): RAPIER.KinematicCharacterController;
|
88
|
-
getActorComputedMovement(actor: BaseActor, cc: RAPIER.KinematicCharacterController, desiredTranslation: Vector3): Vector3;
|
88
|
+
getActorComputedMovement(actor: BaseActor, cc: RAPIER.KinematicCharacterController, desiredTranslation: Vector3, collisionGroup?: number): Vector3;
|
89
89
|
setNextKinematicTranslation(actor: BaseActor, vel: Vector3): void;
|
90
90
|
setAngularVelocity(actor: BaseActor, velocity: Vector3): void;
|
91
91
|
setLinearVelocity(actor: BaseActor, velocity: Vector3): void;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{__decorate as e,__metadata as t}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 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 I}from"../world.js";import*as P from"three/examples/jsm/utils/BufferGeometryUtils.js";import{calculateEffectiveScale as L}from"../../../utils/three/traverse.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.hitNormal=new B}}export var PhysicsBodyType;!function(e){e[e.dynamic=1]="dynamic",e[e.static=2]="static",e[e.kinematic=4]="kinematic",e[e.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));let j=class{set showDebug(e){this.shouldRenderDebug=e,this.debugMesh&&(this.debugMesh.visible=e)}get showDebug(){return this.shouldRenderDebug}constructor(e,t){this.viewController=e,this.gameWorld=t,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 e=this.world.debugRender();this.debugMesh.geometry.setAttribute("position",new u(e.vertices,3))}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await K(),this.eventQueue=new i.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe((e=>{e=Math.min(.1,e),this.beforeStep.next(e),this.updatePhysics(e),this.afterStep.next(e),this.showDebug&&this.renderDebug(),this.world.bodies.forEach((e=>{if(e.isFixed())return;const t=this.staticMeshes.get(e)??this.bodyActors.get(e)?.object;var i,s;null!=t&&(t.parent instanceof b&&(J(t.position,e.translation()),(e.isDynamic()||e.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(e)?.id))&&(i=t.quaternion,s=e.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(e){this.world.timestep=e,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents(((e,t,i)=>{this.collisionEvents.next({handle1:e,handle2:t,started:i}),this.collisionEvents.next({handle1:t,handle2:e,started:i})}))}rayTestFromCamera(e,t,i){this._raycaster.setFromCamera(U,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(e).add(s);return this.rayTest(s,o,t,i)}rayTest(e,t,s,o){null==s&&(s=this._reusableResult);const n=this._raytestDiff,r=this._raytestDirection;if(n.subVectors(t,e),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(e,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,o?.excludeTriggers?e=>!e.isSensor():void 0);if(s.hasHit=null!=l,s.hasHit){const t=a.pointAt(l.timeOfImpact);s._internal=l,J(s.hitNormal,l.normal),J(s.hitPoint,t),s.distance=Z.subVectors(s.hitPoint,e).length();const i=this.world.bodies.getAll().find((e=>function(e,t){for(let i=0,s=e.numColliders();i<s;i++){const s=e.collider(i);if(t(s))return s}}(e,(e=>e===l.collider))));s.actor=null!=i?this.bodyActors.get(i):null}if(this.showDebug){const t=new h(r,e,c,o?.debugColor??255);this.gameWorld.scene.add(t),setTimeout((()=>this.gameWorld.scene.remove(t)),o?.debugLifetime??200)}return this._reusableResult}setGravity(e,t,i){this.world.gravity.x=e,this.world.gravity.y=t,this.world.gravity.z=i}getGravity(){return q.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(e){this.addRecursively(e);for(const e of this.staticBodies.values())Y(e,(e=>e.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)))}addRecursively(e){if(this.removeSceneObject(e),!function(e){if(null!=e.userData?.src){const t=e.userData?.src;return"actor"===t.type}return!1}(e))if(e instanceof S&&null!=e.collisionShape){const t=this.createStaticBody(e,[e.collisionShape],e.physics);this.staticMeshes.set(t,e),this.staticBodies.set(e,t)}else if(e instanceof C&&!1!==e.userData?.src?.collisionDetection)if(e.children[0]&&e.children[0].instanceMatrix)this.createForInstancedMesh(e.children[0],e.collisionShapes);else{const t=this.createStaticBody(e,e.collisionShapes,e.physics);this.staticMeshes.set(t,e),this.staticBodies.set(e,t)}else e instanceof _?this.addLandscapeGroup(e):(e instanceof p||e instanceof b)&&e.children.forEach((e=>this.addRecursively(e)))}createForInstancedMesh(e,t){const i=new m;for(let s=0;s<e.count;s++){const o=new w;o.matrix.identity(),i.fromArray(e.instanceMatrix.array,16*s),o.applyMatrix4(i);this.createStaticBody(o,t)}}getCharacterController(e=.01){return this.world?.createCharacterController(e)}getActorComputedMovement(e,t,i){const o=this.actorBodies.get(e.id);this.controlledActors.add(e.id);const n=o.collider(0);t.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,null,ee);const r=t.computedMovement();return J($,r),$}setNextKinematicTranslation(e,t){const i=this.actorBodies.get(e.id),s=i.translation();s.x+=t.x,s.y+=t.y,s.z+=t.z,i?.setNextKinematicTranslation(s)}setAngularVelocity(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.setAngvel(G,!0)}setLinearVelocity(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.setLinvel(G,!0)}getLinearVelocity(e,t=new B){const i=this.actorBodies.get(e.id).linvel();return t.x=i.x,t.y=i.y,t.z=i.z,t}getAngularVelocity(e,t=new B){const i=this.actorBodies.get(e.id).angvel();return t.x=i.x,t.y=i.y,t.z=i.z,t}setLinearDamping(e,t){const i=this.actorBodies.get(e.id);i?.setLinearDamping(t)}setAngularDamping(e,t){const i=this.actorBodies.get(e.id);i?.setAngularDamping(t)}createCharacterCollision(){return new i.CharacterCollision}addLandscapeGroup(e){const t=e.userData.src,s=t.landscape.heightMaps;for(const n of e.sections){this.staticBodies.has(n)&&this.world.removeRigidBody(this.staticBodies.get(n));const e=t.landscape.options.density+1,r=t.landscape.options.sectionSize,a=new Array(e);for(let t=0;t<e;t++)a[t]=new Array(e).fill(0);const c=s.find((e=>e.x===n.x&&e.y==n.y));if(null!=c)for(const t of c.points){if(null==a[t.i%e])continue;const i=e-1-Math.floor(t.i/e);i in a[t.i%e]?a[t.i%e][i]=t.y/r:console.warn("wrong index",{points:a,point:t,i:t.i%e,k:i,heightMap:c})}const l=t.landscape.options.density,d=a.flatMap((e=>e.reverse())),h=i.ColliderDesc.heightfield(l,l,new Float32Array(d),new i.Vector3(r,r,r));var o=n.getWorldPosition(new B);if(!1!==t.collisionDetection){const e=this.world.createRigidBody(i.RigidBodyDesc.fixed()),t=new i.Vector3(0,0,0);X(t,o),e.setTranslation(t,!1),this.world.createCollider(h,e),this.staticBodies.set(n,e)}}}addActor(e,t,s={}){if(0==t.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(e);const o=e.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():i.RigidBodyDesc.fixed()}const r=this.world.createRigidBody(n);r.enableCcd(1==s.continousCollisionDetection);for(const e of t)this.addShape(r,e,o);Y(r,(e=>{null!=s.isTrigger&&(e.setSensor(s.isTrigger),e.setActiveCollisionTypes(i.ActiveCollisionTypes.ALL),e.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)),null!=s.friction&&e.setFriction(s.friction),null!=s.density&&e.setDensity(s.density),null!=s.mass&&e.setMass(s.mass),null!=s.restitution&&e.setRestitution(s.restitution)})),N(r,o),!0===s.ignoreForNavMesh&&(r.userData={ignoreForNavMesh:!0}),this.actorBodies.set(e.id,r),this.bodyActors.set(r,e)}applyTorque(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.addTorque(G,!0)}applyTorqueImpulse(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.applyTorqueImpulse(G,!0)}resetForces(e){const t=this.actorBodies.get(e.id);t?.resetForces(!1)}resetTorques(e){const t=this.actorBodies.get(e.id);t?.resetTorques(!1)}applyForce(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.addForce(G,!0)}applyImpulse(e,t){const i=this.actorBodies.get(e.id);G.x=t.x,G.y=t.y,G.z=t.z,i?.applyImpulse(G,!0)}applyLocalForce(e,t,i){const s=this.actorBodies.get(e.id);X(G,t),null==i?s?.addForce(G,!0):(X(Q,i),s?.addForceAtPoint(G,Q,!0))}applyLocalImpulse(e,t,i){const s=this.actorBodies.get(e.id);X(G,t),null==i?s.applyImpulse(G,!0):(X(Q,i),s.applyImpulseAtPoint(G,Q,!0))}applyRadiusImpulse(e,t,s){this.world.bodies.forEach((o=>{if(o.collider(0)?.isSensor())return;if(o.bodyType()!==i.RigidBodyType.Dynamic)return;const n=H;J(n,o.translation());const r=n.clone().sub(e);if(r.length()>t)return;const a=r.clone().normalize().multiplyScalar(s);G.x=a.x,G.y=a.y,G.z=a.z,o.applyImpulse(G,!0)}))}removeActor(e){if(null==e)return;this.controlledActors.delete(e.id);const t=this.actorBodies.get(e.id);null!=t&&(this.bodyActors.delete(t),this.world.removeRigidBody(t)),this.actorBodies.delete(e.id)}removeSceneObject(e){let t=this.staticBodies.get(e);null!=t&&this.world.getRigidBody(t.handle)&&this.world.removeRigidBody(t),this.staticBodies.delete(e)}activateActorEvents(e){this.actorBodies.get(e.id)}_onCollisionWithActorEvent(e,t,i){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((({started:e})=>e===i)),a((({handle1:e,handle2:t,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(e)?.parent()),a2:this.bodyActors.get(this.world.getCollider(t)?.parent()),started:i}))),r((({a1:i,a2:s})=>null!=i&&null!=s&&i.id===e.id&&t(i,s))),a((({a2:e})=>e)))}onBeginContact(e){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((e=>e.started)),r((({handle1:t})=>{const i=this.bodyActors.get(this.world.getCollider(t)?.parent());return null!=i&&i.id===e.id})),a((e=>e.handle2)))}onEndContact(e){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((e=>!e.started)),r((({handle1:t})=>{const i=this.bodyActors.get(this.world.getCollider(t)?.parent());return null!=i&&i.id===e.id})),a((e=>e.handle2)))}onHasContactChanged(e){const t=new Set,i=new o(!1);return this.onBeginContact(e).subscribe((e=>{t.add(e),i.next(t.size>0)})),this.onEndContact(e).subscribe((e=>{t.delete(e),i.next(t.size>0)})),i.pipe(n())}onBeginOverlapWithActorType(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>i instanceof t),!0)}onEndOverlapWithActorType(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>i instanceof t),!1)}onBeginOverlapWithActor(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>t.id===i.id),!0)}onEndOverlapWithActor(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>t.id===i.id),!1)}onCollisionWithActor(e,t){return this.onBeginOverlapWithActor(e,t)}onCollisionWithActorType(e,t){return this.onBeginOverlapWithActorType(e,t)}updateActorTransform(e){const t=this.actorBodies.get(e.id);null!=t?N(t,e.object):console.warn("Actor has not been added to physics world",e)}setupWorld(){const e=new i.World({x:0,y:-9.81,z:0});this.world=e}getActorContacts(e,t){const s=this.actorBodies.get(e.id);if(s&&s.numColliders()>0){const o=s.collider(0);let n=o.shape,r=o.translation(),a=o.rotation(),c=t,l=.3;const d=this.world.castShape(r,a,c,n,.1,l,!0,null,null,null,this.actorBodies.get(e.id),(e=>e.shape.type!=i.ShapeType.HeightField));if(null!=d){const e=new B,t=new B,i=new B;return J(e,d.witness2),J(t,d.witness1),J(i,d.normal1),i.negate(),[{ri:e,rj:t,ni:i}]}return[]}return console.warn("Actor is not added to the physics system"),[]}stop(){this.world?.bodies.forEach((e=>this.world.removeRigidBody(e))),this.world?.free(),this.fixedupdateSub?.unsubscribe()}createStaticBody(e,t,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed(),n=this.world.createRigidBody(o);for(const i of t){if(null==i){console.warn("Collision shape is missing for object",e);continue}const o=this.addShape(n,i,e);null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/t.length),null!=s?.restitution&&o.setRestitution(s.restitution)}return N(n,e),n}addShape(e,t,i){const s=i.getWorldScale(te),o=this.createShape(t,s);o.friction=.1;const n=t.offset.clone().multiply(s);var r,a;return X(o.translation,n),r=o.rotation,a=(new v).setFromEuler(t.rotation),r.x=a.x,r.y=a.y,r.z=a.z,r.w=a.w,this.world.createCollider(o,e)}createShape(e,t){if(e instanceof D)return i.ColliderDesc.cuboid(e.dimensions.x*t.x/2,e.dimensions.y*t.y/2,e.dimensions.z*t.z/2);if(e instanceof z){return i.ColliderDesc.capsule(e.length/2*t.y,e.radius*Math.max(t.z,t.x))}if(e instanceof F){const s=null!=e.geometry.getIndex()?e.geometry:P.mergeVertices(e.geometry),o=new Float32Array(s.getAttribute("position").array);for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z;return i.ColliderDesc.trimesh(o,new Uint32Array(s.getIndex().array))}if(e instanceof M){let s;e.mesh instanceof d.Mesh?s=e.mesh.geometry:e.mesh instanceof d.BufferGeometry?s=e.mesh:console.log("Unknownd shape",{shapeInfo:e});const o=new Float32Array(s.getAttribute("position").array);if(e.mesh instanceof d.Mesh){const t=L(e.mesh);for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z}for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z;const n=o;return i.ColliderDesc.convexHull(n)}return e instanceof W?i.ColliderDesc.ball(e.radius*Math.max(t.x,t.y,t.z)):e instanceof R?i.ColliderDesc.cylinder(e.height/2*t.y,e.radiusTop*Math.max(t.z,t.x)):e instanceof T?i.ColliderDesc.cone(e.height*t.y,e.radiusBottom/2*Math.max(t.z,t.x)):e instanceof E?i.ColliderDesc.cuboid(e.width/2*t.x,e.height/2*t.y,.01):(console.error("Unsupported shape",e),i.ColliderDesc.cuboid(1,1,1))}};j=e([A(),t("design:paramtypes",[V,I])],j);export{j as PhysicsSystem};const k=new B,O=new d.Quaternion;function N(e,t){const s=t.getWorldPosition(k),o=t.getWorldQuaternion(O);e.setTranslation(new i.Vector3(s.x,s.y,s.z),!1),e.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,U=new d.Vector2,K=async()=>{let e=await import("@dimforge/rapier3d-compat");return await e.init(),e};function X(e,t){e.x=t.x,e.y=t.y,e.z=t.z}function J(e,t){e.x=t.x,e.y=t.y,e.z=t.z}function Y(e,t){for(let i=0,s=e.numColliders();i<s;i++){t(e.collider(i))}}const Z=new B,$=new B,ee=e=>!e.isSensor(),te=new B;
|
1
|
+
import{__decorate as e,__metadata as t}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 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 I}from"../world.js";import*as P from"three/examples/jsm/utils/BufferGeometryUtils.js";import{calculateEffectiveScale as L}from"../../../utils/three/traverse.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.hitNormal=new B}}export var PhysicsBodyType;!function(e){e[e.dynamic=1]="dynamic",e[e.static=2]="static",e[e.kinematic=4]="kinematic",e[e.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));let j=class{set showDebug(e){this.shouldRenderDebug=e,this.debugMesh&&(this.debugMesh.visible=e)}get showDebug(){return this.shouldRenderDebug}constructor(e,t){this.viewController=e,this.gameWorld=t,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 e=this.world.debugRender();this.debugMesh.geometry.setAttribute("position",new u(e.vertices,3))}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await K(),this.eventQueue=new i.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe((e=>{e=Math.min(.1,e),this.beforeStep.next(e),this.updatePhysics(e),this.afterStep.next(e),this.showDebug&&this.renderDebug(),this.world.bodies.forEach((e=>{if(e.isFixed())return;const t=this.staticMeshes.get(e)??this.bodyActors.get(e)?.object;var i,s;null!=t&&(t.parent instanceof b&&(J(t.position,e.translation()),(e.isDynamic()||e.isKinematic()&&!this.controlledActors.has(this.bodyActors.get(e)?.id))&&(i=t.quaternion,s=e.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(e){this.world.timestep=e,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents(((e,t,i)=>{this.collisionEvents.next({handle1:e,handle2:t,started:i}),this.collisionEvents.next({handle1:t,handle2:e,started:i})}))}rayTestFromCamera(e,t,i){this._raycaster.setFromCamera(U,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(e).add(s);return this.rayTest(s,o,t,i)}rayTest(e,t,s,o){null==s&&(s=this._reusableResult);const n=this._raytestDiff,r=this._raytestDirection;if(n.subVectors(t,e),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(e,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,o?.excludeTriggers?e=>!e.isSensor():void 0);if(s.hasHit=null!=l,s.hasHit){const t=a.pointAt(l.timeOfImpact);s._internal=l,J(s.hitNormal,l.normal),J(s.hitPoint,t),s.distance=Z.subVectors(s.hitPoint,e).length();const i=this.world.bodies.getAll().find((e=>function(e,t){for(let i=0,s=e.numColliders();i<s;i++){const s=e.collider(i);if(t(s))return s}}(e,(e=>e===l.collider))));s.actor=null!=i?this.bodyActors.get(i):null}if(this.showDebug){const t=new h(r,e,c,o?.debugColor??255);this.gameWorld.scene.add(t),setTimeout((()=>this.gameWorld.scene.remove(t)),o?.debugLifetime??200)}return this._reusableResult}setGravity(e,t,i){this.world.gravity.x=e,this.world.gravity.y=t,this.world.gravity.z=i}getGravity(){return G.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(e){this.addRecursively(e);for(const e of this.staticBodies.values())Y(e,(e=>e.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)))}addRecursively(e){if(this.removeSceneObject(e),!function(e){if(null!=e.userData?.src){const t=e.userData?.src;return"actor"===t.type}return!1}(e))if(e instanceof S&&null!=e.collisionShape){const t=this.createStaticBody(e,[e.collisionShape],e.physics);this.staticMeshes.set(t,e),this.staticBodies.set(e,t)}else if(e instanceof C&&!1!==e.userData?.src?.collisionDetection)if(e.children[0]&&e.children[0].instanceMatrix)this.createForInstancedMesh(e.children[0],e.collisionShapes);else{const t=this.createStaticBody(e,e.collisionShapes,e.physics);this.staticMeshes.set(t,e),this.staticBodies.set(e,t)}else e instanceof _?this.addLandscapeGroup(e):(e instanceof p||e instanceof b)&&e.children.forEach((e=>this.addRecursively(e)))}createForInstancedMesh(e,t){const i=new m;for(let s=0;s<e.count;s++){const o=new w;o.matrix.identity(),i.fromArray(e.instanceMatrix.array,16*s),o.applyMatrix4(i);this.createStaticBody(o,t)}}getCharacterController(e=.01){return this.world?.createCharacterController(e)}getActorComputedMovement(e,t,i,o=null){const n=this.actorBodies.get(e.id);this.controlledActors.add(e.id);const r=n.collider(0);t.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,o,ee);const a=t.computedMovement();return J($,a),$}setNextKinematicTranslation(e,t){const i=this.actorBodies.get(e.id),s=i.translation();s.x+=t.x,s.y+=t.y,s.z+=t.z,i?.setNextKinematicTranslation(s)}setAngularVelocity(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.setAngvel(q,!0)}setLinearVelocity(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.setLinvel(q,!0)}getLinearVelocity(e,t=new B){const i=this.actorBodies.get(e.id).linvel();return t.x=i.x,t.y=i.y,t.z=i.z,t}getAngularVelocity(e,t=new B){const i=this.actorBodies.get(e.id).angvel();return t.x=i.x,t.y=i.y,t.z=i.z,t}setLinearDamping(e,t){const i=this.actorBodies.get(e.id);i?.setLinearDamping(t)}setAngularDamping(e,t){const i=this.actorBodies.get(e.id);i?.setAngularDamping(t)}createCharacterCollision(){return new i.CharacterCollision}addLandscapeGroup(e){const t=e.userData.src,s=t.landscape.heightMaps;for(const n of e.sections){this.staticBodies.has(n)&&this.world.removeRigidBody(this.staticBodies.get(n));const e=t.landscape.options.density+1,r=t.landscape.options.sectionSize,a=new Array(e);for(let t=0;t<e;t++)a[t]=new Array(e).fill(0);const c=s.find((e=>e.x===n.x&&e.y==n.y));if(null!=c)for(const t of c.points){if(null==a[t.i%e])continue;const i=e-1-Math.floor(t.i/e);i in a[t.i%e]?a[t.i%e][i]=t.y/r:console.warn("wrong index",{points:a,point:t,i:t.i%e,k:i,heightMap:c})}const l=t.landscape.options.density,d=a.flatMap((e=>e.reverse())),h=i.ColliderDesc.heightfield(l,l,new Float32Array(d),new i.Vector3(r,r,r));var o=n.getWorldPosition(new B);if(!1!==t.collisionDetection){const e=this.world.createRigidBody(i.RigidBodyDesc.fixed()),t=new i.Vector3(0,0,0);X(t,o),e.setTranslation(t,!1),this.world.createCollider(h,e),this.staticBodies.set(n,e)}}}addActor(e,t,s={}){if(0==t.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(e);const o=e.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():i.RigidBodyDesc.fixed()}const r=this.world.createRigidBody(n);r.enableCcd(1==s.continousCollisionDetection);for(const e of t)this.addShape(r,e,o);Y(r,(e=>{null!=s.isTrigger&&(e.setSensor(s.isTrigger),e.setActiveCollisionTypes(i.ActiveCollisionTypes.ALL),e.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS)),null!=s.friction&&e.setFriction(s.friction),null!=s.density&&e.setDensity(s.density),null!=s.mass&&e.setMass(s.mass),null!=s.restitution&&e.setRestitution(s.restitution)})),N(r,o),!0===s.ignoreForNavMesh&&(r.userData={ignoreForNavMesh:!0}),this.actorBodies.set(e.id,r),this.bodyActors.set(r,e)}applyTorque(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.addTorque(q,!0)}applyTorqueImpulse(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.applyTorqueImpulse(q,!0)}resetForces(e){const t=this.actorBodies.get(e.id);t?.resetForces(!1)}resetTorques(e){const t=this.actorBodies.get(e.id);t?.resetTorques(!1)}applyForce(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.addForce(q,!0)}applyImpulse(e,t){const i=this.actorBodies.get(e.id);q.x=t.x,q.y=t.y,q.z=t.z,i?.applyImpulse(q,!0)}applyLocalForce(e,t,i){const s=this.actorBodies.get(e.id);X(q,t),null==i?s?.addForce(q,!0):(X(Q,i),s?.addForceAtPoint(q,Q,!0))}applyLocalImpulse(e,t,i){const s=this.actorBodies.get(e.id);X(q,t),null==i?s.applyImpulse(q,!0):(X(Q,i),s.applyImpulseAtPoint(q,Q,!0))}applyRadiusImpulse(e,t,s){this.world.bodies.forEach((o=>{if(o.collider(0)?.isSensor())return;if(o.bodyType()!==i.RigidBodyType.Dynamic)return;const n=H;J(n,o.translation());const r=n.clone().sub(e);if(r.length()>t)return;const a=r.clone().normalize().multiplyScalar(s);q.x=a.x,q.y=a.y,q.z=a.z,o.applyImpulse(q,!0)}))}removeActor(e){if(null==e)return;this.controlledActors.delete(e.id);const t=this.actorBodies.get(e.id);null!=t&&(this.bodyActors.delete(t),this.world.removeRigidBody(t)),this.actorBodies.delete(e.id)}removeSceneObject(e){let t=this.staticBodies.get(e);null!=t&&this.world.getRigidBody(t.handle)&&this.world.removeRigidBody(t),this.staticBodies.delete(e)}activateActorEvents(e){this.actorBodies.get(e.id)}_onCollisionWithActorEvent(e,t,i){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((({started:e})=>e===i)),a((({handle1:e,handle2:t,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(e)?.parent()),a2:this.bodyActors.get(this.world.getCollider(t)?.parent()),started:i}))),r((({a1:i,a2:s})=>null!=i&&null!=s&&i.id===e.id&&t(i,s))),a((({a2:e})=>e)))}onBeginContact(e){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((e=>e.started)),r((({handle1:t})=>{const i=this.bodyActors.get(this.world.getCollider(t)?.parent());return null!=i&&i.id===e.id})),a((e=>e.handle2)))}onEndContact(e){return this.activateActorEvents(e),this.collisionEvents.pipe(l(e.disposed),r((e=>!e.started)),r((({handle1:t})=>{const i=this.bodyActors.get(this.world.getCollider(t)?.parent());return null!=i&&i.id===e.id})),a((e=>e.handle2)))}onHasContactChanged(e){const t=new Set,i=new o(!1);return this.onBeginContact(e).subscribe((e=>{t.add(e),i.next(t.size>0)})),this.onEndContact(e).subscribe((e=>{t.delete(e),i.next(t.size>0)})),i.pipe(n())}onBeginOverlapWithActorType(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>i instanceof t),!0)}onEndOverlapWithActorType(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>i instanceof t),!1)}onBeginOverlapWithActor(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>t.id===i.id),!0)}onEndOverlapWithActor(e,t){return this._onCollisionWithActorEvent(e,((e,i)=>t.id===i.id),!1)}onCollisionWithActor(e,t){return this.onBeginOverlapWithActor(e,t)}onCollisionWithActorType(e,t){return this.onBeginOverlapWithActorType(e,t)}updateActorTransform(e){const t=this.actorBodies.get(e.id);null!=t?N(t,e.object):console.warn("Actor has not been added to physics world",e)}setupWorld(){const e=new i.World({x:0,y:-9.81,z:0});this.world=e}getActorContacts(e,t){const s=this.actorBodies.get(e.id);if(s&&s.numColliders()>0){const o=s.collider(0);let n=o.shape,r=o.translation(),a=o.rotation(),c=t,l=.3;const d=this.world.castShape(r,a,c,n,.1,l,!0,null,null,null,this.actorBodies.get(e.id),(e=>e.shape.type!=i.ShapeType.HeightField));if(null!=d){const e=new B,t=new B,i=new B;return J(e,d.witness2),J(t,d.witness1),J(i,d.normal1),i.negate(),[{ri:e,rj:t,ni:i}]}return[]}return console.warn("Actor is not added to the physics system"),[]}stop(){this.world?.bodies.forEach((e=>this.world.removeRigidBody(e))),this.world?.free(),this.fixedupdateSub?.unsubscribe()}createStaticBody(e,t,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed(),n=this.world.createRigidBody(o);for(const i of t){if(null==i){console.warn("Collision shape is missing for object",e);continue}const o=this.addShape(n,i,e);null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/t.length),null!=s?.restitution&&o.setRestitution(s.restitution)}return N(n,e),n.userData=e.uuid,n}addShape(e,t,i){const s=i.getWorldScale(te),o=this.createShape(t,s);null!=t.collisionGroup&&o.setCollisionGroups(t.collisionGroup),o.friction=.1;const n=t.offset.clone().multiply(s);var r,a;X(o.translation,n),r=o.rotation,a=(new v).setFromEuler(t.rotation),r.x=a.x,r.y=a.y,r.z=a.z,r.w=a.w;return this.world.createCollider(o,e)}createShape(e,t){if(e instanceof D)return i.ColliderDesc.cuboid(e.dimensions.x*t.x/2,e.dimensions.y*t.y/2,e.dimensions.z*t.z/2);if(e instanceof z){return i.ColliderDesc.capsule(e.length/2*t.y,e.radius*Math.max(t.z,t.x))}if(e instanceof F){const s=null!=e.geometry.getIndex()?e.geometry:P.mergeVertices(e.geometry),o=new Float32Array(s.getAttribute("position").array);for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z;return i.ColliderDesc.trimesh(o,new Uint32Array(s.getIndex().array))}if(e instanceof M){let s;e.mesh instanceof d.Mesh?s=e.mesh.geometry:e.mesh instanceof d.BufferGeometry?s=e.mesh:console.log("Unknownd shape",{shapeInfo:e});const o=new Float32Array(s.getAttribute("position").array);if(e.mesh instanceof d.Mesh){const t=L(e.mesh);for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z}for(let e=0;e<o.length;e+=3)o[e]*=t.x,o[e+1]*=t.y,o[e+2]*=t.z;const n=o;return i.ColliderDesc.convexHull(n)}return e instanceof W?i.ColliderDesc.ball(e.radius*Math.max(t.x,t.y,t.z)):e instanceof R?i.ColliderDesc.cylinder(e.height/2*t.y,e.radiusTop*Math.max(t.z,t.x)):e instanceof T?i.ColliderDesc.cone(e.height*t.y,e.radiusBottom/2*Math.max(t.z,t.x)):e instanceof E?i.ColliderDesc.cuboid(e.width/2*t.x,e.height/2*t.y,.01):(console.error("Unsupported shape",e),i.ColliderDesc.cuboid(1,1,1))}};j=e([A(),t("design:paramtypes",[V,I])],j);export{j as PhysicsSystem};const k=new B,O=new d.Quaternion;function N(e,t){const s=t.getWorldPosition(k),o=t.getWorldQuaternion(O);e.setTranslation(new i.Vector3(s.x,s.y,s.z),!1),e.setRotation(new i.Quaternion(o.x,o.y,o.z,o.w),!1)}const G=new B,q=new i.Vector3(0,0,0),Q=new i.Vector3(0,0,0),H=new B,U=new d.Vector2,K=async()=>{let e=await import("@dimforge/rapier3d-compat");return await e.init(),e};function X(e,t){e.x=t.x,e.y=t.y,e.z=t.z}function J(e,t){e.x=t.x,e.y=t.y,e.z=t.z}function Y(e,t){for(let i=0,s=e.numColliders();i<s;i++){t(e.collider(i))}}const Z=new B,$=new B,ee=e=>!e.isSensor(),te=new B;
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -24,7 +24,7 @@ export declare class AssetResourceLoader {
|
|
24
24
|
private getUri;
|
25
25
|
getTexture(asset: Asset): Promise<Texture>;
|
26
26
|
private _getTextureLoader;
|
27
|
-
getMesh(asset: Asset): Promise<LoadedMesh>;
|
27
|
+
getMesh(asset: Asset, options?: GetMeshOptions): Promise<LoadedMesh>;
|
28
28
|
getAudio(asset: Asset): Promise<AudioBuffer>;
|
29
29
|
private collisionShapeCache;
|
30
30
|
private computeCollisionShapes;
|
@@ -42,3 +42,11 @@ export declare class AssetMeshInstance extends Object3D {
|
|
42
42
|
physics?: SceneObjectPhysicsSettings;
|
43
43
|
}
|
44
44
|
export declare function getElectronArg(name: string): string;
|
45
|
+
export type GetMeshOptions = {
|
46
|
+
/**
|
47
|
+
* Meshes can be optimized by merging geometries. This is appropriate for most static objects
|
48
|
+
* but it makes it impossible to animate only specific parts of the mesh.
|
49
|
+
* @default false
|
50
|
+
*/
|
51
|
+
mergeGeomtries: boolean;
|
52
|
+
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import{AudioLoader as e,BufferGeometry as t,Group as
|
1
|
+
import{AudioLoader as e,BufferGeometry as t,Group as s,LoadingManager as a,Mesh as i,Object3D as r,TextureLoader as o}from"three";import{GLTFLoader as n,MTLLoader as h,OBJLoader as c}from"three-stdlib";import{FBXLoader as l}from"three-stdlib";import{cloneMesh as d}from"../utils/mesh.js";import{pathJoin as m}from"../utils/files.js";import{Subject as p,firstValueFrom as f}from"rxjs";import{importCollisionShapes as u,isCollisionMesh as g}from"./collision/collision-shape-import.js";import*as w from"three";import{iterateMaterials as y}from"../utils/materials.js";import{BufferGeometryUtils as x,KTX2Loader as L,TGALoader as M}from"three/examples/jsm/Addons.js";const b=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new a,this.glbLoader=new n(this.loadingManager),this.fbxLoader=new l(this.loadingManager),this.objLoader=new c(this.loadingManager),this.textureLoader=new o(this.loadingManager),this.tgaLoader=new M(this.loadingManager),this.ktx2Loader=new L(this.loadingManager),this._textureLoader=new w.ImageBitmapLoader(this.loadingManager),this.audioLoader=new e(this.loadingManager),this.makeReady=new p,this.ready=f(this.makeReady),this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}setDataDir(e){this.basePath=m(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){return m(this.basePath,e)+`?windowId=${getElectronArg("windowId")}`}async getTexture(e){return null==e?null:(await this.ready,this.textureCache.has(e.id)||await this._getTextureLoader(e.fileKey).loadAsync(this.getUri(e.fileKey)).then((t=>(t.wrapS=S(e.texture?.wrapS),t.wrapT=S(e.texture?.wrapT),t.flipY=e.texture?.flipY??!0,this.textureCache.set(e.id,t),t))),this.textureCache.get(e.id))}_getTextureLoader(e){return e.toLowerCase().endsWith(".tga")?this.tgaLoader:e.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:this.textureLoader}async getMesh(e,t){if(await this.ready,!b.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new s,animations:[]};if(!this.cache.has(e.fileKey))try{this.cache.set(e.fileKey,await this.loadMesh(e))}catch(e){return this.onError(e),{scene:new s,animations:[]}}const a=this.cache.get(e.fileKey).scene,r=this.computeCollisionShapes(e,a);!0===t?.mergeGeomtries&&this.optimizeDrawGroups(a);const o=d(a),n=this.cache.get(e.fileKey).animations;o.traverse((e=>{e instanceof i&&e.material instanceof Array&&(e.material=e.material.slice())}));const h=new AssetMeshInstance;h.add(o),h.collisionShapes=r,h.animations=n;const c=e.receiveShadow??!0,l=e.castShadow??!1;return o.traverse((e=>{e.castShadow=l,e.receiveShadow=c})),{scene:h,animations:n}}async getAudio(e){return await this.ready,this.audioLoader.loadAsync(this.getUri(e.fileKey))}computeCollisionShapes(e,t){const s=e.id+e.mesh?.collisions?.shapeType;return this.collisionShapeCache.has(s)||this.collisionShapeCache.set(s,u(t,e)),this.collisionShapeCache.get(s)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then((e=>(e.scene=function(e,t){let s=!1;if(t.traverseVisible((e=>{C.test(e.name)&&(s=!0)})),!s)return t;const a=new w.LOD,i=[t];for(;i.length>0;){const e=i.shift(),t=e.name.match(C);if(null!=t){const s=parseInt(t[1]);0===s?a.addLevel(e,0):console.warn(`Skipping LOD level ${s} for now as LOD is not fully supported`)}else i.push(...e.children)}return a}(0,e.scene),e)))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid);let s=!0,a=0;if(e.traverse((e=>{e instanceof i&&e.geometry instanceof t&&!g(e)?a++:(e instanceof w.SkinnedMesh||e instanceof w.Bone)&&(s=!1)})),a>1&&s){const s=[],a=[],r=[];e.updateWorldMatrix(!0,!0),e.traverse((e=>{e instanceof i&&e.geometry instanceof t&&!g(e)&&!Array.isArray(e.material)&&(e.updateWorldMatrix(!0,!0),e.geometry.applyMatrix4(e.matrixWorld),s.push(e.geometry),a.push(e.material),r.push(e))}));for(const e of r)e.removeFromParent();const o=x.mergeGeometries(s,!0),n=[];let h=0;e:for(const e of a){for(const t of n)if(t.m.id===e.id){t.indices.push(h),h++;continue e}n.push({m:e,indices:[h]}),h++}let c=0;for(const e of n){for(const t of e.indices)o.groups[t].materialIndex=c;c++}e.add(new i(o,n.map((e=>e.m))))}e.traverse((e=>{if(e instanceof i&&e.geometry instanceof t){const t=e.geometry;Array.isArray(e.material)&&t.groups.length>1&&t.groups.length>e.material.length&&x.mergeGroups(t)}}))}async loadByAsset(e){const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then((e=>({scene:e.scene,animations:e.animations})));case"fbx":return this.fbxLoader.loadAsync(t).then((e=>({scene:e,animations:e.animations})));case"obj":if(null!=e.materialLib){const t=new h;t.materialOptions={normalizeRGB:!1};const s=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(s)}return this.objLoader.loadAsync(t).then((e=>(A(e),e))).then((e=>({scene:e,animations:e.animations})))}}}function A(e){if(e instanceof i)for(const t of y(e.material))t instanceof w.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach(A)}export class AssetMeshInstance extends r{}export function getElectronArg(e){const t=`--${e}=`,s=window.process?.argv.find((e=>e.startsWith(t)));return s?.substring(t.length)}function S(e){switch(e){case"clamp":return w.ClampToEdgeWrapping;case"repeat":return w.RepeatWrapping;case"mirror":return w.MirroredRepeatWrapping}return w.RepeatWrapping}const C=/_LOD(\d+)$/;
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
@@ -3,6 +3,7 @@ import { BufferGeometry, Euler, Material, Mesh, Vector3 } from "three";
|
|
3
3
|
export declare class CollisionShape {
|
4
4
|
offset: Vector3;
|
5
5
|
rotation: Euler;
|
6
|
+
collisionGroup?: number;
|
6
7
|
withOffset(vector: Vector3): this;
|
7
8
|
withRotation(rotation: Euler): this;
|
8
9
|
static box(dimensions: Vector3): BoxCollisionShape;
|
@@ -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 l,Matrix4 as c,Mesh as h,MeshLambertMaterial as m,MeshPhongMaterial as p,MeshStandardMaterial as d,Object3D as u,PointLight as f,Quaternion as y,SphereGeometry as g,Texture as w,Vector2 as S,Vector3 as v,Vector4 as A}from"three";import b,{SpriteRenderer as M}from"three-nebula";import{bool as x,BooleanNode as j,float as P,FloatNode as I,NodeShaderMaterial as D,rgb as N,RgbNode as E,Texture2dLookupNode as V,textureSampler2d as C,vec2 as F,Vec2Node as k,vec3 as z,Vec3Node as O,vec4 as _}from"three-shader-graph";import{VfxActor as B}from"../effects/vfx/vfx-actor.js";import{VisualEffect as T}from"../effects/vfx/vfx-param.js";import{BaseActor as $}from"../gameplay/actors/actor.js";import L from"../gameplay/actors/builtin/index.js";import{PhysicsBodyType as U,withInjectionContext as R}from"../gameplay/index.js";import{Sampler2DNode as W}from"../shader-nodes/index.js";import{LambertShader as J}from"../shader/builtin/lambert-shader.js";import{StandardShader as H}from"../shader/builtin/standard-shader.js";import{UnlitShader as q}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as X}from"../shader/parameter.js";import{ArrayMap as G,groupBy as Y}from"../utils/collections.js";import{iterateMaterials as Z}from"../utils/materials.js";import{filterChildrenShallow as Q,filterSceneShallow as K,findFirstVisibleObject as ee}from"../utils/three/traverse.js";import{AssetMeshInstance as te}from"./asset-resource-loader.js";import{isCollisionMesh as ae}from"./collision/collision-shape-import.js";import{BoxCollisionShape as se,PhysicalShapeMesh as re}from"./collision/collision-shape.js";import{LandscapeManager as ie}from"./landscape/landscape-manager.js";import{initLandscape as ne}from"./landscape/landscape.js";import{SectionGrid as oe,smoothNormalsCrossMeshes as le}from"./landscape/utils.js";import{createGrassFoliageMaterial as ce}from"./materials/grass-foliage.js";import{createGrassMaterial as he}from"./materials/grass.js";import{getMaterialAttribute as me}from"./materials/utils/material-painting.js";import{createWaterMaterial as pe}from"./materials/water.js";import{SerializedParamType as de}from"./model.js";import{ShapeLibrary as ue,ShapeLibraryKeys as fe}from"./objects/shapes.js";import{ambientLightName as ye,createSky as ge,defaultSkyMaterial as we}from"./sky.js";const Se={};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,l,c){this.scene=a,this.dataProvider=s,this.assetsService=r,this.assetManagerService=i,this.renderingView=n,this.shaders=o,this.actorTypes=l,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.assets=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.createAssetSubscription=r.onCreate.subscribe((e=>{this.assets.set(e.id,e)})),this.updateSubscription=r.onUpdate.subscribe((async e=>{this.assets.set(e.id,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=>{Ee(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,null!=s?Ce(e.material[s],r)||(e.material[s]=r):Ce(e.material,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=>{if(null!=e)return this.assetManagerService.getMesh(e)})))))}async init(){await this.preInit(),Ae.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 xe(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){}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await xe(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!==U.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=>{!ae(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=a[0]instanceof h&&null!=a[0].geometry.morphAttributes&&Object.keys(a[0].geometry.morphAttributes).length>0,i=!0;this._canBeInstancedCache.set(e.assetId,s&&i&&!r)}return this._canBeInstancedCache.get(e.assetId)}async preInit(){this.renderingView?.onLoop((()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)})),this.assetsService.getAssets().then((e=>{for(const t of e)this.assets.set(t.id,t)}))}async initWithInstancing(){await this.preInit(),await this.prefetchAssets();const e=[],a=new G,i=new G;for(const t of this.dataProvider.getObjects())await Ne(t,(async(t,r,n)=>{const o="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t),l="shape_mesh"===t.type&&"landscape"!==t.shape&&t.physics?.type!==U.dynamic;if(o||l)if(r&&r.children?.length>0&&r.children.splice(r.children.findIndex((e=>e.id===t.id)),1),l){let e=t.shape+JSON.stringify(t.shapeParams??{})+t.castShadow+t.receiveShadow;const a=t.materialAssignments?.at(0)?.materialId,r=null!=a?this.assets.get(a):null;let o=null;if(null!=r&&"shader"!==r.material.type){if(e+=r.material.type+r.material.shader,null!=r.material.shaderParams){if(e+=Object.entries(r.material.shaderParams).filter((([e,t])=>"color"!=e)).map((e=>JSON.stringify(e))).join(),null!=r.material.shaderParams.color){const e=r.material.shaderParams.color;e.type===de.Color&&null!=e.value&&(o=new s(e.value))}}}else e+=a;i.push(e,{object:{...t,parentTransform:n},color:o})}else{const e=t.assetId+JSON.stringify(t.materialAssignments??[]);a.push(e,{...t,parentTransform:n})}else null==r&&e.push({...t,parentTransform:n})}));for(const e of a.values()){if(0==e.length)continue;const t=await this.createFromAsset(e[0]);if(null==t)continue;const a=await this.createInstancedMesh(e,t),s=new te;s.add(a),s.userData.src=e[0],t instanceof te&&(s.collisionShapes=t.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}for(const e of i.values()){if(0==e.length)continue;const a=e[0].object,i=await this.createFromShape(a),n=ee(i,(e=>!ae(e)&&null!=e.geometry)),o=n.material.clone();null!=e[0].color&&null!=o.color&&(o.color=new s(16777215));const l=n.geometry,h=new t.InstancedMesh(l,o,e.length);for(let a=0;a<e.length;a++){const s=e[a],o=(new t.Matrix4).compose((new v).fromArray(s.object.position),(new y).setFromEuler((new r).fromArray(s.object.rotation)),(new v).fromArray(s.object.scale)),l=(new c).copy(s.object.parentTransform).multiply(o);h.setMatrixAt(a,l),null!=s.color&&h.setColorAt(a,s.color),h.castShadow=i.castShadow??!0,h.receiveShadow=n.receiveShadow??!0;const m=new te;m.add(h),m.userData.src=e[0],i instanceof re&&(m.collisionShapes=[i.collisionShape]),m.castShadow=!1,m.receiveShadow=!1,this.scene.add(m)}}await Promise.all(e.map((e=>this.materialize(e)))),await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=ee(a,(e=>!ae(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,e.length);s.material instanceof l&&(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 y).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new c).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=e[0].castShadow??i.castShadow??!0,o.receiveShadow=e[0].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()):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 K(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))))}async applyMaterial(e,t){await applyMaterial(e,t,(e=>{const t=this.assets.get(e);if(null!=t)return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}),this._originalMaterials)}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof h)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(L));K(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 Ae.entries())t.userData.customShaderName&&Ae.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),K(this.scene,(e=>!0)).forEach((e=>{e.traverse((async e=>{if(e instanceof h)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=this.assets.get(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=this.assets.get(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 h&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof h&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=this.assets.get(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 h){const t=e.material;t instanceof D&&(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"),r||(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 re&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&ve(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 Ne(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:Q(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?K(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))}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof h&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=Y(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof h){const t=me(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=me(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=ge(),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 re&&(e=function(e){if(e instanceof se)return new h(new a(...e.offset.toArray()),De);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!==U.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)))),this.inEditor||"asset_mesh"!=e.type&&"shape_mesh"!==e.type||null!=e.physics?.type&&e.physics.type==U.dynamic||Pe(r),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=we);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 Se[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??L[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(B,(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),a.traverse((e=>{e instanceof h&&this._originalMaterials.set(e.id,e.material)}));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||(await Promise.all((e.materialAssignments??[]).filter((e=>null!=e.materialId)).map((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=ne(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new ie(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 oe(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((()=>le(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&fe.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,ue[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,ue[e].collision(s)),new re(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,ve(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 h&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&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 u;return await b.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new M(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 g(.3,10,10),a=new d({color:new s(16771709)}),r=new h(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===ye));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.createAssetSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function ve(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Ae=new Map,be=new m({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const l=JSON.stringify(e.material);if(o&&Ae.has(l))return Ae.get(l);const c={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),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&&(c.map=await i.getTexture(a))}let m;switch(e.material.type){case"phong":m=new p({...c,...h});break;case"water":m=pe(c,a);break;case"grassFoliage":m=ce({color:c.color,map:c.map},a);break;case"grass":m=he({...c,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"unlit":case"lambert":case"shader":const t={standard:H,lambert:J,unlit:q}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await xe(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{m=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),m=Me.get(e.material.shader)}m.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),m=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(m),o&&Ae.set(l,m),m.side=e.material.side??m.side??t.FrontSide,m.transparent=(e.material.transparent??c.transparent??!1)||m.transparent,e.material.bloom&&(m.userData.hasBloom=!0),m.userData.assetId=e.id,m}async function xe(e,t,a,s,r,i,n,o){const l={};for(const[t,c]of Object.entries(e)){const e=await je(c,a,s,r,i,n,o);null!=e&&(l[t]=e)}return l}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await je(s,null,null,null);null!=e&&(t[a]=e)}return t}async function je(e,t,a,i,n,o,l){if(de.String,null==e||null==e.value||""==e.value)return null;const c=e.value;switch(e.type){case de.Number:case de.FloatNode:let h="string"==typeof c?parseFloat(c):c;return e.type===de.FloatNode?P(h):h;case de.Texture:return await a.getTexture(await t.getAsset(c));case de.Sampler2DNode:return C(await a.getTexture(await t.getAsset(c)));case de.Boolean:return c;case de.BooleanNode:return x(c);case de.Vector2:case de.Vec2Node:if("object"==typeof c){const t=c instanceof Array?(new S).fromArray(c):new S(c.x,c.y);return e.type===de.Vec2Node?F(t):t}return null;case de.Vector3:case de.Vec3Node:if("object"==typeof c){const t=c instanceof Array?(new v).fromArray(c):new v(c.x,c.y,c.z);return e.type===de.Vec3Node?z(t):t}return null;case de.Color:case de.RgbNode:const m=new s(c);return e.type===de.RgbNode?N(m):m;case de.String:return c;case de.BaseActor:const p=c;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(p);case de.Euler:const d=c;return(new r).fromArray(d);case de.Object3D:return(await a.getMesh(await t.getAsset(c))).scene;case de.Material:return await materialFromAsset(await t.getAsset(c),n,t,a,o);case de.AudioBuffer:return await a.getAudio(await t.getAsset(c));case de.VisualEffect:const u=await t.getAsset(c);if(null==l){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in u)return new T(l,u);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Pe(e){e.updateWorldMatrix(!1,!0),e.traverse((e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1}));const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}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 De=new d({color:4229780});async function Ne(e,a,s,i){null==i&&(i=(new c).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){if(null==e.position||null==e.rotation||null==e.scale)return t.identity();return t.compose((new v).fromArray(e.position),(new y).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>Ne(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?de.Number:t instanceof I||"function"==typeof e.prototype.isFloat?de.FloatNode:t instanceof w||e===w||e.isTexture?de.Texture:t instanceof W||e===V?de.Sampler2DNode:t instanceof Boolean||e===Boolean?de.Boolean:t instanceof j?de.BooleanNode:t instanceof s||e==s?de.Color:t instanceof E||"function"==typeof e.prototype.isRgb?de.RgbNode:t instanceof S||e==S?de.Vector2:t instanceof k||"function"==typeof e.prototype.isVec2?de.Vec2Node:t instanceof v||e==v?de.Vector3:t instanceof O||"function"==typeof e.prototype.isVec3?de.Vec3Node:t instanceof String||e===String?de.String:t instanceof $||e==$||e.prototype instanceof $||e.prototype==$?de.BaseActor:t instanceof r||e==r?de.Euler:t instanceof u||e==u?de.Object3D:t instanceof l||e==l?de.Material:t instanceof AudioBuffer||e==AudioBuffer?de.AudioBuffer:t instanceof T||e==T?de.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=X(e);if(0===s.length)return{};let r;null!=a?R(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 S:return t instanceof S?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([[de.RgbNode,"#000000"],[de.Color,"#000000"],[de.Vector4,[0,0,0,0]],[de.Vec4Node,[0,0,0,0]],[de.Vector3,[0,0,0]],[de.Vec3Node,[0,0,0]],[de.Vector2,[0,0]],[de.Vec2Node,[0,0]],[de.Euler,[0,0,0,"XYZ"]]]);export function applyMaterial(e,a,r,i){const n=[];return e.traverse((async e=>{if(e instanceof h||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of Z(e.material))t.hasOwnProperty("color")&&n.push(e)})),Promise.all(n.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const n=e.material[t];if(null==n.color||!(n.color instanceof s))continue;const o="#"+n.color.getHexString(),l=n.name;if(o===a.color&&(n.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await r(a.materialId),n=e.material[t];null!=s&&(e.material[t]=s,e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??o,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??l,null!=i&&i.set(e.id+"#"+t,n))}}else if("color"in e.material){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 n=await r(a.materialId),o=e.material;null!=n&&(e.material=n,e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,null!=i&&(i.has(e.id)||i.set(e.id,o)))}}})))}function Ce(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){return e.fragmentShader+e.vertexShader==a.fragmentShader+a.vertexShader&&function(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){for(const t in e.uniforms){if(null==a.uniforms[t])return!1;if(a.uniforms[t].value!==e.uniforms[t].value)return console.log("Different values",a.uniforms[t].value,e.uniforms[t].value),!1}return!0}return!1}(e,a)}return!1}
|
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 l,Matrix4 as c,Mesh as h,MeshLambertMaterial as m,MeshPhongMaterial as p,MeshStandardMaterial as d,Object3D as u,PointLight as f,Quaternion as y,SphereGeometry as g,Texture as w,Vector2 as S,Vector3 as v,Vector4 as A}from"three";import b,{SpriteRenderer as M}from"three-nebula";import{bool as x,BooleanNode as j,float as P,FloatNode as I,NodeShaderMaterial as D,rgb as N,RgbNode as E,Texture2dLookupNode as V,textureSampler2d as C,vec2 as F,Vec2Node as k,vec3 as z,Vec3Node as O,vec4 as _}from"three-shader-graph";import{VfxActor as B}from"../effects/vfx/vfx-actor.js";import{VisualEffect as T}from"../effects/vfx/vfx-param.js";import{BaseActor as $}from"../gameplay/actors/actor.js";import L from"../gameplay/actors/builtin/index.js";import{PhysicsBodyType as U,withInjectionContext as R}from"../gameplay/index.js";import{Sampler2DNode as W}from"../shader-nodes/index.js";import{LambertShader as J}from"../shader/builtin/lambert-shader.js";import{StandardShader as H}from"../shader/builtin/standard-shader.js";import{UnlitShader as q}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as G}from"../shader/parameter.js";import{ArrayMap as X,groupBy as Y}from"../utils/collections.js";import{iterateMaterials as Z}from"../utils/materials.js";import{filterChildrenShallow as Q,filterSceneShallow as K,findFirstVisibleObject as ee}from"../utils/three/traverse.js";import{AssetMeshInstance as te}from"./asset-resource-loader.js";import{isCollisionMesh as ae}from"./collision/collision-shape-import.js";import{BoxCollisionShape as se,PhysicalShapeMesh as re}from"./collision/collision-shape.js";import{LandscapeManager as ie}from"./landscape/landscape-manager.js";import{initLandscape as ne}from"./landscape/landscape.js";import{SectionGrid as oe,smoothNormalsCrossMeshes as le}from"./landscape/utils.js";import{createGrassFoliageMaterial as ce}from"./materials/grass-foliage.js";import{createGrassMaterial as he}from"./materials/grass.js";import{getMaterialAttribute as me}from"./materials/utils/material-painting.js";import{createWaterMaterial as pe}from"./materials/water.js";import{SerializedParamType as de}from"./model.js";import{ShapeLibrary as ue,ShapeLibraryKeys as fe}from"./objects/shapes.js";import{ambientLightName as ye,createSky as ge,defaultSkyMaterial as we}from"./sky.js";const Se={};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,l,c){this.scene=a,this.dataProvider=s,this.assetsService=r,this.assetManagerService=i,this.renderingView=n,this.shaders=o,this.actorTypes=l,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.assets=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.createAssetSubscription=r.onCreate.subscribe((e=>{this.assets.set(e.id,e)})),this.updateSubscription=r.onUpdate.subscribe((async e=>{this.assets.set(e.id,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=>{Ee(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,null!=s?Ce(e.material[s],r)||(e.material[s]=r):Ce(e.material,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=>{if(null!=e)return this.assetManagerService.getMesh(e)})))))}async init(){await this.preInit(),Ae.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 xe(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){}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await xe(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!==U.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=>{!ae(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=a[0]instanceof h&&null!=a[0].geometry.morphAttributes&&Object.keys(a[0].geometry.morphAttributes).length>0,i=!0;this._canBeInstancedCache.set(e.assetId,s&&i&&!r)}return this._canBeInstancedCache.get(e.assetId)}async preInit(){this.renderingView?.onLoop((()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)})),this.assetsService.getAssets().then((e=>{for(const t of e)this.assets.set(t.id,t)}))}async initWithInstancing(){await this.preInit(),await this.prefetchAssets();const e=[],a=new X,i=new X;for(const t of this.dataProvider.getObjects())await Ne(t,(async(t,r,n)=>{const o="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t),l="shape_mesh"===t.type&&"landscape"!==t.shape&&t.physics?.type!==U.dynamic;if(o||l)if(r&&r.children?.length>0&&r.children.splice(r.children.findIndex((e=>e.id===t.id)),1),l){let e=t.shape+JSON.stringify(t.shapeParams??{})+t.castShadow+t.receiveShadow;const a=t.materialAssignments?.at(0)?.materialId,r=null!=a?this.assets.get(a):null;let o=null;if(null!=r&&"shader"!==r.material.type){if(e+=r.material.type+r.material.shader,null!=r.material.shaderParams){if(e+=Object.entries(r.material.shaderParams).filter((([e,t])=>"color"!=e)).map((e=>JSON.stringify(e))).join(),null!=r.material.shaderParams.color){const e=r.material.shaderParams.color;e.type===de.Color&&null!=e.value&&(o=new s(e.value))}}}else e+=a;i.push(e,{object:{...t,parentTransform:n},color:o})}else{const e=t.assetId+JSON.stringify(t.materialAssignments??[]);a.push(e,{...t,parentTransform:n})}else null==r&&e.push({...t,parentTransform:n})}));for(const e of a.values()){if(0==e.length)continue;const t=await this.createFromAsset(e[0]);if(null==t)continue;const a=await this.createInstancedMesh(e,t),s=new te;s.add(a),s.userData.src=e[0],t instanceof te&&(s.collisionShapes=t.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}for(const e of i.values()){if(0==e.length)continue;const a=e[0].object,i=await this.createFromShape(a),n=ee(i,(e=>!ae(e)&&null!=e.geometry)),o=n.material.clone();null!=e[0].color&&null!=o.color&&(o.color=new s(16777215));const l=n.geometry,h=new t.InstancedMesh(l,o,e.length);for(let a=0;a<e.length;a++){const s=e[a],o=(new t.Matrix4).compose((new v).fromArray(s.object.position),(new y).setFromEuler((new r).fromArray(s.object.rotation)),(new v).fromArray(s.object.scale)),l=(new c).copy(s.object.parentTransform).multiply(o);h.setMatrixAt(a,l),null!=s.color&&h.setColorAt(a,s.color),h.castShadow=i.castShadow??!0,h.receiveShadow=n.receiveShadow??!0;const m=new te;m.add(h),m.userData.src=e[0],i instanceof re&&(m.collisionShapes=[i.collisionShape]),m.castShadow=!1,m.receiveShadow=!1,this.scene.add(m)}}await Promise.all(e.map((e=>this.materialize(e)))),await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=ee(a,(e=>!ae(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,e.length);s.material instanceof l&&(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 y).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new c).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=e[0].castShadow??i.castShadow??!0,o.receiveShadow=e[0].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()):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 K(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))))}async applyMaterial(e,t){await applyMaterial(e,t,(e=>{const t=this.assets.get(e);if(null!=t)return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}),this._originalMaterials)}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof h)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(L));K(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 Ae.entries())t.userData.customShaderName&&Ae.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),K(this.scene,(e=>!0)).forEach((e=>{e.traverse((async e=>{if(e instanceof h)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=this.assets.get(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=this.assets.get(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 h&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof h&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=this.assets.get(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 h){const t=e.material;t instanceof D&&(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"),r||(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 re&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&ve(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 Ne(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:Q(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?K(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))}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof h&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=Y(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof h){const t=me(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=me(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=ge(),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 re&&(e=function(e){if(e instanceof se)return new h(new a(...e.offset.toArray()),De);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!==U.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)))),this.inEditor||"asset_mesh"!=e.type&&"shape_mesh"!==e.type||null!=e.physics?.type&&e.physics.type==U.dynamic||Pe(r),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=we);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 Se[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??L[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(B,(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),a.traverse((e=>{e instanceof h&&this._originalMaterials.set(e.id,e.material)}));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||(await Promise.all((e.materialAssignments??[]).filter((e=>null!=e.materialId)).map((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=ne(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new ie(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 oe(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((()=>le(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&fe.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,ue[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,ue[e].collision(s)),new re(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,{mergeGeomtries:!0});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,ve(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 h&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&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 u;return await b.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new M(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 g(.3,10,10),a=new d({color:new s(16771709)}),r=new h(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===ye));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.createAssetSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function ve(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Ae=new Map,be=new m({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const l=JSON.stringify(e.material);if(o&&Ae.has(l))return Ae.get(l);const c={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),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&&(c.map=await i.getTexture(a))}let m;switch(e.material.type){case"phong":m=new p({...c,...h});break;case"water":m=pe(c,a);break;case"grassFoliage":m=ce({color:c.color,map:c.map},a);break;case"grass":m=he({...c,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"unlit":case"lambert":case"shader":const t={standard:H,lambert:J,unlit:q}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await xe(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{m=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),m=Me.get(e.material.shader)}m.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),m=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(m),o&&Ae.set(l,m),m.side=e.material.side??m.side??t.FrontSide,m.transparent=(e.material.transparent??c.transparent??!1)||m.transparent,e.material.bloom&&(m.userData.hasBloom=!0),m.userData.assetId=e.id,m}async function xe(e,t,a,s,r,i,n,o){const l={};for(const[t,c]of Object.entries(e)){const e=await je(c,a,s,r,i,n,o);null!=e&&(l[t]=e)}return l}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await je(s,null,null,null);null!=e&&(t[a]=e)}return t}async function je(e,t,a,i,n,o,l){if(de.String,null==e||null==e.value||""===e.value)return null;const c=e.value;switch(e.type){case de.Number:case de.FloatNode:let h="string"==typeof c?parseFloat(c):c;return e.type===de.FloatNode?P(h):h;case de.Texture:return await a.getTexture(await t.getAsset(c));case de.Sampler2DNode:return C(await a.getTexture(await t.getAsset(c)));case de.Boolean:return c;case de.BooleanNode:return x(c);case de.Vector2:case de.Vec2Node:if("object"==typeof c){const t=c instanceof Array?(new S).fromArray(c):new S(c.x,c.y);return e.type===de.Vec2Node?F(t):t}return null;case de.Vector3:case de.Vec3Node:if("object"==typeof c){const t=c instanceof Array?(new v).fromArray(c):new v(c.x,c.y,c.z);return e.type===de.Vec3Node?z(t):t}return null;case de.Color:case de.RgbNode:const m=new s(c);return e.type===de.RgbNode?N(m):m;case de.String:return c;case de.BaseActor:const p=c;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(p);case de.Euler:const d=c;return(new r).fromArray(d);case de.Object3D:return(await a.getMesh(await t.getAsset(c))).scene;case de.Material:return await materialFromAsset(await t.getAsset(c),n,t,a,o);case de.AudioBuffer:return await a.getAudio(await t.getAsset(c));case de.VisualEffect:const u=await t.getAsset(c);if(null==l){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in u)return new T(l,u);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Pe(e){e.updateWorldMatrix(!1,!0),e.traverse((e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1}));const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}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 De=new d({color:4229780});async function Ne(e,a,s,i){null==i&&(i=(new c).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){if(null==e.position||null==e.rotation||null==e.scale)return t.identity();return t.compose((new v).fromArray(e.position),(new y).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>Ne(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?de.Number:t instanceof I||"function"==typeof e.prototype.isFloat?de.FloatNode:t instanceof w||e===w||e.isTexture?de.Texture:t instanceof W||e===V?de.Sampler2DNode:t instanceof Boolean||e===Boolean?de.Boolean:t instanceof j?de.BooleanNode:t instanceof s||e==s?de.Color:t instanceof E||"function"==typeof e.prototype.isRgb?de.RgbNode:t instanceof S||e==S?de.Vector2:t instanceof k||"function"==typeof e.prototype.isVec2?de.Vec2Node:t instanceof v||e==v?de.Vector3:t instanceof O||"function"==typeof e.prototype.isVec3?de.Vec3Node:t instanceof String||e===String?de.String:t instanceof $||e==$||e.prototype instanceof $||e.prototype==$?de.BaseActor:t instanceof r||e==r?de.Euler:t instanceof u||e==u?de.Object3D:t instanceof l||e==l?de.Material:t instanceof AudioBuffer||e==AudioBuffer?de.AudioBuffer:t instanceof T||e==T?de.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=G(e);if(0===s.length)return{};let r;null!=a?R(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 S:return t instanceof S?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([[de.RgbNode,"#000000"],[de.Color,"#000000"],[de.Vector4,[0,0,0,0]],[de.Vec4Node,[0,0,0,0]],[de.Vector3,[0,0,0]],[de.Vec3Node,[0,0,0]],[de.Vector2,[0,0]],[de.Vec2Node,[0,0]],[de.Euler,[0,0,0,"XYZ"]]]);export function applyMaterial(e,a,r,i){const n=[];return e.traverse((async e=>{if(e instanceof h||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of Z(e.material))t.hasOwnProperty("color")&&n.push(e)})),Promise.all(n.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const n=e.material[t];if(null==n.color||!(n.color instanceof s))continue;const o="#"+n.color.getHexString(),l=n.name;if(o===a.color&&(n.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await r(a.materialId),n=e.material[t];null!=s&&(e.material[t]=s,e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??o,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??l,null!=i&&i.set(e.id+"#"+t,n))}}else if("color"in e.material){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 n=await r(a.materialId),o=e.material;null!=n&&(e.material=n,e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,null!=i&&(i.has(e.id)||i.set(e.id,o)))}}})))}function Ce(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){return e.fragmentShader+e.vertexShader==a.fragmentShader+a.vertexShader&&function(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){for(const t in e.uniforms){if(null==a.uniforms[t])return!1;if(a.uniforms[t].value!==e.uniforms[t].value)return console.log("Different values",a.uniforms[t].value,e.uniforms[t].value),!1}return!0}return!1}(e,a)}return!1}
|
2
2
|
/*
|
3
3
|
* Copyright (©) 2023. All rights reserved.
|
4
4
|
* See the LICENSE.md file for details.
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@hology/core",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.64",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"type": "module",
|
@@ -87,10 +87,11 @@
|
|
87
87
|
},
|
88
88
|
"dependencies": {
|
89
89
|
"@babel/runtime": "^7.24.8",
|
90
|
-
"@dimforge/rapier3d-compat": "^0.
|
90
|
+
"@dimforge/rapier3d-compat": "^0.14.0",
|
91
91
|
"@plumier/reflect": "^1.1.0",
|
92
|
+
"@recast-navigation/three": "^0.35.2",
|
92
93
|
"@types/three-nebula": "^10.0.3",
|
93
|
-
"recast-navigation": "^0.
|
94
|
+
"recast-navigation": "^0.35.2",
|
94
95
|
"rxjs": "7.8.1",
|
95
96
|
"three-csm": "^4.2.1",
|
96
97
|
"three-mesh-bvh": "^0.7.5",
|