2022. 7. 17. 20:27ㆍPublic/Shader
Tags {"LightMode" = "ForwardBase"}
이것의 의미는 이 패스를 포워드 렌더러의 첫 번째 라이트 패스로 사용하겠다는 것이다. ForwardBase 패스가 오직 하나라면 첫 번째 빛을 제외한 다른 빛은 최종 결과에 영향을 미치지 않을 것이다. 만약 다른 빛도 영향을 주길 원한다면 또 다른 패스를 추가하고 그것의 태그를 다음과 같이 바꾼다.
Tags {"LightMode" = "ForwardAdd"}
#include "UnityLightingCommon.cginc"
UnityLightingCommon.cginc는 라이팅 셰이더에 필요한 많은 유용한 변수 및 함수들이 담긴 파일이다.
커스텀 라이팅을 할때 주의해야 할 점은
노멀 벡터와 빛의 방향 벡터의 좌표 공간을 일치시켜야 한다. 생각해보자. 객체 공간을 사용해선 안 된다. 왜냐하면 빛은 렌더링하는 모델의 바깥에 있기 때문이다. 이러한 라이팅 계산을 하는 데 적합한 공간은 월드 공간이다.
먼저 렌더러에게 노멀 벡터에 대한 정보를 받아야한다. 따라서 렌더러에게 요청하는 정보가 담긴 appdata에 노멀 슬롯을 하나 추가해야한다.
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL; //추가
};
NORMAL 시맨틱 선언을 추가해 노멀을 사용하겠다고 컴파일러에게 알려주고 있다.
이 정점 함수에서는 노멀 위치 벡터를 월드 공간에서 계산해야 한다.
우리에게는 편리한 함수가 존재한다. UnityObjectToWorldNormal
이 함수는 appdata를 통해 정점 셰이더로 방금 전달한 노말 벡터를 기존의 객체 공간에서 월드 공간으로 변환한다.
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal); //추가 , 월드 노멀 벡터 계산
o.worldNormal = worldNormal; //추가 , 출력 데이터 구조체에 할당
return o;
}
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD0; //추가 , 출력 구조처에 결과 값을 할당해야 한다.
};
TEXCOORD0 시맨틱을 사용해 해당 슬롯을 추가해야 한다. 그러면 3차원 혹은 4차원 벡터에 적합한 슬롯을 ㅏㅅ용할 것이라고 알려주는 것이다.
필요한 정보를 얻기 위해 이제 람버트 디퓨즈를 계산에 이용할 수 있게 됐다.
광원의 색상을 _LightColor0을 통해 얻을 수 있다. LightColor0은 방금 추가한 include 파일에 존재한다. 그리고 월드 공간상의 씬 내에 첫 번째 광원의 위치는 _WorldSpaceLightPos0 변수를 통해 구할 수 있다.
변환을 거치면 벡터의 크기가 1이 아닐 수도 있기 때문에 프레그먼트 셰이더에서는 우선 worldNormal값을 정규화해야 한다. 그런 후 노멀 값과 빛의 위치 벡터의 내적을 계산한다. 계산 결과가 음수 값이 되지 않도록 주의해야 한다. max 함수에서 이것을 담당한다.
fixed4 frag(v2f i) : SV_Target
{
float3 normalDirection = normalize(i.worldNormal);
//WorldSpaceLightPos0 : 월드 공간상의 씬 내에 처 번째 광원의 위치
float nl = max(0.0, dot(normalDirection,_WorldSpaceLightPos0.xyz)); //변환후 벡터의 크기가 1이 아닐 수도 있기 때문에 정규화
float4 diffuseTerm = nl * _Color * _LightColor0; //광원의 색상을 얻을수 있다. (UnityLightingCommon.cginc)
return diffuseTerm;
}
내적 값과 함께 표면의 색상값과 광원의 색상값을 모두 곱한다. 이것이 끝이다.
Shader "Custom/DiffuseShader"
{
Properties
{
_Color("Color", Color) = (1,0,0,1)
}
SubShader
{
Tags { "LightMode" = "ForwardBase"}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//CGPROGRAM문 뒤쪽 어딘가에 선언을 추가
fixed4 _Color;
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD0; //추가 , 출력 구조처에 결과 값을 할당해야 한다.
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal); //추가 , 월드 노멀 벡터 계산
o.worldNormal = worldNormal; //추가 , 출력 데이터 구조체에 할당
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float3 normalDirection = normalize(i.worldNormal);
//WorldSpaceLightPos0 : 월드 공간상의 씬 내에 처 번째 광원의 위치
float nl = max(0.0, dot(normalDirection,_WorldSpaceLightPos0.xyz)); //변환후 벡터의 크기가 1이 아닐 수도 있기 때문에 정규화
float4 diffuseTerm = nl * _Color * _LightColor0; //광원의 색상을 얻을수 있다. (UnityLightingCommon.cginc)
return diffuseTerm;
}
ENDCG
}
}
}
'Public > Shader' 카테고리의 다른 글
Alpha Blend (0) | 2022.07.25 |
---|---|
Cubemap Reflection (0) | 2022.07.25 |
커스텀 라이팅 (0) | 2022.07.17 |
좌표 공간 (0) | 2022.07.10 |
정점 색상 지원 (0) | 2022.07.10 |