본문 바로가기

Shader/물방울책

Shader 1

*Split

: 말 그대로 색 등을 R,G,B,A로 각각 나눠주는 것

 

*Combine

: 말그대로 RGBA(4자리 값)으로 합쳐주는 것

 

*Linear와 Gamma 146p

: 색의 RGB값에 각각 0.5의 float값을 넣은 Vector 3의 값과 그냥 0.5의 color값을 비교해보면 color값을 넣은 회색이 더 어둡다. float값은 Linear, color값은 Gamma이기 때문이다

색을 0~1로(검흰) 표현했을 때 그라데이션되는 것을 생각해볼 수 있다. Linear는 선형의, 수학적인 그라데이션이다. 이게 수학적인 계산 상으로 원래 옳은 그라데이션 값이다. 그러나 이 정석의 그라데이션을 사람이 보면 균형잡힌 그라데이션으로 보이지 않는다. 회색 부분이 너무 0쪽에 몰려있고 흰색의 값이 더 많아보인다는 것이다. 그래서 인간의 눈에 맞게 이 회색의 값을 좀 더 1쪽으로 끌어내린 것이 감마라고 부르는 상태이다. 사실 수학적으로는 잘못된 그라데이션이지만 인간의 눈에 맞게 중간 회색부분을 더 어둡게 만든 상태라고 할 수 있다

텍스처를 가져올 때(0~1의 숫자값 말고) 원래 상태는 Linear지만 출력할 때 어두워질 것을 예상해서 밝게 저장된 sRGB로 되었다가 모니터에서 출력될 때는 다시 Linear로 돌아온다

 

*Colorspace Conversion

: 컬러를 제대로 연산하려면 Color노드를 Linear로 바꿔줘야 함. 이때 쓰는 노드임. 이 노드에서 Linear > RGB로 설정해주면 됌

 

*Saturate

: 0~1로 값을 제한해주는 노드

 

*Clamp

: Saturate랑 비슷함. 그대신 얘는 0~1인 정해진 값으로 자르는데 아니라 최대최소값을 내가 입력한 범위의 값으로 제한할 수 있음. 그대신 Saturate보다 연산이 무겁다

 

*흑백 만드는 법 173p

1.RGB 채널을 모두 합치면 색이 되지만 하나하나씩 보면 0~1의 값, 즉 흑백으로 표현할 수 있음. (1,1,0)은 노란색이지만 1(흰) 1(흰) 0(검)인 것처럼. 그러면 R+B+G의 평균값을 구하면 색의 밝기의 평균을 구할 수 있지 않을까. 흑백이란 것은 RGB 각 채널의 숫자가 동일한 것. 그래서 (R+B+G)/3을 해주고 이 한자리 float를 Base Color노드의 R,G,B에 각각 연결해주면 됌. 3으로 나누는 이유는 0~1의 값을 3번이나 더했기 때문에 색의 밝기가 원본보다 3배나 밝아짐. 그래서 다시 3으로 나눠줘야 함

2.보다 정확하게 하는 법. 빨초파는 휘도(밝기)가 각각 다름. 초록이 가장 휘도가 높고 그다음 빨, 그다음 파임. 밝기 순이 초>빨>파라는 뜻. 이 비율은 (0.2126729, 0.7151522, 0.0721750)이라고 함. 이 휘도의 가중치를 각 RGB에 곱한 후 R+G+B를 해주면 더 정확한 흑백을 만들 수 있음

3.Saturation(채도) 노드를 쓰면 됌. 얘는 Saturate랑은 다른 것!! 그냥 색이나 텍스처 뒤에 Saturation 노드를 연결해주고 Saturation 값을 0으로 해주면 됌. 이건 휘도 차이 별 강도를 적용시켜주는 노드임

 

*Opaque

: 불투명. <-> Transparent (투명)

 

*Normalize

: 벡터를 정규화시켜서 단위벡터로 만드는 것. 단위벡터는 각 벡터를 벡터의 크기만큼 나눈 값을 말하며, 0~1의 값임. 그러니깐 그냥 원래 벡터를 0~1의 값으로 바꾸기 위해서 쓰는거라고 보면 됌. 벡터의 크기가 1이 아니면 계산할 때 곤란해진다. 벡터들이 너무 크면 normalize해서 0~1의 값으로 바꾸어서 사용. 근데 머티리얼에서 texcoord 같은 곳에 normalize를 하면 경계선이 진해진다!

모르겠으면 유튜브에 unreal engine normalize 찾아보기

 

*사선 만들기 \

: TexCoord 일단 가져와야되고 그다음 R과 G(U와 V)만 쓰기 위해서 BreakOutFloat2Components 라는 노드를 씀(Mask에서 RG 체크하는거랑 다른가). R은 왼>오로 검>흰이고 G는 위>아래로 검>흰이잖아 여기서 사선을 만들려면 R-G를 하면 됌. (모르겠으면 R과 G의 검흰 그림 그려보고 그 숫자값을 빼보기. 색의 숫자값을 좌표값이랑 헷갈리면 안됌!)사선을 여러개 만들고 싶으면 Subtract로 뺀 값에 Sine 노드 붙여주면 됌. 그리고 만약 사선의 밀도를 더 올리고 싶으면 BreakOutFloat2Components에서 R과 G 각각에 일정값을 Multiply 해주면 됌.

(참고 4:00)

https://youtu.be/QnOnjWXeDAA

 

 

 

*감마와 linear

: 감마를 끄고 리니어로 적용하려면 sRGB를 꺼주면 됌. 유니티는 texture 노드를 클릭하고 Inspector에서 수정하면 되고 언리얼은 texture 더블클릭해서 열어서 체크를 꺼주면 됌. 이렇게 감마를 리니어로 바꿔주는 걸 Gamma Correction이라고 함

 

*Metalic 메탈릭과 Specular 스페큘러

: 물리기반셰이더 (PBS - Unlit 말고 Lit 셰이더로, base color, metalic, normal 등등이 있는 셰이더를 말하는 것)에서 메탈릭이 0이면 Specular 컬러가 흑백이 되고, 메탈릭이 1이면 스페큘러 컬러가 Albedo 색이 된다. 금속은 고유의 스페큘러 컬러를 가지고 있기 때문임

비금속(전도체, 유전체)의 스페큘러(정반사,하이라이트) 컬러는 조명의 색임. 하지만 금속은 어떤 색의 빛을 비추어도 자신의 고유 스페큘러 색이 반사돼서 나옴.

 

*Roughness 러프니스

: 러프니스가 1이면 거친 표면이 되는거고, 이로 인해 정반사(Specular)보다 난반사(Diffuse)가 심해진다. Lit Shader인 물리기반 렌더링의 기본 원리는 에너지 보존 법칙임. 그래서 러프니스에 따라 정반사와 난반사의 비율이 결정되고, 난반사가 높아지면 그만큼 정반사는 줄어드는 것임.

 

*Ambient Occlusion 앰비언트 오클루젼

: 앰비언트 오클루젼을 적용하면 구석진 곳에 추가적인 음영을 주는 것을 말함. 오브젝트는 일반적으로 환경광(Ambient Color)를 받는데 구석지거나 가려져서 환경광이 닿지 않는 곳이 앰비언트 오클루젼. AO는 환경광을 차폐하는 것. 앰비언트 오클루젼을 적용하면 구석진 곳이 어두워지는데 주광 + 환경광 연산에 AO가 곱해진 거임.

주광(Diffuse) + 환경광(Ambient) X AO의 결과라고 보면 됌

앰비언트 오클루젼 텍스쳐에 Add 노드를 연결해서 강도를 조절할 수 있음. 0을 더하면 아무 변화가 없을거고, 1에 가까워질수록 약해지며 음수가 되면 Occlusion이 강해짐. 그리고 이후에 다시 0~1의 값으로 만들어주기 위해 Saturate 노드 붙여주면 됌

 

*함수, Sub Graph

: 언리얼 머티리얼 그래프에서 마스터 머티리얼 같은 걸 보면 함수가 있는걸 볼 수 있음. 그냥 노드들로 주욱 연결하면 너무 길어져서 알아보기 힘드므로 반복되는 부분을 모아서 노드 하나로 압축해버리는 기능임.

유니티는 Sub Graph라고 함. 노드들을 드래그해서 우클릭 후 Convert to Subgraph 해주면 됌. 그러면 저장이 되고 다른 프로젝트에서도 이용할 수 있으며 다른사람꺼 다운받아서 이용도 가능. 수정하고 싶으면 그냥 더블클릭

 

*API

: Application Programming Interface를 의미. 여기서는 Direct 3D와 같은 프로그램을 의미함. API는 프로그램과 프로그램이 서로 통신할 수 있게 도와주는 매개체임. 앱과 기기가 원활하게 통신할 스 있게 해주고 기계, 운영체제에 상관없이 누구나 동일한 액세스를 얻을 수 있게 접속을 표준화한다.

API는 소프트웨어 개발에서 호환성을 위해 지켜야하는 추상적인 원칙임. API가 실제 기능 구현체인 ’라이브러리‘(API를 기반으로 플랫폼에서 바로 실행될 수 있도록 모듈화된 프로그램)와 함께 제공되는 경우를 SDK라고 한다.

라이브러리의 종류에는 안드로이드 - OpenGL, Vulkan (openGL의 차세대) / 윈도우 - DirectX /  - Metal 등이 있다

 

*Sampler State 샘플러 상태 (유니티) 1권 297p

: 이 노드를 추가하면 Filter와 Wrap를 바꿀 수 있음. Texture2D 노드에 있는 Sampler에 연결해주면 됌.

Filter 모드에는 Linear와 Point가 있는데 Linear는 텍스쳐가 화면에서 축소, 확대될 때 주변 픽셀과 블렌딩되면서 부드러워지는 것이고, point는 블렌딩되지 않는 것임.  Trilinear가 있는데 얘는 Linear와 기본적으로 같은데 Mipmap 변화가 될 때 Mipmap의 경계서도 부드럽개 보간하므로 가장 좋음.

그다음 Wrap은 UV의 0~1 범위를 넘어가는 텍스처를 어떻게 표현할지에 대한 세팅임. 기본은 Repeat이고, Clamp, Mirror, Repeat V 등이 있음.

Direct3D 11는 한 셰이더에 최대 128개의 텍스쳐와 16개의 샘플러를 지원함. 이걸 넘어가면 오류남. 그래서 Sampler State 노드 하나를 만들어놓고 공유해서 쓰면 샘플링 수를 줄여 오류를 피할 수 있음

 

*Height Map (Parallax Mapping) 1권 311p

: 하이트맵은 높이를 저장하고 있는 그레이스케일의 텍스처임. 유니티의 Lit Shader에서는 하이트맵을 Parallax의 맵으로 쓰고 있다.

Parallax Mapping (시차 맵핑)이란 시야각에 따라 UV를 이동시켜 깊이감을 흉내내는 기법을 의미함. 실제로 Vertex를 이동시키는 기법이 아니라 노말맵으로 표현하기 힘든 기울어진 표면에서 입체감을 강화시켜주는 효과를 보여주는 이미지 변형 기법임. 따라서 UV를 얼마나 이동시켜줄까에 대한 깊이맵이 필요하며, 깊이맵의 정도에 따라 UV개 시야각에 맞추어 이동하는 정도가 다름

 

*Normal Vector 노말 벡터

: 노말 벡터와 라이트 벡터(라이트의 방향)가 서로 마주보면 가장 밝고, 각도가 멀어질수록 점점 어두워짐. 예를들어 Plane과 Directional Light의 방향이 서로 직각이 된다면 엄청 어두워지고, 방향이 서로 마주보면 아주 밝음.

그런데 노말 벡터가 면에 있으면 부드러운 라이팅을 구현할 수 없음. 오브젝트의 면 별로 딱딱 끊어진 라이팅이 될거임. 그래서 요즘에는 노말 벡터가 버텍스에 들어가있음. 그리고 버텍스 사이 값들은 보간(interpolate)하여 부드러운 라이팅을 구현함. 이걸 ‘버텍스 라이팅’이라고 한다. (요즘엔 이게 픽셀라이팅으로 발전되었다)

그러나 부드러운 오브젝트가 아니라 각진 오브젝트(하드서피스)에서의 버텍스 라이팅을 면에 노말이 있던 것처럼 라이팅을 구현하는 방법은 좀 다름. 하나의 버텍스에는 각이 여러 개가 있을거임. 주변의 4방향(혹은 3방향 등)이 모두 다른 밝기를 가져야 하니깐 하나의 버텍스가 3,4개의 노말이 필요하단 말임. 그런데 하나의 버텍스는 하나의 노말만 가질 수 있음. 그래서 게임엔진에선 어떻게 했냐면 버텍스를 복사해서 같은 자리에 추가하여 표현함. 즉 각진 형태를 표현하랴면 버텍스의 양이 늘어난다는 것임.

따라서 총 정리해보면, 노말 벡터와 라이트 벡터와의 각도가 빛의 밝기룰 정하며 노말 벡터는 버텍스에 있다.

 

*벡터의 연산

: 길이가 같은 두 벡터를 더하면, 두 벡터 사이의 절반인 각도가 나온다.

두 벡터 사이의 정확히 절반인 각도의 벡터를 구하고 싶을 때 유용함. 그러나 위 문장을 만족하려면 두 벡터의 길이가 같은 즉, 단위벡터로 만들어서 연산해야 한다.

그리고 길이가 같은 두 벡터를 더한 벡터의 길이는 1이 아니게 된다. 그래서 이 벡터를 Normalize해서 1로 만들어서 다시 연산에 사용해야 한다

벡터의 뺄셈을 한 그림을 봐보면 알겠지만, A벡터에서 B벡터를 뺀 벡터는 B에서 A로 향하는 방향(벡터)가 나오게 된다. 이 공식은 셰이더에서 버텍스가 바라보는 조명의 방향이나 카메라의 방향을 구할 때 사용됨. 혹은 몬스터가 플레이어를 쫓아오는 기능을 맨들 때. 그러나 이 뺀 벡터는 다시 Normalize 해줘야 함!

 

*벡터의 곱셈 351p 참고!!

: 벡터의 곱셈은 덧셈뺄셈과 달리 내적(Dot)과 외적(Cross) 2종류가 있음. 벡터의 내적은 닷연산이라고도 하며, ‘두 벡터의 각도의 차이를 숫자로 표현한 것’이다. 이걸 내적이라고 하며, 그냥 각도의 차이를 cos연산 해주면 된다. (cos0 = 1, cos90 = 0, cos180 = -1). 그래서 Dot Product의 결과는 -1~1의 값이 된다(필요하면 Saturate로 0~1로 만들어주기). 이 내적 연산은 라이팅이 아니더라도 두 벡터의 방향이 어떤가를 구할 때 쓰는 공식이다.

또한 벡터의 내적은 벡터의 각 요소끼리 곱한 값을 더한 것과도 같다. float3(a,b,c)  float3(x,y,z) = ax + by + cz

 

*Dot Product

: 닷 연산으로 할 수 있는 3가지

1. Desaturate : 일반 텍스처 샘플과 RGB의 휘도의 가중치 값 (0.2126729, 0.7151522, 0.0721750)을 닷연산하면 됌. 결국 위에서 했었던 흑백만들기 방법과 똑같은 것임. 닷연산 자체가 float3(a,b,c)  float3(x,y,z) = ax + by + cz 이거니깐. 나누기 3하면 더 정확한가봄. 그리고 위에서 했던것처럼 곱하고 더하고 이렇게 노드를 쭈욱 쓰는 것보다 닷연산 노드 하나만 쓰는게 더 빠르다고 함

2. Channel Selector : 텍스처에 있는 RGBA 채널 중 하나를 선택하게 하는 기능으로 사용할 수 있음. 플레이 도중 유저가 머티리얼 선택해서 바꿔줘야 할 때 유용하게 쓰일 듯. 텍스처의 RGBA채널에 각각 다른 텍스처들을 넣어놓고 float4 노드와 닷연산. float4에서 그냥 내가 쓰고싶은 텍스처에 1값 넣어두면 됌

 

3. Compare two Vectors : 두 벡터의 방향이 어떤가를 구할 때 쓰는 것. 위에 벡터의 곱셈 파트에서 다 설명함

 

 

*1. 램버트 라이트 만들기 Lambert (유니티) 368p

: 라이트 벡터는 언리얼과 유니티 둘 다 기본적으로 뒤집혀서 나온다. 그러니깐 노말 벡터와 조명 벡터의 방향이 같을 때가 0도 이므로 내적 계산을 하면 cos 0도니깐 1, 가장 밝은 상태가 된다.

램버트 라이트의 기본형은 노말 벡터와 라이트 벡터를 Dot 연산한 것이다. 그러나 닷연산의 결과는 -1~1이므로 Saturate나 Clamp, Half Lambert (하프 램버트 : x0.5 + 0.5) 해준다. 하프 램버트이 경우 매직 넘버로 계산해준 뒤 saturate해주고 음영의 정도가 너무 부드럽게 되기 때문에 더 자연스러운 효과를 위해 power로 3제곱 정도를 해줘서 부드러움을 조금 낮춰준다.

노말 맵도 마찬가지로 조명 벡터와 닷연산 후 Saturate 등을 하여 더 정교하게 표현할 수 있다

 

*2. 램버트 라이트에 텍스처 곱하기 (유니티) 381p

: 위에 것만 한다면 빛 방향에 따른 음영만 구현할 수 있다. 우선 NdotL  Saturate한 결과를 Base Color 텍스처와 곱해준다. 이 상태에서는 아직 빛의 색상을 받아올 수 없기 때문에 라이트 벡터에서 HLSL 코드를 추가해준다. Color = float3(1,1,1);

Color = light.color; 위에 곱했던 것을 취소하고 NdotL후 Saturate한 결과를 라이트 벡터 HLSL코드의 Color와 곱해준 후, 이 결과를 Base Color 텍스처와 곱해준다. 이제 조명의 색이 반영된다.

 

*정반사와 난반사, 환경광 Ambient Light

: 정반사는 Specular, 난반사는 Diffuse다. 물체가 빛에 닿아 사방으로 반사된 것이 바로 우리 눈에 들어온다면 난반사(Diffuse)고, 물체가 빛에 닿아 반사된 것이 다른 물체에 닿아 그 물체를 밝혀주게 된 것이 다시 우리 눈에 들어온다면 그건 환경광(Ambient Light)이다. 직접광에 의해 밝혀져야 Diffuse라고 할 수 있다

 

*3. 환경광 받아오기 Ambient Light (유니티) 386p

: 위에 램버트 라이트에다가 조명의 색까지 받아올 수 있는 연산까지 한 값에서부터 이어서 한다. 지금까지 한 것은 주광에 대한 연산이다. 기본 공식은 주광 + 환경광이므로 환경광을 구해 더해주기만 하면 된다. 유니티에서 Baked GI 노드를 꺼낸다. 이 노드의 input에 Normal을 연결하도록 되어있으니깐 연결해주고 Output은 Base Color 텍스쳐와 곱해준다. 이를 주광 연산 (NdotL을 Saturate한 것)에 더해주면 된다

 

*4. Ambient Occlusion 연산하기

: 주광(Diffuse) + 환경광(Ambient) * AO임. AO 텍스처를 환경광 연산의 결과와 곱해준 뒤 주광 연산과 더해주면 되는 것. AO은 환경광(Ambient)를 어둡게 해주는 것이기 때문에 AO 텍스처맵은 환경광(Ambient)의 결과에만 곱해줘야 함. 그럼 이제 Lambert 완성!

 

*Vertex Interpolator (언리얼)

: 셰이딩에는 버텍스 셰이더와 픽셀 셰이더가 있는데 버텍스 셰이더가 더 쌈. 그래서 연산을 픽셀 셰이더에서 버텍스 셰이더로 바꿔주게 하는 것이 이 Vertex Interpolator 노드임.

(참고)

https://youtu.be/ZEXVQgbWxQY

두번째 사진에서 Vertex Interpolator 노드를 보면 VS에 들어와서 연결된 것들이 버텍스 셰이딩되는 것들이고 PS에서 나가는 것들은 픽셀 셰이딩 된다는 뜻임.

두번째 사진에서 제일 아래 Stats에서 Base pass shader가 픽셀 셰이딩되는 Instructions 수를 말하고, Base pass vertex shader가 버텍스 셰이딩되는 수임. 저 사진에선 base pass shader에서 빠진만큼 base pass vertex shader 수가 늘어났음. 그리고 이 노드를 사용하는 횟수에는 제한이 있으니깐 아무때나 사용할 수는 없음

 

*Fresnel 프레넬

: 나의 시선 벡터(카메라 벡터)와 노말벡터가 90도가 되면 될수록 반사가 심해진다. 반질반질한 책상 위에 물체를 놓고 관찰해보면 알 수 있듯이 물체를 기울일수록 책상에 반사되는 물체의 모습이 더 선명해지는 것을 볼 수 있다.

그러나 이 반사는 재질 별로 차이가 있는데, 특히 비금속은 기울어질수록 반사가 더 심해지지만 금속은 각도에 따른 반사의 차이가 매우 적다. 이걸 공식으로 정리한 것을 프레넬이라고 한다.

우선 오브젝트의 노말 벡터와 카메라 벡터를 닷연산한다. 그러면 카메라가 보는 방향(내가 보는 방향)과 오브젝트의 노말 벡터가 평행하면 흰색, 90도가 될수록 검은색으로 나올 것임. 여기서 One Minus 노드로 뒤집어준다. 이걸 그래프로 보면 좌측 사진과 같은데 이를 우측 사진처럼 만들어주려면 Power를 이용하면 된다. 그러면 림라이트와 같은 효과를 얻을 수 있다

 

 

*Camera Vector

: 언리얼의 Camera Vector의 노드는 이미 Normalize 된 값이라서 따로 Normalize 해줄 필요 없다

그렇다면 Normalize 되지 않은 카메라 벡터값을 구하려면 이렇게 하면 된다. VectorLength 노드를 써서 벡터의 길이를 구하면 된다. Camera Position - 절대월드포지션 한 값을 Vector Length에 넣어주면 실제 Camera Vector를 구할 수 있음(=물체와 얼마나 멀리 떨어져있는지)

 

 

*디퍼드 렌더링 Deferred Rendering

: 게임 엔진은 주로 디퍼드와 포워드 렌더링 방식을 지원한다. 포워드 렌더링은 디퍼그 렌더링 이전에 사용되던 랜더링 기법이다.

디퍼드 렌더링은 많은 수의 동적 라이트를 괜찮은 성능으로 처리할 수 있다. 한 번에 여러 개의 버퍼에 한꺼번에 렌더링하는 멀티 렌더 타겟을 이용하여 여러 개의 지오메트리 버퍼(Gbuffer)에 불투명(Opaque)한 오브젝트들의 정보를 렌더링한다. 이때 버퍼애는 다양한 정보가 기록되고 모든 오브젝트들을 버퍼에 렌더링한 후 이 정보들을 토대로 라이팅을 처리한다. 최종적으로 프레임 버퍼에 이를 출력하여 씬의 렌더링이 완성된다. 그러나 투명 오브젝트를 처리할 수 없고 후처리가 어렵지만 빠르다. 씬이 바로 렌더링되는게 아니라 여러 과정을 거치면서 지연되기 때문에 Deferred 렌더링이라고 한다

언리얼 엔진 3 에서 사용되던 포워드(바로바로 처리하는) 라이팅 방법과는 달리, 언리얼 엔진 4 의 모든 라이트는 디퍼드(비슷한 종류의 패스(pass)를 모아 한꺼번에 처리하는) 방식으로 적용됩니다. 머티리얼은 그 특성을 GBuffer 에 쓰고, 라이팅 패스에서는 픽셀별로 머티리얼 프로퍼티를 읽어들여 라이팅을 처리합니다. https://docs.unrealengine.com/4.27/ko/RenderingAndGraphics/Overview/

 

렌더링 개요

렌더링 서브시스템 주요 기능에 대한 개요입니다.

docs.unrealengine.com

 

*포워드 렌더링 Forward Rendering

: 포워드 렌더러(유니티)에서 렌더링의 순서는 Opaque(알파가 없는 불투명 / 알파테스트) > Skybox > Transparent(알파 블렌딩 반투명) > Post Process > After Rendering(렌더링 끝)

 

*Opaque, Translucent, Transparent

: 각각 불투명, 반투명, 투명. 오른쪽으로 갈수록 투명해진다.

 

*Light Vector (언리얼)

: 언리얼에서는 Light Vector를 그냥 쓰면 에러가 남. 디퍼드 렌더러쓰니깐 라이팅 연산 안할거야라고 함. NdotL이 디퓨즈 라이팅인가본데 이걸 이미 엔진에서 해주고 있고 이게 G버퍼에서 일어남. 얘는 G버퍼에서 렌더링하지 않는다는 특정 조건에서만 이용할 수 있다

드디어 알아냄 Custom Node에 HLSL코드를 써넣으면 Light Vector와 Light Color 등등을 받아올 수 있음.

아래 3가지를 각각 3개의 Custom 노드에 따로 넣어주면 된다. (return이 한번만 돼서 그런듯?)

//Light Vector가 필요한 경우
float3 lightVector = View.DirectionalLightDirection;
return lightVector;

//Light Color가 필요한 경우
float3 lightColor = View.DirectionalLightColor;
return lightColor;

//SkyLight Color가 필요한 경우
float3 skyLightColor = View.SkyLightColor.rgb;
return skyLightColor;

 

 

https://youtu.be/pPWCw9_LVC0

*흘러가는 줄무늬 만들기. Stripe Pattern

: 절대 월드 포지션을 Mask 노드에 연결한다. 원하는 방향으로 Mask하면 된다. B와 연결했다면 z축에서 0보다 크면 흰색, 0보다 작으면 검정색이 되는 걸 볼 수 있다. 그다음 선의 갯수를 만들어주기 위해이 Mask한 값을 원하는 값으로 나눈다. 이 나눈 값을 Time과 더한다. 그러면 무한대로 값이 커지는 숫자값을 만들게 된다. 줄무늬가 움직이는게 아니라 엄청나게 발광하는 하얀색이 될 것이다. 그러나 이 값을 Sine노드에 연결시켜주면 무한대 값이라도 주기에 따라 -1~1값만 반복하기 때문에 좌표가 움직이는 줄무늬를 만들 수 있다.

절대월드 포지션이 아니라 Texcoord를 이용해도 된다. 2D와 3D의 차이이다. 그러나 Texcoord는 UV 맵의 영향을 받기 때문에 줄무늬의 방향이 일정하지 않을 것이다. 헷갈린다면 직접 해보면 차이를 알 수 있다.

 

*Step

: X < Y면 0을 반환하고, X >= Y면 1을 반환한다. 만약 Y에 0.25가 들어가있다면, X가 0.25 미만이면 0을 반환하고 0.25 이상이면 1을 반환한다. 그러니깐 기준이 될 값을 X에 넣으면 된다. 비교 대상은 Y에 넣고

 

*스페큘러 Specular (정반사)

: 스페큘러 != 하이라이트. 스페큘러는 거울반사한다는 의미의 정반사이고, 하이라이트는 강한 조명을거울반사한 것을 의미하기 때문에 하이라이트는 스페큘러의 일부 현상임.

그러나 과거 정반사를 제대로 계산하는 것은 어려웠기 때문에 근사치 정도로만 계산함. 광원에서 나오는 반사 부분을 계산해서 밝은 동그라미를 그려주는 것 정도로만 구현함. 즉 광원에 의한 스페큘러만 적당히 계산함. 따라서 이런 조명의 정반사로 인한 하이라이트를 스페큘러로 부르게 되었고, 현재 PBR에서는 더 이상 맞지 않는 표현이 됨. 왜냐면 PBR에서는 이제 빛에 의한 하이라이트 뿐만 아니라 주변을 정확히 반사하는 정도를 말하기 때문. 스페큘러 수치는 여전히 이용됨.

전체 공식은 (주광 Diffuse + 환경광 Ambient * AO) + 정반사 Specular 이다. 여기서 스페큘러는 덧셈의 교환법칙이 성립되므로 반드시 최종 결과 후에 더할 필요는 없다

 

*Phong Reflection 퐁 반사 436p

: (디퓨즈 램버트 + 앰비언트 칼라) + 스페큘러 = Simple Lit(유니티). Simple Lit은 PBR 이전에 널리 사용되던 라이팅 방식임. 스페큘러 표현 공식에서 가장 유명한 표현 방식은 퐁 반사다. 이 원리의 기본 원리는 ‘내가 보는 방향으로부터 반사된 방향에 조명이 있으면 그 부분의 하이라이트가 가장 높다‘이다.

그래서 ‘조명에 의한 스페큘러 반사‘만 표현해보자면 퐁 공식의 원리는 ‘조명벡터(L)를 노말 방향(N)을 기준으로 반사하는 반사 벡터(R)와 시선 벡터(V)의 내적으로 스페큘러가 표현된다.’

R  V가 기본 공식임.

반사 벡터(R)을 구하는 공식은 R= 2N(L•N)-L

 

* 블린-퐁 공식 (Blinn-Phong Reflection Model)

: 반사 벡터를 구하는 공식을 더 간략화한 것이 블린-퐁 공식. ‘시선 벡터(V)와 조명 벡터(L)의 중간 값인 하프 벡터(H)를 구하고, 이를 노말 벡터(N)와 내적한다‘

공식으로 표현하면 H  N

하프벡터를 구하는 방법은 벡터의 덧셈 파트에서 했었음. 길이가 같은 두 벡터를 더하면, 두 벡터 사이의 절반인 각도가 나온다. 그래서 H = L + V이다. 두 벡터를 더했으니 당연히 H의 길이는 1이 아닐 것임. 그래서 이 뒤에는 꼭 Noramlize를 붙여줘야 한다.

 

*라이트 공식 473p

: Diffuse + (Ambient * AO) + Specular + Rim(Fresnel) + Fake Specular

(AO은 환경광Ambient를 어둡게 해주는 것이기 때문에 곱해주는 것이고, 나머지 빛 효과들은 그냥 더해주면 되는 듯!)

 

*Fresnel을 이용한 가짜 Specular 만들기 469p

: Fresnel을 one minus로 뒤집은 뒤 power를 100정도로 주어서 작게 만들고, color값도 곱해줌.

이렇게 해서 보면 스페큘러처럼 보임! 연산 양을 줄일 수 있음. 여기에 노말이랑 gloss까지 적용하면 더 그럴듯함

 

*그림자 감쇠 Shadow Attenuation 476p
: 지금까지 한 걸 보면 그림자를 드리우는 연산은 작동하지만 내가 그림자를 받는 연산은 적용되지 않은 것을 볼 수 있음. 유니티 Shader Graph에서는 그림자가 그려지는 Shadow Pass는 자동으로 생성되어 작동되게 만들어놨지만 내 조명 연산에서 그림자를 받는 것으로 인한 조명의 감쇠 Shadow Attenuation 연산은 없는 것. (만약 HLSL코드로 셰이더를 짠다면 Shadow Pass도 작성해줘야 하고 Depth Pass도 또 작성해줘야 함)