본문 바로가기

개발/개발 일기

2021.08.02 개발 일기 - Specular 특성을 가진 반사 및 투과 처리

코넬박스를 구현한 뒤에 코넬 박스의 가운데에 여러 물체들을 넣어보면서 이미지를 렌더링해보고 있던 와중에 뭔가 이상한 점을 발견했다.

 

인터넷에 코넬 박스를 검색하면, 나오는 이미지 중에 코넬 박스 안에 Specular Reflection과 Specular Transmission 특성을 가진 물체를 배치한 것들이 있다. 그 이미지는 아래와 같다.

 

사진 1) Mantra Cornell Box Tests 출처 : https://tinyhawkus.com/

 

하지만 내가 렌더링한 이미지는 아래와 같다.

 

사진 2) Specular Transmission 특성을 가진 Cornell Box

 

이미지의 분산은 SPP가 낮기 때문에 어쩔 수 없는 부분이지만 가운데에 있는 구의 가장자리를 보면, 첫번째 사진과 다르게 어두운 것을 볼 수가 있다. 

 

처음에 이 문제를 보고 어디서 문제가 생겼는지 몇가지 가정을 세워봤다.

 

  • 패스트레이싱 코드에 문제가 있다.
  • 프레넬 효과를 고려하지 않았다.
  • 반사 및 투과 효과에 대한 코드를 잘못작성했다.

결론적으로 말하면, 반사 및 투과 효과에 대한 코드를 잘못작성한 것이었다. 이 부분을 알기 전에 패스트레이싱 코드와 프레넬 효과에 대한 부분만을 고려하고 있었다. 

 

처음에 패스트레이싱 코드를 몇번을 봤지만, 큰 문제는 없어보여서 프레넬 효과를 고려해보았다. 하지만 프레넬 효과는 각도에 따른 반사 및 투과 비율을 결정하기 때문에, 구의 가장자리가 어두워보이는 것과는 거리가 멀어보였다. 

 

사실 위 두개의 가정은 처음에 문제를 발견했을 때 바로 생각을 했지만, 세번째 부분은 책을 뒤져보다가 알게 된 것이다. 패스트레이서에서는 이와 같은 Specular의 특성(델타 분포)을 가진 머티리얼이나 빛들은 특별히 처리해주어야 한다. 

 

위 머티리얼은 Specular Trasmission의 특성을 가지고, 특정한 위치로만 투과되고 나머지의 위치에서는 모든 값이 0이 되는 델타 분포를 가지고 있기 때문에 특별한 처리를 해줘야하지만, 내 코드에서는 별도의 처리를 해주지 않았다. 

 

우선 특별한 처리를 해줘야 하는 이유는 아래와 같다.

 

델타 분포의 특성은 아래와 같다.

 

$$\int {f(x)\delta(x-x_{0})}dx=f(x_{0})$$

 

위 특성으로 인해 델타 분포는 x의 값이 x0일 때만 특정한 값을 가지고, x0가 아닌 경우에는 모든 값이 0이라는 사실을 알 수 있다. 그래프로 나타내면 아래와 같다.

 

사진 3) 델타 분포 함수 출처 : wikipedia

 

만약 머티리얼이 델타 분포를 가진 반사 특성이라면, 이 부분을 고려한 산란 방정식은 아래와 같다(물체는 방출하지 않는다고 가정한다).

 

우선은 기존의 산란 방정식이다. 

 

$$\int f(\omega_{o},\omega_{i})L_{i}(\omega_{i})|\cos\theta_{i}|dw_{i}$$

 

하지만, 만약 brdf가 델타 분포를 가진다고 하면 위 산란 방정식은 아래와 같이 표현할 수 있다.

 

$$\int f(\omega_{o},\omega_{i})\delta(\omega_{i}-\omega_{r})L_{i}(\omega_{i})|\cos\theta_{i}|dw_{i}$$

 

위 식은 입사 방향인 \(\omega_{i}\)가 \(\omega_{r}\)인 경우를 제외한 모든 입사 방향에서 0을 반환한다. 만약 이 식을 적분하게 된다면 \(\omega_{r}\)인 경우만 남게 된다. 이 식은 아래와 같다.

 

$$f(\omega_{o},\omega_{r})L_{i}(\omega_{r})|\cos\theta_{r}|$$

 

하지만 Specular 특성을 가지고 있는 산란 방정식에 \(|\cos\theta_{r}|\)은 필요없다. 왜냐하면 Specular 특성은 들어온 빛을 그대로 반사하기 때문에 기존의 산란 방정식에서 빛의 입사 방향에 따라 빛이 들어오는 양이 달라지는 Cosine 법칙이 적용되지 않기 때문이다.

 

그렇기 때문에, 코사인 법칙을 없애야 하는데, 패스트레이서 코드에서는 이런 Cosine 법칙을 패스트레이서에서 입사광을 구할 때 일괄적으로 적용하기 때문에, 단순히 입사된 빛의 양을 그대로 반환한다고 하면 패스트레이서 코드에서 Cosine 법칙이 적용된다.

 

이 부분을 수정하기 위해서 Specular 특성의 BRDF를 반환하기 전에 미리 이 값을 보정을 해준다면, 패스트레이서 코드에서 일괄적으로 Cosine 법칙을 적용하더라도 제대로 된 반사양을 가질 것이다.

 

이 부분을 고려한 최종적인 Specular 특성의 BRDF는 아래와 같습니다.

 

$$\frac{f(\omega_{o},\omega_{r})}{|\cos\theta_{r}|}$$

 

코드는 아래와 같습니다.

 

사진 4) 수정된 코드

 

만약 위 코드에서 마지막에 반환전 코사인 항을 나누지 않으면, 패스트레이서 코드에서 일괄적으로 코사인 항을 곱하기 때문에 구의 가장자리 부분이 어두워집니다.

 

위 코드를 적용하고 다시 이미지를 렌더링하면 최종 결과는 아래와 같습니다. 

 

사진 5) 코사인 항 보정을 한 이미지

 

이렇게 또 렌더러에 있는 오래된 문제를 하나 해결했다. 이 문제를 해결하고 든 생각은 패스트레이서 만드는 사람들은 이러한 부분을 다 고려하고 개발을 한건지, 아니면 나처럼 문제를 발견하고 수정을 한걸까?

 

이제는 광택 표면이나 미세면 표면 같은 셰이더를 개발할 때도 사용할 수 있는 부분을 개발해야겠다.