본문 바로가기

Unity3D/2021_엔진 심화

[Unity] Z-buffer, Shader Lab

 

Z-buffer란?

 

엔진 내에서 3차원 이미지를 렌더링 할 때 픽셀의 깊이 정보가 테스트 후 업데이트 되어 버퍼에 저장 됩니다.

 

그런 정보를 아래의 사진처럼 전체 화면 해상도에 오브젝트 마다 픽셀로 저장되어 같은 위치에 여러 물체가 있을 시 깊이 값에 따라 해당 오브젝트를 그릴지 말지 결정하는 역할을 하게 됩니다. 

이 과정이 없다면 각 오브젝트의 앞, 뒤를 구별하지 못해 가림 처리를 할 수 없게 됩니다.

 

Alpha blend

 

DirextX에서

가까운 거리는 0

먼 거리는 1로 나타냅니다.

 

 

ZWrite를 끌 경우 Z-buffer 대상에서 제외 되면서 가림처리를 하지 않게 되는데 alpha Blend의 add, Multiply를 적용하면 자동으로 ZWrite가 꺼지게 됩니다. 왜냐하면 반투명 이미지의 경우 Z-buffer로 인해 알파가 적용된 부분의 너머까지 가려지는 부분으로 처리하게 되기 때문이죠.

(alpha 이미지의 경우에는 그려지는 순서가 중요하기 때문에 ZWrite를 키고, Alpha Clipping을 사용. Opaque를 사용하더라도 알파 모양대로의 그림자를 얻을 수 있다.) 

 

ZBuffer에 존재하지 않는 반투명 이미지 위에 불투명 오브젝트가 그려지는 오류가 발생하는 것을 막기 위해서

Opaque = Render Queue 2000

Transparent = Render Queue 3000

이렇게 분류를 해서 유니 자동으로 세팅을 하게 되어있습니다.

 

노란 동그라미는 ZWrite를 끈 오브젝트

 

Z-buffer의 0~1의 기준은 카메라의 Near, Far 값으로 정해집니다.

Near- 그려지는 곳 중에서 가장 가까운 거리 

Far- 그려지는 곳 중에서 가장 먼 거리

최대 거리가 멀 수록 더 먼거리를 0~1로 나눠 그려야 하기 때문에 그려지는 정밀도가 낮아지게 됩니다.

 

정밀도가 낮아지거나 오브젝트 간의 거리가 매우 유사할 경우 서로의 깊이 값도 유사하기 때문에 겹치는 부분에 노이즈가 발생하게 됩니다.

 

 

 


깊이값은 셰이더에서도 활용이 가능합니다.

간단하게 예를 들어 outLine Shader를 적용한 두 오브젝트가 있습니다. 같은 두께의 외각선을 가지고 있으나 오브젝트의 거리에 따라 외각선의 두께가 달라지게 되죠. 이런 현상을 방지하기 위해 카메라에 가까워질 수록 외각선의 두께가 얇아지는 기능을 추가하려고 합니다.

 

화면 위치의 깊이값을 가져와 외각선의 두께에 곱해준다면 카메라와 가까울 수록 두께는 0에 수렴하게 되고, 멀수록 1의 가까운 수가 곱해져 기존 외각선의 두께와 같게 됩니다. 결과적으로 서로 다른 위치의 오브젝트가 같은 두께의 외각선을 가지게 됩니다.

  


유니티 Shader Lab

 

쉐이더 언어

프로그래밍 언어는 종류가 많다 각 소프트웨어, 플렛폼에 따라 주로 사용하는 언어가 다르듯이 쉐이더에도 주로 사용되는 언어들은 아래와 같습니다.

 

HLSL: 고급 쉐이더 언어 (High Level Shader Language) DirectX에 동작하는 언어. (URP)

GLSL: OpenGL 쉐이더 언어(OpenGL Shading Language) 이름대로 OpenGL에 동작하는 언어. 

CG: (C for Graphics) nVidia에서 제작한 언어. (리거시)

 

이 세 언어들은 서로 유사해 하나를 먼저 배우면 나머지 언어를 익히는데 큰 어려움이 없다고한다.

HLSL과 CG는 서로 공동 개발했고, 브랜딩 이름이 다른 거라고 함.

 

Shader Lab

유니티에서는 멀티 플렛폼 개발을 지원하죠. 여러 플렛폼에 대응하기 위한 자체 언어를 개발했는데 그것이 Shader Lab입니다.

코드를 작성하면 플렛폼에 따라 유니티내에서 자체 변환을 해주지만 자체 스크립트 언어만으로는 제약이 많았기 때문에 내부에서 CG를 같이 사용할 수 있게 하였습니다.

 

 

 

이제 본격적으로 URP에서 코드를 만져봅시다.

오늘은 짧고 간단하게만 보고 다음 시간부터 세부 내용을 알아봅시다.

 

유니티 URP 텍스쳐 코드를 토대로하여 작성했습니다.

Drawing a texture | Universal RP | 10.4.0 (unity3d.com)

 

Drawing a texture | Universal RP | 10.4.0

Drawing a texture The Unity shader in this example draws a texture on the mesh. Use the Unity shader source file from section URP unlit shader with color input and make the following changes to the ShaderLab code: In the Properties block, replace the exist

docs.unity3d.com

에러가 나는지 안나는지 하나하나 지우면서 유니티에서 확인할 것

 

 

쉐이더 이름

맨 윗 줄에서는 쉐이더의 이름을 정합니다.

 

 

Properties 문법은 주로 아래와 같은 구조로 이루어져 있습니다.

_변수이름 ("인터페이스 이름" , 프로퍼티 종류 ) = 디폴트값

Properties에서 작성한 내용은 쉐이더 외부에서 수정할 수 있도록 내보내집니다.

(노드에서는 블랙보드가 있었죠. 똑같습니다.)

 

변수는 간단히 설명하면 정보를 저장 할 수 있는 공간에 이름을 붙인 것입니다.

컴퓨터 메모리에 존재하며, 정보를 저장하기 위한 공간, 그 공간을 쉽게 찾기 위해 이름을 지정하는 것입니다.

그래서 비유로 상자 이미지가 많이 보이죠. 상자 만큼은 잘 기억하고있음

 

 

텍스쳐와 float1 값을 기본과 슬라이드 형태로 내보냈습니다.

 

 

야호 추가 되었습니다. 그러나 값을 아무리 변경해봐도 기존에 있던 텍스쳐 외에는 작동을 하지 않습니다. 왜냐하면 노드에 이어지지 않으면 출력되지 않는 것과 같이 코드도 내부에서 값을 적용해줘야 출력할 수 있기 때문입니다.

 

 

이제 SubShader 내부를 봐봅시다.

 

코드를 보면 중괄호를 통해 구역이 나눠져있습니다. 집과 같은 형태로 상상해보면 훨씬 이해하기 쉽습니다.

Shader 란 집 안에 Properties(현관)와 SubShader(마루)가 들어있고 안에 또 작은 방들이 들어있죠.

 

HLSLPROGRAM~ ENDHLSL의 사이에서는 HLSL을 사용합니다. 이제부터 ( ; )을 잊지 맙시다.

 

 

TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
//아래 추가
float4 _MainColor; //색상은 float4값. float4 변수를 추가해줍니다.

 

텍스쳐 변수를 담고있는 변수 color에 새로 만든 변수인 _MainColor를 곱해줍니다.

이제 color는 텍스쳐의 색상에 _MainColor의 색상을 곱한 값을 담게 됩니다.

 

return을 통해서 결과를 출력 할 수 있습니다. 세이브하고 유니티로 돌아가 봅시다.

//기존에 있던 변수 color에 *(Multiply)_MainColor 를 해줍니다. 
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv)* _MainColor;

return color;

전체 코드

 

결과가 잘 나온 것을 확인했습니다. 다음 부터는 더 자세히 코드를 알아가봅시다.

 

'Unity3D > 2021_엔진 심화' 카테고리의 다른 글

[Unity Shader] 좌표계, 벡터  (0) 2021.05.26
[Unity] 키워드, 색상 연산2  (0) 2021.04.21
[Unity] 색상 연산, 블렌더  (0) 2021.04.07
[Unity] Shader Graph 기초 / UI  (0) 2021.04.01