# 기술 사양서 (Technical Specifications) ## 🏗️ 시스템 아키텍처 ### 전체 시스템 구조 ``` [모션캡쳐 스튜디오] → [Unity 서버] → [WebSocket] → [웹 클라이언트] ↓ ↓ ↓ 모션 데이터 수집 실시간 스트리밍 3D 렌더링 + 제어 ``` ### 데이터 흐름 1. **모션캡쳐 → Unity**: Mocap 장비에서 Unity로 실시간 데이터 입력 2. **Unity → Web**: WebSocket을 통한 실시간 아바타 Transform 전송 3. **Web → Unity**: 녹화 명령 및 제어 신호 전송 4. **Web**: 로컬 모션 데이터 저장 및 파일 생성 ## 📡 통신 프로토콜 ### WebSocket 메시지 포맷 #### 1. 모션 데이터 (Unity → Web) ```json { "type": "motion_frame", "timestamp": 1640995200000, "frameRate": 30, "avatar": { "bones": [ { "name": "Hips", "position": {"x": 0.0, "y": 1.0, "z": 0.0}, "rotation": {"x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0}, "scale": {"x": 1.0, "y": 1.0, "z": 1.0} }, { "name": "Spine", "position": {"x": 0.0, "y": 1.2, "z": 0.0}, "rotation": {"x": 0.1, "y": 0.0, "z": 0.0, "w": 0.995} } ] } } ``` #### 2. 녹화 제어 명령 (Web → Unity) ```json { "type": "recording_command", "command": "start_recording", "parameters": { "filename": "motion_capture_001", "format": "fbx", "frameRate": 30, "duration": 300 } } ``` #### 3. 상태 응답 (Unity → Web) ```json { "type": "recording_status", "status": "recording", "filename": "motion_capture_001.fbx", "duration": 45.2, "frameCount": 1356, "fileSizeKB": 2048 } ``` ### 에러 처리 ```json { "type": "error", "code": "RECORDING_FAILED", "message": "녹화 파일 생성에 실패했습니다.", "details": { "cause": "disk_space_insufficient", "timestamp": 1640995200000 } } ``` ## 🎮 Unity 구현 사양 ### 핵심 컴포넌트 #### 1. WebSocketServer.cs ```csharp public class WebSocketServer : MonoBehaviour { [SerializeField] private int port = 8080; [SerializeField] private float updateRate = 30f; private WebSocketSharp.Server.WebSocketServer server; private MotionDataStreamer streamer; public void StartServer() { /* 서버 시작 */ } public void StopServer() { /* 서버 종료 */ } public void BroadcastMotionData(MotionFrame frame) { /* 데이터 전송 */ } } ``` #### 2. MotionDataStreamer.cs ```csharp public class MotionDataStreamer : MonoBehaviour { [SerializeField] private Transform avatarRoot; [SerializeField] private string[] boneNames; private Dictionary boneTransforms; public MotionFrame CaptureCurrentFrame() { // 현재 아바타 상태를 MotionFrame으로 변환 } public void SendMotionData() { // 실시간으로 모션 데이터 전송 } } ``` #### 3. RemoteMotionRecorder.cs ```csharp public class RemoteMotionRecorder : MonoBehaviour { private EasyMotionRecorder motionRecorder; private bool isRecording = false; public void StartRecording(string filename) { /* 녹화 시작 */ } public void StopRecording() { /* 녹화 종료 */ } public RecordingStatus GetStatus() { /* 상태 조회 */ } } ``` ### 데이터 구조 ```csharp [System.Serializable] public class MotionFrame { public long timestamp; public float frameRate; public BoneData[] bones; } [System.Serializable] public class BoneData { public string name; public Vector3 position; public Quaternion rotation; public Vector3 scale; } ``` ## 🌐 웹 클라이언트 사양 ### 핵심 모듈 #### 1. WebSocketClient.js ```javascript class WebSocketClient { constructor(url) { this.url = url; this.socket = null; this.onMotionData = null; this.onStatusUpdate = null; } connect() { this.socket = new WebSocket(this.url); this.setupEventHandlers(); } sendCommand(command) { this.socket.send(JSON.stringify(command)); } setupEventHandlers() { this.socket.onmessage = (event) => { const data = JSON.parse(event.data); this.handleMessage(data); }; } } ``` #### 2. MotionViewer.js ```javascript class MotionViewer { constructor(containerId) { this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(); this.renderer = new THREE.WebGLRenderer(); this.avatar = null; this.bones = new Map(); } loadAvatar(modelPath) { // 3D 아바타 모델 로드 } updateMotion(motionFrame) { // 실시간 모션 데이터 적용 motionFrame.bones.forEach(bone => { const boneObject = this.bones.get(bone.name); if (boneObject) { boneObject.position.set(bone.position.x, bone.position.y, bone.position.z); boneObject.quaternion.set(bone.rotation.x, bone.rotation.y, bone.rotation.z, bone.rotation.w); } }); } render() { this.renderer.render(this.scene, this.camera); requestAnimationFrame(() => this.render()); } } ``` #### 3. MotionRecorder.js ```javascript class MotionRecorder { constructor() { this.isRecording = false; this.motionData = []; this.startTime = null; } startRecording() { this.isRecording = true; this.motionData = []; this.startTime = Date.now(); } addFrame(motionFrame) { if (this.isRecording) { this.motionData.push({ ...motionFrame, relativeTime: Date.now() - this.startTime }); } } stopRecording() { this.isRecording = false; return this.motionData; } } ``` #### 4. MotionExporter.js ```javascript class MotionExporter { exportToBVH(motionData) { // BVH 포맷으로 변환 const bvhContent = this.generateBVHContent(motionData); return this.createDownloadableFile(bvhContent, 'motion.bvh'); } exportToFBX(motionData) { // FBX 포맷으로 변환 (Three.js FBXExporter 활용) const fbxContent = this.generateFBXContent(motionData); return this.createDownloadableFile(fbxContent, 'motion.fbx'); } exportToJSON(motionData) { // JSON 포맷으로 내보내기 const jsonContent = JSON.stringify(motionData, null, 2); return this.createDownloadableFile(jsonContent, 'motion.json'); } createDownloadableFile(content, filename) { const blob = new Blob([content], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; link.click(); URL.revokeObjectURL(url); } } ``` ## 🎨 사용자 인터페이스 사양 ### HTML 구조 ```html 원격 모션캡쳐 시스템
연결 대기 중...
00:00:00 프레임: 0 크기: 0KB

녹화 설정

``` ### CSS 스타일 가이드 ```css /* 주요 색상 팔레트 */ :root { --primary-color: #2c3e50; --secondary-color: #3498db; --success-color: #27ae60; --warning-color: #f39c12; --danger-color: #e74c3c; --background-color: #ecf0f1; } /* 레이아웃 */ #app { display: grid; grid-template-areas: "status status" "viewer controls" "viewer settings"; grid-template-columns: 2fr 1fr; height: 100vh; gap: 10px; padding: 10px; } #viewer-container { grid-area: viewer; background: #2c3e50; border-radius: 8px; position: relative; } /* 반응형 디자인 */ @media (max-width: 768px) { #app { grid-template-areas: "status" "viewer" "controls" "settings"; grid-template-columns: 1fr; } } ``` ## ⚡ 성능 최적화 ### 네트워크 최적화 - **데이터 압축**: gzip 압축 적용 - **전송 주기**: 30fps 기본, 네트워크 상태에 따라 조절 - **델타 압축**: 이전 프레임과의 차이만 전송 - **버퍼링**: 클라이언트 사이드 적응형 버퍼 ### 렌더링 최적화 - **LOD 시스템**: 거리에 따른 모델 디테일 조절 - **프러스텀 컬링**: 카메라 시야 밖 객체 제외 - **인스턴싱**: 반복 객체 최적화 - **텍스처 압축**: 적절한 해상도 및 포맷 사용 ### 메모리 최적화 - **오브젝트 풀링**: 반복 생성/삭제 객체 재사용 - **가비지 컬렉션**: 불필요한 객체 생성 최소화 - **IndexedDB**: 대용량 모션 데이터 효율적 저장 ## 🔒 보안 고려사항 ### 데이터 보안 - **HTTPS/WSS**: 암호화된 통신 프로토콜 사용 - **토큰 인증**: JWT 기반 사용자 인증 - **데이터 무결성**: 체크섬을 통한 데이터 검증 ### 네트워크 보안 - **CORS 설정**: 허용된 도메인에서만 접근 - **레이트 리미팅**: 과도한 요청 방지 - **방화벽 설정**: 필요한 포트만 개방 ## 📊 모니터링 및 로깅 ### 성능 메트릭 - **지연시간**: WebSocket 왕복 시간 측정 - **프레임 드롭**: 누락된 프레임 수 추적 - **대역폭 사용량**: 실시간 네트워크 사용량 - **CPU/메모리 사용률**: 시스템 리소스 모니터링 ### 로그 시스템 ```javascript class Logger { static logMotionData(frameData) { console.log(`[MOTION] Frame ${frameData.frameNumber} received`); } static logError(error, context) { console.error(`[ERROR] ${context}:`, error); } static logPerformance(metric, value) { console.log(`[PERF] ${metric}: ${value}ms`); } } ``` ## 🧪 테스트 전략 ### Unity 단위 테스트 - WebSocket 서버 연결/해제 테스트 - 모션 데이터 직렬화/역직렬화 테스트 - 녹화 기능 통합 테스트 ### 웹 클라이언트 테스트 - WebSocket 통신 테스트 - 3D 렌더링 성능 테스트 - 파일 내보내기 기능 테스트 ### 통합 테스트 - 전체 시스템 End-to-End 테스트 - 장시간 연결 안정성 테스트 - 다양한 네트워크 환경 테스트 --- *이 기술 사양서는 개발 과정에서 지속적으로 업데이트됩니다.*