본문 바로가기

Unity3D/shader_스터디

[Unity 쉐이더] Reflection

개인 학습 정리용으로 작성된 글입니다.

 

 

 

반사란? 

파동이 다른 두 매질의 경계에서 방향을 바꿔 진행하는 물리 현상. (정반사, 난반사, 굴절, 회절 등등)

물체의 종류와 표면의 상태에 따라 빛이 반사되는 정도가 달라지고, 그것을 쉽게 구별하기 위해 정반사, 난반사 등으로 부릅니다. 

 

같은 물체에 표면의 상태가 다른 예시 

 

 

빛의 반사를 컴퓨터 그래픽으로 구현하는 방법은 다양합니다. 레이 트레이싱의 경우 광추적방식 렌더링 이라고도 부르는데 광원에서 나온 광선이 물체에 반사하는 모습을 역으로 시뮬레이션한다고 합니다. 실시간 렌더링에 연산량도 어마 무시해 게임에서는 더 가벼운 방법으로 빛의 반사를 실제와 비슷해 보이도록 구현했습니다. 오늘은 그중 큐브 맵을 이용한 반사 구현을 해보고자 합니다.

 


큐브맵

큐브맵은 오브젝트의 반사를 나타낼 때와 주변 환경을 캡쳐하는데 사용됩니다.

3차원 공간의 데이터가 필요함으로 (+x, -x, +y, -y, +z, -z) 6개의 텍스쳐를 이용해 오브젝트를 둘러쌀 가상의 큐브를 만듭니다. 각 텍스쳐는 월드 축을 따른 뷰를 나타냅니다.

 

 

 

파라노마 이미지는 이런 식으로 구성됨

 

 


반사된 물체는 항상 거울의 반대편에 형성된다.
반사된 개체의 크기는 원래 개체의 크기와 동일하다.

 

위와 같은 반사 이론에 따라 오브젝트에 큐브맵을 담아내도록 반사 벡터를 사용합니다.

 

 

큐브맵 적용

1. 유니티 내장 큐브맵 쉐이더에 6개의 텍스쳐를 각 위치에 할당해 준다. 

 

 

2. 파라노마 이미지일 경우 텍스쳐의 속성을 Cube로 변경합니다.

하단 맵핑 설정에서 수동으로 맵핑 방식을 조정할 수 있습니다. 

스카이 박스 등에는 밉맵을 생성할 필요가 없으니 체크해주면 좋음.

 

 

 


리플렉션 적용

큐브맵을 준비했다면 실제로 적용을 해봅시다.

이번에는 램버트 기본형에서 시작합니다.

 

 

 

큐브맵의 프로퍼티는 cube를 사용합니다. 

마찬가지로 변수도 텍스쳐 함수도 기존의 2D텍스쳐에 사용하던 2D가 아닌 CUBE입니다. 큐브 텍스쳐니까요.

samplerCUBE, texCUBE

 

 

큐브맵의 UV를 적용할 때는 위에서 얘기한 반사 벡터가 필요합니다. 저희는 복잡한 과정을 생략할 수 있도록 유니티가 준비해준 worldRefl 변수를 사용합니다. 이후에는 구조체 Input에 준비해둔 worldRefl를 큐브맵의 UV자리에 넣어주면 됩니다.

 

 

 

결과를 봅시다.

열심히 광을 낸 플라스틱 같이 묘한 결과물이 나왔습니다. 

 

 

문제의 원인에는 알베도가 있습니다. 모든 물체는 들어오는 정반사와 난반사가 적정 비율 섞여 들어오는 빛에 맞게 반사를 하게 됩니다. 그러나 지금은 알베도와 이미션을 동시에 내보내면서 괴리감이 느껴지는 결과물이 출력된 것입니다.

 

 

 

문제를 바로잡기 위해서 두 값을 조정할 수 있도록 smoothness를 추가합니다.

물리 이론 상으로 맞는 결과물이 나오려면 합계 1이 나올 수 있도록 해줍니다. 또한 완전한 정반사, 완전한 난반사는 현실에 없기 때문에 smoothness값에 제한을 줘도 괜찮습니다.

이제 반사 결과물을 다시 봅시다.

 

 

 

뺀질뺀질하게 잘 반사하고 있습니다. 금속 느낌이 나네요.

 

 

 

단점이라면 주변 오브젝트는 반사되지 않는다는 것.

큐브맵의 이미지를 입혔기 때문에 그 외의 오브젝트는 당연히 보이지 않습니다.(심령현상)

 

 

 

반대로 없는 게 존재하는 것도 가능하겠죠.

 

 


이제 뺀질뺀질한 투구에 리플렉션 값을 조정하고 노말까지 추가해 간지 나는 투구로 까지 진화시켜봅시다.

 

smoothness값을 마스크를 이용해 오브젝트의 부분별 반사 정도를 조절합니다.

 

 

마찬가지로 노말도 추가합니다.

 

 

띠용

 

 

노말맵을 적용하려 하니 아래와 같은 처음보는 오류가 뜹니다.

 

 

이유는 행렬과 관련이 있습니다. 

행렬은 잘 모르니까 간략하게 설명

노말맵은 각 픽셀당 탄젠트 노말을 가지고 있고, 반사를 위해서는 월드 좌표계를 이용한 연산을 하고 있습니다. 기존에는 탄젠트 노말을 월드 노말로 변경하는 과정을 통해 노말맵을 월드 좌표계에서 같이 사용할 수 있지만 Surface Shader에서는 그 과정이 생략되어 오류가 난다고 합니다. 

 

간단한 쉐이더 코딩을 위해 이것저것 준비해준 유니티는 이 문제의 해결 방법도 준비해두었습니다.

변환 과정을 축약해둔 INTERNAL_DATA로 노말을 같이 사용할 수 있습니다.

 

 

 

위의 과정을 통해 노말까지 무사히 출력해 낼 수 있습니다.