WinCNT

커스텀 셰이더의 머티리얼을 Bakery(라이트 맵 생성 에섯)으로 Bake하기(feat. Meta Pass) 본문

Unity/URP or Shader 관련

커스텀 셰이더의 머티리얼을 Bakery(라이트 맵 생성 에섯)으로 Bake하기(feat. Meta Pass)

WinCNT_SSS 2023. 10. 12. 19:51

서론

우여곡절이 있었으나 아무튼 라이트 맵를 Bake하는 에셋(Bakery)은 도입할 수 있었다

https://wincnt-shim.tistory.com/357

 

유니티의 Bakery(라이트 맵 생성 에셋) 적용기

서론 Bakery라는 에셋을 적용하면서 삽질했던 것을 정리해봤다 참고로 Bakery는 라이트 맵을 생성해주는 에셋이며 아래의 페이지에서 구입할 수 있다 Bakery - GPU Lightmapper Bakery - GPU Lightmapper | 레벨

wincnt-shim.tistory.com

 

 

하지만! 여기서 끝이 아니다!!

라이트 맵의 확인을 위해 Unity의 Lit 셰이더(사실 조금 다름)로 확인했지만 프로젝트에서 실제로 사용할 셰이더는 다른 셰이더이기 때문!

 

즉, 커스텀 셰이더의 머티리얼을 가진 게임 오브젝트도 제대로 라이트 맵에 Bake되도록하는 처리와, 그 라이트 맵을 커스텀 셰이더에서 사용할 수 있도록 하는 처리가 필요하다

이 글에선 커스텀 셰이더의 머티리얼을 가진 게임 오브젝트도 제대로 라이트 맵에 Bake되도록하는 처리에 대해 삽질한 내용들을 정리하고자 한다


Meta Pass란?

아무런 처리도 안 한 커스텀 셰이더를 가지고 라이트 맵을 베이크하려고 하면 Bakery은 다음과 같은 Log를 표시해준다친절하다

Material New Material doesn't have meta pass - maps are taken by name

 

공식 문서에 따르면 Meta Pass는 GI 시스템에 Albedo 값이나 Emission 값을 제공하는 셰이더 패스라고 한다

Unity - Manual: Lightmapping and shaders

 

Unity - Manual: Lightmapping and shaders

Lightmaps: Technical information Lightmap UVs introduction Lightmapping and shaders This page contains information about how to make shadersA program that runs on the GPU. More infoSee in Glossary compatible with Unity’s lightmappersA tool in Unity that

docs.unity3d.com

Meta Pass는 리얼 타임 렌더링에는 영향을 주지 않고, Light Map에만 영향을 주는 것이 특징이다

그리고 Albedo나 Emission 이외, 예를 들어 다른 물체에의 그림자 등과는 상관이 없었다

(그건 어떻게 제어하는 거지…?)

 

Meta Pass는 LightMode에서 설정할 수 있으며, 이 패스는 Unity 에디터에서 라이트 맵을 베이킹할 때만 실행된다고 한다

SubShader {
    Pass
    {
        Name "META"
        Tags {"LightMode"="Meta"}
        Cull Off
        // ...
    }

유니티의 스탠다드 셰이더(Lit 등)에는 이미 Meta Pass가 포함되어 있어서 딱히 추가하지 않아도 제대로 라이트 맵에 Bake된다

 

참고로 Bakery에서도 다음과 같이 Meta Pass가 있는지 찾고 있는 코드가 있었다

materials[i].FindPass("META");

Meta Pass 추가하기

참고 샘플들 - 복붙 실패…

일단 공식 문서에는 샘플이 존재한다

Unity - Manual: Lightmapping and shaders

 

Unity - Manual: Lightmapping and shaders

Lightmaps: Technical information Lightmap UVs introduction Lightmapping and shaders This page contains information about how to make shadersA program that runs on the GPU. More infoSee in Glossary compatible with Unity’s lightmappersA tool in Unity that

docs.unity3d.com

 

혹은 아래의 사이트에도 샘플이 있었다

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダー - Qiita

 

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダ

Unity のみで完結できる頂点アニメーションテクスチャー(VAT・Vertex Animation Texture)のエクスポーターとシェーダーを作りました。 Vertex Animation Texture shader,...

qiita.com

 

처음에는 신이 나서 복붙해봤으나…잘 되지 않았다

아래는 공식 문서의 샘플을 복붙해서 라이트 맵을 Bake한 다음, 드로우 모드에서 Bake된 라이트 맵만을 그리도록 한 이미지이다

Lit 셰이더는 큐브와 스피어에는 서로의 색이 묻어있는데 Custom에는 그러한 흔적을 찾아볼 수 없었다

참고) 드로우 모드에서 라이트 맵만 그리도록 변경하는 법

다음과 같이 체크하면 된다

 

코드 분석 후 간단히 정리한 코드

코드를 분석해보니 Meta Pass의 내용은 일반적인 Pass와 비슷했다

버텍스 셰이더와 프래그먼트 셰이더가 있고 CBuffer도 있었다

즉, 공식 문서에 써있듯이 라이트 맵을 Bake할 때 이 패스를 사용한다는 것을, 말이 아닌 마음으로 이해한 듯한 느낌이 들어서 최대한 코드를 간략화 해봤다

Pass
{
    Name "META"
    Tags {"LightMode"="Meta"}
    Cull Off
    
    HLSLPROGRAM
    #include"UnityStandardMeta.cginc"

    #pragma vertex vert_meta
    #pragma fragment frag_meta_Toon
    #pragma shader_feature _EMISSION
    #pragma shader_feature _METALLICGLOSSMAP
    #pragma shader_feature ___ _DETAIL_MULX2

    CBUFFER_START(UnityPerMaterial)
    sampler2D _BaseMap;
    half4 _BaseColor;
    CBUFFER_END
    
    float4 frag_meta_Toon(v2f_meta i): SV_Target
    {
        UnityMetaInput o;
        UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o);

        half4 c = tex2D(_BaseMap, i.uv);
        o.Albedo = half3(c.rgb * _BaseColor.rgb);
        o.Emission = Emission(i.uv.xy);
        return UnityMetaFragment(o);
    }
    ENDHLSL
}

 

버텍스 셰이더는 대부분 비슷할 것이니 UnityStandardMeta.cginc에 있는 vert_meta를 그대로 쓰기로 하고 프래그먼트 셰이더만 커스텀으로 추가했다

또한 CBUFFER에는 프로퍼티 중에 필요한 부분만 가져왔다

Properties
{
    [Header(Base)]
    _BaseMap ("Base Map", 2D) = "white" {}
    _BaseColor ("Base Color", Color) = (1,1,1,1)
}

참고로 프로퍼티UnityStandardMeta.cginc(UnityStandardInput.cginc)에 미리 정의된 변수와 같은 이름(_MainTex, _MainTex_ST, _EmissionColor 등)이 있으면 굳이 CBUFFER에 따로 안 넣어도 가져와 주는 것 같다

 

아무튼 그 결과는 다음과 같았다

커스텀 셰이더이기 때문에 Lit 셰이더와 결과가 완전히 같진 않지만 원하는 결과는 얻을 수 있었다!


Emission

처음에는 Emission도 당연히 문제 없이 될 거라고 생각했다

그러나…

Emission의 빨간색은 없어지고 본래의 색인 초록색만 묻어나왔다…

 

원래라면 다음과 같은 결과가 나와야 한다(Unity의 Lit 셰이더)

 

MaterialGlobalIlluminationFlags라는 게 있었다

Bakery의 매뉴얼과 아래의 참고 사이트에서 MaterialGlobalIlluminationFlags라는 게 있다는 것을 알게 되었다

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダー - Qiita

 

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダ

Unity のみで完結できる頂点アニメーションテクスチャー(VAT・Vertex Animation Texture)のエクスポーターとシェーダーを作りました。 Vertex Animation Texture shader,...

qiita.com

 

공식 문서에 따르면 머티리얼이 라이트맵 및 라이트 프로브와 상호 작용하는 방식을 설정하는 플래그라고 한다

Unity - Scripting API: MaterialGlobalIlluminationFlags

 

Unity - Scripting API: MaterialGlobalIlluminationFlags

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close

docs.unity3d.com

 

그래서 처음에는 다음과 같은 코드를 넣어서 테스트해봤는데 잘 되지 않았다

그리고 메챠쿠챠 삽질했다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GlobalIlluminationFlags : MonoBehaviour
{
    public MaterialGlobalIlluminationFlags flag = MaterialGlobalIlluminationFlags.AnyEmissive;

    void OnEnable()
    {
        SetFlags();
    }
    
    void OnValidate()
    {
        SetFlags();
    }

    private void SetFlags()
    {
        var rend = GetComponent<Renderer>();
        if (rend && rend.sharedMaterial)
        {
            rend.sharedMaterial.globalIlluminationFlags = flag;
        }
    }
}

 

문제는 플래그 설정이었다

 

Bakery에서는 Baked Emissive 플래그만 설정되어 있어야 라이트 맵에 Emissive를 적용해준다

(이 부분은 유니티의 기본 LightMap Bake 기능과는 다를 수 있음)

💡 해당 스크립트는 Emissive를 사용할 머티리얼과 같이 붙여서 사용해야 한다
또한 만약 다른 오브젝트에서도 같은 머테리얼과 스크립트를 붙였으면, Light Map 베이크 시 마지막으로 체크된 플래그 설정으로 Light Map을 Bake하므로 주의해야 한다
예) 마지막으로 체크된 플래그가 Baked Emissive 이외였을 경우, 다른 쪽에서 아무리 플래그를 설정했어도 해당 머티리얼의 Emissive는 Bake 안 됨

 

또한 현재의 커스텀 셰이더에는 아직 Emission Map이 없으므로, 그 부분도 다음과 같이 수정했다

float4 frag_meta_Toon(v2f_meta i): SV_Target
{
    UnityMetaInput o;
    UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o);

    half4 c = tex2D(_BaseMap, i.uv);
    o.Albedo = half3(c.rgb * _BaseColor.rgb);
    //o.Emission = Emission(i.uv.xy);
    o.Emission = _EmissionColor;
    return UnityMetaFragment(o);
}

 

참고로 _EmissionMap과 _EmissionColor는 UnityStandardMeta.cginc(UnityStandardInput.cginc)에 미리 정의된 변수라서 프로퍼티에만 있어서 그대로 사용할 수 있었다

Properties
{
	[HDR] _EmissionColor ("EmissionColor", Color) = (0, 0, 0, 1)
}


최후의 이슈…

다 구현해서 좋아하고 있었는데 우연히 프레임 디버거를 보고 절망했다…

교에에에에엑!!!

 

전혀 SRP Batcher가 작동하지 않았다

물론 셰이더의 SRP Batcher가 not Compatible이 되어있던 것이 문제였다

그리고 위의 코드에서는 생략했지만, 커스텀 셰이더의 독자적인 부분이 있다면 그것도 최대한 같게 구현해줘야 한다는 것을 깨달았다

이 부분은 이슈쪽에서 따로 정리하보고자 한다


마무리

이번 태스크도 너무 힘들었다…


참고 사이트

UPR 셰이더 코딩 튜토리얼 : 제 3편 - 커스텀 라이트 맵, 에디셔널 라이트, fake Shadowmask (feat : TS Normal)

 

UPR 셰이더 코딩 튜토리얼 : 제 3편 - 커스텀 라이트 맵, 에디셔널 라이트, fake Shadowmask (feat : TS Norma

안녕하세요 마둠파입니다. URP 코딩 튜토리얼도 이 글로 벌써 3편이나 작성하게 되었네요. 2편까지의 코...

blog.naver.com

URP ShaderLab Pass tags | Universal RP | 12.0.0

 

URP ShaderLab Pass tags | Universal RP | 12.0.0

This section contains descriptions of URP-specific ShaderLab Pass tags. NOTE: URP does not support the following LightMode tags: Always, ForwardAdd, PrepassBase, PrepassFinal, Vertex, VertexLMRGBM, VertexLM. LightMode The value of this tag lets the pipelin

docs.unity3d.com

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダー - Qiita

 

Unity のシェーダー開発方法のまとめと備忘録・頂点アニメーションテクスチャ(VAT)シェーダ

Unity のみで完結できる頂点アニメーションテクスチャー(VAT・Vertex Animation Texture)のエクスポーターとシェーダーを作りました。 Vertex Animation Texture shader,...

qiita.com

Global Illumination

 

Global Illumination

A Unity Scriptable Render Pipeline tutorial about supporting both static and dynamic global illumination.

catlikecoding.com