mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-01-19 20:25:01 +00:00
Hide hulls.
This commit is contained in:
parent
1c6d7effac
commit
c09fb315d5
|
|
@ -2,6 +2,8 @@ import { Suspense } from "react";
|
|||
import { useGLTF, useTexture } from "@react-three/drei";
|
||||
import { BASE_URL, shapeTextureToUrl, shapeToUrl } from "../loaders";
|
||||
import { setupColor } from "../textureUtils";
|
||||
import { filterGeometryByVertexGroups, getHullBoneIndices } from "../meshUtils";
|
||||
import { MeshStandardMaterial } from "three";
|
||||
|
||||
const FALLBACK_URL = `${BASE_URL}/black.png`;
|
||||
|
||||
|
|
@ -13,45 +15,74 @@ export function useStaticShape(shapeName: string) {
|
|||
return useGLTF(url);
|
||||
}
|
||||
|
||||
export function ShapeTexture({ materialName }: { materialName: string }) {
|
||||
// console.log({ materialName });
|
||||
const url = shapeTextureToUrl(materialName, FALLBACK_URL);
|
||||
export function ShapeTexture({
|
||||
material,
|
||||
}: {
|
||||
material?: MeshStandardMaterial;
|
||||
}) {
|
||||
const url = shapeTextureToUrl(material.name, FALLBACK_URL);
|
||||
const texture = useTexture(url, (texture) => setupColor(texture));
|
||||
|
||||
return <meshStandardMaterial map={texture} side={2} />;
|
||||
material.map = texture;
|
||||
material.side = 2;
|
||||
material.transparent = true;
|
||||
return <primitive object={material} attach="material" />;
|
||||
}
|
||||
|
||||
export function ShapeModel({ shapeName }: { shapeName: string }) {
|
||||
const { nodes } = useStaticShape(shapeName);
|
||||
|
||||
let hullBoneIndices = new Set<number>();
|
||||
const skeletonsFound = Object.values(nodes).filter(
|
||||
(node: any) => node.skeleton
|
||||
);
|
||||
|
||||
if (skeletonsFound.length > 0) {
|
||||
const skeleton = (skeletonsFound[0] as any).skeleton;
|
||||
hullBoneIndices = getHullBoneIndices(skeleton);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.entries(nodes)
|
||||
.filter(
|
||||
([name, node]: [string, any]) =>
|
||||
!node.material || !node.material.name.match(/\.\d+$/)
|
||||
node.material &&
|
||||
node.material.name !== "Unassigned" &&
|
||||
!node.name.match(/^Hulk/i)
|
||||
)
|
||||
.map(([name, node]: [string, any]) => (
|
||||
<mesh key={node.id} geometry={node.geometry} castShadow receiveShadow>
|
||||
{node.material ? (
|
||||
<Suspense
|
||||
fallback={
|
||||
// Allow the mesh to render while the texture is still loading;
|
||||
// show a wireframe placeholder.
|
||||
<meshStandardMaterial color="gray" wireframe />
|
||||
}
|
||||
>
|
||||
{Array.isArray(node.material) ? (
|
||||
node.material.map((mat, index) => (
|
||||
<ShapeTexture key={index} materialName={mat.name} />
|
||||
))
|
||||
) : (
|
||||
<ShapeTexture materialName={node.material.name} />
|
||||
)}
|
||||
</Suspense>
|
||||
) : null}
|
||||
</mesh>
|
||||
))}
|
||||
.map(([name, node]: [string, any]) => {
|
||||
const geometry = filterGeometryByVertexGroups(
|
||||
node.geometry,
|
||||
hullBoneIndices
|
||||
);
|
||||
|
||||
return (
|
||||
<mesh key={node.id} geometry={geometry} castShadow receiveShadow>
|
||||
{node.material ? (
|
||||
<Suspense
|
||||
fallback={
|
||||
// Allow the mesh to render while the texture is still loading;
|
||||
// show a wireframe placeholder.
|
||||
<meshStandardMaterial color="gray" wireframe />
|
||||
}
|
||||
>
|
||||
{Array.isArray(node.material) ? (
|
||||
node.material.map((mat, index) => (
|
||||
<ShapeTexture
|
||||
key={index}
|
||||
material={mat as MeshStandardMaterial}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<ShapeTexture
|
||||
material={node.material as MeshStandardMaterial}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
) : null}
|
||||
</mesh>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
81
src/meshUtils.ts
Normal file
81
src/meshUtils.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* 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")
|
||||
*/
|
||||
export function getHullBoneIndices(skeleton: any): Set<number> {
|
||||
const hullBoneIndices = new Set<number>();
|
||||
|
||||
skeleton.bones.forEach((bone: any, index: number) => {
|
||||
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(
|
||||
geometry: any,
|
||||
hullBoneIndices: Set<number>
|
||||
): any {
|
||||
// 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;
|
||||
}
|
||||
Loading…
Reference in a new issue