目の前でゲームを作成する-パート2:CRT / LCDで写真をスタイリングするためのシェーダー

今回はテクノロジーについて話しましょう。 この記事では、古いCRTのグラフィックスをスタイリングするためにUnityでシェーダーを作成する方法を説明します。 このようなシェーダーは、ピクセルアートや、古代の手法で画像をスタイリングするのに適しています。 彼らは虐待されるべきではありませんが、時々それは場所に使用することができます。 (特に明確にします-そのような効果を絶えず使用することを提案しません。しかし、例えば、スプラッシュ画面で-それは場所に来るかもしれません)。







そして、私はすぐに予約をします-シェーダーについて深く理解していませんが、読者にはさらに少ないことを期待しています。 したがって、シェーダーについては何も知らないか、ほとんど何も知らないということに基づいて書きます。 そして、はい、シェーダーの作業の基本を説明しようと思いますので、もしあなたがそれらについて何も知らないなら-ようこそ!







シェーダーとは何ですか?



ここで、次のことを知っておく必要があります。シェーダーは、各頂点(頂点シェーダー)およびレンダリングされたピクセル(ピクセルまたは「フラグメント」シェーダー)ごとにグラフィックカードプロセッサで実行される小さなプログラムです。



実際、テクスチャを三角形に引っ張るだけでもシェーダーです。 このようなシェーダーでは、頂点部分が三角形の頂点を計算し、ピクセル部分がテクスチャのピクセルを直接描画します。 そして、それに応じて、各ピクセルを描画するためにシェーダーが呼び出されます。 さらに、それらは並行して動作できます。



重要な発言。 各シェーダーは入力パラメーターを読み取り、出力を提供します。 何で、それは任意の順序で起こります。 最新のカードでは、多数のシェーダースレッドを並行して起動できます。 つまり、1つのシェーダーが座標(0、0)のピクセルを処理するとき、同時に他のシェーダーは座標(10、10)のピクセルを計算できます。



したがって、(0、1)のピクセルを処理する場合、シェーダーはピクセル(0、0)の処理結果を認識しません(アクセスできません)。 元の値のみを参照できます。 したがって、互いに依存する複数の効果を順番に適用する必要がある場合、ほとんどの場合、いくつかのシェーダーを作成する必要があります。


Unityでは、さまざまなシェーダー言語を使用できますが、CGをお勧めします。 OpenGLとDirectXの両方で正常にコンパイルされます。 したがって、2つの異なるシェーダーを記述する必要はありません。



さて、次の瞬間-画像の後処理を実装するため(これはまさに計画通りです)-スプライト自体のシェーダーではなく、画面全体の共通シェーダーを記述する必要があります。 より正確には、最初にレンダリングがテクスチャに向けられ、シェーダーを既に使用しているこのテクスチャが画面に描画されます。 はい、このためには、UnityパッケージのProバージョンが必要です。



だから戦いに



最初に必要なことは、カメラ全体に対してシェーダーを作成する方法を学ぶことです。シェーダーは何も変更しません。



これを行うには、新しいシェーダー(拡張子が.shaderのファイル)を作成し、このディスクをそこにコピーします。



Shader "Custom/CRTShader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" #pragma target 3.0 struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; uniform sampler2D _MainTex; v2f vert(appdata_img v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord); return o; } half4 frag(v2f i): COLOR { half4 color = tex2D(_MainTex, i.uv); return color; } ENDCG } } FallBack "Diffuse" }
      
      





主なポイントについて説明します。



少し残った。 カメラにシェーダーを適用する必要があります。



これを行うには、C#で別の制御スクリプトを作成します。

非表示のテキスト
 using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Camera))] public class TVShader : MonoBehaviour { public Shader shader; private Material _material; protected Material material { get { if (_material == null) { _material = new Material(shader); _material.hideFlags = HideFlags.HideAndDontSave; } return _material; } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (shader == null) return; Material mat = material; Graphics.Blit(source, destination, mat); } void OnDisable() { if (_material) { DestroyImmediate(_material); } } }
      
      





カメラに投げて、「shader」フィールドにシェーダーを指定するだけです。



このビジネスが機能することを理解する方法は? 「 return color



」の前に、シェーダーでcolor.r = 0;



ようなものを書き込もうとしcolor.r = 0;



すべてが正常であれば、赤い色のない写真が得られます。



そこで、シェーダーを見つけました。



エフェクトの実装を取得します。



何を達成したいですか? まず、画像がカラーRGBピクセルで構成されている場合の効果を実現してみましょう。 つまり、このように:





それを行う方法はかなり明白です。 3ピクセルのサイクルでは、画面上の各ピクセルのR、G、Bコンポーネントのみを残す必要があります。



タスク番号1-ピクセルシェーダーの現在のポイントの画面座標を取得します。



これを行うには、頂点シェーダーで何かをカウントし、ピクセルのものに転送する必要があります。 上記のように、頂点シェーダーとピクセルシェーダーの間のデータ交換には、現在2つのフィールドpos



uv



があるv2f



コンストラクトがv2f



れます。 そこに追加:

 float4 scr_pos : TEXCOORD1;
      
      





また、頂点シェーダーに線を追加します。

 o.scr_pos = ComputeScreenPos(o.pos);
      
      





ピクセルシェーダーで、(0 ... 1)の範囲の画面座標を取得します。 ピクセルが必要です。 これも簡単に行えます:

 float2 ps = i.scr_pos.xy *_ScreenParams.xy / i.scr_pos.w;
      
      





やった! ps



、画面上にピクセル座標があります。 その後、すべてが非常に簡単です。 次のようなものを書く必要があります。

 int pp = (int)ps.x % 3; //     3 float4 outcolor = float4(0, 0, 0, 1); if (pp == 1) outcolor.r = color.r; else if (pp == 2) outcolor.g = color.g; else outcolor.b = color.b; return outcolor;
      
      





次のようなものが得られます。





2つのポイントがすぐに明らかになります。まず、効果が非常に強くなり、次に、画像が暗くなったことがわかりました。 神に感謝します。最初の問題を修正したら、2番目の問題も修正されます。



R / G / Bに従って厳密に分離するのではなく、すべてのコンポーネントを異なる比率で残すことをお勧めします。 つまり、「赤」列には100%のRと、約50%のGとBが残ります。さらに、このビジネスをカスタマイズできればさらに良いでしょう。



実際、この変換は、色に特定の乗数を掛けることで実行できます。 Rのみを残すには、 color



float4(1, 0, 0, 1)



を掛ける必要があります(4番目のコンポーネントはアルファであり、変更しません)。 係数を調整します。 つまり、赤の列に(1、k1、k2、1)を掛け、緑の列に(k2、1、k1、1)を掛け、青の列に(k1、k2、1、1)を掛けます。



まず、シェーダーの最初に2つのパラメーターの説明を追加します。

 _VertsColor("Verts fill color", Float) = 0 _VertsColor2("Verts fill color 2", Float) = 0
      
      





次に、リンクを記述します。

 uniform float _VertsColor; uniform float _VertsColor2;
      
      





ピクセルシェーダーコードに移動して、色を操作します。

 if (pp == 1) { muls.r = 1; muls.g = _VertsColor2; } else if (pp == 2) { muls.g = 1; muls.b = _VertsColor2; } else { muls.b = 1; muls.r = _VertsColor2; } color = color * muls;
      
      





Unityでこれらのパラメーターを管理する方法を学ぶだけです。 C#で記述しましょう。

 [Range(0, 1)] public float verts_force = 0.0f; [Range(0, 1)] public float verts_force_2 = 0.0f;
      
      





OnRenderImageメソッドで、Graphics.Blitの前に追加します。

 mat.SetFloat("_VertsColor", 1-verts_force); mat.SetFloat("_VertsColor2", 1-verts_force_2);
      
      





ここでは、1を引いてより視覚的にします。 パラメータが大きいほど、列の調光が強くなります。



すべてを正しく行った場合、カメラを選択するときにUnityインスペクターにスライダーが表示されます。





効果を見てみましょう:





より良いが、それでも明るさが欲しい。 シェーダーに明るさとコントラストの調整を追加しましょう。

 _Contrast("Contrast", Float) = 0 _Br("Brightness", Float) = 0 .... uniform float _Contrast; uniform float _Br; .... color += (_Br / 255); color = color - _Contrast * (color - 1.0) * color *(color - 0.5);
      
      





C#スクリプト:

  [Range(-3, 20)] public float contrast = 0.0f; [Range(-200, 200)] public float brightness = 0.0f; ... mat.SetFloat("_Contrast", contrast); mat.SetFloat("_Br", brightness);
      
      





結果:



(コントラスト= 2.1、輝度= 27)



次に、スキャンラインを実装しましょう。 ここではすべてが簡単です。 3行ごとに暗くする必要があります。

 if ((int)ps.y % 3 == 0) muls *= float4(_ScansColor, _ScansColor, _ScansColor, 1);
      
      











そして最後の仕上げはブルーム効果です。 たとえば、このようなシェーダーを使用できます



できた! 記事の上部から写真を取得します!







はい、そしてもちろん-このシェーダーは、私の例のように、トリプルピクセルで最適に見えます。



UPD :以下のコメントで示唆されているように、1つのテクスチャに別のテクスチャを掛けるだけでこの問題全体を解決できます。 つまり バンドの強度の指定されたパラメーターに従って、テクスチャテンプレートをレンダリングし、乗算を実行します。 速度の点ではより高速になりますが、この記事の目的は最適なシェーダーを書くことではなく、一般的な原理を示すことでした。



シリーズのすべての記事:

  1. アイデア、ビジョン、設定の選択、プラットフォーム、配信モデルなど。
  2. CRT / LCDの下で写真をスタイリングするためのシェーダー
  3. スクリプト言語をUnity(UniLua)に固定します
  4. パレットによるフェードイン用のシェーダー(la NES)
  5. 小計(プロトタイプ)
  6. PRインディーズゲームについて話しましょう
  7. Unityの2Dアニメーション(「フラッシュのような」)
  8. Unityでのカットシーンのビジュアルスクリプト(uScript)



All Articles