Add volume state resolution and point inside oriented volume check in RuntimeHost

This commit is contained in:
2026-04-06 08:26:06 +02:00
parent 104808b876
commit edf3552c5f

View File

@@ -1,4 +1,4 @@
import { AmbientLight, AnimationClip, AnimationMixer, DirectionalLight, Group, LoopOnce, LoopRepeat, Mesh, MeshStandardMaterial, PerspectiveCamera, PointLight, Quaternion, Scene, Vector3, SpotLight, WebGLRenderer } from "three";
import { AmbientLight, AnimationClip, AnimationMixer, DirectionalLight, Euler, Group, LoopOnce, LoopRepeat, Mesh, MeshStandardMaterial, PerspectiveCamera, PointLight, Quaternion, Scene, Vector3, SpotLight, WebGLRenderer } from "three";
import { createModelInstanceRenderGroup, disposeModelInstance } from "../assets/model-instance-rendering";
import { buildBoxBrushDerivedMeshData } from "../geometry/box-brush-mesh";
import { createStarterMaterialSignature, createStarterMaterialTexture } from "../materials/starter-material-textures";
@@ -14,6 +14,8 @@ export class RuntimeHost {
scene = new Scene();
camera = new PerspectiveCamera(70, 1, 0.05, 1000);
cameraForward = new Vector3();
volumeOffset = new Vector3();
volumeInverseRotation = new Quaternion();
domElement;
ambientLight = new AmbientLight();
sunLight = new DirectionalLight();
@@ -78,6 +80,7 @@ export class RuntimeHost {
return this.runtimeScene;
},
resolveFirstPersonMotion: (feetPosition, motion, shape) => this.collisionWorld?.resolveFirstPersonMotion(feetPosition, motion, shape) ?? null,
resolvePlayerVolumeState: (feetPosition) => this.resolvePlayerVolumeState(feetPosition),
setRuntimeMessage: (message) => {
if (message === this.currentRuntimeMessage) {
return;
@@ -91,6 +94,33 @@ export class RuntimeHost {
}
};
}
resolvePlayerVolumeState(feetPosition) {
if (this.runtimeScene === null) {
return {
inWater: false,
inFog: false
};
}
const inWater = this.runtimeScene.volumes.water.some((volume) => this.isPointInsideOrientedVolume(feetPosition, volume));
const inFog = this.runtimeScene.volumes.fog.some((volume) => this.isPointInsideOrientedVolume(feetPosition, volume));
return {
inWater,
inFog
};
}
isPointInsideOrientedVolume(point, volume) {
this.volumeOffset.set(point.x - volume.center.x, point.y - volume.center.y, point.z - volume.center.z);
this.volumeInverseRotation
.setFromEuler(new Euler((volume.rotationDegrees.x * Math.PI) / 180, (volume.rotationDegrees.y * Math.PI) / 180, (volume.rotationDegrees.z * Math.PI) / 180, "XYZ"))
.invert();
this.volumeOffset.applyQuaternion(this.volumeInverseRotation);
const halfX = volume.size.x * 0.5;
const halfY = volume.size.y * 0.5;
const halfZ = volume.size.z * 0.5;
return (Math.abs(this.volumeOffset.x) <= halfX &&
Math.abs(this.volumeOffset.y) <= halfY &&
Math.abs(this.volumeOffset.z) <= halfZ);
}
mount(container) {
this.container = container;
container.appendChild(this.domElement);