-->



using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
/// <summary>
/// Universal Render Dataに登録させるポストプロセス処理のクラス
/// </summary>
public class URPGrabRenderFeature : ScriptableRendererFeature
{
//介入する描画処理がGameViewのカメラかどうか。シェーダー側では基本GameViewのカメラにだけ処理を実行させる
//(後述の_URPGrabTextureはGameViewから画面をキャプチャするので、それ以外のViewで使用するとおかしくなる)
private readonly int _isGameViewId = Shader.PropertyToID("_IsGameView");
private URPGrabRenderPass _pass;
/// <summary>
/// URPGrabRenderPassのインスタンスを生成
/// </summary>
public override void Create() => _pass = new URPGrabRenderPass();
/// <summary>
/// Unityに対しURPGrabRenderPass.RecordRenderGraphのロジックをカメラ描画工程に追加するように依頼
/// </summary>
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// この描画工程がGameViewのカメラかそれ以外かの情報だけは、この段階で全シェーダーに即時送信する
bool isGameViewCamera = renderingData.cameraData.cameraType == CameraType.Game;
Shader.SetGlobalInt(_isGameViewId, isGameViewCamera? 1 : 0);
//描画工程を追加
renderer.EnqueuePass(_pass);
}
}
/// <summary>
///具体的なロジック処理クラス
/// </summary>
public class URPGrabRenderPass : ScriptableRenderPass
{
private readonly int _textureId = Shader.PropertyToID("_URPGrabTexture");
private readonly int _texelSizeId = Shader.PropertyToID("_URPGrabTexture_TexelSize");
/// <summary>
/// 初期化処理、このポストプロセスの実行タイミングを定義しているだけ
/// </summary>
public URPGrabRenderPass()
{
//カメラ描画処理が全て終わってからURPGrabRenderPass.RecordRenderGraphを実行させる事をUnityに伝える
renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
}
/// <summary>
/// 追加される新しい工程に必要なデータ(Context)を受け渡すのためクラス
/// </summary>
private class PassData
{
public TextureHandle destination; //テクスチャコピー先のメモリ領域
public int textureId;
public int texelSizeId;
public Vector4 texelSize;
}
/// <summary>
///カメラの画角に映っている情報をテクスチャとしてシェーダーに渡す処理
/// </summary>
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
//今この瞬間にカメラに書き込んでいる画面の色や深度のデータを取得
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
//resourceDataからカメラが描画しているテクスチャのメモリ領域を取得
TextureHandle originalTextureHandle = resourceData.activeColorTexture;
//これから生成するテクスチャの設計図を作成
TextureDesc grabTextureDesc;
try
{
//テクスチャの設計図をコピー
grabTextureDesc = renderGraph.GetTextureDesc(originalTextureHandle);
}
catch
{
return;
}
//設計図を出力用に上書き
grabTextureDesc.name = "URPGrabTexture";
grabTextureDesc.clearBuffer = false;
grabTextureDesc.msaaSamples = MSAASamples.None;
grabTextureDesc.depthBufferBits = 0;
var texelSize = new Vector4(1.0f / grabTextureDesc.width, 1.0f / grabTextureDesc.height,
grabTextureDesc.width, grabTextureDesc.height);
//設計図から新しいメモリ領域を作成
TextureHandle grabTextureHandle = renderGraph.CreateTexture(grabTextureDesc);
//Blitで実物のテクスチャデータを丸々コピー
renderGraph.AddBlitPass(originalTextureHandle, grabTextureHandle, Vector2.one, Vector2.zero, passName: "BlitCopyToGrabTexture");
using (var builder = renderGraph.AddRasterRenderPass("SetGrabTextureToGlobalState", out PassData passData))
{
//読み込み対象をbuilderに登録
builder.UseTexture(grabTextureHandle, AccessFlags.Read);
//この描画工程の中でのみ「グローバル変数(全シェーダー共通の設定)」を書き換えることを許可する
builder.AllowGlobalStateModification(true);
//コピーしたを画像をpassDataに代入
passData.destination = grabTextureHandle;
passData.textureId = _textureId;
passData.texelSizeId = _texelSizeId;
passData.texelSize = texelSize;
//予約されたスケジュールが実行された時の処理
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
//GPUに対して「このテクスチャ(destination)を、このIDの名前で公開せよ」と命令を出す
//これにより、全シェーダーの _URPGrabTexture に中身が流し込まれる
context.cmd.SetGlobalTexture(data.textureId, data.destination);
context.cmd.SetGlobalVector(data.texelSizeId, data.texelSize);
});
}
}
}



Shader "URPGrab/NoiseWave"
{
Properties
{
[HideInInspector]_MainTex("-",2D)="white"{}
_FluctPow("FluctPow", Range(0.01, 0.1)) = 0.05 //歪みの強さ
_AnimSpeed("AnimSpeed", Range(0.1, 10)) = 0.2 //歪みが変化するスピード
[Space(10)]
[Toggle] _UseAutoAnim("UseAutoAnim", float) = 0 //経過時間によって自動でアニメーションをするか
_ManualAnimVal("ManualAnimVal", float) = 0 //AutoAnimを使わない場合の、アニメの移動値
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
}
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
half2 uv : TEXCOORD0;
float4 positionOS : POSITION; //オブジェクト空間座標(対象の大元の座標と寸法)
};
struct Varyings
{
half2 uv : TEXCOORD0;
float4 positionCS : SV_POSITION; //クリップ空間座表(カメラの四角い画角内での対象の座標)
float4 positionVP : TEXCOORD1; //ビューポート空間座標(クリップ空間座表 -w ~ +w を 0 ~ w の範囲に修正した座標)
};
//URPGrabScreenFeatureから全画面の色情報などを受け取る
int _IsGameView;
TEXTURE2D(_URPGrabTexture);
SAMPLER(sampler_URPGrabTexture);
half4 _URPGrabTexture_TexelSize;
//SRP Batcherを適用
CBUFFER_START(UnityPerMaterial)
//Propertiesに対応する変数
float _FluctPow;
float _AnimSpeed;
float _UseAutoAnim;
float _ManualAnimVal;
CBUFFER_END
//ランダムノイズ(粗いノイズ、0~1の値がランダムに広がる)
float random (half2 p)
{
p = half2(dot(p, float2(127.1, 311.7)),
dot(p, half2(269.5, 183.3)));
return -1.0 + 2.0 * frac(sin(p) * 43758.5453123);
}
//パーリンノイズ(隣接する値が少しずつ異なる滑かなノイズ、ランダムノイズを参照する)
float perlinNoise(half2 st)
{
half2 p = floor(st);
half2 f = frac(st);
half2 u = f * f * (3.0 - 2.0 * f);
float v00 = random(p + half2(0, 0));
float v10 = random(p + half2(1, 0));
float v01 = random(p + half2(0, 1));
float v11 = random(p + half2(1, 1));
return lerp(lerp(dot(v00, f - half2(0, 0)), dot(v10, f - half2(1, 0)), u.x),
lerp(dot(v01, f - half2(0, 1)), dot(v11, f - half2(1, 1)), u.x),
u.y) + 0.5f;
}
//fBmノイズ(究極に滑らかなノイズ、パーリンノイズを参照する)
float fBm (half2 st)
{
float f = 0;
half2 q = st;
f += 0.5000*perlinNoise( q ); q = q*2.01;
f += 0.2500*perlinNoise( q ); q = q*2.02;
f += 0.1250*perlinNoise( q ); q = q*2.03;
f += 0.0625*perlinNoise( q ); q = q*2.01;
return f;
}
//頂点シェーダー
Varyings vert(Attributes input)
{
Varyings output;
//uv座標を代入
output.uv = input.uv;
//オブジェクト空間座標をクリップ空間、ビューポート空間座標にそれぞれ変換
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.positionVP = ComputeScreenPos(output.positionCS);
return output;
}
//ピクセルシェーダー
half4 frag (Varyings input) : SV_Target
{
//GameViewのカメラ以外に対しては半透明ピンクを返すだけ
if (_IsGameView == 0)
{
return half4(1, 0, 1, 0.2);
}
//ビューポート空間座標から奥行を省いて座標を平面化する
float2 screenUV = input.positionVP.xy / input.positionVP.w;
float2 nUv = screenUV;
//UseAutoAnimがOnの時は時間経過によってノイズの位置をずらす、Offの時はManualAnimValを参照する
nUv.y += lerp(_ManualAnimVal * _AnimSpeed, _Time.y * _AnimSpeed, _UseAutoAnim);
//fBmノイズで滑らかなノイズを作成した上で、値の範囲を0~1から-1~1に拡大
float noise = 2 * fBm(nUv) -1 ;
//画面の上下端では歪みを実行させないためのnoise配合率を算出
half isUvBotom = step(screenUV.y, 0.1);
half rate1 = isUvBotom * (screenUV.y / 0.1) + (1 - isUvBotom) * 1;
half isUvUp = 1 - step(screenUV.y, 0.9);
half rate2 = isUvUp * ((0.1 - (screenUV.y - 0.9)) / 0.1) + (1 - isUvUp) * 1;
half noiseRate = rate1 * rate2;
//noiseの値は-1~1の範囲に収まっている
//これに_FluctPowを掛けると、最小で-0.01~0.01、最大で-0.1~0.1の範囲に収まる
//その修正された値で、対象画像のuv座標のy軸だけ移動させ、描画するピクセルをズラす
screenUV.y += noiseRate * (noise * _FluctPow);
//Grabした画像に変形させたuv座標を適用させ歪ませる
return SAMPLE_TEXTURE2D(_URPGrabTexture, sampler_URPGrabTexture, screenUV);
}
ENDHLSL
}
}
}





Properties
{
[HideInInspector]_MainTex("-",2D)="white"{}
_FluctPow("FluctPow", Range(0.01, 0.1)) = 0.05 //歪みの強さ
_AnimSpeed("AnimSpeed", Range(0.1, 10)) = 0.2 //歪みが変化するスピード
[Space(10)]
[Toggle] _UseAutoAnim("UseAutoAnim", float) = 0 //経過時間によって自動でアニメーションをするか
_ManualAnimVal("ManualAnimVal", float) = 0 //AutoAnimを使わない場合の、アニメの移動値
}

//UseAutoAnimがOnの時は時間経過によってノイズの位置をずらす、Offの時はManualAnimValを参照する
nUv.y += lerp(_ManualAnimVal * _AnimSpeed, _Time.y * _AnimSpeed, _UseAutoAnim);
DOTween.To(() => star.material.GetFloat("_ManualAnimVal"), (val) =>
{
star.material.SetFloat("_ManualAnimVal", val);
}, 50, 3f);