Frame at 0.00s
# 3D 투영 공식 시각화 ## 1. 3D 포인트 투영 기본 공식 * **개념**: 3D 공간상의 점(X, Y, Z)을 2D 화면에 투영하는 간단한 수학 공식 * **계산**: * 화면 상의 X 좌표: `X / Z` * 화면 상의 Y 좌표: `Y / Z` * **결과**: Z 값이 동일한 여러 점을 애니메이션하고 회전시키면 3D 장면처럼 보임 ## 2. 웹 기술을 이용한 구현 ### 2.1. HTML 구조 ```html ``` ### 2.2. JavaScript (index.js) * **Canvas 접근**: ID를 사용하여 `canvas` 엘리먼트 직접 접근 * `let canvas = game;` (HTML 엘리먼트 ID가 유효한 JavaScript 변수명일 경우) * **Canvas 크기 설정**: * `canvas.width = 800;` * `canvas.height = 800;` * **2D 렌더링 컨텍스트 확보**: * `let ctx = canvas.getContext('2d');` * **기본 도형 그리기**: * `ctx.fillStyle = 'green';` (채우기 색상 설정) * `ctx.fillRect(0, 0, 100, 100);` (사각형 그리기) * **배경 채우기**: * `ctx.fillStyle = 'background';` * `ctx.fillRect(0, 0, canvas.width, canvas.height);` * **상수 정의**: * `const background = '#222';` * `const foreground = '#fff';` * **화면 지우기 함수**: ```javascript function clear() { ctx.fillStyle = background; ctx.fillRect(0, 0, canvas.width, canvas.height); } ``` * **점(Point) 그리기 함수**: ```javascript function point(x, y, size, color) { ctx.fillStyle = color; ctx.fillRect(x - size / 2, y - size / 2, size, size); // 중앙 정렬 } ``` * `s = 20;` (점의 크기) ### 2.3. 좌표계 변환 * **3D 디스플레이 좌표계**: * `0,0`이 **중앙** * X축: 왼쪽 `-1` ~ 오른쪽 `1` * Y축: 위쪽 `1` ~ 아래쪽 `-1` * **HTML Canvas 좌표계**: * `0,0`이 **좌측 상단** * X축: `0` ~ `width` * Y축: `0` ~ `height` * **좌표 변환 함수 (`screen`)**: 3D 좌표계를 Canvas 좌표계로 변환 ```javascript function screen(p) { let x = p.x; let y = p.y; // x: [-1, 1] -> [0, 2] -> [0, 1] -> [0, width] x = (x + 1) / 2 * canvas.width; // y: [-1, 1] -> [0, 2] -> [0, 1] -> [0, height] y = (y + 1) / 2 * canvas.height; return { x, y }; } ``` * **Canvas 좌표계 변환 시 Y축 뒤집기**: * `y = canvas.height - y;` 또는 `y = 1 - y;` (정규화된 Y 값 사용 시) ## 3. 3D 투영 구현 ### 3.1. 투영 함수 (`project`) * 3D 점을 2D 화면 좌표로 변환 ```javascript function project(p) { const x = p.x / p.z; const y = p.y / p.z; return { x, y }; } ``` * **주의**: `z` 값이 0이면 **division by zero** 오류 발생. Z값은 0보다 커야 함. ### 3.2. 애니메이션 * **프레임 함수**: ```javascript function frame(dt) { // ... (점들의 Z 값 업데이트 등) // ... (점 렌더링) requestAnimationFrame(frame); // 다음 프레임 예약 } ``` * **Z축 이동**: `zOffset` 증가 * **델타 타임 (`dt`)**: `1000 / FPS` (FPS: 초당 프레임 수) ### 3.3. 회전 함수 (`rotate`) * Y축 기준 회전 (XZ 평면 회전) ```javascript function rotate(p, angle) { const c = Math.cos(angle); const s = Math.sin(angle); const x = p.x * c - p.z * s; const z = p.z * c + p.x * s; return { x, y: p.y, z }; } ``` ## 4. 큐브 렌더링 ### 4.1. 버텍스 (Vertices) * 3D 공간상의 점들의 배열 (`vs`) ### 4.2. 면 (Faces) * 버텍스 인덱스를 이용해 면을 정의하는 배열 (`fs`) * 각 면은 폴리곤을 형성하는 버텍스 인덱스의 배열 ### 4.3. 선 그리기 함수 (`line`) ```javascript function line(p1, p2) { ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.stroke(); } ``` ### 4.4. 렌더링 로직 1. **각 버텍스**에 대해: * `translateZ` 함수를 사용하여 Z축 이동 적용 * `rotate` 함수를 사용하여 회전 적용 * `project` 함수를 사용하여 2D로 투영 * `screen` 함수를 사용하여 Canvas 좌표계로 변환 * `point` 함수로 화면에 그리기 2. **각 면**에 대해: * 면을 구성하는 버텍스들을 순회하며 `line` 함수로 연결 ### 4.5. 와이어프레임 큐브 * 버텍스 렌더링을 제거하고 면의 선만 그림 ## 5. 투영 공식의 원리 (기하학적 해석) * **유사 삼각형**: * `Eye` (0,0)에서 `3D Point (X, Y, Z)`를 거쳐 `Screen (X', Y')`에 도달하는 광선 * `Eye`에서 `Screen`까지의 거리 (1)와 `Eye`에서 `3D Point`까지의 Z 거리 (`Z`) * `Screen`상의 X' 좌표와 `3D Point`의 X 좌표 * 두 삼각형의 닮음비를 이용: `1 / Z = X' / X` => `X' = X / Z` * 두 삼각형의 닮음비를 이용: `1 / Z = Y' / Y` => `Y' = Y / Z` ## 6. 활용 * OpenGL, WebGL, WebGPU 없이 2D HTML Canvas와 간단한 공식만으로 복잡한 3D 모델 렌더링 가능