炸殺
카테고리
작성일
2020. 6. 28. 18:56
작성자
炸殺

 

Reflection shader를 이용한 물 만들기

 

이번에는 지난 강의에서 배웠던 Reflection을 이용하여 물을 만들어 봅시다.

물은 비물리적인 물리기반 쉐이더입니다. 물리적으로 옳지만 PBR로 구현하기 굉장히 힘든 친구....

그야말로 눈속임의 결정체!라고 할 수 있죠.

 

 

 

 

 

 

 

 

Reflection와 Fresnel 

가장 먼저 하늘을 투영해봅시다. 우선 Custom Shader를 만들어 준비 작업을 해줍니다.

 

우기엔 얕은 호수가 되어 세상에서 가장 큰 거울이 되는 우유니 소금사막.

넓은 호수를 바라보고 있으면 저 멀리 풍경들과 하늘이 수면에 비치는 것을 확인할 수 있습니다.

수면의 반사를 표현하기 위해 플렌에 Reflection넣어줍시다.

 

 

그냥 거울이 되었다.

위의 우유니 소금사막도 완전히 거울처럼 하늘을 비치고 있는 것 같지만 사실 자세히 보면 바라보는 각도에 따라 점점 하늘 보다는 수면 아래의 소금들이 투과되어 보이는 것을 확인할 수 있습니다.

 

반사율이 높지 않은 물체도 비스듬하게 보면 어느 정도의 반사율을 같게 됩니다.

직각으로 내려다봤을 때보다 비스듬히 봤을 때 정반사되어 눈에 들어오는 빛이 더 많기 때문인데

모든 사물은 그 정도가 다를 뿐 Fresnel을 가지고 있으며 물 또한 마찬가지 입니다.

 

물은 원래 투명합니다!

 

투명한 물이 마치 거울처럼 주변을 반사하는 이유가 바로 이 Fresnel Reflection 때문입니다.

물은 투명하게 수면 아래를 보이다가도 투사각이 60˚ 이상이 되면 급격하게 반사율이 올라가는 특징을 가지고 있어

발 아래 물은 투명하고 저 멀리 비스듬히 보이는 수면엔 주변 풍경이 거울처럼 비쳐보이는 것이죠.

 

 

이러한 Fresnel Reflection은 RimLight 공식을 이용하여 만들어줄 수 있습니다.

 

 

그 전에! 

발 아래는 "투명한" 물을 만들기 위함이기에 반드시 랜더 타입을 Transparent로 변경해주시고 

alpha:blend도 작성해줍시다.

 

 

 

View vector에 따라 비스듬해지질 수록 검정색에서 하얀색으로 변화하는 것을 확인할 수 있습니다.

이 rim을 알파로 사용하면 흰색은 거울처럼 하늘을 반사하고 검은 색은 투명하게 바닥을 투영할 것입니다.

 

void surf의 Emission은 코드 끝 마지막에 한 번 더 더해집니다. return의 결과에 Emission이 더해지죠.

또한 라이트를 자연스럽게 받도록 _LightColor0도 곱해주었습니다.

 

처음엔 림을 알파로만 사용하기 위해 이렇게 리턴을 했는데.... 뭔가 코드가 안예쁘기도 하고 기울어졌을 때

끝이 하얗게 번지는게 더 이쁘더라구요. 

 

 

하지만 아직 물이라기엔 너무 어색합니다. 아무리 바람이 약한 날이여도 수면은 바람에 따라 일렁이기 마련이죠.

 

 

 

 

 

 

Normal을 이용한 파도

 

현실이라면 바람에 의해 자연스럽게 수면에 파장이 일어야 합니다만....

그걸 실시간으로 연산하려면 어마어마한 성능의 컴퓨터가 필요하겠죠, 인공적으로 파도를 만들어줍시다.

 

출렁이는 수면의 표현을 위해 Normal을 넣고, UV에 _Time을 더해줍니다.

잔잔하게 흐르는 바다나 호수 같은 느낌을 주고싶었기에 속도 조절을 해주었습니다.

 

 

 

 

하지만 여전히 어색하네요....

단순히 Normal Map이 이동하고 있을 뿐이기에 물이 넘실 거린다기보단 굳은 레진이 이동하는 느낌입니다.

 

 

이 때, 물이 마치 자연스럽고 불규칙하게 흘러가는 것처럼 '눈속임'을 하기 위하여

두 개의 노말을 합친 뒤 서로 다른 방향으로 흐르게 해줍니다. 제자리에서 잔잔하게 흐르는 느낌을 주겠어요.

 

여기서 주의할 점은 노말 맵 두 개를 더할 시 Normal Map의 강도도 강해지기 때문에

두 Normal Map의 평균 값을 구해줍니다.

 

가까운 쪽은 rim을 연하게 들어간 것이 예쁘고, 멀리있는 곳은 림을 많이 제곱한 쪽이 더 예쁩니다. 이 둘을  섞어봅시다.

 

 

 

편-안-

더 자연스러운 물결이 되었지만 노말을 이용한 것이기 때문에 여전히 평면적인 느낌이 있습니다.

여기서 더 나아가 버텍스를 움직여 입체적인 출렁임, 파도까지 더해봅시다.

 

 

 

 

 Vertex Shader를 이용한 파도

 

가장 먼저 버텍스를 조작하기 위해 Vertex Shader를 가동합니다.

 

버텍스의 Y값에 UV X값을 더하게 되면 어떻게 될까요?

UV를 따로 떨어뜨려 색상으로 본다면 검은색에서 하얀색으로 변하는 그라데이션입니다.

사용하고 있는 오브젝트가 90도 로테이션 되어있어 z에 더해주었다.
UV의 x값에 따라 높이가 서서히 홀라간다

올라간 쪽은 1의 값을, 올라가지 않은 쪽은 0의 값을 가지고 있습니다.

물을 제작할 때 커다란 하나의 플렌이 아닌 여러 플렌을 조각조각 이어붙여 만들어주는데요,

물이 이렇게 갈라지면 곤란하겠죠, 여기서 하프 렘버트의 역공식을 이용해줍니다.

 

 

하프 렘버트가 -1에서 1사이의 값을 0에서 1사이의 값으로 만들었다면,

이의 역공식인 [ *2-1 ]은 0과 1사이의 값을 -1과 1사이의 값으로 변환합니다.

이렇게 변환된 수에 abs를 씌워 절대값으로 만들어주면 1, 0, 1의 값으로 변환되어 서로 끊어지지 않고 이어지게 됩니다.

 

 

 

부드러운 물결을 위해 여기에 Cos을 넣어 완만한 곡선으로 만들어줍니다.

이때 버텍스가 많으면 많을 수록 부드럽게 곡선이 들어가 보다 더 자연스러운 파도가 만들어집니다.

 

구해진 절대값에 수를 곱하여 굴곡의 간격을 조절해주고...

 

 

다음과 같이 파도의 간격과 흐르는 시간, 완성된 값에 수를 곱해 파도의 높이를 조절해주면 

 

 

완성~~~

 

 

++

커스텀 라이트로 하다보니 뭔가 배웠던 거랑 다른 노선으로 하게 된 것 같습니다...

surf에서 알파에 0.3을 더하고 saturate를 걸었을 땐 투명하게 되는데 커스텀 라이트 알파에 그렇게 하니까 걍 다시 거울처럼 되어버리더라구요... 왤까...난 뭘 잘못 한걸까......