加入很多新内容,这波一块交了
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user