본문 바로가기
Shader

9주차, 스펙큘러를 만들어보자.

by JDCM 2023. 6. 9.

반질반질, 반딱반딱한 것들을 만들어보자.

 

1. 스펙큘러(Specular)?

(https://www.allure.com/story/what-is-hyaluronic-acid-skin-care)

 

스펙큘러는 정반사, 즉 거울처럼 매끈한 면을 경계로 일어나는 반사이다.

 

게임그래픽 에서는 물체의 질감을 나타낼 수 있게 보여주는데 메탈릭 물질과 글로시 물질에 따라 다르게 나오기는 하지만 우선 스펙큘러를 만들어보고 생각해보자.

 

1-1. Phong 공식의 스펙큘러 만들기

(https://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Specular_Highlights)

 

저번 시간에 이야기 했듯이 뷰 벡터라는 것은 결국 내가 바라보는 시점(View), 즉 카메라를 기준으로 바라보는 시각의 벡터를 나타낸다.

 

스펙큘러는 정반사, 즉 우리가 보는 방향의 정방향에서 나타나게 된다. 

어? 그럼 저번에 림라이트를 만들었던 방식 그대로 뷰 벡터를 가져오면 되는 것 아닐까?



사실은…

우리가 뷰 벡터를 뒤집어서 림라이트를 만들었지만 뒤집지 않는다면 스펙큘러에 가깝긴 하다. 그러나 정확한 방식이 아니므로…

 

(https://en.wikipedia.org/wiki/Phong_shading)

 

 

스펙큘러 구현의 공식 중 ‘퐁 스펙큘러 공식(Phong Specular)’이 있다.

 

 

어… 잘 모르겠으니까 일단 기본 쉐이더를 짜놓고 시작해보자.


( 클릭해서 보세요! )

 

우선 Lambert 형식으로 기본 베이스를 만들어두었다.

 

일전에 림라이트를 만들 때의 공식을 사용해서 viewDir도 미리 받아왔다.


블린 퐁은 viewDir를 그대로 가져오지 않는데,

블린 퐁 내의 방식으로는 라이트 벡터와 뷰 벡터를 더한 값을 정규화하고, 구한 중간 벡터를 버텍스 노말 벡터와 함께 내적(Dot)하면 된다.

 

말이 어려우니까 천천히 풀어보자면 …

 

(https://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Specular_Highlights)

 

빛은 반사가 된다. 그리고 반사가 된 벡터가 눈으로 정확히 들어왔을 때 우리는 스펙큘러 현상을 볼 수 있다. 

 

그렇다면 반사된 벡터(Reflection Vector)와 뷰 벡터(View Vector)가 동일했을 때, 즉 0도… 같은 방향이라고 한다면 최고로 높은 반사 형태가 나오게 된다.

 

 라이트 벡터와 뷰 벡터를 더했을 때 라이트와 뷰 벡터 사이의 중간 벡터(Half Vector)를 구한 뒤, 노말 벡터(Normal Vector)와 내적하여서 각도를 구해주면 된다.

 

주절주절 설명하지 말고 코드로 보면 이렇다.

 

 

문제는 이렇게 출력하는 순간 결과물은 대략 이렇다.

 

( 하얗게 불태웠어... )

 

엥? 너무 밝다. Specular라면서 하얗게 죽어버렸다.

이 문제는 바로 림라이트때 겪었던 그대로이다.

제곱(Power)를 해주어서 하얀 경계를 죽일 수 있다.

(잘 모르겠으면 8주차 참고!)

그럴싸? 한 림이 나오기는 했지만… 아직은 좀 부족한 것 같다.

이제 Texture와 제작했던 Rim까지 넣어 모든 것들을 추합해보도록 하자.

잘 되었겠지?! 하고 출력하는 순간 이런 현상을 볼 수 있을 것이다.



모델링이 로봇이기에 윤곽이 뚜렷해 그럴싸 해보일 수도 있지만
이 문제는 Specular의 마이너스 값이 보여지게 되는 것이다.

 

그러다보니 가짜 아웃라인처럼 나타나게 되는데 이건 모델링이 적당해서 그런 것과 동시에 마이너스 값을 가만히 두어서 좋을 일은 하나도 없으니…

 

Specular 값에 Saturate를 잊지 말자.

그렇게 되면 깔끔하게 모든 것들이 적용될 것이다!

 

추가적으로 Fake Specular 방식도 있는데, 이는  맨 처음에 잘못되었다 설명하였던 스펙큘러, 즉 림 라이트를 만들 때 반대가 되기 전의 방식을 사용할 수도 있는 것이다 

 

전체적인 부분을 이해하는 것이 가장 중요했으므로, 이제 응용 해보자!

 

코드를 생각보다 정리하는 것이 쉽지 않았다.

더하고 곱하는 것에 대한 것을 많이 고민해야 했고...이에 대한 결과물이다!

 

 

개인적으로 Specular는 Normal과의 조화가 너무 잘 어울린다고 생각해서 Normal을 더 강하게 했다. 그러다 보니 Normal이 두드러진 곳은 더욱 예쁘게 보인다.



아쉬운 점은

 

  1. 눈을 반짝이게 하려고 했으나 실패했음 (빨간 색으로 하는 것도, 반짝이는 것도)
    텍스쳐의 알파 맵에 눈을 강조할 부분을 넣었고  _Time.y를 곱하면 될 줄 알았지만…계속 하얗게 죽기도 했고 알파 맵이다보니 색을 넣을 수도 없었다. (RGB 안에서 해결하는 법을 더 연구해야겠다.)

  2. Rim Light에 Bloom을 주면 반짝반짝 하게 되는 이유가 Saturate 문제라는 것을 뒤늦게 알 수 있었음 (HDR도 Saturate를 해야 하는 것인가? 싶어졌다.)


 2. 셀 쉐이딩(Cel Shading) 맛보기

(https://www.animatormag.com/blog/computer/cel-shading-hero-animation/)

 

말 그대로 “카툰”같이 표현하기 위해 사용되는 셀 쉐이더, 또는 툰 쉐이더(Cel, Toon Shader)는 단순한 음영 기법과 뚜렷한 외곽선이 눈에 띈다.

 

내부 음영 단계 구분에 대해서 아직 우리 수준에서 알 수 없지만, 외곽선에 대해서 가볍게 이해할 수 있다. 외곽선을 만드는 것에만 해도 다양한 기법이 있다.

 

2-1. 2-Pass 기법

( https://www.codinblack.com/outline-effect-using-shader-graph-in-unity3d/ )

 

Multipass, 또는 2-Pass로 불리는 이 기법은 말 그대로 “두 번”(콩) 불러오는 것이다.

대신 한 번 불러온 모델링보다 노말 방향으로 더 크게 한(버텍스가 이동이 된) 모델링을 겹쳐내어 아웃 라인이 보이는 것처럼 처리하는 방식이다.

 

(  https://shaderforge.userecho.com/communities/1/topics/651-outline-alternate-method  )

 

두 번 불러오는 만큼 드로우 콜 횟수도 늘어나지만, 하드 엣지의 경우 노말의 방향의 문제로 좌측의 이미지처럼 나오게 되기 때문에 스무싱 그룹을 잘 처리해야 할 필요가 있다.



2-2. Fresnel 기법

( https://docs.unrealengine.com/en-US/Engine/Rendering/Materials/HowTo/Fresnel/index.html )

 

우리가 사용한 림라이트 기법처럼 Fresnel(굴절률...이라고 기억하면 좋을 것 같다.) 기법을 통해서 구현이 된다.

림라이트 자체를 더 뚜렷하게 만들어 외곽선을 주는 것이지만 이미지 상으로, 구현 방식으로도 선이 모델링 안 쪽에 자리하게 된다.

 

2-3. Post Processing 기법

(https://www.tomlooman.com/multi-color-outline-post-process-in-unreal-engine-4/)

 

Post Processing, 즉 후처리를 통해 처리하는 방식이지만 찾아보았을 때 대다수 Unreal 내의 구현 방식으로 정확한 정보는 알 수 없었다.



다수 사용되는 기법은 2-Pass이고, 다음 10주차 시간에는 2-Pass와 함께 셀 쉐이더를 알아보도록 하자!