スプラトゥーンでダメージを受けた時みたいな画面エフェクトを作りたくて作りました。
スプラトゥーンには及びませんが、だいたいこんな感じになりました。
でろでろエフェクト
テクスチャを調整したら、もっとスプラ感が出るんじゃないかと思います。
まずはShader、
Shader "Damage"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_NoiseTex ("Damage Tex", 2D) = "white" {}
_VignetteTex ("Vignette Tex", 2D) = "white" {}
}
SubShader
{
Pass
{
Cull Off ZWrite Off ZTest Always
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma target 3.0
#pragma glsl
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform sampler2D _NoiseTex;
uniform sampler2D _VignetteTex;
uniform float _Timer;
uniform float _DamageMag;
uniform float _Darkness;
uniform float _Sharpness;
uniform float _AspectRatio;
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 texcoord : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color;
return OUT;
}
half4 _MainTex_ST;
float4 frag(v2f i) : COLOR
{
float2 org_uv = UnityStereoScreenSpaceUVAdjust(i.texcoord, _MainTex_ST);
float2 adjusted_uv = org_uv.xy;//アスペクト比を考慮した uv
adjusted_uv.x *= _AspectRatio;//アスペクト比の考慮
float noise0 = tex2D(_NoiseTex, float2( adjusted_uv.x + _Timer, adjusted_uv.y )).x;
float noise1 = tex2D(_NoiseTex, float2( adjusted_uv.x, adjusted_uv.y + _Timer )).x;
float vignette = clamp( ( tex2D(_VignetteTex, org_uv.xy).r * noise0 * noise1 + _DamageMag ) * _Sharpness, 0.0f, 1.0f );
vignette = 1.0f - vignette * _Darkness;
float4 color = tex2D(_MainTex, org_uv.xy) * vignette;
return color;
}
ENDCG
}
}
}
仕組みとしては、周辺を暗くするテクスチャにノイズ用のテクスチャを重ね合わせています。
ノイズ用のテクスチャは、X方向に移動するのとY方向に移動するのを重ね合わせて見た目のランダム性が高まるようにしています。
ノイズ用のテクスチャは、こういう感じのを使っています。
このテクスチャはフォトショップのフィルターで、ノイズを加える -> 雲模様 -> 波型の歪み として作ったものを、レベル補正してコントラスト上げて、ボカして、端でちゃんとループするようにしたものです。
周辺を暗くする用のテクスチャは、こういう感じです。
次にc#スクリプト側はこんな感じです↓
using UnityEngine;
using System.Collections;
public class DamageEffect : MonoBehaviour {
[SerializeField]
[Range(0.0f, 1.0f)]
private float timer = 0.5f;
[Range(0f, 1f)]
public float speed = 1f;
[SerializeField]
[Range(0f, 1f)]
protected float damage = 0.5f;
[SerializeField]
[Range(0f, 1f)]
protected float darkness = 0.5f;
[SerializeField]
[Range(0f, 3f)]
protected float sharpness = 1.0f;
[SerializeField]
protected Material material;
void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture)
{
material.SetFloat("_Timer", timer );
material.SetFloat("_DamageMag", ( damage - 1.0f ) );
material.SetFloat("_Darkness", darkness );
material.SetFloat("_Sharpness", Mathf.Pow( 10.0f, sharpness ) );
material.SetFloat("_AspectRatio", sourceTexture.width/(float)sourceTexture.height );
Graphics.Blit(sourceTexture, destTexture, material);
}
void Update ()
{
timer += Time.deltaTime * speed;
timer = Mathf.Repeat( timer, 1.0f );
}
}
特に変わったところはないです。
使い方は、
- c#スクリプトをカメラに引っ付ける
- 先のシェーダーを元にMaterialを作る
- MaterialのTableTexにテクスチャを当てる
- カメラにひっつけたスクリプトにMaterialをassignする
という感じです。
説明が雑くてすいません。質問がありましたらコメント欄でお願いしますm(_ _)M