2025. 11. 22. 12:33ㆍ개인 공부 및 연구
요약
- 하프 벡터(H)는 광원 방향 벡터 L과 시점 벡터 V를 더한 후 정규화한 벡터, 즉 L과 V 사이에 위치하는 벡터(두 벡터와의 사잇각이 동일)이다.
- Blinn이 Phong Specular의 연산을 최적화하기 위해 고안하였다
- 기하학적으로, 하프 벡터 H는 L이 V방향으로 정반사 되기위해 필요한 노멀 벡터 이다. 즉 reflect(L, H) = V의 관계를 만족한다. Microfacet Theory나 다른 반사와 관련된 이론/표현에서 하프 벡터가 사용되는 이유는, 이런 관계에 기인한 경우가 크다.
하프 벡터에 대해서 설명하기 위해서는 먼저 Phong BRDF (Phong Specular Reflection Model)에서 부터 시작해야 한다.
Phong BRDF는 표면에서 광원을 가르키는 벡터 L(입사 벡터), 표면 노멀 N, 표면에서 관찰자를 가르키는 벡터 V(시점 벡터)가 주어졌을 때, 빛이 표면 노멀 N에 대해서 '정반사' 하였을 때 그 방향을 나타내는 반사 벡터 R과 시점 벡터 V 사이의 사잇각의 코사인 값을 사용해 재질의 specular reflection을 표현 하는 경험적 모델 이다.
$$f(\textbf{L}, \textbf{N}, \textbf{V}, s) = dot(\textbf{V}, reflect(\textbf{L}, \textbf{N}))^{s} = dot(\textbf{V}, \textbf{R})^{s} $$
이때, Phong BRDF의 단점은 표면 노멀 벡터 N, 입사 벡터 L, 시점 벡터 V중 하나라도 변경 되면 모든 것을 새롭게 계산해야 해서 당시 기준으로 코스트가 높은 편이였다는 것 이다.
이를 보완하기 위해서 Blinn-Phong 모델에서는 Halfway Vector(Half Vector; H)라는 벡터와 표면 노멀 벡터 사잇각의 코사인 값으로 specular reflection을 표현 한다.
이 때, 하프 벡터 H는 아래 수식을 통해 얻어 낼 수 있다.
$$ \textbf{H} = \frac{\textbf{L} + \textbf{V}}{\| \textbf{L} + \textbf{V} \|} $$
사실 수식으로만 봐서는 그저 입사 벡터와 시점 벡터 사이에 낀 벡터로 밖에 안보인다. 하지만 사실 하프 벡터는 입사 벡터 L이 시점 벡터 V 방향으로 정반사 되기 위해 필요한 노멀 벡터를 의미한다.
즉, 빛의 에너지가 표면의 노멀이 하프 벡터와 유사할 수록 (둘 사이의 사잇각이 작을 수록) 더 큰 에너지를 반사한다는 것을 의미하고. Blinn-Phong 모델은 이 사실을 근거로 specular reflection 연산을 제안한다.
$$f(\textbf{L}, \textbf{N}, \textbf{V}, s) = dot(\textbf{N}, \textbf{H})^{s}$$
표면 노멀이 변할 때 마다 reflect(..) 함수를 통해 반사 벡터를 계산해야 했던 Phong 과는 다르게 Half Vector는 reflect 보다 적은 연산으로도 계산 해낼 수 있다.
이번엔, 하프 벡터의 정의를 통해 대수적으로 하프 벡터의 수식을 유도해보자.
하프 벡터는 입사 벡터 L이 시점 벡터 V 방향으로 정반사될 때의 노멀 벡터이므로 (이때, 벡터 L과 벡터 H는 단위 벡터이다 따라서 벡터 V도 단위 벡터이다),
$$ \textbf{V} = 2({\textbf{H}} \cdot {\textbf{L}})\textbf{H} - \textbf{L} $$
$$ \textbf{L} + \textbf{V} = 2({\textbf{H}} \cdot {\textbf{L}})\textbf{H} $$
$$ \textbf{H} = \frac{\textbf{L} + \textbf{V}}{ 2({\textbf{H}} \cdot {\textbf{L}}) } = \frac{\textbf{L} + \textbf{V}} {2\cdot cos(\theta _ {r})} $$
여기서, 하프 벡터는 벡터 L이 벡터 V로 정반사 될 때의 노멀 벡터이기 때문에, 벡터 L과 벡터 H 그리고 벡터 V와 벡터 H 사잇각 (즉, 반사각)은 동일 하기 때문에 아래와 같이 적을 수 있다.
$$ \textbf{H} = \frac{\textbf{L} + \textbf{V}} {(\textbf{H} \cdot \textbf{L}) + (\textbf{H} \cdot \textbf{V}
)} = \frac{\textbf{L} + \textbf{V}} { \textbf{H} \cdot (\textbf{L} +\textbf{V}
)} $$
이때 벡터 H는 단위 벡터이고 아래 조건이 항상 만족하므로, 벡터 H와 벡터 L+V는 동일선상에 놓이게된다. 즉 두 벡터간의 사잇각을 사용한 코사인 결과 값이 1이다.
$$ \cos(\theta _ {r}) > 0 $$
$$ \textbf{H} = \ \frac{\textbf{L} + \textbf{V}} { \textbf{H} \cdot (\textbf{L} +\textbf{V}
)} = \frac{\textbf{L} + \textbf{V}} { \| \textbf{L} + \textbf{V} \| \cdot cos(\theta) } = \frac{\textbf{L} + \textbf{V}}{\| \textbf{L} + \textbf{V} \|}$$
'개인 공부 및 연구' 카테고리의 다른 글
| [번역] 그래픽스 프로그래머를 위한 구면 조화(Spherical Harmonics) 입문 (0) | 2026.04.25 |
|---|---|
| 블로그에 게시할 장기 연재(?) 주제 선정 (0) | 2026.01.20 |
| 언리얼 엔진에서 더 디비전 스타일 UI 재현 해보기 - 3D 위젯 (0) | 2025.11.15 |
| 언리얼 엔진 4 렌더링 시리즈 파트 6 관련 노트 (0) | 2025.04.12 |
| [역] 언리얼 엔진 4.22를 위한 메시 드로잉 파이프라인 변환 가이드 (0) | 2025.04.11 |