Skip to content

Instantly share code, notes, and snippets.

@rngtm
Last active August 28, 2023 23:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rngtm/ac4a7ae611db1fe5553fe925b1fe5901 to your computer and use it in GitHub Desktop.
Save rngtm/ac4a7ae611db1fe5553fe925b1fe5901 to your computer and use it in GitHub Desktop.
Spriteにガウシアンブラーを適用した結果をMeshRendererで表示するスクリプトとシェーダー (ブラーの復習に書いた)
Shader "Hidden/GaussianBlur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Variance ("Variance", Float) = 1.0
_Range ("Range (px)", Float) = 5.0
_GaussianSum ("Gaussian Sum", Float) = 1.0
_KernelSize ("Kernel Size", Float) = 5
}
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;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize; // x: 1/width y:1/height
float _Variance; // 標準偏差
float _Range; // サンプリング範囲
float _GaussianSum; // ガウス分布の合計
int _KernelSize; // カーネルの大きさ
#define V (_Variance) // 分散
// 1次元ガウス分布
float Gauss(float x)
{
return exp(- x * x / (2.0 * V))
/ sqrt(2.0 * V * UNITY_TWO_PI);
}
// 2次元ガウス分布
float Gauss(float2 p)
{
return exp(- dot(p, p) / (2.0 * V))
/ sqrt(2.0 * V * UNITY_PI);
}
fixed4 frag(v2f i) : SV_Target
{
float4 c = 0;
#define KERNEL_SIZE _KernelSize
#define N (KERNEL_SIZE * KERNEL_SIZE)
for (int y = -KERNEL_SIZE/2; y <= KERNEL_SIZE/2; y++)
{
float ty = (float)y / KERNEL_SIZE;
for (int x = -KERNEL_SIZE/2; x <= KERNEL_SIZE/2; x++)
{
float tx = (float)x / KERNEL_SIZE;
float2 p = float2(tx, ty);
float2 uv = i.uv + p * _Range * _MainTex_TexelSize.xy;
c += Gauss(p) * tex2D(_MainTex, uv) / _GaussianSum;
}
}
c.a = 1.0;
return c;
}
ENDCG
}
}
}
using Rendering.Utility;
using UnityEngine;
public class SpriteBlur : MonoBehaviour
{
[SerializeField] private Sprite sprite;
[SerializeField, Range(0.01f, 2f)] private float variance = 1f;
[SerializeField] private float range = 5f;
[SerializeField, Range(1, 9)] private int kernelSize = 5;
private MeshRenderer meshRenderer;
private RenderTexture renderTexture;
private Material _renderMaterial;
private Shader blurShader;
private Material _blurMaterial;
private float _gaussianSum;
private void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
_blurMaterial = CreateGaussianBlurMaterial();
_renderMaterial = meshRenderer.material;
CreateRenderTexture();
_renderMaterial.mainTexture = renderTexture;
ExecuteBlur();
}
private void OnValidate()
{
ExecuteBlur();
}
private void ExecuteBlur()
{
if (sprite == null)
{
return;
}
if (renderTexture == null)
{
return;
}
if (_blurMaterial == null)
{
return;
}
_gaussianSum = GaussianDistribution.GetSum(kernelSize, variance);
_blurMaterial.SetFloat("_GaussianSum", _gaussianSum);
_blurMaterial.SetFloat("_Variance", variance);
_blurMaterial.SetFloat("_Range", range);
_blurMaterial.SetInt("_KernelSize", kernelSize);
Graphics.Blit(sprite.texture, renderTexture, _blurMaterial);
}
private void OnDestroy()
{
DestroyRenderTexture();
_renderMaterial.mainTexture = null;
DestroyMaterial();
}
private Material CreateGaussianBlurMaterial()
{
return CreateMaterial("Hidden/GaussianBlur");
}
static Material CreateMaterial(string shaderName)
{
var shader = Shader.Find(shaderName);
if (shader == null)
{
Debug.LogError($"Fail to find shader: {shaderName}");
}
return new Material(shader);
}
private void DestroyMaterial()
{
Destroy(_renderMaterial);
Destroy(_blurMaterial);
_blurMaterial = null;
blurShader = null;
}
private void CreateRenderTexture()
{
renderTexture = new RenderTexture(512, 512, 0);
}
private void DestroyRenderTexture()
{
renderTexture.Release();
renderTexture = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment