72 lines
2.5 KiB
JavaScript
72 lines
2.5 KiB
JavaScript
import { fileURLToPath } from "node:url";
|
|
import { dirname, resolve } from "node:path";
|
|
import { NodeIO } from "@gltf-transform/core";
|
|
import {
|
|
BufferAttribute,
|
|
BufferGeometry,
|
|
DoubleSide,
|
|
Ray,
|
|
Vector3,
|
|
} from "three";
|
|
import { MeshBVH } from "three-mesh-bvh";
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const collisionPath = resolve(
|
|
here,
|
|
"../src/assets/game/dungeons/wailing-caverns/wailing-caverns-collision.glb",
|
|
);
|
|
const document = await new NodeIO().read(collisionPath);
|
|
const primitive = document.getRoot().listMeshes()[0]?.listPrimitives()[0];
|
|
if (!primitive) throw new Error("Collision GLB has no mesh primitive.");
|
|
|
|
const positions = primitive.getAttribute("POSITION")?.getArray();
|
|
const indices = primitive.getIndices()?.getArray();
|
|
if (!positions || !indices) throw new Error("Collision GLB lacks indexed positions.");
|
|
|
|
const geometry = new BufferGeometry();
|
|
geometry.setAttribute("position", new BufferAttribute(positions, 3));
|
|
geometry.setIndex(new BufferAttribute(indices, 1));
|
|
const bvh = new MeshBVH(geometry);
|
|
|
|
const foot = new Vector3(163.49, -73.66, 132.9);
|
|
const alternateFoot = new Vector3(-163.49, -73.66, -132.9);
|
|
const body = foot.clone().add(new Vector3(0, 0.84, 0));
|
|
const yaw = -2.024;
|
|
const pitch = 0.32;
|
|
const horizontalDistance = 5.8 * Math.cos(pitch);
|
|
const target = body.clone().add(new Vector3(0, 0.45, 0));
|
|
const camera = new Vector3(
|
|
target.x - Math.sin(yaw) * horizontalDistance,
|
|
target.y + 0.8 + 5.8 * Math.sin(pitch),
|
|
target.z - Math.cos(yaw) * horizontalDistance,
|
|
);
|
|
const lookAt = new Vector3(
|
|
target.x + Math.sin(yaw) * 1.25,
|
|
target.y + 0.08,
|
|
target.z + Math.cos(yaw) * 1.25,
|
|
);
|
|
|
|
function closest(point) {
|
|
const hit = bvh.closestPointToPoint(point);
|
|
return hit ? { distance: hit.distance, point: hit.point.toArray() } : null;
|
|
}
|
|
|
|
function raycast(origin, destination, far = Infinity) {
|
|
const direction = destination.clone().sub(origin).normalize();
|
|
const hit = bvh.raycastFirst(new Ray(origin, direction), DoubleSide, 0, far);
|
|
return hit ? { distance: hit.distance, point: hit.point.toArray() } : null;
|
|
}
|
|
|
|
console.log(JSON.stringify({
|
|
foot: foot.toArray(),
|
|
footClosestSurface: closest(foot),
|
|
alternateFoot: alternateFoot.toArray(),
|
|
alternateClosestSurface: closest(alternateFoot),
|
|
camera: camera.toArray(),
|
|
cameraClosestSurface: closest(camera),
|
|
target: target.toArray(),
|
|
cameraToTargetDistance: camera.distanceTo(target),
|
|
cameraToTargetFirstCollision: raycast(camera, target, camera.distanceTo(target)),
|
|
cameraViewFirstCollision: raycast(camera, lookAt),
|
|
}, null, 2));
|