From 1330ebac018477e2ec8b2a6a72b7ac0c9125c29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Thu, 12 Mar 2026 12:50:06 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[construction-pmis]=20BIM=20=EB=B7=B0?= =?UTF-8?q?=EC=96=B4=20=EA=B8=B0=EC=88=A0=20=EB=AC=B8=EC=84=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Three.js 기반 웹 3D 건물 모델 뷰어 기술 원리 문서화 - 렌더링 파이프라인, 건물 모델 생성, React-Three.js 연동 패턴 - INDEX.md에 문서 등록 --- INDEX.md | 1 + features/construction-pmis/bim-viewer.md | 314 +++++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 features/construction-pmis/bim-viewer.md diff --git a/INDEX.md b/INDEX.md index b0ab518..93629cc 100644 --- a/INDEX.md +++ b/INDEX.md @@ -155,6 +155,7 @@ DB 도메인별: | [approvals/README.md](features/approvals/README.md) | 결재관리 시스템 | | [approvals/mng-api-comparison.md](features/approvals/mng-api-comparison.md) | 결재관리 MNG↔API 비교 분석 및 React 구현 가이드 | | [email/README.md](features/email/README.md) | 이메일 시스템 (테넌트별 SMTP 설정, 프리셋, 연결 테스트) | +| [construction-pmis/bim-viewer.md](features/construction-pmis/bim-viewer.md) | BIM 뷰어 (Three.js 기반 웹 3D 건물 모델 뷰어) | --- diff --git a/features/construction-pmis/bim-viewer.md b/features/construction-pmis/bim-viewer.md new file mode 100644 index 0000000..e1ddeca --- /dev/null +++ b/features/construction-pmis/bim-viewer.md @@ -0,0 +1,314 @@ +# BIM 뷰어 — Three.js 기반 웹 3D 건물 모델 뷰어 + +> **작성일**: 2026-03-12 +> **상태**: Phase 1 완료 (프로토타입) +> **소스**: `mng/resources/views/juil/bim-viewer.blade.php` + +--- + +## 1. 개요 + +### 1.1 목적 + +건설PMIS(Construction Project Management Information System)의 BIM(Building Information Modeling) 뷰어 기능이다. 웹 브라우저에서 별도 플러그인 없이 3D 건물 모델을 렌더링하고, 요소를 선택하여 속성 정보를 조회할 수 있다. + +### 1.2 핵심 기술 스택 + +| 기술 | 역할 | CDN | +|------|------|-----| +| **Three.js r128** | WebGL 기반 3D 렌더링 엔진 | `cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js` | +| **OrbitControls** | 카메라 회전/줌/팬 조작 | `cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js` | +| **React 18** | UI 컴포넌트 (사이드바, 툴바, 정보 패널) | CDN + Babel 브라우저 트랜스파일 | +| **Tailwind CSS** | UI 스타일링 | CDN | + +### 1.3 아키텍처 + +``` +┌─────────────────────────────────────────────────┐ +│ Blade 템플릿 (@extends layouts.app) │ +│ ┌─────────────────────────────────────────────┐│ +│ │ React (CDN + Babel) ││ +│ │ ┌──────┐ ┌──────────────┐ ┌───────────┐ ││ +│ │ │사이드 │ │ Three.js │ │ 정보 패널 │ ││ +│ │ │ 바 │ │ 3D Viewport │ │ (React) │ ││ +│ │ │(React)│ │ (WebGL) │ │ │ ││ +│ │ └──────┘ └──────────────┘ └───────────┘ ││ +│ │ ┌──────────────┐ ││ +│ │ │ 툴바(React) │ ││ +│ │ └──────────────┘ ││ +│ └─────────────────────────────────────────────┘│ +└─────────────────────────────────────────────────┘ +``` + +- **React**: UI 컴포넌트 관리 (사이드바, 툴바, 정보 패널) +- **Three.js**: 3D 렌더링 (건물, 조명, 그림자, 카메라) +- **연결 방식**: React `useRef`로 DOM 요소를 Three.js에 전달, `useEffect`로 생명주기 관리 + +--- + +## 2. Three.js 렌더링 파이프라인 + +### 2.1 기본 구조 + +``` +브라우저 (Chrome/Edge) + └── WebGL API (GPU 가속 그래픽) + └── Three.js (WebGL 추상화 라이브러리) + ├── Scene — 3D 공간 (모든 객체의 컨테이너) + ├── Camera — 시점 (PerspectiveCamera, FOV 45도) + ├── Renderer — 화면 출력 (WebGLRenderer, 안티앨리어싱) + ├── Lights — 조명 (Hemisphere + Directional + Ambient) + └── Mesh — 물체 = Geometry(형태) + Material(재질) +``` + +### 2.2 렌더링 루프 + +Three.js는 매 프레임(~60fps)마다 장면을 다시 그린다: + +```javascript +animate() { + requestAnimationFrame(() => this.animate()); // 다음 프레임 예약 + + // 카메라 전환 애니메이션 (lerp: 선형 보간) + if (this.targetPos) { + this.camera.position.lerp(this.targetPos, 0.07); // 현재→목표, 7%씩 이동 + this.controls.target.lerp(this.targetLook, 0.07); + if (this.camera.position.distanceTo(this.targetPos) < 0.2) + this.targetPos = null; // 도착 시 애니메이션 종료 + } + + this.controls.update(); // 사용자 조작 반영 + this.renderer.render(this.scene, this.camera); // GPU 렌더링 +} +``` + +> `lerp` (Linear Interpolation): 현재 값에서 목표 값으로 매 프레임 일정 비율만큼 이동하는 방식이다. 처음엔 빠르게, 목표에 가까울수록 느리게 이동하여 자연스러운 이징 효과를 만든다. + +### 2.3 조명 구성 + +```javascript +// 반구광 — 하늘(파랑) + 지면(갈색) 사이 자연 채광 +HemisphereLight(0xb1e1ff, 0xb97a20, 0.55) + +// 태양광 — 그림자 생성, 건물에 방향성 빛 +DirectionalLight(0xffffff, 0.85) // 위치: (45, 50, 35) + └── Shadow Map: 2048×2048 (PCFSoftShadowMap) + +// 환경광 — 그림자 영역의 최소 밝기 +AmbientLight(0xffffff, 0.25) +``` + +--- + +## 3. 건물 모델 생성 + +### 3.1 건물 사양 + +| 항목 | 값 | +|------|------| +| 건물 용도 | 물류센터 (데모) | +| 크기 | 60m (가로) × 30m (세로) × 12m (높이) | +| 층수 | 지상 3층 (각 4m) | +| 기둥 격자 | 7 × 4 (간격 10m × 10m) | +| 좌표계 | X = 가로(길이), Y = 높이(상향), Z = 세로(깊이) | + +### 3.2 핵심 원리 — 모든 요소는 박스의 조합 + +```javascript +// 기둥 하나 = 가로 0.45m × 높이 3.7m × 세로 0.45m 박스 +new THREE.BoxGeometry(0.45, 3.7, 0.45) + +// 바닥 슬래브 = 60m × 0.3m × 30m 얇은 판 +new THREE.BoxGeometry(60.6, 0.3, 30.6) + +// 창문 = 반투명 재질 + 얇은 박스 +new THREE.MeshPhongMaterial({ color: 0x00BCD4, transparent: true, opacity: 0.35 }) +``` + +이것을 **반복문**으로 배치하면 건물이 완성된다: + +```javascript +// 7 × 4 격자 × 3층 = 기둥 84개 +for (let floor = 0; floor < 3; floor++) + for (let x = 0; x < 7; x++) + for (let z = 0; z < 4; z++) + this.box(0.45, 3.7, 0.45, [x * 10, floor * 4 + 2, z * 10], {...}, 'column'); +``` + +### 3.3 요소 색상 체계 + +| 요소 | 색상 코드 | 시각적 | 개수 | +|------|----------|--------|------| +| 바닥 슬래브 | `0x81C784` | 연두 | 3 | +| 지붕 | `0x4CAF50` | 초록 | 1 | +| 기둥 | `0xFF9800` | 주황 | 84 | +| 보 | `0xFFC107` | 황금 | 33 | +| 벽체 | `0x42A5F5` | 파랑 | ~50 | +| 창호 | `0x00BCD4` | 시안 (반투명) | 18 | +| 출입문 | `0x8B4513` | 갈색 | 3 | +| 계단실 | `0xFFAB91` | 살몬 | 15 | +| **합계** | | | **~200+** | + +### 3.4 건물 구성 상세 + +``` +지붕 슬래브 ────── y = 12.0m + │ +3F 기둥/벽/창 ─── y = 8.0 ~ 12.0m + │ +2F 바닥 슬래브 ── y = 8.0m + │ +2F 기둥/벽/창 ─── y = 4.0 ~ 8.0m + │ +1F 바닥 슬래브 ── y = 4.0m + │ +1F 기둥/벽/창 ─── y = 0.0 ~ 4.0m (후면: 하역장 도어 3개) + │ +기초 슬래브 ───── y = 0.0m + │ +지면 (그라운드) ─ y = -0.02m +``` + +--- + +## 4. 사용자 인터랙션 + +### 4.1 카메라 조작 (OrbitControls) + +| 조작 | 동작 | 원리 | +|------|------|------| +| 마우스 드래그 | 카메라가 건물 중심을 공전 | Orbit (구면 좌표계 회전) | +| 스크롤 (휠) | 줌 인/아웃 | 카메라 거리 조절 | +| 우클릭 드래그 | 시점 평행 이동 | Pan (카메라 + 타겟 동시 이동) | + +OrbitControls는 `damping` (감쇠)이 적용되어 조작 후 부드럽게 멈춘다: + +```javascript +this.controls.enableDamping = true; +this.controls.dampingFactor = 0.08; +``` + +### 4.2 요소 클릭 선택 (Raycaster) + +``` +마우스 클릭 좌표 (2D 화면) + ↓ NDC 좌표 변환 (-1 ~ +1) +카메라에서 클릭 방향으로 "광선(Ray)" 발사 + ↓ raycaster.intersectObjects() +광선이 3D 메시와 충돌 검사 + ↓ +충돌한 메시의 userData (이름, 재질, 층, 치수) 읽기 + ↓ +React 상태 업데이트 → 우측 패널에 정보 표시 +``` + +각 요소에 메타데이터를 미리 저장해두어 클릭 시 즉시 조회된다: + +```javascript +mesh.userData = { + type: 'column', // 요소 유형 + name: 'C-001', // 식별자 + material: 'H형강 (SS400)', // 재질 + floor: '1F', // 층 + dimensions: '400×400×3,700mm', // 치수 + grid: '(1,1)', // 격자 위치 +}; +``` + +### 4.3 시점 전환 + +| 프리셋 | 카메라 위치 | 용도 | +|--------|-----------|------| +| 투시도 | (55, 35, 55) | 전체 조감 | +| 정면 | (30, 8, -35) | 남측 입면 | +| 우측 | (85, 8, 15) | 동측 입면 | +| 상부 | (30, 55, 15) | 평면도 | +| 배면 | (30, 8, 55) | 북측 (하역장) | + +`lerp` 보간으로 현재 위치에서 목표까지 부드럽게 전환된다. + +### 4.4 요소 토글 & 와이어프레임 + +- **요소 토글**: `THREE.Group` 단위로 `visible` 속성을 전환하여 요소 유형별 표시/숨김 +- **와이어프레임**: 모든 메시의 `material.wireframe` 속성을 일괄 전환 + +--- + +## 5. React-Three.js 연동 패턴 + +### 5.1 BimScene 클래스 + +Three.js 로직을 `BimScene` 클래스로 캡슐화하여 React와 분리한다: + +```javascript +class BimScene { + constructor(el) { /* DOM 요소 참조 */ } + init() { /* Scene, Camera, Renderer, Controls, 건물 생성 */ } + onClick(e) { /* Raycaster로 요소 선택 */ } + setView(preset) { /* 카메라 전환 */ } + toggleGroup() { /* 요소 유형 표시/숨김 */ } + animate() { /* 렌더 루프 */ } + dispose() { /* 리소스 정리 */ } +} +``` + +### 5.2 React에서 사용 + +```javascript +function BimViewerApp() { + const vpRef = useRef(null); // 3D 뷰포트 DOM 참조 + const sceneRef = useRef(null); // BimScene 인스턴스 참조 + + useEffect(() => { + const bim = new BimScene(vpRef.current); + bim.init(); + bim.onSelect = setSelected; // 선택 이벤트 → React 상태 + sceneRef.current = bim; + return () => bim.dispose(); // 언마운트 시 정리 + }, []); + + return ( +
+ +
{/* Three.js 렌더링 대상 */} + +
+ ); +} +``` + +핵심 원칙: +- Three.js는 React 렌더 사이클 **밖에서** 자체 애니메이션 루프를 실행한다 +- React → Three.js 통신: `sceneRef.current.setView()` 등 메서드 직접 호출 +- Three.js → React 통신: `onSelect` 콜백으로 React `setState` 호출 + +--- + +## 6. 파일 구조 + +| 파일 | 위치 | 설명 | +|------|------|------| +| `bim-viewer.blade.php` | `mng/resources/views/juil/` | BIM 뷰어 전체 (Three.js + React) | +| `PlanningController.php` | `mng/app/Http/Controllers/Juil/` | `bimViewer()` 메서드 | +| `web.php` | `mng/routes/` | `GET /juil/construction-pmis/bim-viewer` | + +--- + +## 7. 향후 계획 (Phase 2+) + +| Phase | 기능 | 기술 | +|-------|------|------| +| **Phase 2** | IFC 파일 업로드 + 실제 BIM 모델 렌더링 | [That Open Engine](https://github.com/ThatOpen/engine_components) (구 IFC.js) | +| **Phase 3** | 요소 속성 패널 고도화, 2D 평면도 모드 | Three.js Orthographic Camera | +| **Phase 4** | 모델 파일 관리, 버전 이력, 협력업체 조회 | Laravel API + DB | + +--- + +## 관련 문서 + +- [건설PMIS 대시보드](../construction-pmis/) — PMIS 메인 대시보드 +- [PmisWorker 모델](../../../../api/database/migrations/2026_03_12_120000_create_pmis_workers_table.php) — PMIS 작업자 프로필 테이블 + +--- + +**최종 업데이트**: 2026-03-12