Unity Shader (HLSL)를 작성하는 방법을 기초의 기초 수준에서 배웠습니다.

10527 단어 Unity

개요



업무로 「2개의 텍스처를 혼합하는 셰이더」와 「크로마키 합성을 실시하는 쉐이더」를 합성한 셰이더를 만드는 것이 되어, 거기서 배운 것을 써 둔다.
  • 【Unity】2개의 텍스처를 합성하는 셰이더 - Qiita
  • Unity에서 크로마 키 셰이더를 만들어 보았습니다.

  • 셰이더 파일의 구조



    템플릿이 될 것 같은 내용을 바탕으로 설명을 코멘트에 추가했다.
    Shader "シェーダの種類/シェーダーの名前"
    {
        // Unityインスペクタに表示される項目 (マテリアルプロパティ)
        Properties
        {
            // テクスチャの設定
            _MainTex("Texture", 2D) = "white" {}
    
            // 色の設定
            _Color ("Main Color", Color) = (1,1,1,1)
        }
    
        SubShader
        {
            // どのようにレンダリングするか
            Tags 
            {
                "Queue" = "Transparent"
                "RenderType" = "Transparent" 
                "IgnoreProjector" = "True" 
                "PreviewType" = "Plane"
            }
    
            // レンダリングを行う
            Pass
            {            
                // 実際の処理を書く (HLSL)
                CGPROGRAM
    
                // vert関数を頂点シェーダーとして利用する
                #pragma vertex vert
    
                // frag関数をフラグメントシェーダーとして利用する
                #pragma fragment frag
    
                // 頂点シェーダーへの入力の構造体を定義
                struct appdata
                {
                    // 頂点座標
                    float4 vertex : POSITION;
    
                    // テクスチャ座標
                    float2 uv : TEXCOORD0;
                };
    
                // フラグメントシェーダーへの入力の構造体を定義
                // 頂点シェーダーで生成して、フラグメントシェーダーの引数で受け取る
                struct v2f
                {
                    // クリップスペース位置
                    float4 vertex : SV_POSITION;
    
                    // テクスチャ座標
                    float2 uv : TEXCOORD0;
                };
    
                // マテリアルプロパティを変数に割り当てる
                sampler2D _MainTex; // メインテクスチャ
                float4 _Color; // 色
    
                // 頂点シェーダーの処理
                // 3Dモデルの拡張点で実行されるプログラム (頂点の位置をオブジェクト空間からクリップスペースに変換する)
                v2f vert(appdata v)
                {
                    // フラグメントシェーダーの入力になる v2f 構造体変数の定義
                    // 変数名は Output の o だと思う
                    v2f o;
    
                    // オブジェクト空間の座標からクリップスペースへの変換を行う処理
                    // クリップスペースはGPU が画面上のオブジェクトをラスタライズするために使用するもの
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    
                    // テクスチャ座標を定義
                    o.uv = v.uv;
    
                    return o;
                }
    
                // フラグメントシェーダーの処理
                // 画面上に見えるすべてのピクセルで実行されるプログラム (各ピクセルの色を計算する)
                // これの最適化がパフォーマンスで重要
                fixed4 frag(v2f i) : SV_Target
                {
                    // ここではマテリアルプロパティで設定された色を返しているだけ
                    return _Color
                }
                ENDCG
            }
        }
    }
    

    HLSL 처리 흐름


  • 정점 셰이더/프래그먼트 셰이더에 사용하는 함수명을 지정 (vert/frag)
  • 버텍스 셰이더/단편 셰이더의 입력 구조체 정의 (appdata/v2f)
  • 머티리얼 속성을 받는 변수 정의 (_MainTex, Color)
  • 정점 쉐이더의 처리를 구현 (입력은 appdata, 출력은 v2f)
  • 프래그먼트 셰이더의 처리를 구현 (입력은 v2f, 출력은 float4의 Color 정보)

  • 어떻게 블렌드 셰이더와 크로마 키 셰이더를 합성 했습니까?



    처음에는 단순히 두 개의 셰이더의 "pass"를 나란히 썼는데, 이것은 잘 작동하지 않았다.
    셰이더의 구조를 이해하면 간단하지만, 구현하려면 프래그먼트 셰이더에서 "블렌드한 결과의 색 정보에 크로마키 합성 처리를 한다"필요가 있다.

    또, 2개의 쉐이더는 코드를 잘 보면 「머티리얼 프로퍼티」와 「프래그먼트 쉐이더」 이외의 부분은 거의 같은 것이 쓰여져 있었기 때문에, 차이가 있던 2개의 부분을 잘 조합했다.

    여기서 문제가 된 것은 크로마 키 셰이더의 실제 처리가 ".cginc"라는 별도의 파일에 정의되어 있었기 때문에, 블렌드 셰이더 측의 프래그먼트 셰이더에 크로마 키 셰이더 측의 프래그먼트 셰이더의 처리를 직접 추가해야합니다 했다.

    코드 자체는 각각 다른 개발자님이 구현하고, 자신은 그것을 조합했을 뿐이므로, 여기에서는 단편 쉐이더 부분만 간단히 기재해 둔다.
    fixed4 frag(v2f i) : SV_Target
    {
        // メインテクスチャの色情報を取得
        fixed4 main = tex2D(_MainTex, i.uv);
    
        // サブテクスチャの色情報を取得
        fixed4 sub = tex2D(_SubTex, i.uv);
    
        // メインテクスチャとサブテクスチャをブレンドした結果の色情報を取得
        fixed4 col = (main * (1-_Blend) + sub * _Blend) * _Color;
    
        // クロマキー合成した結果の色情報を取得 (実装は ChromaKey.cginc にある)
        ChromaKeyApplyAlpha(col);
    
        // FOGを適用する
        UNITY_APPLY_FOG(i.fogCoord, col);
    
        // 計算した結果の色情報を返す
        return col;
    }
    

    그 결과, 블렌딩된 결과를 정확하게 크로마키 합성하는데 성공하였다.



    요약



    Unity는 배우기 시작한지 ​​4년이 되었지만, 셰이더 코드를 확실히 읽고 손을 넣은 것은 처음이었기 때문에 좋은 경험이 되었다. 실제로 HLSL을 읽는 것으로, 셰이더는 기본적으로 이하의 처리를 하고 있는 것을 이해했다.
  • 정점 좌표의 변환
  • 픽셀 정보 변환

  • 여기에서 더욱 밟으면 좀 더 복잡한 세계가 있다고 생각하지만, 현재의 업무에서는 필요한 충분한 지식을 얻을 수 있었기 때문에 만족했다. 만약 기사에 실수 등이 있으면 코멘트에서 지적해 주시면 감사하겠습니다.

    참고 자료


  • 셰이더: 정점 및 단편 프로그램 - Unity 매뉴얼
  • 정점 셰이더와 단편 셰이더의 예 - Unity 매뉴얼
  • 좋은 웹페이지 즐겨찾기