반응형

URP에서 코드기반 Shader 파일을 생성하면 기본적으로 CG기반의 쉐이더가 생성됩니다.

하지만 URP 내장 쉐이더 기능이나 SRP Batcher를 사용하기 위해서는 HLSL기반으로 쉐이더를 작성해야하는데,

매번 CG쉐이더는 HLSL로 바꾸기 귀찮아서 HLSL 기본 쉐이더 생성 스크립트를 제작했습니다.

 

 

https://github.com/CatDarkGame/URPShaderTemplateGenerater

 

GitHub - CatDarkGame/URPShaderTemplateGenerater: URP HLSL ShaderTemplate Generater

URP HLSL ShaderTemplate Generater. Contribute to CatDarkGame/URPShaderTemplateGenerater development by creating an account on GitHub.

github.com

 

 

 


사용법

Create->URP Shader->Unlit Shader 메뉴를 클릭하면 HLSL 기반 기본 Unlit쉐이더가 생성됩니다.

 

Shader "URP/Unlit/#NAME#"
{
    Properties
    { 
        [MainTexture] _BaseMap("Texture", 2D) = "white" {}
        [MainColor] _BaseColor("Color", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" "Queue"="Geometry" "RenderPipeline" = "UniversalPipeline" }
        LOD 100

        Pass
        {
            Name  "URPUnlit"
            Tags {"LightMode" = "SRPDefaultUnlit"}

            HLSLPROGRAM
            #pragma target 4.5
            #pragma exclude_renderers gles d3d9
            
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"


            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                float4 _BaseColor;
            CBUFFER_END

            TEXTURE2D(_BaseMap);    SAMPLER(sampler_BaseMap);


            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
            }; 
            

            Varyings vert(Attributes input)
            {
                Varyings output = (Varyings)0;

                float4 positionOS = input.positionOS;
                float3 positionWS = TransformObjectToWorld(positionOS.xyz);
                // float3 positionVS = TransformWorldToView(positionWS);
                float4 positionCS = TransformWorldToHClip(positionWS);

                output.positionCS = positionCS;
                output.uv = input.uv;
                return output;
            }

            float4 frag(Varyings input) : SV_Target
            {
                float2 baseMapUV = input.uv.xy * _BaseMap_ST.xy + _BaseMap_ST.zw;
                float4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, baseMapUV);
                
                float4 finalColor = texColor * _BaseColor;
                return finalColor;
            }
            
            ENDHLSL
        }
    }
}

 

 

 

 

구현 원리

URPShaderTemplate/Editor/ShaderTemplates에 쉐이더 샘플 파일을 기반으로 신규 쉐이더를 제작하는 방식입니다.

 

namespace URPShaderTemplate
{
    // 커스텀 쉐이더 템플릿 유니티 메뉴
    public class MenuItem
    {
        // 기본 메뉴 경로
        private const string MENUITEM_BASEPATH = "Assets/Create/URP Shader/";
        // 쉐이더 템플릿 폴더 이름
        private const string SHADERTEMPLATE_FOLDERNAME = "ShaderTemplates";
        
        // Unlit 쉐이더 - 템플릿 경로, 메뉴 경로
        private const string MENUITEMNAME_UNLIT = "Unlit Shader";
        private const string SHADERTEMPLATE_UNLIT = "URPUnlitShader.shader.txt";
        [UnityEditor.MenuItem(MENUITEM_BASEPATH + MENUITEMNAME_UNLIT, false, 85)]
        public static void GenerateNewURPShader_Unlit()
        {
            string shaderTemplatePath = GenerateURPShader.GetCurrentScriptFolerPath(SHADERTEMPLATE_FOLDERNAME);
            GenerateURPShader.CreateShaderTemplate(shaderTemplatePath + SHADERTEMPLATE_UNLIT);
        }
       
        /*
        // 추가 쉐이더 템플릿 예제
        private const string MENUITEMNAME_EXAMPLE = "Example Shader";
        private const string SHADERTEMPLATE_EXAMPLE = "URPExampleShader.shader.txt";
        [UnityEditor.MenuItem(MENUITEM_BASEPATH + MENUITEMNAME_EXAMPLE, false, 85)]
        public static void GenerateNewURPShader_Example()
        {
            string shaderTemplatePath = GenerateURPShader.GetCurrentScriptFolerPath(SHADERTEMPLATE_FOLDERNAME);
            GenerateURPShader.CreateShaderTemplate(shaderTemplatePath + SHADERTEMPLATE_EXAMPLE);
        }
        */
    }

}

신규로 쉐이더 템플릿을 추가하기 위해서는 txt확장자로 샘플 쉐이더를 추가하고 MenuItem.cs의 아래 주석 부분을 복사해서 경로 & 네이밍을 맞춰주면 됩니다.

 

      public class GenerateURPShader
    {
        private const string LOG_FILENOTEXIST = "TemplateShader is not exists : ";
        
        // 신규 쉐이더 접두사
        private const string NEWSHADERWORD_FRONT = "New";
        
        // 쉐이더 템플릿 내부 키워드
        private const string KEYWORD_SHADERNAME = "#NAME#";
        
        
  public static void CreateShaderTemplate(string templateShaderPath)
        {
            // 템플릿 쉐이더 파일 유무 체크
            if (!System.IO.File.Exists(templateShaderPath))
            {
                Debug.LogError(LOG_FILENOTEXIST + templateShaderPath);
                return;
            }
            
            // 템플릿 쉐이더 경로 & 이름 정보 가져오기
            string newShaderFileName = GetShaderFileName(templateShaderPath);
            string newShaderName = newShaderFileName.Substring(0, newShaderFileName.Length - 7);
            
            // 생성할 폴더 경로 + 쉐이더 파일명 세팅
            string generateDirectoryPath = GetGenerateDirectoryPath(); 
            string generateAssetPath = AssetDatabase.GenerateUniqueAssetPath(generateDirectoryPath + "/" + newShaderFileName);

            // 쉐이더 코드 복사 & 키워드 수정
            string fileContent = System.IO.File.ReadAllText(templateShaderPath);
            fileContent = fileContent.Replace(KEYWORD_SHADERNAME, newShaderName);

            // 신규 쉐이퍼 파일 생성
            System.IO.FileInfo file = WriteTextFile(generateAssetPath, fileContent);
            AssetDatabase.Refresh();
        }

신규 쉐이더 파일 생성 방식은 단순하게 txt파일을 읽어서 #NAME#키워드 문자를 바꾸고 .shader파일을 생성하는 방식입니다.

 

 

 

 

포스팅 업데이트

 - 23.03.07 / URP 쉐이더 코드 스타일로 최신화 및 MVP 행렬 변환 부분 분할

 

 

반응형

WRITTEN BY
CatDarkGame
Technical Artist dhwlgn12@gmail.com

,