Company
교육 철학

구체 교차 판정 (ray sphere intersection)

df9278f252c398b6bed912992b81ce4182a01ed0
commit

개요

Ray Tracing in One Weekend 4장(구체 교차 / Ray-Sphere Intersection)에서 사용하는 레이-구체 교차 판정식을 CUDA 디바이스 코드로 구현하고, RayColor()에서 교차 여부에 따라 구체는 빨간색, 그 외는 하늘 배경 그라디언트를 출력하도록 수정한 작업을 정리한다.
이번 단계의 포인트는 아래 3가지다.
교차 판정은 이차방정식의 판별식(discriminant)으로 빠르게 처리 가능
디바이스 함수에서 자주 쓰는 형태로 HitSphere()를 정리
Ray가 값으로 전달되는 상황을 대비해(코드 구조/컴파일러 옵션에 따라) 디바이스 복사 생성자 추가

변경 파일 목록

파일
변경 유형
설명
Ray.h
수정
디바이스 복사 생성자 추가(값 전달/복사 안전성 확보)
수정
HitSphere() 추가, RayColor()에서 구체/배경 분기

1. 레이-구체 교차 판정 수학 정리

1.1 구체 방정식

구체 중심을 C, 반지름을 r, 구체 표면 위의 점을 P라고 하면:
(PC)(PC)=r2(P - C) \cdot (P - C) = r^2

1.2 레이 방정식

레이 원점을 O, 방향을 D(정규화가 필수는 아님), 매개변수를 t라고 하면:
P(t)=O+tDP(t) = O + tD

1.3 대입 후 이차방정식 형태

레이를 구체 방정식에 대입하면:
(O+tDC)(O+tDC)=r2(O + tD - C) \cdot (O + tD - C) = r^2
oc = O - C라고 두면:
(oc+tD)(oc+tD)=r2(oc + tD) \cdot (oc + tD) = r^2
전개하면 아래와 같은 이차방정식이 된다.
at2+bt+c=0a t^2 + b t + c = 0
a=DDa = D\cdot D
b=2(ocD)b = 2(oc\cdot D)
c=ococr2c = oc\cdot oc - r^2

1.4 판별식(discriminant)

Δ=b24ac\Delta = b^2 - 4ac
$Delta gt 0$: 두 점에서 교차
$Delta = 0$: 접함
$Delta lt 0$: 교차 없음
이번 단계에서는 “맞는다/안맞는다”만 필요하므로 Δ > 0 여부만 체크한다.
다음 단계(정확한 hit 위치, 노멀 계산, 가까운 t 선택)로 가면 t 해를 실제로 구하게 된다.

2. kernel.cu: HitSphere() 구현

2.1 함수 시그니처

현재 글의 흐름을 유지하면서도 C++/CUDA 스타일로 읽기 좋게 정리하면 아래 형태가 깔끔하다.
__device__ bool HitSphere(const Vec3& center, double radius, const Ray& r);
C++
복사

2.2 구현 코드(C++/CUDA C++)

__device__ bool HitSphere(const Vec3& center, double radius, const Ray& r) { Vec3 oc = r.origin() - center; double a = Dot(r.direction(), r.direction()); double b = 2.0 * Dot(oc, r.direction()); double c = Dot(oc, oc) - radius * radius; double discriminant = b * b - 4.0 * a * c; return (discriminant > 0.0); }
C++
복사

2.3 부연 설명: b를 2배로 두는 형태

책/구현에 따라 아래처럼 half_b = dot(oc, D)를 쓰는 버전이 많다.
b = 2 * dot(oc, D)를 쓰면 판별식 계산에 4ac가 같이 들어가고
half_b를 쓰면 Δ = half_b^2 - a*c로 단순해진다.
지금 단계는 “개념 정리”가 목적이라면 현재 형태도 충분히 좋다.

3. RayColor() 수정: 구체면 빨강, 아니면 하늘

__device__ Color RayColor(const Ray& r) { // 중심 (0,0,-1), 반지름 0.5 구체에 맞으면 빨간색 if (HitSphere(Vec3(0.0, 0.0, -1.0), 0.5, r)) return Color(1.0, 0.0, 0.0); // 배경: 하늘색 그라디언트 Vec3 unitDirection = UnitVector(r.direction()); double t = 0.5 * (unitDirection.y() + 1.0); return (1.0 - t) * Color(1.0, 1.0, 1.0) + t * Color(0.5, 0.7, 1.0); }
C++
복사

4. Ray.h: 디바이스 복사 생성자 추가

4.1 추가 이유

커널/디바이스 함수에서 객체를 값으로 전달하거나, 컴파일러가 임시 객체를 만들면서 복사가 발생할 수 있다.
이때 복사 생성자가 명시되어 있으면 의도가 명확해지고, 특정 상황에서 컴파일 이슈를 줄이는 데 도움이 된다.
class Ray { public: __device__ Ray(const Ray& other) : orig(other.orig), dir(other.dir) {} // ... };
C++
복사
C++에서 복사 생성자는 보통 컴파일러가 자동 생성해 주지만,
CUDA 디바이스 컴파일 경로에서 클래스 정의/가시성/인라인 여부에 따라 문제가 되는 경우가 있어 명시하는 선택이 유효하다.

렌더링 결과(현재 단계)

해상도: 1440 × 720
구체: 중심 (0, 0, -1), 반지름 0.5
구체 색상: 빨간색 (1, 0, 0)
배경: 흰색(하단) → 하늘색(상단) 그라디언트
출력 파일: output.ppm