본문 바로가기

Game/Graphics

Learn OpenGL - Advanced Lighting : Advanced Lighting

link : https://learnopengl.com/Advanced-Lighting/Advanced-Lighting


Advanced Lighting


 조명 튜토리얼에서 Phong 조명 모델을 간략하게 소개해 현장에 기본적인 사실감을 선사했다.



Blin-Phong


 퐁 조명은 조명의 훌륭한 근사이지만, 특정 조건에서는 특히 반사율이 낮아 반사 영역이 겇니 경우 반사 현상이 발생한다.


아래 이미지는 평평한 텍스처면에서 1.0의 반사광 지수를 사용할 때 어떤 일이 일어나는지 보여준다:


Result of Phong specular reflection with low exponent


 가장자리에서 반사 영역이 즉시 끊어지는 것을 볼 수 있다. 그 이유는 뷰 벡터와 반사 벡터 사이의 각도가 90도 이상으로 올라가지


않도록 하기 위함이다. 각도가 90도 이상이면 결과 내적이 음수가 되고 반사 지수가 0.0이 된다. 우리는 어쨌든 90도 이상의 각도로


빛을 얻지 않아야하기 때문에 이 것이 문제가 되지 않을 것이라고 생각하고 있나?



 틀린 점은 일반 광원과 광원 사이의 90도 이상인 각도가 광원이 조명된 표면 아래에 있으므로 광원의 확산 기여도가 0.0이어야한다는


것을 의미한다. 그러나 우리는 광원과 법선 사이의 각도를 측정하지 않고, 뷰와 반사 방향 벡터 사이의 각도를 측정한다. 다음 두 이미지를


살펴보자:


Image of Phong's reflection vectors being incorrect when larger than 90 degrees


 여기에 문제가 분명해진다. 왼쪽 이미지는 θ가 90도 미만인 Phong 반사를 보여준다. 오른쪽 이미지에서 우리는 뷰와 반사 방향 사이의


각도 θ가 90도보다 크다는 것을 볼 수 있으며, 결과적으로 반사 기여도를 무효화 할 수 있다. 뷰 방향은 반사 방향과는 거리가 멀기 때문에


일반적으로 문제가 되지 않지만, 낮은 반사 지수를 사용하면 반사 반경은 이러한 조건에서 공헌할 만큼 충분히 크다. 이 경우 첫 번째 이미지에서


보았듯이 90도 이상의 각도에서 이 기여를 무효화한다.



 1977년 Blinn-Phong 쉐이딩 모델은 James F. Blinn에 의해 우리가 지금까지 사용해왔던 Phong 쉐이딩의 확장으로 소개되었다.


Blinn-Phong 모델은 대체로 유사하지만 결과적으로 우리의 문제를 극복하는 약간 다른 specular 모델에 접근한다.


반사 벡터를 사용하는 대신 뷰 방향과 조명 방향 중간의 단위 벡터인 소위 중간 벡터를 사용한다. 이 중간 벡터가 surface의 법선 벡터에


가까울수록 반사도가 높아진다.


Illustration of Blinn-Phong's halfway vector


 뷰 방향이 (현재 가상의) 반사 벡터와 완벽하게 정렬되면 중간 벡터는 법선 벡터와 완벽하게 정렬된다. 따라서 시청자가 원래의 반사 방향으로


가까이 갈수록 반사 밝은 부분이 강해진다.



 여기서 관찰자가 바라는 방향이 무엇이든 간에 중간 벡터와 표면 법선 사이의 각도는 절대적으로 90도를 초과하지 않는다.


이것은 Phong 방향과 비교해 약간 다른 결과를 생성하지만, 대개 낮은 반사 지수로 인해 시각적으로 약간 더 보기가 쉽다.


Blinn-Phong 쉐이딩 모델은 OpenGL의 이전 고정 함수 파이프 라인에서 사용된 정확한 쉐이딩 모델이기도 하다.



 중간 벡터를 얻는 것은 쉽다. 라이트으 방향 벡터와 벡터를 함께 추가하고 결과를 정규화한다:



 이것은 다음과 같이 GLSL 코드로 변환된다:

vec3 lightDir   = normalize(lightPos - FragPos);
vec3 viewDir    = normalize(viewPos - FragPos);
vec3 halfwayDir = normalize(lightDir + viewDir);

 그런 다음 specular term의 실제 계산은 기본적으로 표면 법선과 중간 벡터 사이의 클램프 된 내적이 되어서 우리가 반사된 shininess 지수로


다시 발생시키는 코사인 각도를 얻는다:

float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
vec3 specular = lightColor * spec;

 Blinn-Phong에는 방금 설명한 것보다 더 많은 것이 없다. Blinn-Phong과 Phong의 정반사와의 유일한 차이점은 뷰 방향과 반사 벡터 사이의


각도와 비교해 법선 벡터와 중간 벡터 사이의 각도를 측정한다는 점이다.



 specular 하이라이트를 계산하기 위한 중간 벡터가 도입됨에 따라 더 이상 Phong shading이라는 specular cutoff 문제가 없어야한다.


아래 이미지는 specular 지수가 0.5인 두 가지 방법의 반사 영역을 보여준다:


Comparrison between Phong and Blinn-Phong shading with a low exponent


 Phong과 Blinn-Phong 쉐이딩의 또 다른 미묘한 차이점은 중간 벡터와 표면 법선 사이의 각도가 뷰와 반사 벡터 사이의 각도보다 짧다는 것이다.


결과적으로 Phong 쉐이딩과 비슷한 결과를 얻으려면 반사광 지수를 약간 높게 설정해야한다. 일반적으로 Phong shininess 지수의 2-4배로 설정한다.



 다음은 Phong 지수가 8.0이고 Blinn-Phong 구성 요소가 32.0으로 설정된 두 반사 모델 사이의 비교이다:


Comparrison between Phong and Blinn-Phong shading with normal exponents


 Blinn-Phong 대수 지수가 Phong에 비해 조금 더 선명하다는 것을 알 수 있다. 이전에 Phong 음영으로 설정한 것과 비슷한 결과를


얻으려면 약간의 조정이 필요하지만 Blinn-Phong 음영은 기본 Phong 음영에 비해 일반적으로 약간 더 정확한 결과를 제공한다.



 여기에서는 일반적인 Phong 반사와 Blinn-Phong 반사를 전환하는 간단한 조각 쉐이더를 사용했다:

void main()
{
    [...]
    float spec = 0.0;
    if(blinn)
    {
        vec3 halfwayDir = normalize(lightDir + viewDir);  
        spec = pow(max(dot(normal, halfwayDir), 0.0), 16.0);
    }
    else
    {
        vec3 reflectDir = reflect(-lightDir, normal);
        spec = pow(max(dot(viewDir, reflectDir), 0.0), 8.0);
    }

 b 키를 누르면 데모가 Phong에서 Blinn-Phong 조명으로 바뀌며 그 반대도 마찬가지이다.