2025-12-07 14:01:26 -08:00
|
|
|
import { Skeleton, Bone, BufferGeometry } from "three";
|
|
|
|
|
|
2025-11-14 23:43:31 -08:00
|
|
|
/**
|
|
|
|
|
* Extract hull bone indices from a skeleton
|
|
|
|
|
* @param skeleton - The Three.js skeleton to scan
|
|
|
|
|
* @returns Set of bone indices for bones matching the hull pattern (starts with "Hulk")
|
|
|
|
|
*/
|
2025-12-07 14:01:26 -08:00
|
|
|
export function getHullBoneIndices(skeleton: Skeleton): Set<number> {
|
2025-11-14 23:43:31 -08:00
|
|
|
const hullBoneIndices = new Set<number>();
|
|
|
|
|
|
2025-12-07 14:01:26 -08:00
|
|
|
skeleton.bones.forEach((bone: Bone, index: number) => {
|
2025-11-14 23:43:31 -08:00
|
|
|
if (bone.name.match(/^Hulk/i)) {
|
|
|
|
|
hullBoneIndices.add(index);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return hullBoneIndices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Filter geometry by removing faces influenced by hull bones
|
|
|
|
|
* @param geometry - The Three.js geometry to filter
|
|
|
|
|
* @param hullBoneIndices - Set of bone indices that represent hull (collision) geometry
|
|
|
|
|
* @returns Filtered geometry with hull-influenced faces removed
|
|
|
|
|
*/
|
|
|
|
|
export function filterGeometryByVertexGroups(
|
2025-12-07 14:01:26 -08:00
|
|
|
geometry: BufferGeometry,
|
2025-11-29 09:08:20 -08:00
|
|
|
hullBoneIndices: Set<number>,
|
2025-12-07 14:01:26 -08:00
|
|
|
): BufferGeometry {
|
2025-11-14 23:43:31 -08:00
|
|
|
// If no hull bones or no skinning data, return original geometry
|
|
|
|
|
if (hullBoneIndices.size === 0 || !geometry.attributes.skinIndex) {
|
|
|
|
|
return geometry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const skinIndex = geometry.attributes.skinIndex;
|
|
|
|
|
const skinWeight = geometry.attributes.skinWeight;
|
|
|
|
|
const index = geometry.index;
|
|
|
|
|
|
|
|
|
|
// Track which vertices are influenced by hull bones
|
|
|
|
|
const vertexHasHullInfluence = new Array(skinIndex.count).fill(false);
|
|
|
|
|
|
|
|
|
|
// Check each vertex's bone influences
|
|
|
|
|
for (let i = 0; i < skinIndex.count; i++) {
|
|
|
|
|
for (let j = 0; j < 4; j++) {
|
|
|
|
|
const boneIndex = skinIndex.array[i * 4 + j];
|
|
|
|
|
const weight = skinWeight.array[i * 4 + j];
|
|
|
|
|
|
|
|
|
|
// If this vertex has significant weight to a hull bone, mark it
|
|
|
|
|
if (weight > 0.01 && hullBoneIndices.has(boneIndex)) {
|
|
|
|
|
vertexHasHullInfluence[i] = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build new index array excluding faces that use hull-influenced vertices
|
|
|
|
|
if (index) {
|
|
|
|
|
const newIndices: number[] = [];
|
|
|
|
|
const indexArray = index.array;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < indexArray.length; i += 3) {
|
|
|
|
|
const i0 = indexArray[i];
|
|
|
|
|
const i1 = indexArray[i + 1];
|
|
|
|
|
const i2 = indexArray[i + 2];
|
|
|
|
|
|
|
|
|
|
// Only keep face if all vertices don't have hull influence
|
|
|
|
|
if (
|
|
|
|
|
!vertexHasHullInfluence[i0] &&
|
|
|
|
|
!vertexHasHullInfluence[i1] &&
|
|
|
|
|
!vertexHasHullInfluence[i2]
|
|
|
|
|
) {
|
|
|
|
|
newIndices.push(i0, i1, i2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create new geometry with filtered indices
|
|
|
|
|
const filteredGeometry = geometry.clone();
|
|
|
|
|
filteredGeometry.setIndex(newIndices);
|
|
|
|
|
return filteredGeometry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return geometry;
|
|
|
|
|
}
|