目次
はじめに:
ポストエフェクトとは、レンダリング結果に効果をかけるエフェクトです
Unityではカメラのオブジェクトを対象にする形で実装が可能で、
デフォルトでも様々な効果が用意されていますが、自作することもできます。
また現在は新しい方法としてPost Processing Stackというパッケージがあり、こちらを利用するとの高品質なエフェクトをオブジェクトの位置やレイヤーで判断して処理することも可能です。
今回は旧来の方法を扱います。
Unity公式:ポストプロセス
今回のサンプルとして
・設定変更で色合い、鮮やかさ、明るさの変更(HSV)
・動作するノイズエフェクト
・二つのエフェクトを重ねる
以上のテストを行います。
環境:
Unity(2018.4.3f1)で実装していきます。
デフォルトとして実装されている Image effect shader の改変をする形で進めていきます。
実装:
プロジェクトを作成して、shaderの効果が視覚的に実感できるようにオブジェクトを配置します。
この時使用するマテリアルは今回あまり関係はないので、Project Create/Material (standard shader) で作成し、ある程度極端な色に調整しておきます。
色相などを変化させるShaderを用意します。
今回はこちらを参考にさせていただきました、ImageEffect用に対応します。
Projectウィンドウから Create/Shader/Image Effect Shader でデフォルトのシェーダを作成して、名前をHsvColorに変更、その中身を以下に書き換えます。
(デフォルトは色反転シェーダが入っています)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
Shader "Hidden/HsvColor" { Properties { [NoScaleOffset] _MainTex("Base (RGB)", 2D) = "white" {} _Hue("Hue", Range(0.0, 360)) = 0 _Vivid("Vivid", Range(0, 1)) = 1 _Blight("Blight", Range(0, 1.0)) = 1 } SubShader { Tags { "RenderType" = "Opaque" } Pass { CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag sampler2D _MainTex; half _Hue, _Vivid, _Blight; struct vertexData { half4 vertex : POSITION; fixed2 uv : TEXCOORD0; }; struct v2f { half4 pos : SV_POSITION; fixed2 uv : TEXCOORD0; }; v2f vert(vertexData v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 shift(fixed4 color, fixed3 shift) { half VSU = shift.z * shift.y * cos(shift.x * .017453292); half VSW = shift.z * shift.y * sin(shift.x * .017453292); return fixed4( (0.299 * shift.z + 0.701 * VSU + 0.168 * VSW) * color.r + (0.587 * shift.z - 0.587 * VSU + 0.330 * VSW) * color.g + (0.114 * shift.z - 0.114 * VSU - 0.497 * VSW) * color.b, (0.299 * shift.z - 0.299 * VSU - 0.328 * VSW) * color.r + (0.587 * shift.z + 0.413 * VSU + 0.035 * VSW) * color.g + (0.114 * shift.z - 0.114 * VSU + 0.292 * VSW) * color.b, (0.299 * shift.z - 0.300 * VSU + 1.25 * VSW) * color.r + (0.587 * shift.z - 0.588 * VSU - 1.05 * VSW) * color.g + (0.114 * shift.z + 0.886 * VSU - .203 * VSW) * color.b, color.a ); } half4 frag(v2f i) : SV_Target { return fixed4(shift(tex2D(_MainTex, i.uv), fixed3(_Hue, _Vivid, _Blight))); } ENDCG } } } |
作製したShaderを右クリックしてそこから直接Materialを作成します。
Assets/HsvColor.shader という形でファイルが作成されます。
次にカメラを対象に、作成したシェーダを作用させるコードを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode, ImageEffectAllowedInSceneView] public class CameraFilter : MonoBehaviour { [SerializeField] private Material filter; private void OnRenderImage(RenderTexture src, RenderTexture dest) { Graphics.Blit(src, dest, filter); } } |
こちらをカメラにAddComponentして作成したマテリアルを設定します。
こちらで設定は完了です、作成したHidden_HsvColorのパラメータを変えることで
マテリアルの値変化による色相・鮮やかさ・明るさの変化テストが行えます
同じようにShaderファイルを作成してノイズ用コードも用意します。
こちらの記事を参考にさせていただきました、更新用の_Sizeもパラメータに追加しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
Shader "Hidden/NoiseColor" { Properties { _MainTex("Texture", 2D) = "white" {} _Size("Size", Float) = 1 } SubShader { Cull Off ZWrite Off ZTest Always 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; }; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } float rand(float3 co) { return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 45.5432))) * 43758.5453); } sampler2D _MainTex; half _Size; static const int blackheight = 1; static const float division = 768; static const float blackinterval = 6; static const float noisewidth = 0.01; fixed4 frag(v2f i) : SV_Target { int divisionindex = i.uv.y * division; int noiseindex = divisionindex / blackinterval; float3 timenoise = float3(0, int(_Time.x * 61), int(_Time.x * 83)); float noiserate = rand(timenoise) < 0.05 ? 10 : 1; float xnoise = rand(float3(noiseindex, 0, 0) + timenoise); xnoise = xnoise * xnoise - 0.5; xnoise = xnoise * noisewidth * noiserate; xnoise = xnoise * (_SinTime.w / 2 + 1.1); xnoise = xnoise + (abs((int(_Time.x * 2000) % int(division / blackinterval)) - noiseindex) < 5 ? 0.005 : 0); float2 uv = i.uv + float2(xnoise * _Size, 0); fixed4 col1 = tex2D(_MainTex, uv); fixed4 col2 = tex2D(_MainTex, uv + float2(0.005, 0)); fixed4 col3 = tex2D(_MainTex, uv + float2(-0.005, 0)); fixed4 col4 = tex2D(_MainTex, uv + float2(0, 0.005)); fixed4 col5 = tex2D(_MainTex, uv + float2(0, -0.005)); fixed4 col = (col1 * 4 + col2 + col3 + col4 + col5) / 8; col.rgb = divisionindex % blackinterval < blackheight ? float4(0, 0, 0, 1) : col.rgb; return col; } ENDCG } } } |
同じようにCameraFilterにマテリアルを設定しますが、
今度は_Sizeでパラメータを渡して更新する必要があるのでその部分だけ別実装します。
以下のコードを実装し、Cameraのcomponentとして追加してMaterialを設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class NoiseUpdate : MonoBehaviour { [SerializeField] Material _Mat; void Update() { _Mat.SetFloat("_Size", Random.Range(0.0f, 1.0f)); } } |
ノイズ処理用にCameraにComponentを追加していきます。
CamearFilterとNoiseUpdateを追加してNoiseのマテリアルを設定します。
こちらで設定は完了です。
Unityで実行すれば、HsvColorシェーダの値変更も合わせて、
横縞のノイズが走っている画面が作れたと思います。
まとめ:
Unityでのポストエフェクトは比較的低コストの実装で画面の見た目を大きく変えることが出来ますが処理負荷は画素数に比例して大きくなるので、多重に処理する場合には注意が必要です。
今回はGraphics.blitを使用する実装方法でしたが、Processingでも様々な画面効果を付与できるので、また試してみたいと思います。