# Part 17 | NPR Rendering

## 01 NPR 렌더링이란?

**블린-퐁 방식의 한계**

* 단순히 램버트 + 스페큘러 이므로 에너지 보존 법칙을 수동으로 알아서 지켜야 한다
* 재질에 따른 스페큘러 색상도 알아서 처리해야 한다
* 스페큘러는 사실상 흰 공 모양이라 실제 세상과 많은 차이가 있다

한계가 있을 뿐, 블린퐁 방식이나 램버트 방식같은 스탠다드 방식이 가진 공통점이 있다.\
실재하는 사물의 재질과 비슷하게 만들려고 한다는 것이다.\
이런 렌더링 방식을 통틀어서 PR(Photo Realistic) 렌더링이라 한다.

사실적이지 않은 렌더링은 NPR(Non-Photo Realistic) 렌더링이라 한다.

툰 셰이딩은 대표적인 NPR 셰이더이다.\
툰 셰이딩의 특징은 다음과 같다.

* 외곽선이 있다
* 음영이 끊어져 있다

## 02 외곽선 만들기 이론

**외곽선 만드는 방법**

* 2Pass를 이용한 외곽선 제작
* Fresnel을 이용한 외곽선 제작
* 후처리(Post Effect)를 이용한 외곽선 제작

> **Pass?**\
> 한 번 그리는 것이 1Pass, 두 번 그리는 것은 2Pass

**2Pass 방식**

* 첫 번째 패스로 오브젝트를 그린다
* 같은 자리에 오브젝트를 그리는데, 조금 다르게 그린다
  * 완전히 검게 그린다
  * 크기를 키워서 그린다
  * 면을 뒤집는다 (뒷면만 그려지게 한다)
* 하지만 그냥 그리면 스케일은 피봇 점을 중심으로 커지기 때문에, 검고 뒤집어진 오브젝트는 스케일이 아닌 노말 방향으로 확장시켜야 한다.

단점

* 두 번 그리는 거라 무겁다
* plane으로 끝난 오브젝트는 외곽선이 안 생긴다
  * 이때는 폴리곤을 조금 말아주는 식으로 모델링한다
* 면을 뒤집은 것일 뿐인 온전한 오브젝트이기 때문에, 메쉬끼리 침범하거나 찌꺼기가 보일 수 있다
  * 선을 되도록 얇게 하거나, 선을 없앨 부위를 버텍스 칼라 마스킹 등을 이용하여 돌출되지 않게 하면 된다
* 각진 면(Hard Edge)에서는 선이 끊어진다
  * Soft Edge를 사용한다
  * Hard Edge에 있는 노말들의 방향을 통일시켜서 남아 있는 Texcord 좌표나 Tangent 좌표에 넣어주는 Asset을 사용한다

**Fresnel 방식**

* 림 라이트로 만들었던 결과물을 뒤집어주거나,
* if 문을 이용해서 외곽 라인을 검출해서 외곽선을 칠해준다

장점

* 폴리곤의 밀도와 각도에 따라 선의 굵기가 다양하게 나올 수 있어 의도적으로 선의 강약을 조절할 수 있어 결과물의 품질이 좋다

단점

* 완전한 평면을 가진 오브젝트에서는 이상한 모양으로 보이게 된다. 기본적으로 각 픽셀의 노말 방향과 시선 방향의 차이로 계산되는 외곽선이기 때문이다.

**외곽선 검출법**

* 포스트 프로세스에서 깊이 버퍼나 노말 등을 이용해서 소벨 마스크나 라플라스 필터 같은 공식들을 이용

## 03 외곽선 만들기

Vertex Shader는 버텍스 하나 마다 한 번씩 실행된다.\
Fragment Shader는 픽셀 하나마다 한 번씩 실행된다.\
즉, 일반적으로 Vertex Shader에서 연산하는 것이 Fragment에서 연산하는 것보다 가볍고 정밀도는 떨어진다.

![](https://velog.velcdn.com/images/biomatrix117/post/d874b405-3b15-4c45-814f-25995ce2ee40/image.png)

Vertex Shader의 Position에 Sine Time을 더한 Position 노드를 연결하면 모델이 움직이는 걸 확인할 수 있다.

이 방법은 애니메이션 키프레임을 따로 잡을 필요가 없어 매우 유용하다.\
깃발이나 물고기가 꼬리치는 애니메이션, 흔들리는 나뭇잎이나 풀 등을 간단하게 만들 수 있다.

![](https://velog.velcdn.com/images/biomatrix117/post/c600676e-46b4-44e8-883f-121368e50d4e/image.png)

Normal Vector만큼 position을 더하면 부풀어오른다.\
Normal Vector에 숫자를 곱해주면 부풀어 오르는 정도를 조절할 수도 있다.

> **Troubleshooting**\
> 이후 외곽선으로서 적용하려고 일반 머테리얼 적용한 모델과 겹쳤는데, 크기가 오히려 줄어든 것을 확인. 책과 비교해보니 Space가 World가 아니라 Object로 돼있어야 했다. (Normal Vector도 Object로 바꿔줘야 하는 것 같음)

![](https://velog.velcdn.com/images/biomatrix117/post/3b9b0daf-f192-4e0a-92bd-a20c0f913c83/image.png)

Graph Settings에서 Render Face를 Back으로 설정하면, 면이 뒤집어진다.\
안쪽 면만 보이는 거지만, Normal은 그대로라서, 어두운 면이 그대로 보이게 되어 Ambient Color만 보인다.

![](https://velog.velcdn.com/images/biomatrix117/post/78a2888e-b774-428c-8648-c6f5aa213b3b/image.png)

Graph Settings에서 Material을 Unlit으로 바꾸고,\
똑같은 오브젝트를 복사한 후 정상적인 머테리얼을 적용시키면 외곽선 효과가 된다.

현재의 아웃라인은 카메라에 가까워질수록 두꺼워진다.\
카메라 거리와 상관없는 균등한 두께의 아웃라인을 만들고 싶다면 카메라의 거리에 따른 두께 보정이 필요하다.

## 04 Render Feature를 이용해서 외곽선 추가하기

방금은 오브젝트를 하나 더 추가해서 외곽선 효과를 만들었고,\
오브젝트의 머테리얼을 하나 더 추가해서 Outline 셰이더를 입혀줄 수도 있다.\
이런 경우엔 오브젝트가 원래 단일 머테리얼을 가지고 있어야만 가능하다.

또 다른 방법으로, SRP의 기능인 Render Feature로 두 번째 패스를 추가할 수 있다.

> **Render Feature?**\
> 렌더링 레이어 같은 개념. 엔진에서 추가 렌더링 오브젝트와 머테리얼, 렌더링 타이밍까지 결정할 수 있다.

![](https://velog.velcdn.com/images/biomatrix117/post/a36e663e-adad-4164-b15c-2dc177d3b9c7/image.png)

Edit > Project Settings > Graphics > Scriptable render Pipeline Settings 더블 클릭 > Inspector > Rendering > Renderer 더블 클릭 > 맨 아래 Add Render Feature > Render Objects

* Event : 언제 이 추가 렌더링의 이벤트가 발생할 것이냐
  * Opaque(알파가 없는 불투명/ 알파 테스트)\
    → Skybox(스카이박스)\
    → Transparent(알파 블렌딩 반투명)\
    → Post Process(화면 후처리 효과)\
    → After Rendering(렌더링 끝)
* Layer Mask : 렌더 피쳐 그릴 레이어 지정
* Lightmode Tags : Shader Graph에서는 안 쓰는 기능
* Overrides : Material, Depth, Stencil, Camera 설정을 독립적으로 이 렌더 피쳐에만 해주는 부분
  * 전에 만든 outline 머테리얼을 넣어주면 outline effect 적용 완료

Skull 레이어에 해당하는 오브젝트만 렌더 피쳐로 한 번 더 그려서, outline 머테리얼로 덮어쓰는 작업을 한 것.

## 05 Branch를 이용해 끊어지는 음영을 만들어 봅시다

sub graph로 만들었던 Lambert를 복사하여 이름을 Toon으로 바꾸고 공식을 Half Lambert로 바꿔준다.

![](https://velog.velcdn.com/images/biomatrix117/post/99862712-38cc-4898-9759-ee908318b5c0/image.png)

Comparison 노드로 Greater than 0.5 조건을 설정해주고,\
Branch 노드에서 이를 '0.5 이상이면 1, 0.5 미만이면 0'으로 바꿔준다.\
이를 응용하여 0과 1 자리에 텍스처나 컬러를 넣어줄 수도 있다.

## 06 Ceiling을 이용해 끊어지는 음영을 만들어 봅시다

Comparison은 2단계가 넘어가는 조건문을 만들 수 없다.

![](https://velog.velcdn.com/images/biomatrix117/post/f6ec7aaa-1b11-49f9-9089-dd7d05f9ba3a/image.png)

Half Lambert의 결과에 5를 곱해주고 값들을 ceiling으로 이산적으로 만들어준 후에 5로 다시 나눠주면 음영이 다섯 단계로 나눠진다.

이 방법은 간단하지만 음영의 범위를 세부적으로 정할 수 없다. 어두운 부분을 좀 더 넓게라던가.

> **Troubleshooting**
>
> <img src="https://velog.velcdn.com/images/biomatrix117/post/71f5da40-51ad-4f5b-b9fc-b20fc0191d4d/image.png" alt="" data-size="original">
>
> 결과가 책과 다르게 너무 밝음. bloom이 켜질 정도. 예제를 불러왔는데 과정은 차이 없으면서 결과는 차이남.\
> 아무리 살펴봐도 다른게 없음. Transform 노드의 결과가 달라서 혹시 이건가 하고 갈아껴봤더니 결과가 똑같음.\
> 그럼 이전에는 노말맵을 어떻게 설정해놨지? 하고 보니까 Transform의 Type이 Position이 아니라 Direction으로 돼있었음.\
> Direction으로 변경했더니 책과 결과가 같아짐.

## 07 Fresnel을 이용해서 외곽선을 만들어 봅시다

우선 설정했던 Outline 렌더를 꺼준다.

![](https://velog.velcdn.com/images/biomatrix117/post/760bdfed-fef6-4549-9098-081ff83c3d0b/image.png)

fresnel effect node에 one minus 노드를 연결해주고 텍스쳐와 곱해주면 된다

power 노드를 빼고 step 노드를 one minus 노드 이전에 연결해주면 좀 더 딱 떨어지는 외곽선을 만들 수도 있다

## 08 Diffuse Warping 기법

![](https://velog.velcdn.com/images/biomatrix117/post/e8c67b8b-2972-40cb-9777-aa0f7db3cd46/image.png)

Ramp 텍스쳐의 UV parameter에 Half Lambert의 결과물을 넣어주면, UV의 원리에 따라 밝기에 따른 색이 지정된다.\
(Ramp 텍스쳐는 Repeat가 아닌 Clamp를 사용하는게 좋다. 압축도 None으로 해야 원하는 색상 값을 고를 수 있다.)

이 방식을 응용하면 빛과 정반대로 반응하는 셰이더를 만들거나, 하프 램버트를 직접 그리거나, 전혀 존재하지 않는 역광을 그릴 수도 있다. 빛이 어둡게 넘어가는 중간 부분에 붉은색을 강제로 칠해서 매우 간단한 가짜 피부의 SSS(Subsurface-Scattering) 효과를 만들어 줄 수도 있다.

## 09 Diffuse Warping을 응용해 봅시다

방금은 UV에 Vector2를 넣을 때 y는 0.5로 뒀는데, 이 값은 다양하게 응용할 수 있다.

* Fake SSS를 두께별로 그려 놓고, 버텍스 컬러로 피부의 두께에 따라 다른 SSS가 나오게 제어
* 스페큘러 공식 기본형인 `N*H` 만들어 놓고, 이에 따라 반응하는 텍스쳐를 만들면 텍스쳐로 스페큘러 두께 조절 가능
* Fresnel 공식인 `N*V`와도 반응하게 만들 수 있음

![](https://velog.velcdn.com/images/biomatrix117/post/6ec43e4d-8655-4ceb-92ea-10b1cedf5685/image.png)

![](https://velog.velcdn.com/images/biomatrix117/post/de8a3e2e-d4b7-494d-98c2-7ed7438cc419/image.png)

맨 위가 하얀색인 ramp 텍스쳐를 사용하고\
`N*H`(블린 퐁 반사)의 결과를 UV의 세로축에 연결하면 가짜 스페큘러를 만들 수 있다.

![](https://velog.velcdn.com/images/biomatrix117/post/09b1a337-e201-4a85-a1b0-d288cdd1b332/image.png)

![](https://velog.velcdn.com/images/biomatrix117/post/f3a839b2-3f6b-43c5-a495-123e8ec9a6d2/image.png)

아래에 대각선으로 검은 부분을 추가한 텍스쳐를 사용하고 `N*V`(Fresnel 구현할 때 사용했던, 카메라가 조명처럼 되는 계산)의 결과를 UV의 세로축에 연결하면\
밝은 부분에는 검은 외곽선이 얇아지고 어두운 부분에는 검은 외곽선이 두꺼워지는 효과가 발생한다


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lazyartisan.gitbook.io/note/main-page/books/urp/part-17-or-npr-rendering.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
