やあ!今日は引き続き 説明します。この記事は前の記事の 2 倍の大きさになります。しっかりしてください! Unity でのレンダリングについて シェーダーとは何ですか? 以前の記事で説明した内容に基づくと、シェーダーはプロジェクトで興味深い効果を作成するために使用できる小さなプログラムです。これには、数学的な計算と命令 (コマンド) のリストが含まれています。これらを使用すると、コンピューター画面上のオブジェクトをカバーする領域の各ピクセルの色を処理したり、オブジェクトの変換を操作したり (たとえば、動的な草や水を作成する) ことができます。 このプログラムを使用すると、多角形オブジェクトのプロパティに基づいて (座標系を使用して) 要素を描画できます。シェーダーは、 同時に処理するように設計された数千の小型で効率的なコアで構成される並列アーキテクチャを備えているため、GPU 上で実行されます。ちなみに、CPUは順次シリアル処理を行うように設計されています。 タスクを Unity には 3 種類のシェーダー関連ファイルがあることに注意してください。 まず、さまざまなタイプのレンダリング パイプラインをコンパイルできる「.shader」拡張子を持つプログラムがあります。 2 番目に、URP または HDRP のいずれかにのみコンパイルできる「.shadergraph」拡張子を持つプログラムがあります。さらに、カスタマイズされた関数を作成できる「.hlsl」拡張子のファイルもあります。これらは通常、シェーダー グラフにあるカスタム関数と呼ばれるノード タイプで使用されます。 「.cginc」拡張子を持つ別のシェーダー タイプ、Compute Shader もあります。これは「.shader」CGPROGRAM に関連付けられ、「.hlsl」は「.shadergraph」HLSLPROGRAM に関連付けられます。 Unity では、シェーダー生成のために少なくとも 4 種類の構造が定義されています。その中には、頂点シェーダーとフラグメント シェーダーの組み合わせ、自動ライティング計算のためのサーフェス シェーダー、より高度な概念のためのコンピューティング シェーダーがあります。 シェーダー言語についての小旅行 一般にシェーダーの作成を開始する前に、Unity には 3 つのシェーダー プログラミング言語があることを考慮する必要があります。 HLSL (高レベルシェーダー言語 - Microsoft) Cg (C for Graphics - NVIDIA) - 廃止された形式 ShaderLab - 宣言型言語 - Unity Cg、 について簡単に説明し、HLSL について少し触れます。 ShaderLab Cg は、ほとんどの GPU でコンパイルできるように設計された高級プログラミング言語です。 NVIDIA は Microsoft と協力してこれを開発し、HLSL に非常によく似た構文を使用しました。シェーダーが Cg 言語で動作する理由は、シェーダーが HLSL と GLSL (OpenGL Shading Language) の両方でコンパイルできるため、ビデオ ゲーム用のマテリアルの作成プロセスが高速化および最適化されるためです。 Unity のすべてのシェーダー (シェーダー グラフとコンピューティングを除く) は、ShaderLab と呼ばれる宣言型言語で書かれています。この言語の構文を使用すると、Unity インスペクターでシェーダーのプロパティを表示できます。これは、変数とベクトルの値をリアルタイムで操作し、シェーダーをカスタマイズして望ましい結果を得ることができるため、非常に興味深いものです。 ShaderLab では、フォールバックなどのいくつかのプロパティとコマンドを手動で定義できます。 Unity に存在するさまざまなタイプのレンダリング パイプラインと互換性があります。 フォールバックは、マルチプラットフォーム ゲームの基本的なコード ブロックです。これにより、エラーを生成したシェーダーの代わりに別のシェーダーをコンパイルできるようになります。コンパイル中にシェーダーが壊れた場合、フォールバックは別のシェーダーを返し、グラフィックス ハードウェアは作業を続行できます。これは、Xbox と PlayStation 用に異なるシェーダーを作成する必要がなく、統合されたシェーダーを使用できるようにするために必要です。 Unity の基本的なシェーダー タイプ Unity の基本的なシェーダー タイプを使用すると、さまざまな目的に使用するサブルーチンを作成できます。 それぞれのタイプが何を担当するかについて説明します。 このタイプのシェーダは、ベース ライティング モデルと対話し、組み込み RP でのみ動作するコードの作成が最適化されることを特徴としています。 標準のサーフェス シェーダ。 点灯していないシェーダー。これは原色モデルを指し、エフェクトを作成するために通常使用する基本構造になります。 構造的には、Unlit シェーダーに非常に似ています。これらのシェーダは主に組み込み RP 後処理エフェクトで使用され、「OnRenderImage()」関数 (C#) が必要です。 イメージエフェクトシェーダー。 このタイプの特徴は、ビデオ カード上で実行されるという事実であり、前述のシェーダとは構造的に大きく異なります。 シェーダーを計算します。 リアルタイムでレイ トレーシングを収集して処理できる実験的なタイプのシェーダ。 HDRP と DXR でのみ動作します。 レイトレーシング シェーダー。 ノードを使用するシェーダー言語の知識がなくても作業できる空のグラフベースのシェーダー。 空白のシェーダー グラフ。 他のシェーダーグラフシェーダーで使用できるサブシェーダーです。 サブグラフ。 Unity でのレンダリングは難しいトピックなので、このガイドを注意深く読んでください。 シェーダ構造 シェーダーの構造を解析するには、Unlit に基づいて簡単なシェーダーを作成し、それを解析するだけです。 初めてシェーダーを作成するとき、Unity はコンパイル プロセスを容易にするためにデフォルトのコードを追加します。シェーダーでは、GPU が解釈できるように 見つけることができます。 構造化されたコードのブロックを シェーダーを開くと、その構造は次のようになります。 Shader "Unlit/OurSampleShaderUnlit" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags {"RenderType"="Opaque"} LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler 2D _MainTex; float4 _MainTex; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o, o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } } 現在の例とその基本構造により、それがもう少し明確になります。シェーダーは、Unity エディターのインスペクター内のパス (InspectorPath) と名前 (shaderName) で始まり、次にプロパティ (テクスチャ、ベクター、カラーなど)、サブシェーダーの順に続きます。最終的に、オプションの Fallback パラメーターはさまざまなバリアントをサポートします。 ShaderLab の使用 ほとんどのシェーダーは、Unity インスペクターでシェーダーとそのパス、および名前を宣言することから始まります。 SubShader や Fallback などの両方のプロパティは、ShaderLab 宣言言語の「Shader」フィールド内に記述されます。 Shader "OurPath/shaderName" { // The shader code will be here } パスとシェーダ名の両方は、プロジェクト内で必要に応じて変更できます。 シェーダーのプロパティは、Unity インスペクター内から操作できるパラメーターのリストに対応します。価値と有用性の両方の点で、8 つの異なるプロパティがあります。これらのプロパティは、作成または変更するシェーダに関連して、動的または実行時に使用します。プロパティを宣言するための構文は次のとおりです。 PropertyName ("display name", type) = defaultValue 「PropertyName」はプロパティの名前 (例: _MainTex) を表し、「表示名」は Unity インスペクター内のプロパティの名前 (例: Texture) を指定し、「type」はそのタイプ (例: Color、Vector、2D など) を示します。最後に、「defaultValue」はプロパティに割り当てられるデフォルト値です (たとえば、プロパティが「Color」の場合、白 (1, 1, 1, 1, 1, 1) に設定できます。 シェーダの 2 番目のコンポーネントはサブシェーダです。各シェーダは、完全なロードを実現するために少なくとも 1 つのサブシェーダで構成されます。複数のサブシェーダーがある場合、Unity はそれぞれのサブシェーダーを処理し、ハードウェア仕様に従って、リストの最初のサブシェーダーから始まり最後のサブシェーダーで終わる最も適切なサブシェーダーを選択します (たとえば、iOS と Android のシェーダーを分けるため)。 SubShader がサポートされていない場合、Unity は標準シェーダーに対応するフォールバック コンポーネントの使用を試み、ハードウェアがグラフィック エラーを発生させずにタスクを続行できるようにします。 Shader "OurPack/OurShader" { Properties { ... } SubShader { // Here will be the shader configuration } } パラメータとサブシェーダの詳細については、 と 参照してください。 ここ ここを ブレンド 2 つのピクセルを 1 つに結合するプロセスにはブレンディングが必要です。ブレンディングは、組み込みと SRP の両方でサポートされています。 ブレンディングは、ピクセルの最終的な色とその深度を組み合わせるステップで発生します。このステージは、ステンシル バッファー、Z バッファー、およびカラー混合を実行する際のフラグメント シェーダー ステージ後のレンダリング パイプラインの最後に発生します。 デフォルトでは、このプロパティはオプションの機能であり、主に透明なオブジェクトを操作するときに使用されるため、シェーダーには書き込まれません。たとえば、不透明度の低いピクセルを別のピクセルの前に描画する必要がある場合に使用されます (これは UI でよく使用されます)。 ここでブレンディングを有効にできます。 Blend [SourceFactor] [DestinationFactor] ブレンドの詳細については ご覧ください。 、こちらを Z バッファ (深度バッファ) 両方の概念を理解するには、まず Z バッファ (深度バッファとも呼ばれます) と深度テストがどのように機能するかを学ぶ必要があります。 始める前に、ピクセルには深度値があることを考慮する必要があります。これらの値は深度バッファに保存され、オブジェクトが画面上の別のオブジェクトの前に来るか後ろに来るかを決定します。 一方、深度テストは、深度バッファ内のピクセルが更新されるかどうかを決定する条件です。 すでにご存知のとおり、ピクセルには RGB カラーで測定され、カラー バッファーに保存される割り当てられた値があります。 Z バッファは、カメラからの距離に関してピクセルの深さを測定する追加の値を追加しますが、その前面領域内にあるサーフェスのみが対象となります。これにより、2 つのピクセルの色は同じですが、深さは異なります。 オブジェクトがカメラに近づくほど、Z バッファ値は小さくなり、バッファ値が小さいピクセルは、大きい値のピクセルを上書きします。 この概念を理解するために、シーンにカメラといくつかのプリミティブがあり、それらはすべて「Z」空間軸上に配置されていると仮定します。 「バッファ」という言葉は、データが一時的に保存される「メモリ空間」を指します。したがって、Z バッファは、各ピクセルに割り当てられる、シーン内のオブジェクトとカメラの間の深度値を指します。 Unity の ZTest パラメーターのおかげで、Depth テストを制御できます。 淘汰 このプロパティは、組み込み RP と URP/HDRP の両方と互換性があり、ピクセル深度を処理するときにポリゴンのどの面を削除するかを制御します。 これは何を意味するのでしょうか?ポリゴン オブジェクトには内側のエッジと外側のエッジがあることを思い出してください。デフォルトでは、外側のエッジが表示されます (CullBack)。ただし、内側のエッジをアクティブにすることはできます。 オブジェクトの両端がレンダリングされます 淘汰。 デフォルトでは、オブジェクトの後端が表示されます。 カルバック。 オブジェクトの前端がレンダリングされます。 カルフロント。 このコマンドには、Back、Front、Off という 3 つの値があります。 「戻る」コマンドはデフォルトでアクティブになっています。ただし、通常、カリングに関連付けられたコード行は、最適化の目的でシェーダーには表示されません。パラメータを変更したい場合は、「Cull」という単語の後に使用したいモードを追加する必要があります。 Shader "Culling/OurShader" { Properties { [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", Float) = 0 } SubShader { // Cull Front // Cull Off Cull [_Cull] } } 「UnityEngine.Rendering.CullMode」依存関係を介して、 動的に設定することもできます。これは Enum であり、関数の引数として渡されます。 Unity インスペクターでカリングパラメータを CG/HLSL の使用 私たちのシェーダーでは、デフォルト ディレクティブの少なくとも 3 つのバリアントを見つけることができます。これらは、Cg または HLSL に含まれるプロセッサ ディレクティブです。これらの機能は、シェーダーが他の方法では認識できない特定の関数を認識してコンパイルできるようにすることです。 これにより、頂点シェーダー ステージを頂点シェーダーとして GPU にコンパイルできるようになります。 #pragma vertex vert. このディレクティブは pragma vertex と同じ機能を実行しますが、「frag」と呼ばれるフラグメント シェーダ ステージをコード内でフラグメント シェーダとしてコンパイルできる点が異なります。 #プラグマフラグメントフラグ。 前のディレクティブとは異なり、これには 2 つの機能があります。まず、multi_compile は、シェーダー内でさまざまな機能を持つバリアントを生成できるようにするバリアント シェーダーを指します。次に、「_fog」という単語には、Unity の Lighting ウィンドウのフォグ機能が含まれています。 [環境/その他の設定] に移動すると、シェーダーのフォグ オプションをアクティブまたは非アクティブにできます。 #pragma multi_compile_fog。 Cg/HLSL ファイルをシェーダーにプラグインすることもできます。通常、これは UnityCG.cginc をプラグインするときに行います。これには、フォグ座標、クリッピング用のオブジェクト位置、テクスチャ変換、フォグキャリーなどが含まれ、UNITY_PI 定数も含まれます。 Cg/HLSL でできる最も重要なことは、頂点シェーダーとフラグメント シェーダーの直接処理関数を記述し、これらの言語の変数やテクスチャ座標 (TEXCOORD0) などのさまざまな座標を使用することです。 #pragma vertex vert #pragma fragment frag v2f vert (appdata v) { // Ability to work with the vertex shader } fixed4 frag (v2f i) : SV_Target { // Ability to work with fragment shader } Cg/HLSL について詳しくは ご覧ください。 、こちらを シェーダーグラフ シェーダー グラフは、シェーダー言語の知識がなくてもソリューションを作成できる Unity の新しいソリューションです。ビジュアル ノードは、それを操作するために使用されます (ただし、それらをシェーダー言語と組み合わせることを禁止する人はいません)。シェーダー グラフは HDRP と URP でのみ動作します。 シェーダー グラフを使用する場合、Unity 2018 用に開発されたバージョンはベータ版であり、サポートを受けられないことに注意してください。 Unity 2019.1+ 用に開発されたバージョンはアクティブな互換性があり、サポートを受けられます。 もう 1 つの問題は、このインターフェイスで作成されたシェーダが異なるバージョンでは正しくコンパイルされない可能性が非常に高いことです。これは、アップデートのたびに新しい機能が追加されるためです。 では、シェーダーグラフはシェーダー開発に適したツールなのでしょうか?もちろん。また、グラフィックス プログラマーだけでなく、テクニカル デザイナーやアーティストも扱うことができます。 グラフを作成するには、Unity エディターで必要なタイプを選択するだけです。 始める前に、シェーダー グラフ レベルで頂点/フラグメント シェーダーを簡単に紹介しましょう。 ご覧のとおり、頂点シェーダー ステージには、Cg または HLSL シェーダーと同様に、Position(3)、Normal(3)、Tangent(3) という 3 つの定義されたエントリ ポイントがあります。通常のシェーダと比較すると、Position(3) = POSITION[n]、Normal(3) = NORMAL[n]、Tangent(3) = TANGENT[n] となることを意味します。 シェーダー グラフには 3 次元があるのに、Cg または HLSL には 4 次元があるのはなぜですか? ベクトルの 4 つの次元がそのコンポーネント W に対応し、ほとんどの場合、それは「1 または 0」であることを思い出してください。 W = 1 の場合、ベクトルは空間または点の位置に対応します。一方、W = 0 の場合、ベクトルは空間内の方向に対応します。 したがって、シェーダを設定するには、まずエディタに移動し、color - _Color と Texture2D - _MainTex という 2 つのパラメータを作成します。 ShaderLab プロパティとプログラムの間にリンクを作成するには、CGPROGRAM フィールドに変数を作成する必要があります。ただし、シェーダーグラフではこの処理が異なります。使用するプロパティをノード ワークスペースにドラッグ アンド ドロップする必要があります。 Texture2D を Sample Texture 2D ノードと連動させるために必要なのは、_MainTex プロパティの出力を入力 Texture(T2) に接続することだけです。 両方のノード (カラーとテクスチャ) を乗算するには、Multiply ノードを呼び出し、両方の値を入力ポイントとして渡すだけです。最後に、フラグメント シェーダーの段階でベース カラーのカラー出力を送信する必要があります。シェーダーを保存すれば完了です。最初のシェーダーの準備が整いました。 また、ノードセクションとグラフセクションに分かれた一般的なグラフ設定に目を向けることもできます。これらには、色の再現を変更できるカスタマイズ可能なプロパティがあります。ブレンディング、アルファ クリッピングなどのオプションがあります。さらに、シェーダー グラフ構成内のノードのプロパティをカスタマイズできます。 ノード自体は、ShaderLab で作成した特定の関数の類似物を提供します。例として、Clamp 関数のコードは次のとおりです。 void Unity_Clamp_float4(float4 In, float4 Min, float4 Max, out float4 Out) { Out = clamp(In, Min, Max); } このようにして、視覚的なグラフを犠牲にして作業を簡素化し、シェーダーを作成する時間を短縮できます。 結論 シェーダーについては、長時間にわたってたくさん話すことができますし、レンダリング プロセス自体についても触れることができます。この 基本をすべて説明しました。ここでは、レイトレーシング シェーダと Compute-Shading については説明していません。私はシェーダー言語について表面的に説明し、氷山の一角からのみプロセスを説明しました。 ガイドでは、Unity でのレンダリングに関する