forked from phenom/healer-man
Release Healer Man 0.1.7
This commit is contained in:
1 parent
b12fb84859
commit
eca6b5db9b
99 files changed
+1931
-150
No files matched your search
@@ -11,6 +11,10 @@ export interface PreparedCollisionTrimesh {
|
||||
readonly indices: ArrayLike<number>;
|
||||
}
|
||||
|
||||
// A surface must be within 30 degrees of vertical to occlude combat sight.
|
||||
// This deliberately rejects floors, ramps, slopes, and ceilings.
|
||||
const MAX_SIGHT_BLOCKER_NORMAL_Y = 0.5;
|
||||
|
||||
export function prepareCollision(root: Object3D): Group {
|
||||
root.updateWorldMatrix(true, true);
|
||||
const inverseRootMatrix = root.matrixWorld.clone().invert();
|
||||
@@ -60,3 +64,61 @@ export function collisionTrimeshes(root: Object3D): readonly PreparedCollisionTr
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export function collisionLineOfSightTrimeshes(root: Object3D): readonly PreparedCollisionTrimesh[] {
|
||||
const result: PreparedCollisionTrimesh[] = [];
|
||||
root.traverse((node) => {
|
||||
const mesh = node as Mesh;
|
||||
if (!mesh.isMesh) return;
|
||||
const position = mesh.geometry.getAttribute("position");
|
||||
const sourceIndices = mesh.geometry.index?.array
|
||||
?? Uint32Array.from({ length: position.count }, (_, vertex) => vertex);
|
||||
const blockerSourceIndices: number[] = [];
|
||||
|
||||
for (let offset = 0; offset + 2 < sourceIndices.length; offset += 3) {
|
||||
const first = Number(sourceIndices[offset]);
|
||||
const second = Number(sourceIndices[offset + 1]);
|
||||
const third = Number(sourceIndices[offset + 2]);
|
||||
const firstX = position.getX(first);
|
||||
const firstY = position.getY(first);
|
||||
const firstZ = position.getZ(first);
|
||||
const abX = position.getX(second) - firstX;
|
||||
const abY = position.getY(second) - firstY;
|
||||
const abZ = position.getZ(second) - firstZ;
|
||||
const acX = position.getX(third) - firstX;
|
||||
const acY = position.getY(third) - firstY;
|
||||
const acZ = position.getZ(third) - firstZ;
|
||||
const normalX = abY * acZ - abZ * acY;
|
||||
const normalY = abZ * acX - abX * acZ;
|
||||
const normalZ = abX * acY - abY * acX;
|
||||
const normalLength = Math.hypot(normalX, normalY, normalZ);
|
||||
if (normalLength <= Number.EPSILON) continue;
|
||||
if (Math.abs(normalY) / normalLength > MAX_SIGHT_BLOCKER_NORMAL_Y) continue;
|
||||
blockerSourceIndices.push(first, second, third);
|
||||
}
|
||||
|
||||
if (!blockerSourceIndices.length) return;
|
||||
const remappedVertices: number[] = [];
|
||||
const remappedIndices = new Uint32Array(blockerSourceIndices.length);
|
||||
const remap = new Map<number, number>();
|
||||
blockerSourceIndices.forEach((sourceIndex, indexOffset) => {
|
||||
let remappedIndex = remap.get(sourceIndex);
|
||||
if (remappedIndex === undefined) {
|
||||
remappedIndex = remap.size;
|
||||
remap.set(sourceIndex, remappedIndex);
|
||||
remappedVertices.push(
|
||||
position.getX(sourceIndex),
|
||||
position.getY(sourceIndex),
|
||||
position.getZ(sourceIndex),
|
||||
);
|
||||
}
|
||||
remappedIndices[indexOffset] = remappedIndex;
|
||||
});
|
||||
result.push({
|
||||
id: `${mesh.uuid}-line-of-sight`,
|
||||
vertices: Float32Array.from(remappedVertices),
|
||||
indices: remappedIndices,
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user