-->




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/InvertColor"
{
Properties
{
[HideInInspector]_MainTex("-",2D)="white"{}
}
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"
//後述のLinearToSRGB、SRGBToLinearで必要なライブラリ
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
struct Attributes
{
float4 positionOS : POSITION; //オブジェクト空間座標(対象の大元の座標と寸法)
};
struct Varyings
{
float4 positionCS : SV_POSITION; //クリップ空間座表(カメラの四角い画角内での対象の座標)
float4 positionVP : TEXCOORD1; //ビューポート空間座標(クリップ空間座表 -w ~ +w を 0 ~ w の範囲に修正した座標)
};
//URPGrabRenderFeatureから全画面の色情報などを受け取る
int _IsGameView;
TEXTURE2D(_URPGrabTexture);
SAMPLER(sampler_URPGrabTexture);
Varyings vert (Attributes input)
{
Varyings output;
//オブジェクト空間座標をクリップ空間、ビューポート空間座標にそれぞれ変換
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;
//受け取った全画面情報から指定uv座標のピクセル色を抜き取る
half4 background = SAMPLE_TEXTURE2D(_URPGrabTexture, sampler_URPGrabTexture, screenUV);
//ピクセル色をリニア空間ルールから一旦ガンマ空間ルールへ変換
half3 sRGB = LinearToSRGB(background.rgb);
//ガンマ空間ルール上で色を反転
sRGB = abs(1 - sRGB);
//色をガンマ空間ルールからリニア空間ルールに戻す
half3 invertColor = SRGBToLinear(sRGB);
return half4(invertColor, 1);
}
ENDHLSL
}
}
}
//URPGrabRenderFeatureから全画面の色情報を受け取る
TEXTURE2D(_URPGrabTexture);
SAMPLER(sampler_URPGrabTexture);
//ビューポート空間座標から奥行を省いて座標を平面化する
float2 screenUV = input.positionVP.xy / input.positionVP.w;
//受け取った全画面情報から指定uv座標のピクセル色を抜き取る
half4 background = SAMPLE_TEXTURE2D(_URPGrabTexture, sampler_URPGrabTexture, screenUV);
//ピクセル色をリニア空間ルールから一旦ガンマ空間ルールへ変換
half3 sRGB = LinearToSRGB(background.rgb);
//ガンマ空間ルール上で色を反転
sRGB = abs(1 - sRGB);
//色をガンマ空間ルールからリニア空間ルールに戻す
half3 invertColor = SRGBToLinear(sRGB);



