diff --git a/index.html b/index.html index 758eff7..1ef4782 100644 --- a/index.html +++ b/index.html @@ -46,12 +46,12 @@
-

+

- + :class="rarityBg(store.selectedFish?.genetics.rarity)" + x-text="store.selectedFish?.genetics.rarity.toUpperCase()"> +
@@ -59,20 +59,20 @@
Gender
-
+
Size
-
+
Speed
-
+
Pattern
-
+
Age
-
+
Sell value: - +
@@ -82,7 +82,7 @@
diff --git a/src/main.ts b/src/main.ts index f3008ba..40e9461 100644 --- a/src/main.ts +++ b/src/main.ts @@ -59,27 +59,10 @@ function getSpeciesUrl(sp: FishSpecies): string { }; return urls[sp]; } -// Per-species true longest rendered extent (model units), measured -// offline with scripts/measure-models.mjs (stride-safe rest-pose + -// swim-clip evaluation of the actual GLB data). Fish are scaled by -// targetLength / modelLength. This replaces the old -// Box3.setFromObject auto-measure, which under-reports armature-scaled -const SPECIES_LENGTH: Record = { - angelfish: 4.2139, - goldfish: 1.7386, - guppy: 2.8070, - betta: 1.0228, - blue_tang: 1.0192, - flower_horn: 1.0516, - neon_tetra: 3.6548, - oscar: 8.8411, - knifefish: 23.0140, -}; function fishToSpec(f: FishData): FishSpec { return { url: getSpeciesUrl(f.species), targetLength: f.genetics.sizeMult * 0.5, - modelLength: SPECIES_LENGTH[f.species], speed: [0.3 * f.genetics.speedMult, 0.7 * f.genetics.speedMult], orient: isQuaternius(f.species) ? { y: Math.PI / 2 } : undefined, genetics: f.genetics, diff --git a/src/scene/GLTFish.ts b/src/scene/GLTFish.ts index 5aff6e6..64e82a9 100644 --- a/src/scene/GLTFish.ts +++ b/src/scene/GLTFish.ts @@ -17,28 +17,6 @@ const FOOD_EAT = 0.15; export interface FishSpec { url: string; targetLength: number; - /** - * The model's true longest rendered extent in model units, measured - * offline with `scripts/measure-models.mjs` (stride-safe evaluation of - * rest pose + swim-clip extremes). The fish is scaled by - * `targetLength / modelLength`. - * - * This replaces the old `Box3.setFromObject` auto-measure, which is - * unreliable: it measures skinned geometry in skeleton space (an - * armature's scale/rotation is not in the mesh's matrixWorld and a - * stale cached bounding box may be used), so it under-reports - * armature-scaled models (e.g. knifefish 8.89 vs true 22.91, oscar - * 6.49 vs true 8.84), and for the clownfish GLB it is dominated by - * the model's 45.3-unit water plane instead of the 8.28-unit fish. - */ - modelLength: number; - /** - * Node names to hide after loading. The clownfish GLB is a whole - * aquarium scene: a 45.3-unit untextured white "Surface" water plane, - * a "TopLight" slab, a "Bubbles" prop, and a mirrored duplicate of the - * body ("Original-Mirrored") — only "ClownFish" is the fish itself. - */ - hideNodes?: string[]; orient?: { x?: number; y?: number; z?: number }; speed?: Range; genetics?: Genetics; @@ -145,31 +123,27 @@ interface Fish { function buildFish(gltf: GLTF, spec: FishSpec): Fish { const model = gltf.scene ?? gltf.scenes[0]; - // Hide non-fish scene props before anything else (clownfish GLB bundles - // a full scene around the fish body). - if (spec.hideNodes) { - for (const name of spec.hideNodes) { - const node = model.getObjectByName(name); - if (node) node.visible = false; - } - } - const orient = new THREE.Group(); if (spec.orient) { orient.rotation.set(spec.orient.x ?? 0, spec.orient.y ?? 0, spec.orient.z ?? 0); } - const scale = (spec.targetLength / spec.modelLength) * rand(0.92, 1.08); - orient.scale.setScalar(scale); - console.log("[Fish]", spec.url, "target:", spec.targetLength.toFixed(3), "modelLen:", spec.modelLength, "scale:", scale.toFixed(4), "expected rendered:", (scale * spec.modelLength).toFixed(3)); + // Add the model to orient BEFORE measuring, so the full node hierarchy + // (including armature scales) is reflected in the world matrices orient.add(model); + orient.updateMatrixWorld(true); + + // Measure the actual world-space extent of the model + const box = new THREE.Box3().setFromObject(model); + const size = box.getSize(new THREE.Vector3()); + const longest = Math.max(size.x, size.y, size.z); + + // Scale so the longest dimension equals targetLength + const scale = (spec.targetLength / longest) * rand(0.92, 1.08); + orient.scale.setScalar(scale); const group = new THREE.Group(); group.add(orient); - group.updateMatrixWorld(true); - const dbgBox = new THREE.Box3().setFromObject(group); - const dbgSize = dbgBox.getSize(new THREE.Vector3()); - console.log("[Fish Box3]", spec.url, "x:", dbgSize.x.toFixed(3), "y:", dbgSize.y.toFixed(3), "z:", dbgSize.z.toFixed(3), "max:", Math.max(dbgSize.x, dbgSize.y, dbgSize.z).toFixed(3)); // Apply genetics (color shift, rarity glow) if (spec.genetics) {