개요
Chapter 10에서는 카메라를 “고정된 위치”에서 벗어나, 임의의 위치(lookfrom) 와 바라보는 지점(lookat) 을 지정해 자유롭게 배치할 수 있도록 확장한다.
또한 카메라의 기울기를 결정하는 월드 업 벡터(vup) 와 수직 시야각(vfov) 을 통해 줌인/광각을 제어한다.
핵심 목표는 다음 3가지를 깔끔하게 정리하는 것이다.
•
카메라 로컬 좌표계(정규직교 기저) 만들기
•
vfov와 종횡비(aspect)로 뷰포트 크기 만들기
•
뷰포트 좌표 (s, t)에서 레이를 생성하기
카메라 파라미터
•
lookfrom: 카메라 위치 (눈의 위치)
•
lookat: 카메라가 바라보는 지점
•
vup: 월드 업 벡터. 보통 (0, 1, 0)
•
vfov: 수직 시야각(degrees). 작을수록 줌인, 클수록 광각
•
aspect: 종횡비 = imageWidth / imageHeight
카메라 좌표계 만들기 (정규직교 기저 u, v, w)
lookfrom과 lookat을 이용해 카메라 기준 축을 만든다.
•
$mathbf{w}$: 카메라의 “뒤쪽” 방향 (시선 반대)
•
$mathbf{u}$: 카메라의 “오른쪽” 방향
•
$mathbf{v}$: 카메라의 “위쪽” 방향
이렇게 만들어진 $mathbf{u}, mathbf{v}, mathbf{w}$는 서로 직교하고 길이가 1인 기저가 된다.
뷰포트 크기 (vfov → height/width)
수직 시야각 vfov로 뷰포트의 높이를 결정한다.
여기서 $h$는 “뷰포트의 반높이(half height)”로 보면 된다.
•
halfHeight =
•
halfWidth = aspect ·
뷰포트의 3개 벡터 (origin / horizontal / vertical)
카메라 위치를 원점(origin)으로 두면,
•
horizontal: 뷰포트 가로 방향 벡터
•
vertical: 뷰포트 세로 방향 벡터
•
lowerLeftCorner: 뷰포트의 좌하단 지점
을 만들 수 있다.
책 구현에서는 focal length를 1로 두는 셈이라, -w가 “카메라에서 뷰포트까지 거리” 역할을 한다.
그림으로 이해하기 (카메라/뷰포트/레이)
flowchart TB O["origin = lookfrom"] --> W["-w 방향으로 뷰포트"] W --> LL["lowerLeftCorner"] LL --> H["horizontal"] LL --> V["vertical"] O --> R["ray(s,t) = origin -> lowerLeft + s*horizontal + t*vertical"]
Mermaid
복사
C++ 코드 (Camera 핵심)
프로젝트에 따라 vec3 이름이나 ray 구현이 다르겠지만, 핵심은 동일하다.
class camera
{
public:
camera(
const point3& lookfrom,
const point3& lookat,
const vec3& vup,
double vfov_degrees,
double aspect
) {
origin = lookfrom;
auto theta = degrees_to_radians(vfov_degrees);
auto halfHeight = tan(theta / 2);
auto halfWidth = aspect * halfHeight;
w = unit_vector(lookfrom - lookat);
u = unit_vector(cross(vup, w));
v = cross(w, u);
lowerLeftCorner = origin
- halfWidth * u
- halfHeight * v
- w;
horizontal = 2 * halfWidth * u;
vertical = 2 * halfHeight * v;
}
ray get_ray(double s, double t) const {
return ray(origin, lowerLeftCorner + s*horizontal + t*vertical - origin);
}
private:
point3 origin;
point3 lowerLeftCorner;
vec3 horizontal;
vec3 vertical;
vec3 u, v, w;
};
C++
복사
변경 파일 요약
•
기존 기본 생성자는 그대로 두고(하위 호환)
•
자유 시점 생성자 추가
◦
lookfrom, lookat, vup, vfov, aspect
•
내부에 u, v, w 정규직교 기저 저장
•
GetRay(s, t)에서 뷰포트 좌표로 레이 생성
•
CreateWorld(imageWidth, imageHeight)처럼 해상도를 전달해
◦
aspect = imageWidth / imageHeight를 GPU에서 계산 가능
•
카메라 생성 예시
◦
lookfrom = (-2, 2, 1)
◦
lookat = (0, 0, -1)
◦
vup = (0, 1, 0)
◦
vfov = 20°
GPU 구현 포인트
•
vfov → tan(theta/2)로 뷰포트 반높이를 만든 뒤, aspect로 반너비를 만든다.
•
cross(vup, w)와 cross(w, u)로 안정적으로 카메라 로컬 좌표계를 만든다.
•
CUDA에서 M_PI가 없을 수 있으니, pi = 3.1415926535897932385처럼 직접 정의하는 편이 안전하다.




