일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- URP로 변경
- Three(Two) Tone Shading
- Virtual Byte
- URP
- Private Bytes
- C언어
- 벡터
- ASW(Application SpaceWarp)
- 프로그래밍 기초
- Rim Light
- 작업 집합
- Specular
- OculusMotionVectorPass
- 3d
- Cartoon Rendering
- ColorGradingLutPass
- 개인 바이트
- Windows Build
- Cell Shader
- AppSW
- VR
- 메모리 누수
- Cell Look
- Toon Shader
- 가상 바이트
- working set
- 게임 수학
- Today
- Total
WinCNT
유니티에서 커스텀 셰이더의 머티리얼에 라이트 맵을 적용해보기 본문
서론
라이트 맵을 커스텀 셰이더에서 사용하는 것은 레퍼런스도 많고 Unity의 함수를 편하게 가져다 사용할 수도 있기에 이전에 삽질했던 것에 비해서 어렵지 않았다
물론 깊이 파면 어렵겠지만 이미 내 HP는 0이기 때문에 파지 않으려고 한다…
라이트 맵의 텍스처 채널
라이트 맵을 구우면 각각의 게임 오브젝트에 알맞은 라이트 맵이 할당된다
할당되는 UV의 채널은 UV1이며, Mesh 클래스의 프로퍼티로는 uv2인데(즉 Mesh.uv2),
아무튼 TEXCOORD1에 할당된다고만 알고 있으면 될 것 같다
Unity - Manual: Generating lightmap UVs
Unity - Scripting API: Mesh.uv2
이건 Bakery 에셋도 마찬가지이며, 매뉴얼을 참고해서 라이트 맵을 구우면, 다음과 같이 오브젝트에 라이트맵이 할당된 것을 볼 수 있다
셰이더에서 라이트 맵의 정보 가져오기
우선 다음과 같이 LIGHTMAP_ON의 지시어를 추가하고, 특정 라이브러리를 include해야 한다
#pragma shader_feature LIGHTMAP_ON
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl"
라이트 맵은 TEXCOORD1에 할당된다고 하니 다음과 같은 느낌으로 시멘틱스를 지정해주면 된다
예시를 위해 다른 정보들도 포함시켰다
struct appdata
{
float3 pos : POSITION;
half3 normal: NORMAL;
float2 uv: TEXCOORD0;
float2 lightmapUV: TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 pos : SV_POSITION;
float4 uv: TEXCOORD0;
float2 uv2: TEXCOORD1;
DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 2);
float3 normal: TEXCOORD3;
float3 tangent: TEXCOORD4;
float3 bi_normal: TEXCOORD5;
float fog_coord : TEXCOORD6;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
버텍스 셰이더에서는 Lighting.hlsl의 매크로인 OUTPUT_LIGHTMAP_UV를 사용하면 된다
마찬가지로 예시를 위해 다른 정보들도 포함시켰다
예를 들어 OUTPUT_SH(Lighting.hlsl의 매크로)는 LIGHTMAP_ON 지시어에 따라서 이번에는 아무런 역할도 하지 않을테지만 예시를 위해 추가해두었다
v2f vert(const appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
ZERO_INITIALIZE(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// 다른 내용은 생략
o.normal = TransformObjectToWorldNormal(v.normal);
OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUV);
OUTPUT_SH(o.normal, o.vertexSH);
// 다른 내용은 생략
o.pos = TransformObjectToHClip(v.pos);
o.fog_coord = ComputeFogFactor(o.pos.z);
return o;
}
참고로 DECLARE_LIGHTMAP_OR_SH하고 OUTPUT_LIGHTMAP_UV는 Lighting.hlsl의 매크로이며, unity_LightmapST는 UnityInput.hlsl의 변수이다
그 다음으로 프래그먼트 셰이더에서는 다음과 같은 매크로로 라이트 맵의 정보를 취득하면 된다
float3 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
float3 color; // 메인 컬러
// 메인 컬러에 대한 계산은 생략(알베도 텍스처 취득 등)
// 라이트 맵의 정보를 취득
float3 light_col = SAMPLE_GI(i.lightmapUV, i.vertexSH, normal);
//return light_col;
// 메인 라이트와 라이트 맵의 정보를 취합
Light mainLight = GetMainLight();
light_col.rgb += mainLight.color * mainLight.distanceAttenuation * max(0, ld);
color = color * light_col;
// 라이트 맵과 관계 없는 안개 처리
color = MixFog(color, i.fog_coord);
return color;
}
SAMPLE_GI는 GlobalIllumination.hlsl의 매크로이지만, GlobalIllumination.hlsl는 이미 Lighting.hlsl에 포함되어 있기 때문에 따로 include할 필요는 없다
결과
참고로 다음과 같이 프래그먼트 셰이더를 살짝 수정하면 라이트 맵 정보만을 확인할 수 있다
float3 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
// 라이트 맵의 정보를 취득
float3 light_col = SAMPLE_GI(i.lightmapUV, i.vertexSH, normal);
return light_col;
}
SAMPLE_GI를 return한 결과가 Baked Lightmap 씬 뷰 드로우 모드와 똑같다면 제대로 라이트 맵 정보를 취득했다고 할 수 있다
마무리
예제도 많았고 이미 유니티에 구현되어 있는 매크로가 많아서 앞선 작업들에 비해서 어렵지 않게 끝낼 수 있었다
참고 사이트
UPR 셰이더 코딩 튜토리얼 : 제 3편 - 커스텀 라이트 맵, 에디셔널 라이트, fake Shadowmask (feat : TS Normal)
URP ShaderLab Pass tags | Universal RP | 12.0.0
Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダー - Qiita
'Unity > URP or Shader 관련' 카테고리의 다른 글
URP에서 Overdraw 확인하기 (0) | 2023.07.10 |
---|---|
URP에서 HDR 텍스처 사용해보기 (0) | 2023.07.03 |
기존 프로젝트를 URP로 변경하기 (0) | 2023.05.30 |
URP로 Toon Shader 만들기 -Rim Light 2- (0) | 2023.05.26 |
URP로 Toon Shader 만들기 -Rim Light 1- (0) | 2023.05.23 |