Slab:
Kay 와 Kajiya가 제안
두 개의 평행한 평면 사이의 무한한 공간
Slab과 Ray의 교차를 이용하여 AABB 교차를 판단
광선(Ray): r(t) = o + td
o: 원점
t: 광선상의 정점들을 생성하는데 사용되는 변수
d: 방향 벡터 ( 일반적으로 편의 위해 정규화 함, ||d|| = 1 )
광선이 Slab의 한 평면과 교차하는 t 값을 구하여 사용
평면: n + D = 0
평면 위의 한 점 x의 경우 다음을 만족함
n • x + D = 0
그러므로 t 값을 구하기 위해 x를 t값을 가지는 광선의 한점으로 대치함
n • (r(t)) + D = 0
n • ( o + td ) + D = 0
(n • o) + t(n • d) + D = 0
t = ( -(n • o) - D ) / (n • d)
여기서 AABB의 특징들을 이용하면 t에 대한 식이 간단히 됨
1. AABB는 표준 기저와 축이 같아서
평면 n의 값이 각 축마다 2개 요소씩 0이 됨
예) x축의 경우: nx = (1, 0, 0)
그래서 nx • o = (1, 0, 0) • (ox, oy, oz) = ox
i ∈ { x, y, z } 이면 위의 t 에 관한 식은 정리 되어서
t = ( -oi - D ) / di
2. 추가로 평면이 표준 기저 축과 평행하므로 평면의 D의 값은
AABB의 min[i], max[i]값을 사용할 수 있음 ( i ∈ { x, y, z } )
또한, di의 절대값이 아주 작을 경우 해당되는 축과 평행하게 됨
이때는 해당되는 축의 원점 oi 값이 AABB의 min, max를
벗어나면 교차 상태가 아니게 됨
광선과 Slab의 평면들과의 교차점을 찾아 tmin, tmax값을 찾는다.
예를 들어 현재 축에 해당되는 Slab 평면과 교차점 찾는 경우
tmin: 광선의 시작점으로 부터 처음 만나는 Slab 평면의 교차점
tmax: 두번째 Slab 평면과 교차점
이렇게 각 축마다 t값을 구하면서 tmin, tmax가 서로 가까운 거리가
유지 되도록 한다.
작업 중간에 tmin > tmax 이렇게 값이 서로 바뀌는 경우가 발생하면
AABB는 서로 교차하지 않는 것이 된다.
//o: 광선의 원점
//d: 광선의 방향벡터
//p: 첫번째 교차점
bool AABBtoRay(AABB a, Vector3 o, Vector3 d, Vector3& p)
{
float t_min = 0;
float t_max = MAX_FLOAT;
for(int i=0; i<3; i++)
{
if(abs(d[i]) < EPSILON)
{
if( o[i] < a.min[i] ||
o[i] > a.max[i] )
return false;
}
else
{
float denom = 1.0f / d[i];
float t1 = (-o[i] - a.min[i]) * denom;
float t2 = (-o[i] - a.max[i]) * denom;
if(t1 > t2)
{
swap(t1, t2);
}
t_min = max(t_min, t1);
t_max = min(t_max, t2);
if(t_min > t_max)
return false;
}
}
p = o + t_min * d;
return true;
}
참고자료:
Real - Time Rendering 2판
Real - Time Collision Detection
죄송하지만 이 내용은 AABB와 ray가 아닌 OBB와 ray 교차 같습니다.
답글삭제좋은 글 감사합니다. 질문이 있는데 AABB의 min/max는 각각 cube의 좌하단 우상단 좌표인가요?
답글삭제