加入很多新内容,这波一块交了

This commit is contained in:
FloatGaming
2026-04-08 20:53:41 +08:00
parent d9376833b6
commit 85dfff28dd
128 changed files with 14546 additions and 474 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3211f9d28619bb347a531aa2252d51eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,159 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalAfterimageInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalAfterimageInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Afterimage")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalAfterimageRendererFeature>(out GlobalAfterimageRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalAfterimageRendererFeature>();
feature.name = "Global Afterimage Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalAfterimageVolume>(out _))
return;
GlobalAfterimageVolume component = profile.Add<GlobalAfterimageVolume>(true);
component.active = false;
component.opacity.overrideState = true;
component.opacity.value = 0f;
component.scale.overrideState = true;
component.scale.value = 1.05f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e5a6ce7542914bd428842b45057360d0
@@ -0,0 +1,167 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalDistortionInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalDistortionInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Distortion")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalDistortionRendererFeature>(out GlobalDistortionRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalDistortionRendererFeature>();
feature.name = "Global Distortion Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalDistortionVolume>(out _))
return;
GlobalDistortionVolume component = profile.Add<GlobalDistortionVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.noiseStrength.overrideState = true;
component.noiseStrength.value = 0.16f;
component.radialStrength.overrideState = true;
component.radialStrength.value = 0.35f;
component.noiseScale.overrideState = true;
component.noiseScale.value = 12f;
component.center.overrideState = true;
component.center.value = new Vector2(0.5f, 0.5f);
component.edgeFade.overrideState = true;
component.edgeFade.value = 1.25f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8da344594051c8647abdb52bec165007
@@ -0,0 +1,167 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalGlitchInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalGlitchInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Glitch")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalGlitchRendererFeature>(out GlobalGlitchRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalGlitchRendererFeature>();
feature.name = "Global Glitch Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalGlitchVolume>(out _))
return;
GlobalGlitchVolume component = profile.Add<GlobalGlitchVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.blockStrength.overrideState = true;
component.blockStrength.value = 0.45f;
component.colorSplit.overrideState = true;
component.colorSplit.value = 0.01f;
component.jitterAmount.overrideState = true;
component.jitterAmount.value = 0.4f;
component.stripFrequency.overrideState = true;
component.stripFrequency.value = 48f;
component.scanlineStrength.overrideState = true;
component.scanlineStrength.value = 0.18f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f7effde50fff3c34c8c188a696cf3bcf
@@ -0,0 +1,157 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalMonochromeInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalMonochromeInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Monochrome")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalMonochromeRendererFeature>(out GlobalMonochromeRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalMonochromeRendererFeature>();
feature.name = "Global Monochrome Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalMonochromeVolume>(out _))
return;
GlobalMonochromeVolume component = profile.Add<GlobalMonochromeVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9530a18d124454244a6fc70d833e3182
@@ -0,0 +1,178 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
public class GlobalAfterimageRendererFeature : ScriptableRendererFeature
{
[Tooltip("When the custom afterimage pass should execute.")]
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
private Material material;
private GlobalAfterimagePass pass;
public override void Create()
{
if (pass == null)
pass = new GlobalAfterimagePass();
pass.renderPassEvent = renderPassEvent;
EnsureMaterial();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!EnsureMaterial())
return;
Camera camera = renderingData.cameraData.camera;
if (camera == null)
return;
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
if (!renderingData.cameraData.postProcessEnabled)
return;
GlobalAfterimageVolume settings = VolumeManager.instance.stack.GetComponent<GlobalAfterimageVolume>();
bool hasVolume = settings != null && settings.active;
float runtimeOpacity = GlobalAfterimageRuntimeController.RuntimeOpacity;
float baseOpacity = hasVolume ? settings.opacity.value : 0f;
float finalOpacity = Mathf.Clamp01(Mathf.Max(baseOpacity, runtimeOpacity));
if (finalOpacity <= 0.0001f)
return;
if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value)
return;
float runtimeScale = Mathf.Max(1f, GlobalAfterimageRuntimeController.RuntimeScale);
float baseScale = hasVolume ? settings.scale.value : 1.05f;
float finalScale = Mathf.Max(baseScale, runtimeScale);
bool captureRequested = GlobalAfterimageRuntimeController.ConsumeCaptureRequest();
pass.Setup(material, finalOpacity, finalScale, captureRequested, renderingData.cameraData.cameraTargetDescriptor);
renderer.EnqueuePass(pass);
}
protected override void Dispose(bool disposing)
{
if (pass != null)
{
pass.Dispose();
pass = null;
}
if (material != null)
{
CoreUtils.Destroy(material);
material = null;
}
}
private bool EnsureMaterial()
{
if (material != null)
return true;
Shader shader = Shader.Find("Hidden/Bansonic/GlobalAfterimage");
if (shader == null)
return false;
material = CoreUtils.CreateEngineMaterial(shader);
return material != null;
}
private sealed class GlobalAfterimagePass : ScriptableRenderPass
{
private static readonly int OpacityId = Shader.PropertyToID("_AfterimageOpacity");
private static readonly int ScaleId = Shader.PropertyToID("_AfterimageScale");
private static readonly int SnapshotTexId = Shader.PropertyToID("_SnapshotTex");
private Material passMaterial;
private float opacity;
private float scale;
private bool captureRequested;
private RenderTextureDescriptor descriptor;
private RTHandle compatibilityCopy;
private RTHandle snapshotTexture;
public void Setup(Material material, float passOpacity, float passScale, bool passCaptureRequested, RenderTextureDescriptor targetDescriptor)
{
passMaterial = material;
opacity = passOpacity;
scale = Mathf.Max(1f, passScale);
captureRequested = passCaptureRequested;
descriptor = targetDescriptor;
descriptor.msaaSamples = 1;
descriptor.depthBufferBits = 0;
requiresIntermediateTexture = true;
RenderingUtils.ReAllocateHandleIfNeeded(ref snapshotTexture, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalAfterimageSnapshot");
}
public void Dispose()
{
compatibilityCopy?.Release();
compatibilityCopy = null;
snapshotTexture?.Release();
snapshotTexture = null;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (passMaterial == null || snapshotTexture == null)
return;
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (resourceData.isActiveTargetBackBuffer)
return;
ApplyMaterialProperties();
TextureHandle source = resourceData.activeColorTexture;
TextureHandle importedSnapshot = renderGraph.ImportTexture(snapshotTexture);
if (captureRequested)
{
renderGraph.AddBlitPass(source, importedSnapshot, Vector2.one, Vector2.zero, passName: "Global Afterimage Capture");
}
TextureDesc tempDesc = renderGraph.GetTextureDesc(source);
tempDesc.name = "CameraColor-GlobalAfterimageTemp";
tempDesc.clearBuffer = false;
TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc);
RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0);
renderGraph.AddBlitPass(effectParameters, passName: "Global Afterimage Effect");
renderGraph.AddBlitPass(tempTexture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Global Afterimage Restore");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (passMaterial == null || snapshotTexture == null)
return;
ApplyMaterialProperties();
RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalAfterimageCompatibilityCopy");
CommandBuffer cmd = CommandBufferPool.Get("Global Afterimage Pass");
if (captureRequested)
{
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, snapshotTexture);
}
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy);
Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void ApplyMaterialProperties()
{
passMaterial.SetFloat(OpacityId, opacity);
passMaterial.SetFloat(ScaleId, scale);
if (snapshotTexture != null)
passMaterial.SetTexture(SnapshotTexId, snapshotTexture);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a28c239b9c2736e489a75bd286167cb9
@@ -0,0 +1,125 @@
using UnityEngine;
public class GlobalAfterimageRuntimeController : MonoBehaviour
{
public static GlobalAfterimageRuntimeController Instance { get; private set; }
[Header("Runtime Afterimage Defaults")]
public float defaultStartOpacity = 0.5f;
public float defaultFadeDuration = 0.22f;
public float defaultEndScale = 1.12f;
public bool useUnscaledTime = true;
public bool triggerOnEnable = false;
private static float sRuntimeOpacity;
private static float sRuntimeScale = 1f;
private static bool sCaptureRequested;
private float activeStartOpacity;
private float activeFadeDuration;
private float activeEndScale = 1f;
private float activeElapsed;
private bool activeAfterimage;
public static float RuntimeOpacity => sRuntimeOpacity;
public static float RuntimeScale => sRuntimeScale;
public static bool HasActiveAfterimage => sRuntimeOpacity > 0.0001f;
private void Awake()
{
if (Instance == null)
{
Instance = this;
return;
}
if (Instance != this)
Destroy(gameObject);
}
private void OnEnable()
{
if (triggerOnEnable)
TriggerAfterimage();
}
private void Update()
{
float delta = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
UpdateAfterimage(delta);
}
public void TriggerAfterimage()
{
TriggerAfterimage(defaultStartOpacity, defaultFadeDuration, defaultEndScale);
}
public void TriggerAfterimage(float startOpacity, float fadeDuration, float endScale)
{
activeStartOpacity = Mathf.Clamp01(startOpacity);
activeFadeDuration = Mathf.Max(0.0001f, fadeDuration);
activeEndScale = Mathf.Max(1f, endScale);
activeElapsed = 0f;
activeAfterimage = activeStartOpacity > 0.0001f;
sRuntimeOpacity = activeStartOpacity;
sRuntimeScale = 1f;
sCaptureRequested = activeAfterimage;
}
private void UpdateAfterimage(float delta)
{
if (!activeAfterimage)
{
sRuntimeOpacity = 0f;
sRuntimeScale = 1f;
return;
}
activeElapsed += delta;
float normalized = Mathf.Clamp01(activeElapsed / activeFadeDuration);
sRuntimeOpacity = Mathf.Lerp(activeStartOpacity, 0f, normalized);
sRuntimeScale = Mathf.Lerp(1f, activeEndScale, normalized);
if (normalized < 1f)
return;
activeAfterimage = false;
sRuntimeOpacity = 0f;
sRuntimeScale = 1f;
}
public static bool ConsumeCaptureRequest()
{
bool requested = sCaptureRequested;
sCaptureRequested = false;
return requested;
}
public static GlobalAfterimageRuntimeController EnsureInstance()
{
if (Instance != null)
return Instance;
GlobalAfterimageRuntimeController existing = FindFirstObjectByType<GlobalAfterimageRuntimeController>();
if (existing != null)
{
Instance = existing;
return existing;
}
GameObject runtimeObject = new GameObject("__global_afterimage_runtime");
Instance = runtimeObject.AddComponent<GlobalAfterimageRuntimeController>();
return Instance;
}
public static void Trigger(float startOpacity, float fadeDuration, float endScale)
{
EnsureInstance().TriggerAfterimage(startOpacity, fadeDuration, endScale);
}
public static void TriggerDefault()
{
EnsureInstance().TriggerAfterimage();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e0fcba34ceffcf34daf70334648d161f
@@ -0,0 +1,24 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[Serializable]
[VolumeComponentMenu("Post-processing/Bansonic/Global Afterimage")]
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
public sealed class GlobalAfterimageVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("Base afterimage opacity from the volume profile.")]
public ClampedFloatParameter opacity = new ClampedFloatParameter(0f, 0f, 1f);
[Tooltip("Scale multiplier of the copied image.")]
public ClampedFloatParameter scale = new ClampedFloatParameter(1.05f, 1f, 2f);
[Tooltip("Whether this effect should run in SceneView cameras.")]
public BoolParameter affectSceneView = new BoolParameter(false);
public bool IsActive() => opacity.value > 0.0001f;
[Obsolete("Unused #from(2023.1)", false)]
public bool IsTileCompatible() => false;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2b5b0fcb28cb9254bbcd2a498e0fe228
@@ -0,0 +1,185 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
public class GlobalDistortionRendererFeature : ScriptableRendererFeature
{
[Tooltip("When the custom distortion pass should execute.")]
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
private Material material;
private GlobalDistortionPass pass;
public override void Create()
{
if (pass == null)
pass = new GlobalDistortionPass();
pass.renderPassEvent = renderPassEvent;
EnsureMaterial();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!EnsureMaterial())
return;
Camera camera = renderingData.cameraData.camera;
if (camera == null)
return;
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
if (!renderingData.cameraData.postProcessEnabled)
return;
GlobalDistortionVolume settings = VolumeManager.instance.stack.GetComponent<GlobalDistortionVolume>();
bool hasVolume = settings != null && settings.active;
float runtimeIntensity = GlobalDistortionRuntimeController.RuntimeIntensity;
float baseIntensity = hasVolume ? settings.intensity.value : 0f;
float finalIntensity = Mathf.Clamp01(baseIntensity + runtimeIntensity);
if (finalIntensity <= 0.0001f)
return;
if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value)
return;
pass.Setup(
material,
finalIntensity,
hasVolume ? settings.noiseStrength.value : 0.16f,
hasVolume ? settings.radialStrength.value : 0.35f,
hasVolume ? settings.noiseScale.value : 12f,
hasVolume ? settings.center.value : new Vector2(0.5f, 0.5f),
hasVolume ? settings.edgeFade.value : 1.25f
);
renderer.EnqueuePass(pass);
}
protected override void Dispose(bool disposing)
{
if (pass != null)
{
pass.Dispose();
pass = null;
}
if (material != null)
{
CoreUtils.Destroy(material);
material = null;
}
}
private bool EnsureMaterial()
{
if (material != null)
return true;
Shader shader = Shader.Find("Hidden/Bansonic/GlobalDistortion");
if (shader == null)
return false;
material = CoreUtils.CreateEngineMaterial(shader);
return material != null;
}
private sealed class GlobalDistortionPass : ScriptableRenderPass
{
private static readonly int IntensityId = Shader.PropertyToID("_DistortionIntensity");
private static readonly int NoiseStrengthId = Shader.PropertyToID("_NoiseStrength");
private static readonly int RadialStrengthId = Shader.PropertyToID("_RadialStrength");
private static readonly int NoiseScaleId = Shader.PropertyToID("_NoiseScale");
private static readonly int CenterId = Shader.PropertyToID("_DistortionCenter");
private static readonly int EdgeFadeId = Shader.PropertyToID("_EdgeFade");
private Material passMaterial;
private float intensity;
private float noiseStrength;
private float radialStrength;
private float noiseScale;
private Vector2 center;
private float edgeFade;
private RTHandle compatibilityCopy;
public void Setup(Material material, float passIntensity, float passNoiseStrength, float passRadialStrength, float passNoiseScale, Vector2 passCenter, float passEdgeFade)
{
passMaterial = material;
intensity = passIntensity;
noiseStrength = passNoiseStrength;
radialStrength = passRadialStrength;
noiseScale = passNoiseScale;
center = passCenter;
edgeFade = passEdgeFade;
requiresIntermediateTexture = true;
}
public void Dispose()
{
compatibilityCopy?.Release();
compatibilityCopy = null;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (passMaterial == null)
return;
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (resourceData.isActiveTargetBackBuffer)
return;
ApplyMaterialProperties();
TextureHandle source = resourceData.activeColorTexture;
TextureDesc tempDesc = renderGraph.GetTextureDesc(source);
tempDesc.name = "CameraColor-GlobalDistortionTemp";
tempDesc.clearBuffer = false;
TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc);
RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0);
renderGraph.AddBlitPass(effectParameters, passName: "Global Distortion Effect");
renderGraph.AddBlitPass(
tempTexture,
resourceData.activeColorTexture,
Vector2.one,
Vector2.zero,
passName: "Global Distortion Restore"
);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (passMaterial == null)
return;
ApplyMaterialProperties();
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
descriptor.msaaSamples = 1;
descriptor.depthBufferBits = 0;
RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalDistortionCompatibilityCopy");
CommandBuffer cmd = CommandBufferPool.Get("Global Distortion Pass");
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy);
Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void ApplyMaterialProperties()
{
passMaterial.SetFloat(IntensityId, intensity);
passMaterial.SetFloat(NoiseStrengthId, noiseStrength);
passMaterial.SetFloat(RadialStrengthId, radialStrength);
passMaterial.SetFloat(NoiseScaleId, noiseScale);
passMaterial.SetVector(CenterId, center);
passMaterial.SetFloat(EdgeFadeId, edgeFade);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d71f5b59ebb9a7640b177e16adf3d6c7
@@ -0,0 +1,238 @@
using UnityEngine;
public class GlobalDistortionRuntimeController : MonoBehaviour
{
public static GlobalDistortionRuntimeController Instance { get; private set; }
[Header("Runtime Distortion Defaults")]
public float defaultTriggerIntensity = 0.45f;
public float defaultHoldDuration = 0.06f;
public float defaultRecoverDuration = 0.18f;
public AnimationCurve recoveryCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
public bool useUnscaledTime = true;
public bool triggerOnEnable = false;
private static float sPersistentIntensity;
private static float sPulseIntensity;
private static float sWaveIntensity;
private float activePulseIntensity;
private float holdRemaining;
private float recoverElapsed;
private float recoverDuration;
private bool recovering;
private float waveTargetIntensity;
private float waveEnterDuration;
private float waveRecoverDuration;
private float waveElapsed;
private WavePhase wavePhase = WavePhase.None;
public static float RuntimeIntensity => Mathf.Clamp01(sPersistentIntensity + sPulseIntensity + sWaveIntensity);
private enum WavePhase
{
None,
Enter,
Exit
}
private void Awake()
{
if (Instance == null)
{
Instance = this;
return;
}
if (Instance != this)
{
Destroy(gameObject);
}
}
private void OnEnable()
{
if (triggerOnEnable)
{
TriggerDistortion();
}
}
private void Update()
{
float delta = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
UpdatePulse(delta);
UpdateWave(delta);
}
public void TriggerDistortion()
{
TriggerDistortion(defaultTriggerIntensity, defaultHoldDuration, defaultRecoverDuration);
}
public void TriggerDistortion(float intensity, float holdDuration, float recoveryDurationSeconds)
{
intensity = Mathf.Clamp01(intensity);
holdDuration = Mathf.Max(0f, holdDuration);
recoveryDurationSeconds = Mathf.Max(0f, recoveryDurationSeconds);
activePulseIntensity = intensity;
holdRemaining = holdDuration;
recoverDuration = recoveryDurationSeconds;
recoverElapsed = 0f;
recovering = recoveryDurationSeconds <= 0f && holdDuration <= 0f;
sPulseIntensity = intensity;
if (holdDuration <= 0f && recoveryDurationSeconds <= 0f)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
recovering = false;
}
}
public void SetPersistentIntensity(float intensity)
{
sPersistentIntensity = Mathf.Clamp01(intensity);
}
public void ClearPersistentIntensity()
{
sPersistentIntensity = 0f;
}
public void TriggerWave(float targetIntensity, float enterDurationSeconds, float recoverDurationSeconds)
{
waveTargetIntensity = Mathf.Clamp01(targetIntensity);
waveEnterDuration = Mathf.Max(0.0001f, enterDurationSeconds);
waveRecoverDuration = Mathf.Max(0.0001f, recoverDurationSeconds);
waveElapsed = 0f;
wavePhase = WavePhase.Enter;
sWaveIntensity = 0f;
}
private void UpdatePulse(float delta)
{
if (activePulseIntensity <= 0f && !recovering)
{
sPulseIntensity = 0f;
return;
}
if (holdRemaining > 0f)
{
holdRemaining -= delta;
sPulseIntensity = activePulseIntensity;
if (holdRemaining > 0f)
return;
recovering = recoverDuration > 0f;
recoverElapsed = 0f;
if (!recovering)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
return;
}
}
if (!recovering)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
return;
}
recoverElapsed += delta;
float normalized = recoverDuration <= 0f ? 1f : Mathf.Clamp01(recoverElapsed / recoverDuration);
float curveValue = recoveryCurve != null && recoveryCurve.length > 0
? recoveryCurve.Evaluate(normalized)
: 1f - normalized;
sPulseIntensity = Mathf.Clamp01(activePulseIntensity * Mathf.Max(0f, curveValue));
if (normalized < 1f)
return;
recovering = false;
activePulseIntensity = 0f;
sPulseIntensity = 0f;
}
private void UpdateWave(float delta)
{
if (wavePhase == WavePhase.None)
{
sWaveIntensity = 0f;
return;
}
waveElapsed += delta;
if (wavePhase == WavePhase.Enter)
{
float normalized = Mathf.Clamp01(waveElapsed / waveEnterDuration);
sWaveIntensity = Mathf.LerpUnclamped(0f, waveTargetIntensity, normalized);
if (normalized < 1f)
return;
sWaveIntensity = waveTargetIntensity;
wavePhase = WavePhase.Exit;
waveElapsed = 0f;
return;
}
float exitNormalized = Mathf.Clamp01(waveElapsed / waveRecoverDuration);
sWaveIntensity = Mathf.LerpUnclamped(waveTargetIntensity, 0f, exitNormalized);
if (exitNormalized < 1f)
return;
sWaveIntensity = 0f;
wavePhase = WavePhase.None;
}
public static GlobalDistortionRuntimeController EnsureInstance()
{
if (Instance != null)
return Instance;
GlobalDistortionRuntimeController existing = FindFirstObjectByType<GlobalDistortionRuntimeController>();
if (existing != null)
{
Instance = existing;
return existing;
}
GameObject runtimeObject = new GameObject("__global_distortion_runtime");
Instance = runtimeObject.AddComponent<GlobalDistortionRuntimeController>();
return Instance;
}
public static void Trigger(float intensity, float holdDuration, float recoverDurationSeconds)
{
EnsureInstance().TriggerDistortion(intensity, holdDuration, recoverDurationSeconds);
}
public static void TriggerDefault()
{
EnsureInstance().TriggerDistortion();
}
public static void SetPersistent(float intensity)
{
EnsureInstance().SetPersistentIntensity(intensity);
}
public static void ClearPersistent()
{
if (Instance != null)
Instance.ClearPersistentIntensity();
else
sPersistentIntensity = 0f;
}
public static void TriggerWaveEffect(float enterDurationSeconds, float recoverDurationSeconds)
{
EnsureInstance().TriggerWave(1f, enterDurationSeconds, recoverDurationSeconds);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f8f82b86940efb345a454d1bc55f82ce
@@ -0,0 +1,36 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[Serializable]
[VolumeComponentMenu("Post-processing/Bansonic/Global Distortion")]
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
public sealed class GlobalDistortionVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("Base distortion intensity from the volume profile.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
[Tooltip("Noise contribution to the UV distortion.")]
public ClampedFloatParameter noiseStrength = new ClampedFloatParameter(0.16f, 0f, 1f);
[Tooltip("Radial pull strength from the distortion center.")]
public ClampedFloatParameter radialStrength = new ClampedFloatParameter(0.35f, 0f, 2f);
[Tooltip("Noise tiling scale.")]
public ClampedFloatParameter noiseScale = new ClampedFloatParameter(12f, 0.1f, 80f);
[Tooltip("Distortion center in viewport coordinates.")]
public Vector2Parameter center = new Vector2Parameter(new Vector2(0.5f, 0.5f));
[Tooltip("How quickly distortion fades towards screen edges.")]
public ClampedFloatParameter edgeFade = new ClampedFloatParameter(1.25f, 0.1f, 8f);
[Tooltip("Whether this effect should run in SceneView cameras.")]
public BoolParameter affectSceneView = new BoolParameter(false);
public bool IsActive() => intensity.value > 0.0001f;
[Obsolete("Unused #from(2023.1)", false)]
public bool IsTileCompatible() => false;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fcaf02ee66ed11d4d9c67508e0130935
@@ -0,0 +1,178 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
public class GlobalGlitchRendererFeature : ScriptableRendererFeature
{
[Tooltip("When the custom glitch pass should execute.")]
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
private Material material;
private GlobalGlitchPass pass;
public override void Create()
{
if (pass == null)
pass = new GlobalGlitchPass();
pass.renderPassEvent = renderPassEvent;
EnsureMaterial();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!EnsureMaterial())
return;
Camera camera = renderingData.cameraData.camera;
if (camera == null)
return;
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
if (!renderingData.cameraData.postProcessEnabled)
return;
GlobalGlitchVolume settings = VolumeManager.instance.stack.GetComponent<GlobalGlitchVolume>();
bool hasVolume = settings != null && settings.active;
float runtimeIntensity = GlobalGlitchRuntimeController.RuntimeIntensity;
float baseIntensity = hasVolume ? settings.intensity.value : 0f;
float finalIntensity = Mathf.Clamp01(baseIntensity + runtimeIntensity);
if (finalIntensity <= 0.0001f)
return;
if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value)
return;
pass.Setup(
material,
finalIntensity,
hasVolume ? settings.blockStrength.value : 0.45f,
hasVolume ? settings.colorSplit.value : 0.01f,
hasVolume ? settings.jitterAmount.value : 0.4f,
hasVolume ? settings.stripFrequency.value : 48f,
hasVolume ? settings.scanlineStrength.value : 0.18f
);
renderer.EnqueuePass(pass);
}
protected override void Dispose(bool disposing)
{
if (pass != null)
{
pass.Dispose();
pass = null;
}
if (material != null)
{
CoreUtils.Destroy(material);
material = null;
}
}
private bool EnsureMaterial()
{
if (material != null)
return true;
Shader shader = Shader.Find("Hidden/Bansonic/GlobalGlitch");
if (shader == null)
return false;
material = CoreUtils.CreateEngineMaterial(shader);
return material != null;
}
private sealed class GlobalGlitchPass : ScriptableRenderPass
{
private static readonly int IntensityId = Shader.PropertyToID("_GlitchIntensity");
private static readonly int BlockStrengthId = Shader.PropertyToID("_BlockStrength");
private static readonly int ColorSplitId = Shader.PropertyToID("_ColorSplit");
private static readonly int JitterAmountId = Shader.PropertyToID("_JitterAmount");
private static readonly int StripFrequencyId = Shader.PropertyToID("_StripFrequency");
private static readonly int ScanlineStrengthId = Shader.PropertyToID("_ScanlineStrength");
private Material passMaterial;
private float intensity;
private float blockStrength;
private float colorSplit;
private float jitterAmount;
private float stripFrequency;
private float scanlineStrength;
private RTHandle compatibilityCopy;
public void Setup(Material material, float passIntensity, float passBlockStrength, float passColorSplit, float passJitterAmount, float passStripFrequency, float passScanlineStrength)
{
passMaterial = material;
intensity = passIntensity;
blockStrength = passBlockStrength;
colorSplit = passColorSplit;
jitterAmount = passJitterAmount;
stripFrequency = passStripFrequency;
scanlineStrength = passScanlineStrength;
requiresIntermediateTexture = true;
}
public void Dispose()
{
compatibilityCopy?.Release();
compatibilityCopy = null;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (passMaterial == null)
return;
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (resourceData.isActiveTargetBackBuffer)
return;
ApplyMaterialProperties();
TextureHandle source = resourceData.activeColorTexture;
TextureDesc tempDesc = renderGraph.GetTextureDesc(source);
tempDesc.name = "CameraColor-GlobalGlitchTemp";
tempDesc.clearBuffer = false;
TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc);
RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0);
renderGraph.AddBlitPass(effectParameters, passName: "Global Glitch Effect");
renderGraph.AddBlitPass(tempTexture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Global Glitch Restore");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (passMaterial == null)
return;
ApplyMaterialProperties();
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
descriptor.msaaSamples = 1;
descriptor.depthBufferBits = 0;
RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalGlitchCompatibilityCopy");
CommandBuffer cmd = CommandBufferPool.Get("Global Glitch Pass");
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy);
Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void ApplyMaterialProperties()
{
passMaterial.SetFloat(IntensityId, intensity);
passMaterial.SetFloat(BlockStrengthId, blockStrength);
passMaterial.SetFloat(ColorSplitId, colorSplit);
passMaterial.SetFloat(JitterAmountId, jitterAmount);
passMaterial.SetFloat(StripFrequencyId, stripFrequency);
passMaterial.SetFloat(ScanlineStrengthId, scanlineStrength);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 84ae0996c2f9f6c43a0d5b735af7f121
@@ -0,0 +1,234 @@
using UnityEngine;
public class GlobalGlitchRuntimeController : MonoBehaviour
{
public static GlobalGlitchRuntimeController Instance { get; private set; }
[Header("Runtime Glitch Defaults")]
public float defaultTriggerIntensity = 0.7f;
public float defaultHoldDuration = 0.05f;
public float defaultRecoverDuration = 0.16f;
public AnimationCurve recoveryCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
public bool useUnscaledTime = true;
public bool triggerOnEnable = false;
private static float sPersistentIntensity;
private static float sPulseIntensity;
private static float sWaveIntensity;
private float activePulseIntensity;
private float holdRemaining;
private float recoverElapsed;
private float recoverDuration;
private bool recovering;
private float waveTargetIntensity;
private float waveEnterDuration;
private float waveRecoverDuration;
private float waveElapsed;
private WavePhase wavePhase = WavePhase.None;
public static float RuntimeIntensity => Mathf.Clamp01(sPersistentIntensity + sPulseIntensity + sWaveIntensity);
private enum WavePhase
{
None,
Enter,
Exit
}
private void Awake()
{
if (Instance == null)
{
Instance = this;
return;
}
if (Instance != this)
Destroy(gameObject);
}
private void OnEnable()
{
if (triggerOnEnable)
TriggerGlitch();
}
private void Update()
{
float delta = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
UpdatePulse(delta);
UpdateWave(delta);
}
public void TriggerGlitch()
{
TriggerGlitch(defaultTriggerIntensity, defaultHoldDuration, defaultRecoverDuration);
}
public void TriggerGlitch(float intensity, float holdDuration, float recoveryDurationSeconds)
{
intensity = Mathf.Clamp01(intensity);
holdDuration = Mathf.Max(0f, holdDuration);
recoveryDurationSeconds = Mathf.Max(0f, recoveryDurationSeconds);
activePulseIntensity = intensity;
holdRemaining = holdDuration;
recoverDuration = recoveryDurationSeconds;
recoverElapsed = 0f;
recovering = recoveryDurationSeconds <= 0f && holdDuration <= 0f;
sPulseIntensity = intensity;
if (holdDuration <= 0f && recoveryDurationSeconds <= 0f)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
recovering = false;
}
}
public void SetPersistentIntensity(float intensity)
{
sPersistentIntensity = Mathf.Clamp01(intensity);
}
public void ClearPersistentIntensity()
{
sPersistentIntensity = 0f;
}
public void TriggerWave(float targetIntensity, float enterDurationSeconds, float recoverDurationSeconds)
{
waveTargetIntensity = Mathf.Clamp01(targetIntensity);
waveEnterDuration = Mathf.Max(0.0001f, enterDurationSeconds);
waveRecoverDuration = Mathf.Max(0.0001f, recoverDurationSeconds);
waveElapsed = 0f;
wavePhase = WavePhase.Enter;
sWaveIntensity = 0f;
}
private void UpdatePulse(float delta)
{
if (activePulseIntensity <= 0f && !recovering)
{
sPulseIntensity = 0f;
return;
}
if (holdRemaining > 0f)
{
holdRemaining -= delta;
sPulseIntensity = activePulseIntensity;
if (holdRemaining > 0f)
return;
recovering = recoverDuration > 0f;
recoverElapsed = 0f;
if (!recovering)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
return;
}
}
if (!recovering)
{
activePulseIntensity = 0f;
sPulseIntensity = 0f;
return;
}
recoverElapsed += delta;
float normalized = recoverDuration <= 0f ? 1f : Mathf.Clamp01(recoverElapsed / recoverDuration);
float curveValue = recoveryCurve != null && recoveryCurve.length > 0
? recoveryCurve.Evaluate(normalized)
: 1f - normalized;
sPulseIntensity = Mathf.Clamp01(activePulseIntensity * Mathf.Max(0f, curveValue));
if (normalized < 1f)
return;
recovering = false;
activePulseIntensity = 0f;
sPulseIntensity = 0f;
}
private void UpdateWave(float delta)
{
if (wavePhase == WavePhase.None)
{
sWaveIntensity = 0f;
return;
}
waveElapsed += delta;
if (wavePhase == WavePhase.Enter)
{
float normalized = Mathf.Clamp01(waveElapsed / waveEnterDuration);
sWaveIntensity = Mathf.LerpUnclamped(0f, waveTargetIntensity, normalized);
if (normalized < 1f)
return;
sWaveIntensity = waveTargetIntensity;
wavePhase = WavePhase.Exit;
waveElapsed = 0f;
return;
}
float exitNormalized = Mathf.Clamp01(waveElapsed / waveRecoverDuration);
sWaveIntensity = Mathf.LerpUnclamped(waveTargetIntensity, 0f, exitNormalized);
if (exitNormalized < 1f)
return;
sWaveIntensity = 0f;
wavePhase = WavePhase.None;
}
public static GlobalGlitchRuntimeController EnsureInstance()
{
if (Instance != null)
return Instance;
GlobalGlitchRuntimeController existing = FindFirstObjectByType<GlobalGlitchRuntimeController>();
if (existing != null)
{
Instance = existing;
return existing;
}
GameObject runtimeObject = new GameObject("__global_glitch_runtime");
Instance = runtimeObject.AddComponent<GlobalGlitchRuntimeController>();
return Instance;
}
public static void Trigger(float intensity, float holdDuration, float recoverDurationSeconds)
{
EnsureInstance().TriggerGlitch(intensity, holdDuration, recoverDurationSeconds);
}
public static void TriggerDefault()
{
EnsureInstance().TriggerGlitch();
}
public static void SetPersistent(float intensity)
{
EnsureInstance().SetPersistentIntensity(intensity);
}
public static void ClearPersistent()
{
if (Instance != null)
Instance.ClearPersistentIntensity();
else
sPersistentIntensity = 0f;
}
public static void TriggerWaveEffect(float enterDurationSeconds, float recoverDurationSeconds)
{
EnsureInstance().TriggerWave(1f, enterDurationSeconds, recoverDurationSeconds);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fc8770c127e6d57478652fa9c3698e91
@@ -0,0 +1,36 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[Serializable]
[VolumeComponentMenu("Post-processing/Bansonic/Global Glitch")]
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
public sealed class GlobalGlitchVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("Base glitch intensity from the volume profile.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
[Tooltip("How strong the horizontal block tearing is.")]
public ClampedFloatParameter blockStrength = new ClampedFloatParameter(0.45f, 0f, 1f);
[Tooltip("How much the RGB channels split apart.")]
public ClampedFloatParameter colorSplit = new ClampedFloatParameter(0.01f, 0f, 0.05f);
[Tooltip("Per-line horizontal jitter amount.")]
public ClampedFloatParameter jitterAmount = new ClampedFloatParameter(0.4f, 0f, 1f);
[Tooltip("How many horizontal strips are used to drive the glitch pattern.")]
public ClampedFloatParameter stripFrequency = new ClampedFloatParameter(48f, 1f, 240f);
[Tooltip("Dark scanline contribution.")]
public ClampedFloatParameter scanlineStrength = new ClampedFloatParameter(0.18f, 0f, 1f);
[Tooltip("Whether this effect should run in SceneView cameras.")]
public BoolParameter affectSceneView = new BoolParameter(false);
public bool IsActive() => intensity.value > 0.0001f;
[Obsolete("Unused #from(2023.1)", false)]
public bool IsTileCompatible() => false;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 54a30677f5d2e4548881a79f4c3e3972
@@ -0,0 +1,144 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
public class GlobalMonochromeRendererFeature : ScriptableRendererFeature
{
[Tooltip("When the custom monochrome pass should execute.")]
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
private Material material;
private GlobalMonochromePass pass;
public override void Create()
{
if (pass == null)
pass = new GlobalMonochromePass();
pass.renderPassEvent = renderPassEvent;
EnsureMaterial();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!EnsureMaterial())
return;
Camera camera = renderingData.cameraData.camera;
if (camera == null)
return;
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
if (!renderingData.cameraData.postProcessEnabled)
return;
GlobalMonochromeVolume settings = VolumeManager.instance.stack.GetComponent<GlobalMonochromeVolume>();
bool hasVolume = settings != null && settings.active;
float runtimeIntensity = GlobalMonochromeRuntimeController.RuntimeIntensity;
float baseIntensity = hasVolume ? settings.intensity.value : 0f;
float finalIntensity = Mathf.Clamp01(Mathf.Max(baseIntensity, runtimeIntensity));
if (finalIntensity <= 0.0001f)
return;
if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value)
return;
pass.Setup(material, finalIntensity);
renderer.EnqueuePass(pass);
}
protected override void Dispose(bool disposing)
{
if (pass != null)
{
pass.Dispose();
pass = null;
}
if (material != null)
{
CoreUtils.Destroy(material);
material = null;
}
}
private bool EnsureMaterial()
{
if (material != null)
return true;
Shader shader = Shader.Find("Hidden/Bansonic/GlobalMonochrome");
if (shader == null)
return false;
material = CoreUtils.CreateEngineMaterial(shader);
return material != null;
}
private sealed class GlobalMonochromePass : ScriptableRenderPass
{
private static readonly int IntensityId = Shader.PropertyToID("_MonochromeIntensity");
private Material passMaterial;
private float intensity;
private RTHandle compatibilityCopy;
public void Setup(Material material, float passIntensity)
{
passMaterial = material;
intensity = passIntensity;
requiresIntermediateTexture = true;
}
public void Dispose()
{
compatibilityCopy?.Release();
compatibilityCopy = null;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (passMaterial == null)
return;
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (resourceData.isActiveTargetBackBuffer)
return;
passMaterial.SetFloat(IntensityId, intensity);
TextureHandle source = resourceData.activeColorTexture;
TextureDesc tempDesc = renderGraph.GetTextureDesc(source);
tempDesc.name = "CameraColor-GlobalMonochromeTemp";
tempDesc.clearBuffer = false;
TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc);
RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0);
renderGraph.AddBlitPass(effectParameters, passName: "Global Monochrome Effect");
renderGraph.AddBlitPass(tempTexture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Global Monochrome Restore");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (passMaterial == null)
return;
passMaterial.SetFloat(IntensityId, intensity);
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
descriptor.msaaSamples = 1;
descriptor.depthBufferBits = 0;
RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalMonochromeCompatibilityCopy");
CommandBuffer cmd = CommandBufferPool.Get("Global Monochrome Pass");
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy);
Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e30db065f184af241b78ce51edc50d96
@@ -0,0 +1,125 @@
using UnityEngine;
public class GlobalMonochromeRuntimeController : MonoBehaviour
{
public static GlobalMonochromeRuntimeController Instance { get; private set; }
[Header("Runtime Monochrome Defaults")]
public float defaultEnterDuration = 0.12f;
public float defaultRecoverDuration = 0.12f;
public bool useUnscaledTime = true;
public bool triggerOnEnable = false;
private static float sRuntimeIntensity;
private float enterDuration;
private float recoverDuration;
private float elapsed;
private Phase phase = Phase.None;
public static float RuntimeIntensity => Mathf.Clamp01(sRuntimeIntensity);
private enum Phase
{
None,
Enter,
Exit
}
private void Awake()
{
if (Instance == null)
{
Instance = this;
return;
}
if (Instance != this)
Destroy(gameObject);
}
private void OnEnable()
{
if (triggerOnEnable)
TriggerMonochrome();
}
private void Update()
{
float delta = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
UpdateWave(delta);
}
public void TriggerMonochrome()
{
TriggerMonochrome(defaultEnterDuration, defaultRecoverDuration);
}
public void TriggerMonochrome(float enterDurationSeconds, float recoverDurationSeconds)
{
enterDuration = Mathf.Max(0.0001f, enterDurationSeconds);
recoverDuration = Mathf.Max(0.0001f, recoverDurationSeconds);
elapsed = 0f;
phase = Phase.Enter;
sRuntimeIntensity = 0f;
}
private void UpdateWave(float delta)
{
if (phase == Phase.None)
{
sRuntimeIntensity = 0f;
return;
}
elapsed += delta;
if (phase == Phase.Enter)
{
float normalized = Mathf.Clamp01(elapsed / enterDuration);
sRuntimeIntensity = Mathf.LerpUnclamped(0f, 1f, normalized);
if (normalized < 1f)
return;
sRuntimeIntensity = 1f;
elapsed = 0f;
phase = Phase.Exit;
return;
}
float exitNormalized = Mathf.Clamp01(elapsed / recoverDuration);
sRuntimeIntensity = Mathf.LerpUnclamped(1f, 0f, exitNormalized);
if (exitNormalized < 1f)
return;
sRuntimeIntensity = 0f;
phase = Phase.None;
}
public static GlobalMonochromeRuntimeController EnsureInstance()
{
if (Instance != null)
return Instance;
GlobalMonochromeRuntimeController existing = FindFirstObjectByType<GlobalMonochromeRuntimeController>();
if (existing != null)
{
Instance = existing;
return existing;
}
GameObject runtimeObject = new GameObject("__global_monochrome_runtime");
Instance = runtimeObject.AddComponent<GlobalMonochromeRuntimeController>();
return Instance;
}
public static void Trigger(float enterDurationSeconds, float recoverDurationSeconds)
{
EnsureInstance().TriggerMonochrome(enterDurationSeconds, recoverDurationSeconds);
}
public static void TriggerDefault()
{
EnsureInstance().TriggerMonochrome();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d2b5933af9f532c469c81a1942ec2220
@@ -0,0 +1,21 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[Serializable]
[VolumeComponentMenu("Post-processing/Bansonic/Global Monochrome")]
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
public sealed class GlobalMonochromeVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("Base monochrome intensity from the volume profile.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
[Tooltip("Whether this effect should run in SceneView cameras.")]
public BoolParameter affectSceneView = new BoolParameter(false);
public bool IsActive() => intensity.value > 0.0001f;
[Obsolete("Unused #from(2023.1)", false)]
public bool IsTileCompatible() => false;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6bf226df2a25ec249a0bda3685d3bcd6