# 시설 3D 모델 배치

사용자가 제공한 `assets/models/structures/`의 관문·대도시·작은성·군사기지·항구·나룻터 GLB 6종을 웹 지도에 적용했습니다. 원본 모델 파일과 역사 좌표, DEM은 수정하지 않습니다.

## 타일과 크기

- 좌표는 기존 화면과 같은 **열, 행**, 0부터 시작하는 256×256 격자입니다.
- 양양은 **125,128**, 번성은 **125,127**에 고정합니다. 서로 인접한 서로 다른 타일입니다.
- 육상 시설 73곳은 각기 한 타일을 점유하는 배치 자료를 갖습니다. 고정 지점을 먼저 확보한 뒤 원래 지명에서 가까운 육지 타일을 선택합니다. 물·고산·배경 바깥을 피하고, 거리·기복과 소속 항구 모델의 간격을 고려합니다. 이번 배치는 모두 원래 위치에서 17.298km 이내입니다. 항구 때문에 조정한 지점도 원래 지명의 인근 타일입니다.
- 대도시 44, 작은 성 20, 관문 8, 군사기지 1곳입니다. 현재 합비신성에 군사기지 표현을 지정했습니다. 역사 지명의 원래 분류를 바꾸는 규칙은 아닙니다.
- 성·관문은 수평 외접 반경 6km, 군사기지는 1.5km로 정규화합니다. **가로 크기 기준 성의 ¼**입니다. 각 모델의 원래 가로·세로 비율은 유지하므로 서로 다른 모델의 높이 비율까지 ¼로 강제하지 않습니다. 실제 건물 크기가 아닌 전략 지도 표현입니다.
- 육상 모델의 모든 수평 꼭짓점은 타일 내접 반경 7.5km 안에 들어갑니다. 모델 아래에는 지형 높이에 맞춘 작은 받침을 두어 산지에서 묻히거나 공중에 떠 보이는 현상을 완화합니다. 지형 자체를 평탄화하지 않습니다.
- 점유 자료는 시설 배치용입니다. 아직 부대 슬롯·공성·도시 진입 규칙이 없는 시제품이므로 시설 타일을 일괄 이동 금지로 바꾸지 않습니다.

## 항구와 나룻터

항구 모델 35곳과 나룻터 모델 8곳은 `historical-harbors.json`의 원래 좌표를 유지합니다. 위치 후보는 기존 후보 표시 필터를 따릅니다. 항구·나루의 명목 면적은 한 칸이지만 육상 타일의 독점 점유·중앙 정렬을 적용하지 않습니다. 성과 수운 접속점은 같은 전략 타일에 있을 수 있습니다.

모델의 +Z 방향을 물 쪽으로 둡니다. 인근 현대 하천의 접선에 수직인 방향을 우선 사용하고, 하천이 멀면 등록된 수로 또는 해안 거리 필드의 물 방향을 사용합니다. 원위치에서 강을 향하는 쪽을 선택합니다. 방향은 게임 표시용 근사이며 고대 부두의 정확한 방향을 복원한 것이 아닙니다. `orientationBasis`와 `yawRadians`를 거점별 배치 데이터에 저장합니다. 기존 수군·일반 항구·도하 나루의 표식과 출처는 유지합니다.

## 웹 사용과 렌더링

**시설 3D 모델 배치 → 시설 배치 찾아가기**에서 모델을 가까이 살펴볼 수 있습니다. 선택한 육상 시설은 타일 정보에 이름·모델 종류·한 칸 점유를 표시합니다. 모델 클릭도 해당 시설의 타일을 선택합니다. **시설·건물 모델 표시**로 끄고 켤 수 있습니다. 기존 도시 종류와 항구 필터도 모델에 적용합니다.

모델은 확대 단계에 따라 표시하고 화면 밖 시설은 그리지 않습니다. 원본 6종을 한 번씩 읽어 노드 변환을 반영하고, 종류·재질별 InstancedMesh를 공유합니다. 최대 25개 모델 배치 메시와 받침 메시 1개이며 실제 화면에 없는 종류는 그리지 않습니다. 원본 지오메트리를 복제해 시설 수만큼 별도 메시를 만들지 않습니다. GLB의 색과 대도시 텍스처를 유지하며 웹에서는 가벼운 Lambert 재질을 사용합니다. 그림자 맵은 추가하지 않습니다. 카메라 이동만으로 지형·시설 지오메트리를 다시 만들지 않습니다.

모델 표시에는 GPU 비용이 추가됩니다. 가까운 화면에서의 삼각형 수·속도는 실제 표시 시설에 따라 달라집니다. 이 기능이 이전보다 FPS를 높인다고 주장하지 않습니다. 먼 화면의 시설은 기존 지명 표식으로 표현합니다.

## 파일과 검증

- `data/structure-models.source.json`: 모델 파일·반경·표시 배율, 지명별 종류 지정, 고정 타일.
- `data/structure-placements.json`: 엔진 독립 배치 자료. 원래 좌표, 게임 좌표·점유 타일·회전을 분리합니다.
- `src/domain/structure-placement.js`: 가까운 타일 선택, 중복 점유 방지, 수변 방향 계산.
- `src/rendering/structure-models.js`: 원본 GLB 노드 변환 반영과 크기 정규화.
- `src/rendering/structure-layer.js`: 모델 공유·화면 범위 선택·지형 높이 추종·모델 클릭.

`node tools/build-structures.mjs`로 배치 데이터를 생성합니다. `node tools/verify-structures.mjs`는 원본 모델 해시, 73개 고유 육상 타일, 양양·번성 좌표, 43개 수운 좌표 보존, 군사기지 크기, 여섯 GLB의 실제 지오메트리, 화면 범위 선택과 높이 갱신·모델 클릭을 검사합니다. 결과는 `exports/structures-validation.json`입니다. 텍스처와 실제 화면은 브라우저에서 확인합니다. Godot 작업과 내보내기는 수행하지 않았습니다.

수정 전 코드·배치 관련 자료·원본 모델은 `backups/pre-structures-20261004-160800.zip`에 보관했습니다. ZIP CRC와 SHA256을 확인했습니다.

모델 로더는 프로젝트 Three.js와 같은 [r170 GLTFLoader](https://github.com/mrdoob/three.js/blob/r170/examples/jsm/loaders/GLTFLoader.js)와 BufferGeometryUtils를 로컬에 포함합니다. Three.js MIT 라이선스는 `vendor/THREE-LICENSE.txt`입니다. 모델 자체의 출처·재배포 조건은 사용자가 제공한 원본의 조건을 따릅니다.
