docs(world): document map lod system
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
This commit is contained in:
@@ -152,6 +152,7 @@ WS ws://localhost:8000/ws
|
||||
| `docs/technical/zustand.md` | Game, settings, and subtitle stores |
|
||||
| `docs/technical/three-debugging.md` | DevTools workflow for stepping into Three.js internals |
|
||||
| `docs/technical/map-performance.md` | Map draw-call bottlenecks and optimization notes |
|
||||
| `docs/technical/map-lod.md` | Runtime map LOD presets, paths, and workflow |
|
||||
| `docs/technical/editor.md` | Editor implementation details |
|
||||
| `docs/technical/animation.md` | Animated, explodable, and reusable 3D model components |
|
||||
| `docs/user/features.md` | Implemented feature inventory |
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# Map LOD System
|
||||
|
||||
This document describes the runtime LOD system used by the production map.
|
||||
|
||||
## Goal
|
||||
|
||||
The map now supports two visual versions for selected models:
|
||||
|
||||
- the regular model in `public/models/<name>/`
|
||||
- the lighter model in `public/models/<name>-LOD/`
|
||||
|
||||
The runtime chooses between those paths from the active graphics preset. This keeps nearby objects visually richer while reducing the cost of distant objects.
|
||||
|
||||
## Graphics Presets
|
||||
|
||||
Presets are configured in:
|
||||
|
||||
```txt
|
||||
src/data/world/graphicsConfig.ts
|
||||
```
|
||||
|
||||
Current behavior:
|
||||
|
||||
| Preset | Chunk load distance | Fog | LOD behavior |
|
||||
| -------- | ------------------: | --- | ------------------------------------- |
|
||||
| `low` | 10m | On | Always use `*-LOD` models |
|
||||
| `medium` | 20m | On | Always use `*-LOD` models |
|
||||
| `high` | Current default 50m | Off | Regular model up to 10m, then `*-LOD` |
|
||||
| `ultra` | 50m | Off | Regular model up to 20m, then `*-LOD` |
|
||||
|
||||
The unload distance stays slightly larger than the load distance to avoid rapid mount/unmount flickering when the player stands near a boundary.
|
||||
|
||||
## Runtime Selection
|
||||
|
||||
LOD path mapping lives in:
|
||||
|
||||
```txt
|
||||
src/data/world/mapLodConfig.ts
|
||||
```
|
||||
|
||||
The main selector is `selectMapModelPathByDistance()`. It receives:
|
||||
|
||||
- the current camera distance
|
||||
- the map model name
|
||||
- the regular model path
|
||||
- the active graphics preset
|
||||
|
||||
It returns either the regular path or the `*-LOD` path.
|
||||
|
||||
## Chunked Instanced Models
|
||||
|
||||
Repeated static assets are rendered through:
|
||||
|
||||
```txt
|
||||
src/world/map-instancing/MapInstancingSystem.tsx
|
||||
```
|
||||
|
||||
For each visible chunk, the system checks the nearest instance in that chunk. If the nearest instance is inside the high-detail threshold, the whole chunk uses the regular model. Otherwise, it uses the `*-LOD` model.
|
||||
|
||||
This is intentionally chunk-level LOD instead of per-instance LOD. It matches the existing chunk streaming architecture and avoids splitting every object into many tiny batches.
|
||||
|
||||
## Single And Generated Models
|
||||
|
||||
Single map nodes use:
|
||||
|
||||
```txt
|
||||
src/hooks/world/useMapLodModelPath.ts
|
||||
src/world/GameMap.tsx
|
||||
```
|
||||
|
||||
Some named map objects are rendered through dedicated generated components instead of the generic `GameMap` path. Those components must call `useMapLodModelPath()` directly.
|
||||
|
||||
Current dedicated generated components with LOD support:
|
||||
|
||||
```txt
|
||||
src/components/three/world/EcoleModel.tsx
|
||||
src/components/three/world/LaFabrikMapModel.tsx
|
||||
```
|
||||
|
||||
This matters for `lafabrik`: adding `public/models/lafabrik-LOD/` is not enough by itself. The component must also be connected to `useMapLodModelPath()`.
|
||||
|
||||
## Adding A New LOD Model
|
||||
|
||||
To add LOD support for a model:
|
||||
|
||||
1. Add the light model in `public/models/<name>-LOD/model.gltf`.
|
||||
2. Keep the regular model in `public/models/<name>/model.gltf`.
|
||||
3. Add the mapping in `src/data/world/mapLodConfig.ts`.
|
||||
4. If the model uses a dedicated component, call `useMapLodModelPath()` in that component.
|
||||
5. Preload both paths when the component is dedicated and uses `useGLTF.preload()`.
|
||||
6. Verify the GLTF references: buffers, textures, opacity maps, and relative paths.
|
||||
|
||||
## Current LOD Models
|
||||
|
||||
The current explicit LOD mappings are:
|
||||
|
||||
```txt
|
||||
ebike
|
||||
eolienne
|
||||
pylone
|
||||
boiteimmeuble
|
||||
ecole
|
||||
immeuble1
|
||||
lafabrik
|
||||
maison1
|
||||
panneauaffichage
|
||||
talkie
|
||||
```
|
||||
|
||||
## Regression Risks
|
||||
|
||||
The most common failure modes are:
|
||||
|
||||
- the `*-LOD` folder exists but is missing from `mapLodConfig.ts`
|
||||
- a dedicated generated component keeps a hardcoded model path
|
||||
- GLTF references point to textures that were renamed during export
|
||||
- a model is added to LOD config but does not spawn through `GameMap` or `MapInstancingSystem`
|
||||
|
||||
Before committing model changes, validate both the regular and LOD folders for missing GLTF refs.
|
||||
@@ -92,6 +92,12 @@ export const docGroups: DocGroup[] = [
|
||||
subtitle: "Draw calls, triangles, and streaming",
|
||||
meta: "13",
|
||||
},
|
||||
{
|
||||
path: "/docs/map-lod",
|
||||
title: "Map LOD System",
|
||||
subtitle: "Presets, paths, and model workflow",
|
||||
meta: "14",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -101,31 +107,31 @@ export const docGroups: DocGroup[] = [
|
||||
path: "/docs/features",
|
||||
title: "Features",
|
||||
subtitle: "Implemented scope",
|
||||
meta: "14",
|
||||
meta: "15",
|
||||
},
|
||||
{
|
||||
path: "/docs/main-feature",
|
||||
title: "Main Feature",
|
||||
subtitle: "Repair-game prototype",
|
||||
meta: "15",
|
||||
meta: "16",
|
||||
},
|
||||
{
|
||||
path: "/docs/editor",
|
||||
title: "Editor User Guide",
|
||||
subtitle: "Editing workflow",
|
||||
meta: "16",
|
||||
meta: "17",
|
||||
},
|
||||
{
|
||||
path: "/docs/animation",
|
||||
title: "Animation & 3D Model System",
|
||||
subtitle: "Components and usage",
|
||||
meta: "17",
|
||||
meta: "18",
|
||||
},
|
||||
{
|
||||
path: "/docs/gallery",
|
||||
title: "Model Gallery",
|
||||
subtitle: "Browsing 3D assets",
|
||||
meta: "18",
|
||||
meta: "19",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -136,7 +142,7 @@ export const docGroups: DocGroup[] = [
|
||||
path: "/docs/code-review",
|
||||
title: "Code Review Prep",
|
||||
subtitle: "Presentation support",
|
||||
meta: "19",
|
||||
meta: "20",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import mapLod from "../../../../docs/technical/map-lod.md?raw";
|
||||
import { DocsDocument } from "@/components/docs/DocsDocument";
|
||||
|
||||
export function DocsMapLodPage(): React.JSX.Element {
|
||||
return <DocsDocument content={mapLod} meta="14" title="Map LOD System" />;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
DocsInteractionRoute,
|
||||
DocsLayoutRoute,
|
||||
DocsMainFeatureRoute,
|
||||
DocsMapLodRoute,
|
||||
DocsMapPerformanceRoute,
|
||||
DocsMissionFlowRoute,
|
||||
DocsReadmeRoute,
|
||||
@@ -93,6 +94,7 @@ const docsChildRoutes = [
|
||||
{ path: "zustand", component: DocsZustandRoute },
|
||||
{ path: "three-debugging", component: DocsThreeDebuggingRoute },
|
||||
{ path: "map-performance", component: DocsMapPerformanceRoute },
|
||||
{ path: "map-lod", component: DocsMapLodRoute },
|
||||
{ path: "features", component: DocsFeaturesRoute },
|
||||
{ path: "main-feature", component: DocsMainFeatureRoute },
|
||||
{ path: "editor", component: DocsEditorRoute },
|
||||
|
||||
@@ -107,6 +107,10 @@ const LazyDocsMapPerformancePage = lazyNamed(
|
||||
() => import("@/pages/docs/map-performance/page"),
|
||||
"DocsMapPerformancePage",
|
||||
);
|
||||
const LazyDocsMapLodPage = lazyNamed(
|
||||
() => import("@/pages/docs/map-lod/page"),
|
||||
"DocsMapLodPage",
|
||||
);
|
||||
|
||||
export const DocsLayoutRoute = createDocsRoute(LazyDocsLayout);
|
||||
export const DocsReadmeRoute = createDocsRoute(LazyDocsReadmePage);
|
||||
@@ -136,3 +140,4 @@ export const DocsThreeDebuggingRoute = createDocsRoute(
|
||||
export const DocsMapPerformanceRoute = createDocsRoute(
|
||||
LazyDocsMapPerformancePage,
|
||||
);
|
||||
export const DocsMapLodRoute = createDocsRoute(LazyDocsMapLodPage);
|
||||
|
||||
Reference in New Issue
Block a user