Files
sam-docs/features/construction-pmis/bim-viewer.md
김보곤 fa85bd388a docs: [bim] BIM 뷰어 문서 Phase 2 반영
- Phase 1 전용 → Phase 2 완료 상태로 업데이트
- IFC 업로드/다운로드, web-ifc, 듀얼 모드 설명 추가
- IFC→Three.js 변환 파이프라인, IFC Export 구조 문서화
- BimScene 클래스 메서드 목록 최신화
2026-03-12 13:35:14 +09:00

16 KiB
Raw Blame History

BIM 뷰어 — Three.js + web-ifc 기반 웹 3D BIM 뷰어

작성일: 2026-03-12 상태: Phase 2 완료 (IFC 업로드 + 다운로드) 소스: mng/resources/views/juil/bim-viewer.blade.php


1. 개요

1.1 목적

건설PMIS(Construction Project Management Information System)의 BIM(Building Information Modeling) 뷰어 기능이다. 웹 브라우저에서 별도 플러그인 없이 3D 건물 모델을 렌더링하고, 요소를 선택하여 속성 정보를 조회할 수 있다.

1.2 주요 기능

기능 설명 Phase
데모 건물 렌더링 물류센터 3D 모델 (BoxGeometry 조합) Phase 1
요소 클릭 선택 Raycaster로 3D 요소 선택 → 속성 조회 Phase 1
시점 전환 투시도/정면/우측/상부/배면 프리셋 Phase 1
요소 토글 & 와이어프레임 요소 유형별 표시/숨김, 와이어프레임 모드 Phase 1
IFC 파일 업로드 .ifc 파일 업로드 → 실제 BIM 모델 렌더링 Phase 2
IFC 파일 다운로드 현재 모델을 IFC 파일로 내보내기 Phase 2
드래그 앤 드롭 IFC 파일을 뷰포트에 드래그하여 로드 Phase 2

1.3 핵심 기술 스택

기술 역할 버전/CDN
Three.js WebGL 기반 3D 렌더링 엔진 r128 (CDN)
OrbitControls 카메라 회전/줌/팬 조작 r128 (CDN)
web-ifc IFC 파일 파싱 (WASM 기반) 0.0.66 (CDN, 지연 로드)
React 18 UI 컴포넌트 (사이드바, 툴바, 정보 패널) CDN + Babel 브라우저 트랜스파일
Tailwind CSS UI 스타일링 CDN

1.4 아키텍처

┌─────────────────────────────────────────────────────────┐
│  Blade 템플릿 (@extends layouts.app)                    │
│  ┌─────────────────────────────────────────────────────┐│
│  │  React (CDN + Babel)                                ││
│  │  ┌──────┐  ┌──────────────────┐  ┌───────────────┐ ││
│  │  │사이드 │  │  Three.js        │  │ 정보 패널     │ ││
│  │  │ 바   │  │  3D Viewport     │  │ (모델/선택/   │ ││
│  │  │(React)│  │  (WebGL)         │  │  통계)        │ ││
│  │  └──────┘  └──────────────────┘  └───────────────┘ ││
│  │            ┌──────────────────┐                     ││
│  │            │  툴바 (React)    │                     ││
│  │            │  IFC업로드/다운로드│                     ││
│  │            └──────────────────┘                     ││
│  └─────────────────────────────────────────────────────┘│
│                                                         │
│  ┌─────────────────┐  ┌──────────────────────────────┐  │
│  │  IFCHelper       │  │  generateDemoIFC()           │  │
│  │  (web-ifc 래퍼)  │  │  (Three.js → IFC2X3 변환)   │  │
│  └─────────────────┘  └──────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
  • React: UI 컴포넌트 관리 (사이드바, 툴바, 정보 패널)
  • Three.js: 3D 렌더링 (건물, 조명, 그림자, 카메라)
  • web-ifc: IFC 파일 파싱 → 지오메트리 추출 (WASM, 지연 로드)
  • 연결 방식: React useRef로 DOM 요소를 Three.js에 전달, useEffect로 생명주기 관리

2. 듀얼 모드 — 데모 / IFC

BIM 뷰어는 두 가지 모드로 동작한다:

항목 데모 모드 (demo) IFC 모드 (ifc)
진입 방식 기본 (페이지 로드 시) IFC 파일 업로드/드래그 시
모델 원본 createDemoBuilding() (코드 내 하드코딩) 사용자 업로드 .ifc 파일
지오메트리 BoxGeometry 조합 (~200개) web-ifc StreamAllMeshesBufferGeometry
요소 선택 시 userData (type, name, material, floor 등) IFCHelper.getElementInfo() (IFC 속성)
요소 토글 유형별 Group 표시/숨김 미지원 (전체 모델 표시)
IFC 다운로드 generateDemoIFC() → IFC2X3 STEP 생성 원본 버퍼 그대로 재다운로드

모드 전환 흐름:

[페이지 로드] → 데모 모드
      │
      ├── IFC 업로드 ──→ IFC 모드 (데모 숨김)
      │                      │
      │                      ├── "데모 모델" 버튼 ──→ 데모 모드 복귀
      │                      └── 다른 IFC 업로드 ──→ 새 IFC 로드
      │
      └── IFC 다운로드 → generateDemoIFC() 실행 → .ifc 파일 다운로드

3. IFC 파일 처리 (Phase 2)

3.1 web-ifc 지연 로드

web-ifc WASM 번들은 약 7MB이다. 페이지 로드 시 다운로드하지 않고, IFC 파일을 처음 업로드할 때만 로드한다:

// 동적 module script 주입 방식
function loadWebIFCLib() {
    const s = document.createElement('script');
    s.type = 'module';
    s.textContent = `
        import * as WebIFC from '${WEBIFC_CDN}web-ifc-api.js';
        window._WebIFC = WebIFC;
        window.dispatchEvent(new CustomEvent('_wifcOk'));
    `;
    document.head.appendChild(s);
}

Babel text/babel 컨텍스트에서 동적 import()가 불안정하므로, 별도 <script type="module">을 주입하여 ES module import를 수행하고 window._WebIFC로 노출한다.

3.2 IFCHelper 클래스

web-ifc API를 래핑하여 파싱과 요소 정보 조회를 담당한다:

class IFCHelper {
    async init(onMsg)          // web-ifc 초기화, WASM 로드, typeMap 구축
    parse(buffer, onMsg)       // IFC 파일 → StreamAllMeshes → 지오메트리 배열
    getElementInfo(expressID)  // expressID → IFC 속성 (타입, 이름, GlobalId 등)
    close()                    // 모델 닫기, 캐시 정리
}

3.3 IFC → Three.js 변환 파이프라인

.ifc 파일 (ArrayBuffer)
    ↓  IFCHelper.parse()
web-ifc StreamAllMeshes
    ↓  각 메시에서 vertices + indices + transform 추출
Float32Array (위치 3 + 노멀 3 = stride 6)
    ↓  Three.js BufferGeometry로 변환
BufferAttribute(position, 3) + BufferAttribute(normal, 3)
    ↓  Matrix4.fromArray(transform) 적용
MeshPhongMaterial (IFC 원본 색상 + 투명도)
    ↓
THREE.Mesh → ifcGroup(THREE.Group)에 추가
    ↓
fitToModel() → 바운딩 박스 기준 카메라 자동 조정

3.4 IFC 파일 다운로드 (IFC Export)

모드 동작 출력 파일명
데모 generateDemoIFC(meshes) → IFC2X3 STEP 텍스트 생성 SAM_Demo_Building.ifc
IFC this.ifcBuffer (업로드 시 저장한 원본) 그대로 다운로드 model.ifc

데모 모델의 IFC 변환 구조:

Three.js 메시 (BoxGeometry)
    ↓  geometry.parameters → width, height, depth
    ↓  mesh.position → x, y, z
    ↓  mesh.userData → type, floor, name, material

IFC2X3 STEP 엔티티 생성:
    IfcProject → IfcSite → IfcBuilding → IfcBuildingStorey (1F~RF)
    각 메시 → IfcRectangleProfileDef + IfcExtrudedAreaSolid + IfcLocalPlacement
    유형 매핑: column→IFCCOLUMN, beam→IFCBEAM, floor/roof→IFCSLAB, ...

좌표계 변환:
    Three.js (x, y, z) → IFC (x, z, y)  // Y-up → Z-up
    요소 기준점: 바닥 중심 (Three.js center → IFC bottom)

4. Three.js 렌더링 파이프라인

4.1 기본 구조

브라우저 (Chrome/Edge)
  └── WebGL API (GPU 가속 그래픽)
       └── Three.js r128 (WebGL 추상화 라이브러리)
            ├── Scene     — 3D 공간 (모든 객체의 컨테이너)
            ├── Camera    — 시점 (PerspectiveCamera, FOV 45도)
            ├── Renderer  — 화면 출력 (WebGLRenderer, 안티앨리어싱)
            ├── Lights    — 조명 (Hemisphere + Directional + Ambient)
            ├── Mesh      — 물체 = Geometry(형태) + Material(재질)
            └── FogExp2   — 거리 안개 (밀도 0.004)

4.2 렌더링 루프

Three.js는 매 프레임(~60fps)마다 장면을 다시 그린다:

animate() {
    requestAnimationFrame(() => this.animate());
    if (this.targetPos) {
        this.camera.position.lerp(this.targetPos, 0.07);
        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);
}

4.3 조명 구성

HemisphereLight(0xb1e1ff, 0xb97a20, 0.55)  // 반구광 (하늘+지면)
DirectionalLight(0xffffff, 0.85)             // 태양광 (그림자)
  └── Shadow Map: 2048×2048 (PCFSoftShadowMap)
AmbientLight(0xffffff, 0.25)                 // 환경광

5. 데모 건물 모델

5.1 건물 사양

항목
건물 용도 물류센터 (데모)
크기 60m (가로) × 30m (세로) × 12m (높이)
층수 지상 3층 (각 4m)
기둥 격자 7 × 4 (간격 10m × 10m)
좌표계 X = 가로(길이), Y = 높이(상향), Z = 세로(깊이)

5.2 요소 색상 체계

요소 색상 코드 개수
바닥 슬래브 0x81C784 연두 3
지붕 0x4CAF50 초록 1
기둥 0xFF9800 주황 84
0xFFC107 황금 33
벽체 0x42A5F5 파랑 ~50
창호 0x00BCD4 시안 (반투명) 18
출입문 0x8B4513 갈색 3
계단실 0xFFAB91 살몬 15
합계 ~200+

5.3 건물 단면

지붕 슬래브 ────── 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

6. 사용자 인터랙션

6.1 카메라 조작 (OrbitControls)

조작 동작
마우스 드래그 카메라가 건물 중심을 공전 (Orbit)
스크롤 (휠) 줌 인/아웃
우클릭 드래그 시점 평행 이동 (Pan)

6.2 요소 클릭 선택 (Raycaster)

마우스 클릭 좌표 (2D)
    ↓  NDC 좌표 변환 (-1 ~ +1)
카메라에서 광선(Ray) 발사
    ↓  raycaster.intersectObjects()
3D 메시와 충돌 검사
    ↓
[데모 모드] userData (type, name, material...) 읽기
[IFC 모드]  expressID → IFCHelper.getElementInfo() → IFC 속성 조회
    ↓
React 상태 업데이트 → 우측 정보 패널 표시

6.3 시점 전환

프리셋 용도
투시도 전체 조감
정면 남측 입면
우측 동측 입면
상부 평면도
배면 북측 (하역장)

IFC 모드에서는 모델 바운딩 박스 기준으로 시점이 자동 계산된다.

6.4 IFC 업로드 / 다운로드

기능 방법
IFC 업로드 툴바 "IFC 업로드" 버튼 또는 뷰포트에 드래그 앤 드롭
IFC 다운로드 툴바 "IFC 다운로드" 버튼 (초록색)
데모 복귀 IFC 모드에서 "데모 모델" 버튼

7. React-Three.js 연동 패턴

7.1 BimScene 클래스

Three.js 로직을 BimScene 클래스로 캡슐화하여 React와 분리한다:

class BimScene {
    constructor(el)       // DOM 요소 참조, 상태 초기화
    init()                // Scene, Camera, Renderer, Controls, 데모 건물 생성
    createDemoBuilding()  // 데모 물류센터 모델 생성
    async loadIFC(buffer) // IFC 파일 파싱 → BufferGeometry → 씬 추가
    clearIFCModel()       // IFC 모델 정리 (geometry/material dispose)
    switchToDemo()        // 데모 모드 복귀
    exportIFC()           // IFC 파일 다운로드 (데모: 생성, IFC: 원본)
    onClick(e)            // Raycaster로 요소 선택
    setView(preset)       // 카메라 전환 (lerp 보간)
    fitToModel(obj)       // 바운딩 박스 기준 카메라 자동 조정
    toggleGroup(name)     // 요소 유형 표시/숨김 (데모 모드)
    toggleWireframe(on)   // 와이어프레임 토글
    getCounts()           // 요소 통계 반환
    animate()             // 렌더 루프
    dispose()             // 리소스 정리
}

7.2 React 컴포넌트 구성

컴포넌트 역할
BimViewerApp 루트 컴포넌트 — 상태 관리, 이벤트 핸들러
BimSidebar 좌측 PMIS 메뉴 사이드바
BimToolbar 하단 툴바 (시점, 토글, 업로드/다운로드)
BimInfoPanel 우측 패널 (모델 정보, 선택 요소, 통계)
LoadingOverlay IFC 로딩 중 오버레이

7.3 통신 패턴

React → Three.js:  sceneRef.current.setView('front')
                    sceneRef.current.exportIFC()
                    sceneRef.current.loadIFC(buffer)

Three.js → React:  bim.onSelect = setSelected      (요소 선택 콜백)
                    bim.onProgress = setLoading      (로딩 상태 콜백)

8. 파일 구조

파일 위치 설명
bim-viewer.blade.php mng/resources/views/juil/ BIM 뷰어 전체 (~900줄, Three.js + web-ifc + React)
PlanningController.php mng/app/Http/Controllers/Juil/ bimViewer() 메서드
web.php mng/routes/ GET /juil/construction-pmis/bim-viewer

9. 향후 계획 (Phase 3+)

Phase 기능 기술
Phase 1 데모 건물 + 3D 뷰어 Three.js r128 (완료)
Phase 2 IFC 업로드/다운로드 + 실제 BIM 렌더링 web-ifc 0.0.66 (완료)
Phase 3 요소 속성 패널 고도화, 2D 평면도 모드 Three.js Orthographic Camera
Phase 4 모델 파일 관리, 버전 이력, 협력업체 조회 Laravel API + DB

관련 문서


최종 업데이트: 2026-03-12