知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】テクスチャのカリング #19

前回の成果

VertexShaderとFragmentShaderを理解しました。

soramamenatan.hatenablog.com

今回やること

テクスチャのカリングを行います。

nn-hokuson.hatenablog.com

前準備

f:id:soramamenatan:20190830150733p:plain

PlaneをScene上に配置します。

今回使用した画像サイト様はこちらです。

青いインコのイラスト | かわいいフリー素材集 いらすとや

ソースコード

2つあります。
1つ目はScriptです。

using UnityEngine;

public class RotateObject : MonoBehaviour {
    void Update () {
        transform.Rotate(new Vector3(0,0,90.0f) * Time.deltaTime);
    }
}

継続的に回転させているだけです。
カメラに移す関係で、Z軸回転をしています。

2つ目はShaderです。

Shader "Unlit/culling" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader{
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 200
        Cull off
        Blend SrcAlpha OneMinusSrcAlpha
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

textureを描画しているように見えます。
しかし、見慣れないソースが何点かあります。

復習

自分自身軽く抜けていた点があったので復習していこうと思います。

Tags

Tags { "RenderType"="Transparent" "Queue"="Transparent" }

Shader側に不透明なオブジェクトと伝えます。
記述がないとこうなります。

f:id:soramamenatan:20190830152615p:plain

LOD

LOD 200

しきい値のことです。
詳しくはこちらになります。

soramamenatan.hatenablog.com

tex2D

fixed4 col = tex2D(_MainTex, i.uv);

UV座標からテクスチャのピクセルの色を返すものです。

Cull off

この1行でカリングがoffになります。

そもそもカリングとは、描画する必要がないポリゴンを描画しないようにする手法です。

例えばこのような広いマップを制作しました。

f:id:soramamenatan:20190830153952j:plain

しかし、カメラに映らない部分(白い線で囲まれていない部分)は、見えないので描画する必要がありません。
なので、次の画像のように描画しないようにするものです。

f:id:soramamenatan:20190830154221j:plain

今回の場合、カリングがonだと次のgifのように裏面が描画されません。

f:id:soramamenatan:20190830163855g:plain

Blend SrcAlpha OneMinusSrcAlpha

ブレンディングのことです。

Blend SrcFactor DstFactor

で定義することができます。

SrcFactorはFragment Shaderでreturenされた色に乗算します。
DstFactorはShaderが処理される前にすでに画面に描画されている色に乗算します。

なので、最終的には

Fragment Shaderで計算した色 * SrcFactor + すでに画面に描画されている色 * DstDactorとなります。

qiita.com

Blend SrcAlpha OneMinusSrcAlpha

上記のソースコードでは、テクスチャの透明部分を透過させるようにしています。

Blend係数一覧

Sourceは計算された色のことを指します。
Destinationはすでに設定されているスクリーン上の色のことです。

係数名 用途
One Source、またはDestinationの色をそのまま使用したい場合
Zero Source、またはDestinationの色を削除したい場合
SrcColor Sourceの色を乗算
SrcAlpha SourceのAlpha値を乗算
DstColor フレームバッファのSourceの色を乗算
DstAlpha フレームバッファのSourceのAlpha値を乗算
OneMinusSrcColor フレームバッファの(1-Sourceの色)を乗算
OneMinusSrcAlpha フレームバッファの(1-SourceのAlpha値)を乗算
OneMinusDstColor フレームバッファの(1-Destinationの色)を乗算
OneMinusDstAlpha フレームバッファの(1-DestinationのAlpha値)を乗算

docs.unity3d.com

#include "UnityCG.cginc"

cgincファイルに定義された処理が使えるようになります。
今回のソースコードにある構造体のappdataもいくつか定義されています。

struct appdata_base {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_tan {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;
    fixed4 color : COLOR;
};

#include "UnityCG.cginc"の中身はこちらです。

https://gist.github.com/hecomi/9580605

TRANSFORM_TEX

テクスチャのスケールとオフセットを適応するものです。
TRANSFORM_TEXを使用する際には定数として、

float4 テクスチャ名_ST

が必要です。
今回は、テクスチャ名が_MainTexなので

float4 _MainTex_ST;

を宣言します。

結果

f:id:soramamenatan:20190830184210g:plain

ソースコードにコメントを付与

Shader "Unlit/culling" {
    // プロパティ
    Properties {
        // テクスチャ
        _MainTex ("Texture", 2D) = "white" {}
    }
    // Shaderの中身を記述
    SubShader{
        // 不透明なオブジェクト
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        // しきい値
        LOD 200
        // カリングをoffに
        Cull off
        // 透過処理
        Blend SrcAlpha OneMinusSrcAlpha
        // レンダリングの方式
        Pass {
            // cg言語記述
            CGPROGRAM
            // vertexShaderの宣言
            #pragma vertex vert
            // fragmentShaderの宣言
            #pragma fragment frag

            // インクルード
            #include "UnityCG.cginc"

            // appdata構造体
            struct appdata {
                // pos
                float4 vertex : POSITION;
                // uv値
                float2 uv : TEXCOORD0;
            };

            // vertex to fragment構造体
            struct v2f {
                // pos
                float4 vertex : SV_POSITION;
                // uv値
                float2 uv : TEXCOORD0;
            };

            // テクスチャ
            sampler2D _MainTex;
            // TRANSFORM_TEXの定数
            float4 _MainTex_ST;

            // vert関数
            v2f vert (appdata v) {
                v2f o;
                // クリップ座標に変換
                o.vertex = UnityObjectToClipPos(v.vertex);
                // テクスチャのスケールとオフセット
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            // frag関数
            fixed4 frag (v2f i) : SV_Target {
                // テクスチャのピクセルの色を返す
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

今回は以上になります。
ご視聴ありがとうございました!