
▲テクスチャブレンド機能を追加したユニティちゃんシェーダー。赤枠に囲んだ部分にテクスチャとスライダーを追加しました。上の例ではテクスチャに頬染め差分をセットしスライダーで頬染めをコントロールしています。
はじめに
※本記事はシェーダーの改造を含みます。場合によっては描画が正しく行われなくなるなどの可能性があります。本記事の内容を実施しようとした結果起きた損害について、作者は責任は負いかねますので、自己責任の上で内容をご利用ください。
現在Unityでトゥーンシェーディング表現を採用する場合、Unity様が配布しているユニティちゃんトゥーンシェーダーを使用する場合が多いのではないかと思います。本当に高機能で素晴らしいシェーダーですが、唯一不満がありまして、テクスチャをブレンドする機能が存在しません。例えば頬染めなどを実装したい場合、染めた頬を仕込んでBlendShapeで表示するなどの工夫が必要になります。
ただ、その方式だと色の強弱をコントロールができない、いちいちモデリング段階で染めた頬を仕込まないといけないなどいくつかのデメリットが生じます。シェーダーにブレンド機能があれば楽なのに・・・ということで本稿では、シェーダーを改造して任意のテクスチャをブレンドする機能を追加する方法を紹介します。
目的
・シェーダーにテクスチャスロットを追加する。
・シェーダーにスライダーを追加する
・スライダーの強弱に従って、追加したテクスチャをメインテクスチャに乗算する。
対象読者
・中級者向けです。基本操作は解説しない場合があります。初心者の方は頑張ってください。
・Unityバージョン – 2022.1.11f1 日本語化済み
・レンダリング – URP
そもそも改造していいの?
いいみたい。以下根拠です。興味ない方は読み飛ばしてね。
配布ページによると、UniversalToonShaderのライセンスはUnity Companion Licenseというのが適用されるそうです。(https://unity.com/legal/licenses/unity-companion-license)
内容を確認するとどうやら関係がありそうな項目が。
3. Ownership; Derivative Works.(所有権:派生作品について)
3.3 Your right to use derivative works. You will always have the right to use derivative works of the Work you create, consonant with this License.(訳:派生作品を使ってもいいです。あなたが作った派生作品はこのライセンス下でいつでも使っていいですよ。)
ということで、二次創作してもよさそうです。ただし、派生作品の権利はUnityに帰属するので、俺が改造したからこのシェーダーの著作権は俺のものだぜ~なんてことにはなりません。(まあそうですよね。)
ちなみにここで言う派生作品はシェーダーを改造しただけのような、シェーダーのみから派生したものを指すので、このシェーダーを使って作ったゲームの著作権はちゃんとゲーム制作者に帰属します。安心です。気になる方は原文を読んでみてね。
※万一解釈に誤りがありましたらご指摘いただけると幸いです。
Unityちゃんシェーダーの導入
まずは導入です。ダウンロードページ(https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/tree/release/urp/2.2)に行きます。
右上のコードボタンをクリック→ダウンロードZIPをクリックしましょう。ダウンロードが成功したらZIPを展開します。
Unityを開き、ウィンドウ→パッケージマネージャーでパッケージマネージャーを起動します。左上の「+」ボタンをクリックし、ディスクからパッケージに加えるを選択。

展開したダウンロードフォルダを開き、package.jsom選択して開く。
適当なマテリアルを作成し、ShaderにUniversal Render Pipeline/toonが追加されていたら成功です。
改造
いよいよ改造の開始です。プロジェクトウィンドウで以下のフォルダを開きます。
Packages/Universal Toon Shader for URP/ Runtime/Shaders
フォルダを開くと、ファイルがいくつかあるはずです。今回改造する必要のあるファイルは以下の3つです。
・UniversalToon - インスペクタ上に表示されるUIなどが記述されています。
・UniversalToonInput - シェーダーに渡す変数などを定義します。
・UniversalToonBodyDoubleShadeWithFeather - 実際に描画を行うロジックが記述されています。
UniversalToon
まずはUniversalToonの改造です。このファイルには、Unityのインスペクタに表示されるテクスチャスロットやスライダーなどの内容が書かれています。今回追加したいのは、乗算するテクスチャと、乗算の度合いをコントロールするスライダーです。
56行目付近を見てみます。見覚えのある名前がありますね。
_MainTex ("BaseMap", 2D) = "white" {}
BaseMapというのは、メインで使用されるテクスチャのことです。_MainTexがプログラムやシェーダー上で使用される名前で、括弧の中はそれぞれインスペクタ上で表示される名前と型のようです。また、=の右側は初期値が入るみたいですね。
さて、これを真似すればインスペクタに表示するテクスチャやスライダーを追加できそうです。というわけで、以下の文を_MainTexの上の行あたりに追加してあげましょう。
_BlendTex("BlendMap", 2D) = "white" {}
_BlendLevel("BlendLevel", Range(0, 1)) = 0
今回の例では、乗算テクスチャを_BlendMap、乗算度合いを_BlendLevelとしました。これで、インスペクタにテクスチャとスライダーが追加されているはずです。保存して確認してみましょう。デフォルトでは今回追加した項目は隠れているので、確認するときはShowAllPropertyボタンを押すのを忘れずに・・・
UniversalToonInput
UniversalToonInputではシェーダーに渡す変数などを定義します。シェーダーの処理はGPUで行われるというのは有名ですが、CPUからGPUに情報を渡すために、何を渡すかをあらかじめ定義する必要があります。本ファイルがその定義が書かれたファイルです。ここの記述をちゃんとしないと、シェーダー本体を記述しても_BlendTex?そんなものねえよ!と怒られてしまいます。
今回もMainTexを参考にガリガリ書いていきましょう。まずは193行目。
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
_MainTexの定義がありました。ここを真似して_BlendTexを追加しましょう。
TEXTURE2D(_BlendTex);
OKです。
つぎはスライダーから渡された値の定義を追加します。ここで注意なのですが、先ほど書いた行の数行上を確認すると以下のような記述があります。
CBUFFER_END
どうもテクスチャを記述する領域と、floatなどの変数を記述する領域は別のようで、スライダーの値を定義する場所はCBUFFER_ENDより上にないといけません。なので、少し上に記述しましょう。今回は140行目付近に以下のように追加しました。
float _BlendLevel;
OKです。ちなみに140行目付近にした理由は同じくインスペクタ上でスライダーを操作する_Clipping_Levelが付近にあったからです。同じ使い方をする変数の近くならば安心だろうということでここにしました。おそらくCBUFFER_START(UnityPerMaterial)から前述のCBUFFER_ENDまでの範囲ならどこでも大丈夫とは思います。
さて、テクスチャもスライダーも定義したし、これで終わりと思いたいところですが、もう一か所記述を追加しないといけないところがあります。14行目付近。
float4 _MainTex_ST;
_MainTex_STという記述がありますね。後ろにSTと書いてありますが、これを真似しないと動かないようでした。(詳しい方は教えていただけると嬉しいです。)改行して下の行に以下を追加します。
float4 _BlendTex_ST;
今度こそ完了です。
UniversalToonBodyDoubleShadeWithFeather
最後です。85行目付近に以下のコードを追加します。
float4 _BlendTex_var = SAMPLE_TEXTURE2D(_BlendTex, sampler_MainTex, TRANSFORM_TEX(Set_UV0, _BlendTex));
直前に_MainTex_varがありましたので、その直後に追加した形です。テクスチャからUV座標を用いて色を取得します。_MainTex_varを用いて色を決定する場所が142行目付近にあります。
float3 Set_BaseColor = lerp( (_BaseColor.rgb*_MainTex_var.rgb), ((_BaseColor.rgb*_MainTex_var.rgb)*Set_LightColor), _Is_LightColor_Base );
ここを改造します。_MainTex_var.rgbに_BlendTex_var.rgbをかけてあげれば乗算処理ができますね。また、BlendLevelで強弱をコントロールできるようにしなければなりません。以下のように書き換えます。
float3 Set_BaseColor = lerp((_BaseColor.rgb * _MainTex_var.rgb * (_BlendTex_var.rgb * _BlendLevel - _BlendLevel + 1)), ((_BaseColor.rgb * _MainTex_var.rgb * (_BlendTex_var.rgb * _BlendLevel - _BlendLevel + 1)) * Set_LightColor), _Is_LightColor_Base);
これでBlendLevelが0のときは、もともとの色に1をかけ(すなわち変化なし)、1のときはBlendTexの色が乗算されるようになります。
UniversalToonShaderは1影、2影で別のテクスチャを使用するので、1影2影も乗算されるように書き換えます。Set_1st_ShadeColor 、Set_2nd_ShadeColor を計算する行を探して以下のように書き換えてください。
float3 Set_1st_ShadeColor = lerp((_1st_ShadeColor.rgb * _1st_ShadeMap_var.rgb * (_BlendTex_var.rgb * _BlendLevel - _BlendLevel + 1)), ((_1st_ShadeColor.rgb * _1st_ShadeMap_var.rgb * (_BlendTex_var.rgb * _BlendLevel - _BlendLevel + 1)) * Set_LightColor), _Is_LightColor_1st_Shade);
float3 Set_2nd_ShadeColor = lerp((_2nd_ShadeColor.rgb * _2nd_ShadeMap_var.rgb * (_BlendTex_var.rgb * _BlendLevel - _BlendLevel + 1)), ((_2nd_ShadeColor.rgb * _2nd_ShadeMap_var.rgb * (_BlendTex_var.rgb* _BlendLevel - _BlendLevel + 1)) * Set_LightColor), _Is_LightColor_2nd_Shade);
これで改造は完了です。
すべての改造が正常に完了した場合、以下のようにシェーダーを使用できます。

赤枠にテクスチャをセットし、スライダーを動かすと・・・

無事乗算されました!
終わりに
今回は乗算を実装しましたが、同じ方法で加算なども実現できそうです。ハイライトやハート目など、表現の幅が広がりそうですね。
