27.5K Views
May 29, 23
スライド概要
友達に「明日シェーダー講習会やってよw」って言われたんで、一日潰してつくったスライドです。
https://github.com/tsmsextreme/shader_lecture/blob/main/target.shader
シェーダーの気持ち ~ 見るか?俺の徹夜 ~
俺の乳首の色
#b08b4c
徹夜ってこういうことだぞ
始める前にSorry… 厳密な考証は行っておりません ・わかりやすさ重視 プログラミング初心者/VRChat改変経験者を想定 ・プログラマー向け専門用語は口頭で言います 詳しくは右の本 ・2000円です マジで安すぎる 以上の理由で 質問歓迎!! https://booth.pm/ja/items/660001 Unityシェーダープログラミングの教科書 ShaderLab言語解説編
今日の目標
このコードを理解してもらいます 1/2 2/2
1.事前知識 (1)シェーダーって何? (2)レンダリングパイプライン (3)座標系(覚えなくていい) (4)シェーダーの作り方
(1)シェーダーって何? シェーダーって何? どうせお前らにはこれで通じます マテリアルの”もと”です。 liltoon シェーダー 肌マテリアル メインカラー : 肌.png Render Queue: 2000 Cull Mode(描画面): Back(裏面のみ描画 ) 髪マテリアル メインカラー : 髪.png Render Queue: 2000 Cull Mode(描画面): Off(両面を描画 ) 服マテリアル メインカラー : 服.png Render Queue: 2000 Cull Mode(描画面): Back(裏面のみ描画 ) マテリアル マテリアルごとの設定 (properties)
(1)シェーダーって何? シェーダーの主な言語は? Cg/HLSL GLSL HLSL ShaderLab ・C言語ベース ・拡張子: .glsl ・WebGLとかです ・C言語ベース ・拡張子: .hlsl ・𝑯𝒊𝒈𝒉 𝑳𝒆𝒗𝒆𝒍 𝑺𝒉𝒂𝒅𝒊𝒏𝒈 𝑳𝒂𝒏𝒈𝒖𝒂𝒈𝒆 ・Unity特有の言語 ・拡張子: .shader ・Cg/HLSLを内包する Unityでは非推奨 「シェーダー」で調べると HLSLもGLSLも出てくるので 適宜読み替える必要がある Unityで使えます! でもあまり主流ではない Unityで使えます! 今回説明します。 ※拡張子って言い方もちょっと不十分ですが、 Unity上でのイメージを持つための比喩表現だと思ってください。 ※厳密には、HLSLをそのままShaderLabに埋め込むこともできます。 神城アオイさんのUnityShader_TextureOverlayがそういうことをしてました
(2)レンダリングパイプライン…シェーダー内部の流れ レンダリングパイプライン 難しそうなカタカナが出てきたなあ 「シェーダー内部の処理の流れ」です。 Unityでは次のような流れです→ ※次のスライドのレンダリングパイプラインも正確ではありません 例えばコンピュートシェーダーは省略しています。 VRChat上でシェーダーを理解するのに必要だと思われるところをかいつまんでいます。
(2)レンダリングパイプライン…シェーダー内部の流れ 情報 頂点シェーダーステージ 情報 テッセレーションステージ 情報 ジオメトリステージ 情報 フラグメントシェーダーステージ 色 出力マージャステージ
(2)レンダリングパイプライン…シェーダー内部の流れ 情報 頂点シェーダーステージ 情報 テッセレーションステージ 情報 ジオメトリステージ 情報 フラグメントシェーダーステージ 色 出力マージャステージ
(2)レンダリングパイプライン…シェーダー内部の流れ 日本語でおkおじさん 日本語でおk
(2)レンダリングパイプライン…シェーダー内部の流れ 情報 頂点シェーダーステージ ①頂点の座標、 uv座標を受け取る。 ②変換して次のステージに投げる。 情報 テッセレーションステージ 面を分割する。 例)視点から遠ければ分割を少なくして、 描画負担を軽くする 情報 ジオメトリステージ 面を増やし、減らし、変形する。 例)ファーシェーダー 情報 フラグメントシェーダーステージ 色を決定する 色 出力マージャステージ 出力する
(2)レンダリングパイプライン…シェーダー内部の流れ
(2)レンダリングパイプライン…シェーダー内部の流れ もっと簡潔におじさん もっと簡潔に
(2)レンダリングパイプライン…シェーダー内部の流れ ①頂点の座標、 uv座標を受け取る。 ②変換して次のステージに投げる。 頂点シェーダーステージ 情報 フラグメントシェーダーステージ 色を決定する 色 ゆっくり魔理沙 この2つだけ覚えるぜ。
(2)レンダリングパイプライン…シェーダー内部の流れ でも冗談じゃなくて… 「頂点シェーダー」と「フラグメントシェーダー」は 重要ポイント。 たとえばこの2つで ・視界ジャック ・数字/文字を表示するシェーダー ・レイマーチング(異界シェーダー) などができる。 まずはこの2つを覚えてください ※AoiKamishiro / UnityShader_TextureOverlay https://github.com/AoiKamishiro/UnityShader_TextureOverlay ※数値を数字として表示するシェーダーを作ったおはなし [Unity] https://qiita.com/noriben327/items/e50cd7922c7cd5f8e74c
(3)座標系(覚えなくていい) 座標系 頂点シェーダーステージ ①頂点の座標、 uv座標を受け取る。 ②変換して次のステージに投げる。
(3)座標系(覚えなくていい) 5つの座標系 耳 (-0.18, 0.6, -0.006) 1.オブジェクト空間(ローカル座標/モデル空間)座標系 オブジェクトの原点を中心とした座標系です。 オブジェクトの原点 =オブジェクトの中心。 ただ、キャラクターでは足元を原点とすることが多いらしい。 頂点シェーダーが最初に受け取る座標の系はこれ。 原点 (0,0,0) 2.ワールド空間座標系 ワールドの原点を中心とした座標系です。 耳 (2.36 , 0.08, -0.33)
(3)座標系(覚えなくていい) 5つの座標系 y 3.ビュー空間(カメラ空間)座標系 z 原点 (0,0,0) カメラを中心とした座標系です。 わかりにくいですね。雰囲気でいいです。 4.クリッピング空間座標系 Haruki Yano.【Unity】プロジェクション行列は掛けるだけじゃなくてw除算しなきゃダメだよという話. LIGHT11. 2018-06-10. https://light11.hatenadiary.com/entry/2018/06/10/233954, (参照2023-05-29) x
(3)座標系(覚えなくていい) 5つの座標系 5. ビューポート空間座標系/スクリーン空間座標系 画面の四隅のどれかが原点になります。 x シェーダーでは基本使いません。 y
(3)座標系(覚えなくていい) unityのシェーダーで座標系を変換する方法 unityにはいろんな変数や関数が標準で用意されています。変換方法は毎回忘れても調べれば OKです。 オブジェクト座標系 unity_ObjectToWorldを掛ける = ワールド空間座標系 UNITY_MATRIX_MVを掛ける もしくは UnityObjectToViewPos関数 = ビュー空間座標系 UNITY_MATRIX_MVPを掛ける もしくは UnityObjectToClipPos関数 = クリッピング空間座標系
(4)シェーダーの作り方 シェーダー作ります ①Assets上で右クリック ②Create > shader > どれか一つをクリック
(4)シェーダーの作り方 シェーダー作ります ③できたシェーダーファイルの内容を、 今回の”目標”に書き換える できた ※暇なときは、書き換える前の シェーダーを読んでみても楽しいです。
2.読む シェーダーを読みましょう (1)シェーダーの構成 (2)Properties (3)Tags (4)Pass
(1)シェーダーの構成 シェーダーの構成 Shader "Custom/target(①Name)" { Properties { (②Properties ブロック) ①Name … シェーダーの名前。 } ②Properties ブロック SubShader { ③Tags ブロック Tags { (③Tags ブロック) ④CGPROGRAM ブロック …頂点シェーダーや フラグメントシェーダーを書く } Pass { (たまにシェーダーの情報をここに書く カリングなど) CGPROGRAM (④CGPROGRAM ブロック) ENDCG } } }
(2)Properties Properties Inspectorタブに出てくるこれを定義します↓ 見出し 具体的なコードはこんな感じ。 Properties { _MainTex ("Texture", 2D) = "white" {} (名前) (見出し } , 形式) = "初期値" 何これ
(2)Properties Properties Properties { _MainTex ("Texture", 2D) = "white" {} 名前 ( 見出し , 形式)= "初期値" 何これ } 名前:シェーダーコードの中でのデータ名です。 形式:いろいろあります。 Int:整数1個 Float:小数1個 Range(min, max):min以上max以下の小数 Color:色 Vector:小数4個 2D:(2Dの)テクスチャ
(3)Tags Tags シェーダーがいつ、どのように動くのか設定します。 Tags { "Queue" = "Geometry" } 見出し (タグ) = 「タグ = 値」の形式で設定します。 (値)
(3)Tags 最初 例 RenderQueue 1000 Background レンダリング順序です。 数字の小さい方から描画されます。 2000 Geometry 背景 服とか体とか 不透明なもの 2450 AlphaTest 3000 Transparent 4000 Overlay 水中で透ける水着はこれの応用 最後 水など 透明なもの ポストエフェクト
(4)Pass 受け渡す情報 思い出しましょう… 頂点シェーダーステージ ①頂点の座標、 uv座標を受け取る。 ②変換して次のステージに投げる。 情報 フラグメントシェーダーステージ 色 色を付ける
(4)Pass おじさん どういう情報を 受け渡すの?
(4)Pass 受け渡すデータたちの形式を定義する どんなものが受け渡されるのか、 定義します。 右のコードは下図のようになります。 struct appdata { float4 vertex : POSITION; (形式) (名前) : (意味) ; float2 uv : TEXCOORD0; }; appdata 値の形式はfloat4 意味はPOSITION[座標] 値 ver tex 値 値の形式はfloat2 意味はTEXCOORD0[uv座標] uv ※上記の言い方は厳密ではありません。 データリスト…「構造体」 意味…「セマンティクス」 形式…「(データ)型」 ※セマンティクスの大文字、小文字は区別されません。
(4)Pass 受け渡す情報(改) 今回のコードはこういう流れ struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; 情報(形式:appdata) }; 頂点シェーダーステージ ①頂点の座標、 uv座標を受け取る。 ②変換して次のステージに投げる。 struct v2f { 情報(形式:v2f) float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; フラグメントシェーダーステージ 色 色を付ける
(4)Pass 頂点シェーダー #pragma vertex vert v2f vert (appdata v){ v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; }
(4)Pass 日本語でおkおじさん 日本語でおk
(4)Pass 頂点シェーダー #pragma vertex vert 「vert」が頂点シェーダーの処理だと宣言。 v2f vert { ... } #pragma vertex vert v2f vert (appdata v){ } { … } 内で行われる処理を「vert」とする。受け渡す情報の形式はv2f。 (appdata v) 受け渡された情報の形式はappdata。この情報をvと命名する。
(4)Pass 頂点シェーダー v2f o; v2fという形式の情報を定義します。 名前はo。 #pragma vertex vert v2f vert (appdata v){ v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.vertex = …; o.uv = v.uv; oのvertexに...という値を入れます。 UnityObjectToClipPos(v.vertex) return o; } v.vertex[オブジェクト空間座標系]をクリッピング座標系に 変換します。 o.uv = v.uv; oのuvにvのuvを入れます。 return o; oを受け渡します。 受け渡された情報の形式: appdata 受け渡された情報の名前: v 受け渡す情報の形式: v2f 受け渡す情報の名前: o ※上記の言い方は厳密ではありません。 情報…「変数」 受け渡す…返す
(4)Pass フラグメントシェーダー #pragma fragment frag fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; }
(4)Pass 日本語でおkおじさん 日本語でおk
(4)Pass フラグメントシェーダー #pragma fragment frag #pragma fragment frag 「frag」がフラグメントシェーダーの処理だと宣言。 fixed4 frag (v2f i) : SV_Target { } fixed4 frag { ... } { … } 内で行われる処理を「frag」とする。 受け渡す情報の形式はfixed4[色]。 (v2f i) 受け渡された情報の形式はv2f。この情報をiと命名する。 : SV_Target 「受け渡す値は色です!」と示す。 ※fixed4は常に色を表すわけではありません。 今回はフラグメントシェーダーでSV_Targetが宣言されているので返す値は色を表す。 SV_Targetはセマンティクスです。
(4)Pass フラグメントシェーダー #pragma fragment frag fixed4 col = …; fixed4 frag (v2f i) : SV_Target { fixedという形式の情報を定義します。 名前はcol。 fixed4 col = tex2D(_MainTex, i.uv); return col; } tex2D(_MainTex, i.uv) iのuv[uv座標]での_MainTex[テクスチャ]の色を取得します。 return col; colを受け渡します。 受け渡された情報の形式: v2f 受け渡された情報の名前: i 受け渡す情報の形式: fixed4[色] 受け渡す情報の名前: col
あらためて全部を見直すと…
1/2 2/2
…シェーダーの名前を宣言 …Inspectorタブでどんな情報を設定できるか、決める …シェーダーがいつ、どのように動くのか設定 …「vert」が頂点シェーダー、 「frag」がフラグメントシェーダーであると宣言。 …頂点シェーダーが受け渡される情報の形式appdataを定義。 1/2
…頂点シェーダーからフラグメントシェーダーに 受け渡される情報の形式v2fを定義。 …Inspectorタブで設定されたテクスチャの名前を _MainTexと定義。 …頂点シェーダー …フラグメントシェーダー …終わり 2/2 つまりこのシェーダーは? →
シェーダーのこと、わかってくれたかな!? 今後に読んでほしいもの ・マッハで学ぶ VRChat Shader LV5 習得 までのLV別 技術情報まとめ https://qiita.com/7CIT/items/bb81f73e0402c693a147 様々なシェーダーを俯瞰できる。 ・Unityシェーダープログラミングの教科書 ShaderLab言語解説編 https://booth.pm/ja/items/660001 今すぐにわからなくても、電子辞書として使える。 ・Shaderで計算機を作る https://phi16.hatenablog.com/entry/2019/09/02/010324 phi16さんの記事は全部面白い!でも今すぐ読むと心折れるかも。半年後読んでください。
ご清聴あざす chu!駆け足でごめんね