물리기반 셰이더를 짤때 가장 먼저 고려되는게 Normalized Blinn-Phong 셰이더입니다.
아시다시피 게임에서 널리 쓰이는 Specular 모델인 Phong 셰이딩은 그다지 물리적으로 정확한 모델은 아닙니다. 실제 Specular는 방향성을 갖고 있지만 Phong 셰이딩은 항상 원형 형태로 Specular가 생기거든요.
이게 구같은 곡면에선 큰 문제가 없지만 편편한 곳에선 실제와 전혀 다른 Specular를 만듭니다. 아래 사진들을 보시죠.


그림에서도 보시면 아시겠지만 물리적으로 정확한 Specular는 Blinn-Phong 셰이딩입니다. 근데 Blinn-Phong 셰이딩은 두가지 문제를 갖고 있습니다.
- Phong 셰이더보다 비쌉니다!
- Normalmap이 깨져보이게 Specular가 생깁니다!
Blinn-Phong 셰이더는 Phong 셰이더와는 달리 Reflection 벡터를 사용하지 않고 Half 벡터를 사용합니다. 그래서 더 실제같은 결과물을 보여주는 대신 좀더 많은 처리를 요하지요. 하지만 요새 하드웨어 성능이 원체 좋아져서 이건 큰 문제가 안됩니다. 그러나!
실제 폴리곤 모델인 경우 생기지 않는 문제지만 Normalmap을 사용하게 되면 Specular가 깨져서 생기게 됩니다. 이게 무슨 소리냐면

그림에서 보시다시피 Flickering 현상이 나타납니다. 이건 Normalmap이 01까지의 값만을 갖으면서 생기는 문제로, Blinn-Phong 셰이더에서 이걸 해결하려면 Normalmap을 한번 더해주고 그걸 다시 나눈다음에 노멀라이즈 해줘서 -11의 값을 갖도록 만들어주면 됩니다.
그런데 가뜩이나 Phong 셰이더보다 무거운데 Normalmap까지 처리해주느라 더 무거워지는 일이 생기는데 이걸 해결한 유사 Blinn-Phon 셰이딩 모델이 있습니다. 심지어 Phong 셰이더보다도 가볍습니다!
a reformulation of the Blinn-Phong model by Richard F. Lyon 에서 나온 셰이딩 모델인데요, 1993년에 Apple에 기고된 연구 논문입니다. (Lyon씨는 광학 마우스까지 만든, 잡스옹의 말을 빌자면 아주 어썸!한 사람입니다.) 자세한 이론적 배경은 링크된 논문을 참고하시고, 구현식은 이렇습니다.
Code:
float Lyon(float3 normal, float3 view, float3 light){
float3 halfVector = normalize(light + view);
float3 difference = halfVector - normal;
float xs = saturate(dot(difference, difference) * specPower / 2);
return pow(1 - xs, 3);
}
이제 Phong 보다도 싼 Lyon/Blinn-Phong 모델을 써서 물리적으로 좀더 정확한 셰이더를 만들어 보세요!