Files
2026-08-14 15:56:39 -04:00

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));