서피스 셰이더



서피스 셰이더 동작원리


먼저 3D모델이 3D모델 지오메트리를 변경할 수 있는 어떤 함수로 넘겨진다. 

그런 다음, 몇몇 직관적인 속성을 사용하여 겉모습을 정의하는 어떤 함수로 넘겨진다.


마지막으로, 이 속성들은 지오메트리가 근처의 광원들에 의해 어떻게 영향을 받을지를 결정하는 라이팅 모델에 의해 사용된다. (각 모델의 픽셀들의 RGB색상으로 나타내짐)


서피스 함수


서피스 함수는 3D모델의 데이터를 인풋으로 가져와서, 결과값으로 렌더링 프로퍼티들을 반환한다. 

아래의 서피스 셰이더는 오브젝트를 흰색 diffuse를 갖는 오브젝트로 렌더링한다.



#pragma surface : 해당 셰이더를 위한 서피스 함수이름은 surf이고 라이팅 모델로는 램버시안 모델을 사용할 것이다 라는 뜻이다.


o.Albedo = 1; : 머티리얼의 알베도 즉, 재질 기본색상이 흰색이라는 것을 나타낸다.


최초의 3D모델로부터의 어떠한 데이터도 사용하지 않지만,

그럼에도 인풋 구조체를 정의하는 형식이 필요하다.




서피스 아웃풋


SurfaceOutput구조체 안에는 머티리얼의 최종 모습을 결정하기 위해 사용되는 여러가지 프로퍼티들을 포함하고 있다.


fixed3 Albedo : 기본색상

fixed3 Normal : 반사각을 결정하는 면의 방향

fixed3 Emission : 이 오브젝트가 스스로 생성하는 빛의 양

half Specular : 머티리얼이 빛을 반사하는 정도(0~1)

fixed Gloss : 스펙큘러 반사가 퍼지는 정도

fixed Alpha : 머티리얼의 투명한 정도


Cg/HLSL은 전통적인 float타입을 지원한다. 하지만 보통 32비트의 정밀도는 거의 필요하지 않을 것이고,

보통 16비트 정도면 충분하기 떄문에 half타입을 주로 사용하게 될 것이다.



텍스처 샘플링


텍스처를 붙이는것을 배우기전에 텍스처 매핑이 어떻게 일어나는지 알아보자

텍스처를 입힐 모델은 여러 개의 삼각형들로 만들어져있고, 각각의 삼각형은 3개의 버텍스로 구성된다.

데이터(UV와 색상)는 이러한 각 버텍스들 안에 저장된다.


삼각형의 버텍스들을 통해 텍스처 상에 맵핑되는 0에서 1사이의 정규값을 가져 올 수 있는데 이것이 텍스처 UV좌표이다.

즉, 3D오브젝트에 텍스처를 매핑하려면, 각 버텍스의 UV좌표가 필요하다.




_MainTex라는 이름으로 텍스처 프로퍼티를 선언했는데 이 프로퍼티는 머티리얼

인스펙터를 통해 접근가능하도록 처리가 되도록 한 것이다.

<쉐이더를 적용한 머티리얼 인스펙터창>


현재 픽셀의 UV데이터는 float2 uv_MainTex에서 추출된다.


tex2D는 텍스처와 UV값을 넘기면, 이에 해당하는 RGB색상으로 반환한다.

tex2D함수는 텍스처를 임포팅할 때, Unity에 의해 직접 설정될 수 있는 다른 파라미터들을

계산에 고려하게 된다.



서피스 인풋

서피스 인풋인 Input의 필드들을 Unity가 계산 할 값들로 채울 수 있다.

예를 들어, float3 worldPos를 추가함으로써 surf에서의 해당 점에 대한 월드 포지션을 가지고 초기화 되는데

이것은 특정 점으로부터의 거리에 의존적인 이펙트를 생성하는데 사용된다.


그 밖의 다른 인풋들

- float3 viewDor : 카메라의 방향(뷰 방향)

- float4 name : COLOR : name변수에 버텍스 색상을 포함한다.

- float4 screenPos : 스크린 좌표 상의 해당 픽셀의 위치

- float3 worldPos : 해당 픽셀에 대한 월드 좌표 상의 위치



버텍스 함수


surf함수로 보내기 전에 이들을 수정/변경해준다. 

surf함수가 RGBA공간 안에서 색상을 다루는 반면, 공간에의 3D점을 제어하기 위해서는 버텍스 모디파이어 사용방법을 알아야한다. 


3d모델을 원래의 모습보다 좀 더 통통하게 만드는 셰이더를 예제로 만들어보자

이렇게 만드려면 모델의 삼각형을 삼각형면이 향하는 방향을 따라서 확장시키면 된다. 

삼각형면이 향하는 방향은 결국 노멀값으로 나타내며, 삼각형 자신의 포면에 수직인 단위 벡터이다.

그렇다면, 이제 다음과 같이 노멀 방향으로 버텍스를 확장하려면 다음과 같은 수식을 사용할 수 있다.



#pragma surface surf Lambert vertex:vert : vert라는 이름을 갖는 버텍스 모디파이어를 설정한다.


실제 vert함수 코드를 보면 ,(v.vertex.xyz += v.normal * _Amount; )

버텍스 위치를 받아서 노멀을 따라 해당 버텍스를 밀어낸다.


appdata_full 구조체는 해당 현재 버텍스의 모든 데이터를 포함하고 있다. 


<결과 화면>



눈 쉐이더


surf함수와 vert함수 이 두가지를 사용하는 snow이펙트가 있다.

어떤 모델의 삼각형 위에 눈이 쌓이는 것을 시뮬레이션하는 것이다.

처음에는 _SnowDirection을 직접 마주하는 삼각형들에만 적용되다가, _Snow가 증가함에 따라서

하늘을 향하지 않는 삼각형들도 결국엔 영향을 받게 되는 방식이다.


우선, 삼각형이 하늘을 향해 있다는 의미를 파악해보자

_SnowDirection은 눈이 내리는 방향을 의미하며 단위벡터의 형태이다.

그것들이 어떻게 정렬되어 있는지를 확인하는 방법중 가장 쉬운 방법은 눈 방향으로 법선(노멀)을 투사하는 것인데,

두 벡터 모두 크기는 1이므로, 결과값은 +1(같은 방향)에 -1(반대 방향)사이가 될 것이다.

이것은 내적과 같다는 것을 Cos세타와 동일하다는 것만 알면된다.

특정 _Snow값보다 도트 연산이 커지게 된다는 것은


  • cos (\ theta) \ geq +1 두 방향이 같은 경우에만 참입니다.
  • cos (\ theta) \ geq 0\ theta90도 미만일 때 true입니다 .
  • cos (\ theta) \ geq -1 항상 사실입니다.

<결과 화면>


벡터 사이의 코사인 값을 수동으로 계산하는 대신,

Cg는 dot라는 이름의 도트 연산 구현을 포함하고 있다.

float4 sn = mul(_SnowDirection, _World2Object);

if (dot(v.normal, sn.xyz) >= _Snow)

v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;

이 부분은 노멀을 월드좌표로 바꾸기 위해서 조금 다른 메소드를 활용하고 있다.

WorldNormalVector함수는 버텍스 모디파이어 안에서는 사실상 이용할 수 없기 때문이다.



http://www.alanzucconi.com/2015/06/17/surface-shaders-in-unity3d/

https://jinhomang.tistory.com/137

반응형

+ Recent posts