Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,108 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(DecalRendererFeature))]
internal class DecalSettings : Editor
{
private struct Styles
{
public static GUIContent Technique = EditorGUIUtility.TrTextContent("Technique", "This option determines what method is used for rendering decals.");
public static GUIContent MaxDrawDistance = EditorGUIUtility.TrTextContent("Max Draw Distance", "Maximum global draw distance of decals.");
public static GUIContent UseRenderingLayers = EditorGUIUtility.TrTextContent("Use Rendering Layers", "When enabled, you can configure specific Decal Projectors to affect only specific objects. The number of Rendering Layers affects the performance.");
public static GUIContent SurfaceData = EditorGUIUtility.TrTextContent("Surface Data", "Allows specifying which decals surface data should be blended with surfaces.");
public static GUIContent NormalBlend = EditorGUIUtility.TrTextContent("Normal Blend", "Controls the quality of normal reconstruction. The higher the value the more accurate normal reconstruction and the cost on performance.");
public static readonly GUIContent OpenGlSupportWarning = EditorGUIUtility.TrTextContentWithIcon("Rendering Layers are not supported on OpenGL.", "This feature is incompatible with OpenGL. Disable 'Auto Graphics API' in Player Settings and remove OpenGL from the list.", MessageType.Warning);
}
private SerializedProperty m_Technique;
private SerializedProperty m_MaxDrawDistance;
private SerializedProperty m_DecalLayers;
private SerializedProperty m_DBufferSettings;
private SerializedProperty m_DBufferSurfaceData;
private SerializedProperty m_ScreenSpaceSettings;
private SerializedProperty m_ScreenSpaceNormalBlend;
private bool m_IsInitialized = false;
private void Init()
{
if (m_IsInitialized)
return;
SerializedProperty settings = serializedObject.FindProperty("m_Settings");
m_Technique = settings.FindPropertyRelative("technique");
m_MaxDrawDistance = settings.FindPropertyRelative("maxDrawDistance");
m_DecalLayers = settings.FindPropertyRelative("decalLayers");
m_DBufferSettings = settings.FindPropertyRelative("dBufferSettings");
m_DBufferSurfaceData = m_DBufferSettings.FindPropertyRelative("surfaceData");
m_ScreenSpaceSettings = settings.FindPropertyRelative("screenSpaceSettings");
m_ScreenSpaceNormalBlend = m_ScreenSpaceSettings.FindPropertyRelative("normalBlend");
m_IsInitialized = true;
}
public override void OnInspectorGUI()
{
Init();
var gfxTypes = PlayerSettings.GetGraphicsAPIs(EditorUserBuildSettings.activeBuildTarget);
var isGLDevice = false;
foreach (var type in gfxTypes)
{
if (type == GraphicsDeviceType.OpenGLES3 || type == GraphicsDeviceType.OpenGLCore)
{
isGLDevice = true;
break;
}
}
EditorGUILayout.PropertyField(m_Technique, Styles.Technique);
DecalTechniqueOption technique = (DecalTechniqueOption)m_Technique.intValue;
if (technique == DecalTechniqueOption.DBuffer)
{
if (isGLDevice)
{
EditorGUILayout.HelpBox("DBuffer technique is not supported on OpenGL. Decals will not be rendered.", MessageType.Error);
EditorGUILayout.Space();
}
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_DBufferSurfaceData, Styles.SurfaceData);
EditorGUI.indentLevel--;
}
if (technique == DecalTechniqueOption.ScreenSpace)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_ScreenSpaceNormalBlend, Styles.NormalBlend);
EditorGUI.indentLevel--;
}
EditorGUILayout.PropertyField(m_MaxDrawDistance, Styles.MaxDrawDistance);
if (isGLDevice)
{
if (m_DecalLayers.boolValue)
{
m_DecalLayers.boolValue = false;
serializedObject.ApplyModifiedProperties();
}
GUI.enabled = false;
}
EditorGUILayout.PropertyField(m_DecalLayers, Styles.UseRenderingLayers);
if (isGLDevice)
{
GUI.enabled = true;
EditorGUILayout.HelpBox(Styles.OpenGlSupportWarning);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bc8495f05d06f4f4e925ef3dcbdd8175
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,202 @@
using System.Collections.Generic;
using UnityEditor.RenderPipelines.Core;
using UnityEditor.ShaderGraph;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
/// <summary>
/// Custom editor for FullScreenPassRendererFeature class responsible for drawing unavailable by default properties
/// such as custom drop down items and additional properties.
/// </summary>
[UnityEngine.Scripting.APIUpdating.MovedFrom("")]
[CustomEditor(typeof(FullScreenPassRendererFeature))]
public class FullScreenPassRendererFeatureEditor : Editor, IOwningRendererDataConsumer
{
private SerializedProperty m_InjectionPointProperty;
private SerializedProperty m_RequirementsProperty;
private SerializedProperty m_FetchColorBufferProperty;
private SerializedProperty m_BindDepthStencilAttachmentProperty;
private SerializedProperty m_PassMaterialProperty;
private SerializedProperty m_PassIndexProperty;
private bool m_ShowDuplicateColorCopyWarning;
private bool m_ShowFetchColorBufferTileOnlyError;
private bool m_ShowRequirementsColorTileOnlyError;
private bool m_ShowRequirementsDepthWithoutNormalTileOnlyError;
private bool m_ShowRequirementsMotionWithoutNormalTileOnlyError;
private static readonly GUIContent k_InjectionPointGuiContent = new GUIContent("Injection Point", "Specifies where in the frame this pass will be injected.");
private static readonly GUIContent k_RequirementsGuiContent = new GUIContent("Requirements", "A mask of URP internal textures that will need to be generated and bound for sampling.\n\nNote that 'Color' here corresponds to '_CameraOpaqueTexture' so most of the time you will want to use the 'Fetch Color Buffer' option instead.");
private static readonly GUIContent k_FetchColorBufferGuiContent = new GUIContent("Fetch Color Buffer", "Enable this if the assigned material will need to sample the active color target. The active color will be bound to the '_BlitTexture' shader property for sampling. Note that this will introduce an internal color copy pass.");
private static readonly GUIContent k_BindDepthStencilAttachmentGuiContent = new GUIContent("Bind Depth-Stencil", "Enable this to bind the active camera's depth-stencil attachment to the framebuffer (only use this if depth-stencil ops are used by the assigned material as this could have a performance impact).");
private static readonly GUIContent k_PassMaterialGuiContent = new GUIContent("Pass Material", "The material used to render the full screen pass.");
private static readonly GUIContent k_PassGuiContent = new GUIContent("Pass", "The name of the shader pass to use from the assigned material.");
private static readonly string k_FetchColorBufferIncompatibleWithTileOnlyMode = L10n.Tr("Fetch Color Buffer is incompatible with the enabled 'Tile-Only Mode'. Disable this setting.");
private static readonly string k_RequirementsColorIncompatibleWithTileOnlyMode = L10n.Tr("Color is incompatible with the enabled 'Tile-Only Mode'. Clear Color from Requirements.");
private static readonly string k_RequirementsDepthWithoutNormalIncompatibleWithTileOnlyMode = L10n.Tr("Depth without Normal is incompatible with the enabled 'Tile-Only Mode'. Add Normal to Requirements or clear Depth.");
private static readonly string k_RequirementsMotionWithoutNormalIncompatibleWithTileOnlyMode = L10n.Tr("Motion without Normal is incompatible with the enabled 'Tile-Only Mode'. Add Normal to Requirements or clear Motion.");
/// <summary>
/// The renderer data that owns the feature when the inspector is drawn.
/// </summary>
public ScriptableRendererData owningRendererData { get; set; }
static readonly GUIContent k_NewFullscreenMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new Fullscreen material.");
static readonly string k_NewBlitShaderText = "SRP Blit Shader";
static readonly string k_NewSGFullscreenText = "ShaderGraph Fullscreen";
static readonly string k_NewSGFullscreenFromTemplateText = "ShaderGraph Fullscreen from Template";
static readonly string k_BlitShaderTemplatePath = "Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt";
static readonly string k_DefaultFullscreenShaderGraphTemplatePath = "Packages/com.unity.render-pipelines.universal/Shaders/FullscreenInvertColors.shadergraph";
private void OnEnable()
{
m_InjectionPointProperty = serializedObject.FindProperty("injectionPoint");
m_RequirementsProperty = serializedObject.FindProperty("requirements");
m_FetchColorBufferProperty = serializedObject.FindProperty("fetchColorBuffer");
m_BindDepthStencilAttachmentProperty = serializedObject.FindProperty("bindDepthStencilAttachment");
m_PassMaterialProperty = serializedObject.FindProperty("passMaterial");
m_PassIndexProperty = serializedObject.FindProperty("passIndex");
}
/// <summary>
/// Implementation for a custom inspector
/// </summary>
public override void OnInspectorGUI()
{
var currentFeature = target as FullScreenPassRendererFeature;
if (currentFeature.passMaterial == null || currentFeature.passIndex >= currentFeature.passMaterial.passCount)
currentFeature.passIndex = 0;
EditorGUILayout.PropertyField(m_InjectionPointProperty, k_InjectionPointGuiContent);
EditorGUILayout.PropertyField(m_RequirementsProperty, k_RequirementsGuiContent);
var requirements = m_RequirementsProperty.GetEnumValue<ScriptableRenderPassInput>();
var rendererData = (this as IOwningRendererDataConsumer).owningRendererData as UniversalRendererData;
if (Event.current.type == EventType.Layout)
{
bool tileOnlyMode = rendererData != null && rendererData.tileOnlyMode;
m_ShowFetchColorBufferTileOnlyError = tileOnlyMode && m_FetchColorBufferProperty.boolValue;
m_ShowRequirementsColorTileOnlyError = tileOnlyMode && (requirements & ScriptableRenderPassInput.Color) != ScriptableRenderPassInput.None;
// Depth without Normal triggers a depth copy; with Normal, URP does a prepass instead (see comment on k_RequirementsDepthWithoutNormalIncompatibleWithTileOnlyMode).
m_ShowRequirementsDepthWithoutNormalTileOnlyError = tileOnlyMode && (requirements & ScriptableRenderPassInput.Depth) != ScriptableRenderPassInput.None && (requirements & ScriptableRenderPassInput.Normal) == ScriptableRenderPassInput.None;
m_ShowRequirementsMotionWithoutNormalTileOnlyError = tileOnlyMode && (requirements & ScriptableRenderPassInput.Motion) != ScriptableRenderPassInput.None && (requirements & ScriptableRenderPassInput.Normal) == ScriptableRenderPassInput.None;
}
if (m_ShowFetchColorBufferTileOnlyError)
EditorGUILayout.HelpBox(k_FetchColorBufferIncompatibleWithTileOnlyMode, MessageType.Error, true);
if (m_ShowRequirementsColorTileOnlyError)
EditorGUILayout.HelpBox(k_RequirementsColorIncompatibleWithTileOnlyMode, MessageType.Error, true);
if (m_ShowRequirementsDepthWithoutNormalTileOnlyError)
EditorGUILayout.HelpBox(k_RequirementsDepthWithoutNormalIncompatibleWithTileOnlyMode, MessageType.Error, true);
if (m_ShowRequirementsMotionWithoutNormalTileOnlyError)
EditorGUILayout.HelpBox(k_RequirementsMotionWithoutNormalIncompatibleWithTileOnlyMode, MessageType.Error, true);
EditorGUILayout.PropertyField(m_FetchColorBufferProperty, k_FetchColorBufferGuiContent);
if (Event.current.type == EventType.Layout)
{
m_ShowDuplicateColorCopyWarning = (requirements & ScriptableRenderPassInput.Color) != ScriptableRenderPassInput.None && m_FetchColorBufferProperty.boolValue;
}
if (m_ShowDuplicateColorCopyWarning)
EditorGUILayout.HelpBox("You request two different color textures: the opaque color texture via \"Requirements: Color\", and the current camera attachment via \"Fetch Color Buffer\". While this is allowed, we recommend disabling one of these two options for optimal performance.", MessageType.Warning, true);
EditorGUILayout.PropertyField(m_BindDepthStencilAttachmentProperty, k_BindDepthStencilAttachmentGuiContent);
MaterialFieldWithButton(m_PassMaterialProperty, k_PassMaterialGuiContent);
if (m_PassMaterialProperty.objectReferenceValue == null)
EditorGUILayout.HelpBox("The full screen feature will not execute - no material is assigned. Please make sure a material is assigned for this feature on the renderer asset.", MessageType.Warning, true);
if (AdvancedProperties.BeginGroup())
{
DrawMaterialPassProperty(currentFeature);
}
AdvancedProperties.EndGroup();
serializedObject.ApplyModifiedProperties();
}
internal void MaterialFieldWithButton(SerializedProperty prop, GUIContent label)
{
const int k_NewFieldWidth = 70;
var rect = EditorGUILayout.GetControlRect();
rect.xMax -= k_NewFieldWidth + 2;
EditorGUI.PropertyField(rect, prop, label);
var newFieldRect = rect;
newFieldRect.x = rect.xMax + 2;
newFieldRect.width = k_NewFieldWidth;
if (!EditorGUI.DropdownButton(newFieldRect, k_NewFullscreenMaterialButtonText, FocusType.Keyboard))
return;
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent(k_NewSGFullscreenText), false, () => CreateFullscreenMaterialFromTemplate(target as FullScreenPassRendererFeature, k_DefaultFullscreenShaderGraphTemplatePath));
menu.AddItem(new GUIContent(k_NewSGFullscreenFromTemplateText), false, () => CreateFullscreenMaterialFromTemplate(target as FullScreenPassRendererFeature));
menu.AddItem(new GUIContent(k_NewBlitShaderText), false, () => CreateDefaultFullscreenMaterial(target as FullScreenPassRendererFeature));
menu.DropDown(newFieldRect);
}
internal static void CreateFullscreenMaterialFromTemplate(FullScreenPassRendererFeature obj, string templatePath = null)
{
var selection = Selection.activeObject; // holding selection
CreateShaderGraph.CreateGraphAndMaterialFromTemplate((material) =>
{
obj.passMaterial = material;
EditorUtility.SetDirty(obj);
Selection.activeObject = selection; //restoring selection
},
templatePath,
$"New {k_NewSGFullscreenText}",
null,
"shadergraph.material=fullscreen");
}
internal static void CreateDefaultFullscreenMaterial(FullScreenPassRendererFeature obj)
{
string materialName = "New " + k_NewBlitShaderText;
var selection = Selection.activeObject; // holding selection
AssetCreationUtil.CreateShaderAndMaterial(
materialName,
(material) =>
{
obj.passMaterial = material;
EditorUtility.SetDirty(obj);
Selection.activeObject = selection; //restoring selection
},
k_BlitShaderTemplatePath
);
}
private void DrawMaterialPassProperty(FullScreenPassRendererFeature feature)
{
List<string> selectablePasses;
bool isMaterialValid = feature.passMaterial != null;
selectablePasses = isMaterialValid ? GetPassIndexStringEntries(feature) : new List<string>() {"No material"};
// If material is invalid 0'th index is selected automatically, so it stays on "No material" entry
// It is invalid index, but FullScreenPassRendererFeature wont execute until material is valid
m_PassIndexProperty.intValue = EditorGUILayout.Popup(k_PassGuiContent, m_PassIndexProperty.intValue, selectablePasses.ToArray());
}
private static List<string> GetPassIndexStringEntries(FullScreenPassRendererFeature component)
{
List<string> passIndexEntries = new List<string>();
for (int i = 0; i < component.passMaterial.passCount; ++i)
{
// "Name of a pass (index)" - "PassAlpha (1)"
string entry = $"{component.passMaterial.GetPassName(i)} ({i})";
passIndexEntries.Add(entry);
}
return passIndexEntries;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 434049f27d9ec4c049092928038efbd3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,260 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
// Create a Scriptable Renderer Feature that implements a post-processing effect when the camera is inside a custom volume.
// For more information about creating scriptable renderer features, refer to https://docs.unity3d.com/Manual/urp/customizing-urp.html
public sealed class #FEATURE_TYPE# : ScriptableRendererFeature
{
#region FEATURE_FIELDS
// Declare the material used to render the post-processing effect.
// Add a [SerializeField] attribute so Unity serializes the property and includes it in builds.
[SerializeField]
[HideInInspector]
private Material m_Material;
// Declare the render pass that renders the effect.
private CustomPostRenderPass m_FullScreenPass;
#endregion
#region FEATURE_METHODS
// Override the Create method.
// Unity calls this method when the Scriptable Renderer Feature loads for the first time, and when you change a property.
public override void Create()
{
#if UNITY_EDITOR
// Assign a material asset to m_Material in the Unity Editor.
if (m_Material == null)
m_Material = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>("Packages/com.unity.render-pipelines.universal/Runtime/Materials/FullscreenInvertColors.mat");
#endif
if(m_Material)
m_FullScreenPass = new CustomPostRenderPass(name, m_Material);
}
// Override the AddRenderPasses method to inject passes into the renderer. Unity calls AddRenderPasses once per camera.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// Skip rendering if m_Material or the pass instance are null.
if (m_Material == null || m_FullScreenPass == null)
return;
// Skip rendering if the target is a Reflection Probe or a preview camera.
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
// Skip rendering if the camera is outside the custom volume.
#VOLUME_TYPE# myVolume = VolumeManager.instance.stack?.GetComponent<#VOLUME_TYPE#>();
if (myVolume == null || !myVolume.IsActive())
return;
// Specify when the effect will execute during the frame.
// For a post-processing effect, the injection point is usually BeforeRenderingTransparents, BeforeRenderingPostProcessing, or AfterRenderingPostProcessing.
// For more information, refer to https://docs.unity3d.com/Manual/urp/customize/custom-pass-injection-points.html
m_FullScreenPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
// Specify that the effect doesn't need scene depth, normals, motion vectors, or the color texture as input.
m_FullScreenPass.ConfigureInput(ScriptableRenderPassInput.None);
// Add the render pass to the renderer.
renderer.EnqueuePass(m_FullScreenPass);
}
protected override void Dispose(bool disposing)
{
// Free the resources the render pass uses.
m_FullScreenPass.Dispose();
}
#endregion
// Create the custom render pass.
private class CustomPostRenderPass : ScriptableRenderPass
{
#region PASS_FIELDS
// Declare the material used to render the post-processing effect.
private Material m_Material;
// Declare a texture to use as a temporary color copy. This texture is used only in the Compatibility Mode path.
private RTHandle m_CopiedColor;
// Declare a property block to set additional properties for the material.
private static MaterialPropertyBlock s_SharedPropertyBlock = new MaterialPropertyBlock();
// Declare a property that enables or disables the render pass that samples the color texture.
private static readonly bool kSampleActiveColor = true;
// Declare a property that adds or removes depth-stencil support.
private static readonly bool kBindDepthStencilAttachment = false;
// Create shader properties in advance, which is more efficient than referencing them by string.
private static readonly int kBlitTexturePropertyId = Shader.PropertyToID("_BlitTexture");
private static readonly int kBlitScaleBiasPropertyId = Shader.PropertyToID("_BlitScaleBias");
#endregion
public CustomPostRenderPass(string passName, Material material)
{
// Add a profiling sampler.
profilingSampler = new ProfilingSampler(passName);
// Assign the material to the render pass.
m_Material = material;
// To make sure the render pass can sample the active color buffer, set URP to render to intermediate textures instead of directly to the backbuffer.
requiresIntermediateTexture = kSampleActiveColor;
}
#region PASS_SHARED_RENDERING_CODE
// Add a command to create the temporary color copy texture.
// This method is used in both the render graph system path and the Compatibility Mode path.
private static void ExecuteCopyColorPass(RasterCommandBuffer cmd, RTHandle sourceTexture)
{
Blitter.BlitTexture(cmd, sourceTexture, new Vector4(1, 1, 0, 0), 0.0f, false);
}
// Add commands to render the effect.
// This method is used in both the render graph system path and the Compatibility Mode path.
private static void ExecuteMainPass(RasterCommandBuffer cmd, RTHandle sourceTexture, Material material)
{
// Clear the material properties.
s_SharedPropertyBlock.Clear();
if(sourceTexture != null)
s_SharedPropertyBlock.SetTexture(kBlitTexturePropertyId, sourceTexture);
// Set the scale and bias so shaders that use Blit.hlsl work correctly.
s_SharedPropertyBlock.SetVector(kBlitScaleBiasPropertyId, new Vector4(1, 1, 0, 0));
// Set the material properties based on the blended values of the custom volume.
// For more information, refer to https://docs.unity3d.com/Manual/urp/post-processing/custom-post-processing-with-volume.html
#VOLUME_TYPE# myVolume = VolumeManager.instance.stack?.GetComponent<#VOLUME_TYPE#>();
if (myVolume != null)
s_SharedPropertyBlock.SetFloat("_Intensity", myVolume.intensity.value);
// Draw to the current render target.
cmd.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Triangles, 3, 1, s_SharedPropertyBlock);
}
// Get the texture descriptor needed to create the temporary color copy texture.
// This method is used in both the render graph system path and the Compatibility Mode path.
private static RenderTextureDescriptor GetCopyPassTextureDescriptor(RenderTextureDescriptor desc)
{
// Avoid an unnecessary multisample anti-aliasing (MSAA) resolve before the main render pass.
desc.msaaSamples = 1;
// Avoid copying the depth buffer, as the main pass render in this example doesn't use depth.
desc.depthBufferBits = (int)DepthBits.None;
return desc;
}
#endregion
#region PASS_NON_RENDER_GRAPH_PATH
// Free the resources the camera uses.
// This method is used only in the Compatibility Mode path.
public override void OnCameraCleanup(CommandBuffer cmd)
{
}
// Free the resources the texture uses.
// This method is used only in the Compatibility Mode path.
public void Dispose()
{
m_CopiedColor?.Release();
}
#endregion
#region PASS_RENDER_GRAPH_PATH
// Declare the resource the copy render pass uses.
// This method is used only in the render graph system path.
private class CopyPassData
{
public TextureHandle inputTexture;
}
// Declare the resources the main render pass uses.
// This method is used only in the render graph system path.
private class MainPassData
{
public Material material;
public TextureHandle inputTexture;
}
private static void ExecuteCopyColorPass(CopyPassData data, RasterGraphContext context)
{
ExecuteCopyColorPass(context.cmd, data.inputTexture);
}
private static void ExecuteMainPass(MainPassData data, RasterGraphContext context)
{
ExecuteMainPass(context.cmd, data.inputTexture.IsValid() ? data.inputTexture : null, data.material);
}
// Override the RecordRenderGraph method to implement the rendering logic.
// This method is used only in the render graph system path.
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
// Get the resources the pass uses.
UniversalResourceData resourcesData = frameData.Get<UniversalResourceData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
// Sample from the current color texture.
using (var builder = renderGraph.AddRasterRenderPass<MainPassData>(passName, out var passData, profilingSampler))
{
passData.material = m_Material;
TextureHandle destination;
// Copy cameraColor to a temporary texture, if the kSampleActiveColor property is set to true.
if (kSampleActiveColor)
{
var cameraColorDesc = renderGraph.GetTextureDesc(resourcesData.cameraColor);
cameraColorDesc.name = "_CameraColorCustomPostProcessing";
cameraColorDesc.clearBuffer = false;
destination = renderGraph.CreateTexture(cameraColorDesc);
passData.inputTexture = resourcesData.cameraColor;
// If you use framebuffer fetch in your material, use builder.SetInputAttachment to reduce GPU bandwidth usage and power consumption.
builder.UseTexture(passData.inputTexture, AccessFlags.Read);
}
else
{
destination = resourcesData.cameraColor;
passData.inputTexture = TextureHandle.nullHandle;
}
// Set the render graph to render to the temporary texture.
builder.SetRenderAttachment(destination, 0, AccessFlags.Write);
// Bind the depth-stencil buffer.
// This is a demonstration. The code isn't used in the example.
if (kBindDepthStencilAttachment)
builder.SetRenderAttachmentDepth(resourcesData.activeDepthTexture);
// Set the render method.
builder.SetRenderFunc((MainPassData data, RasterGraphContext context) => ExecuteMainPass(data, context));
// Set cameraColor to the new temporary texture so the next render pass can use it. You don't need to blit to and from cameraColor if you use the render graph system.
if (kSampleActiveColor)
{
resourcesData.cameraColor = destination;
}
}
}
#endregion
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 03e97e85a392e23469cd704039e21501
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
using System.IO;
using UnityEngine;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
namespace UnityEditor.Rendering.Universal
{
internal static class NewPostProcessTemplateDropdownItems
{
const string k_FeatureTemplatePath =
"Packages/com.unity.render-pipelines.universal/Editor/RendererFeatures/NewPostProcessRendererFeature.cs.txt";
const string k_VolumeTemplatePath =
"Packages/com.unity.render-pipelines.universal/Editor/RendererFeatures/NewPostProcessVolumeComponent.cs.txt";
static string PreprocessScriptTemplate(string content, string featureType = null, string volumeType = null, string displayName = null)
{
if(featureType != null)
content = content.Replace("#FEATURE_TYPE#", featureType);
if(volumeType != null)
content = content.Replace("#VOLUME_TYPE#", volumeType);
if(displayName != null)
content = content.Replace("#DISPLAY_NAME#", displayName);
return content;
}
static Object CreateScriptAssetFromTemplate(string templatePath, string targetPath, string featureType = null, string volumeType = null, string displayName = null)
{
string content = File.ReadAllText(templatePath);
return ProjectWindowUtil.CreateScriptAssetWithContent(targetPath, PreprocessScriptTemplate(content, featureType, volumeType, displayName));
}
internal class CreateCombinedScriptTemplateAssetsAction : ProjectWindowCallback.AssetCreationEndAction
{
public override void Action(EntityId entityId, string userPath, string resourceFile)
{
string directoryPath = Path.GetDirectoryName(userPath);
string enteredName = Path.GetFileNameWithoutExtension(userPath);
string cleanedEnteredNamed = enteredName.Replace(" ", "");
string featureTypeName = cleanedEnteredNamed + "RendererFeature";
string volumeTypeName = cleanedEnteredNamed + nameof(VolumeComponent);
try
{
AssetDatabase.StartAssetEditing();
Object o = CreateScriptAssetFromTemplate(k_FeatureTemplatePath,
Path.Combine(directoryPath, featureTypeName + ".cs"), featureTypeName, volumeTypeName, null);
CreateScriptAssetFromTemplate(k_VolumeTemplatePath,
Path.Combine(directoryPath, volumeTypeName + ".cs"), featureTypeName, volumeTypeName,
enteredName);
ProjectWindowUtil.ShowCreatedAsset(o);
}
finally
{
AssetDatabase.StopAssetEditing();
}
}
}
[MenuItem("Assets/Create/Scripting/URP Post-process Volume Scripts", priority = UnityEngine.Rendering.CoreUtils.Priorities.scriptingPriority + 1)]
static void MenuCreateCustomPostProcessVolumeRendererFeature()
{
Texture2D icon = EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D;
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(EntityId.None,
ScriptableObject.CreateInstance<CreateCombinedScriptTemplateAssetsAction>(), "NewPostProcessEffect.cs", icon, k_FeatureTemplatePath);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a1f945299a132004b958edeb1e9441dd
@@ -0,0 +1,35 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
// Defines a custom Volume Override component that controls the intensity of the URP Post-processing effect on a Scriptable Renderer Feature.
// For more information about the VolumeComponent API, refer to https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@17.2/api/UnityEngine.Rendering.VolumeComponent.html
// Add the Volume Override to the list of available Volume Override components in the Volume Profile.
[VolumeComponentMenu("Post-processing Custom/#DISPLAY_NAME#")]
// If the related Scriptable Renderer Feature doesn't exist, display a warning about adding it to the renderer.
[VolumeRequiresRendererFeatures(typeof(#FEATURE_TYPE#))]
// Make the Volume Override active in the Universal Render Pipeline.
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
// Set the name of the volume component in the list in the Volume Profile.
[DisplayInfo(name = "#DISPLAY_NAME#")]
// Create the Volume Override by inheriting from VolumeComponent
public sealed class #VOLUME_TYPE# : VolumeComponent, IPostProcessComponent
{
// Create a property to control the intensity of the effect, with a tooltip description.
// You can set the default value in the project-wide Graphics settings window. For more information, refer to https://docs.unity3d.com/Manual/urp/urp-global-settings.html
// You can override the value in a local or global volume. For more information, refer to https://docs.unity3d.com/Manual/urp/volumes-landing-page.html
// To access the value in a script, refer to the VolumeManager API: https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/api/UnityEngine.Rendering.VolumeManager.html
[Tooltip("Enter the description for the property that is shown when hovered")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(1f, 0f, 1f);
// Optional: Implement the IsActive() method of the IPostProcessComponent interface, and get the intensity value.
public bool IsActive()
{
return intensity.GetValue<float>() > 0.0f;
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: de03ee604e709ec44b8356ef5776a893
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(OnTilePostProcessFeature))]
internal class OnTilePostProcessFeatureEditor : Editor, IOwningRendererDataConsumer
{
#region Serialized Properties
private SerializedProperty m_UseFallbackProperty;
#endregion
static class Styles
{
public static readonly string k_NoSettingsHelpBox = L10n.Tr("Only pixel local post-processing effects are supported. For example color adjustments, vignette or film grain. There are currently no available settings.");
public static readonly string k_TileOnlyModeOffWarning = L10n.Tr("Tile-Only Mode is not enabled on this Renderer. This feature will fallback to texture sampling mode. This uses more GPU bandwidth and can reduce performance.");
}
private void OnEnable()
{
}
/// <summary>
/// The renderer data that owns the feature when the inspector is drawn.
/// </summary>
public ScriptableRendererData owningRendererData { get; set; }
public override void OnInspectorGUI()
{
var rendererData = (this as IOwningRendererDataConsumer).owningRendererData as UniversalRendererData;
if (rendererData == null || !rendererData.tileOnlyMode)
EditorGUILayout.HelpBox(Styles.k_TileOnlyModeOffWarning, MessageType.Warning);
EditorGUILayout.HelpBox(Styles.k_NoSettingsHelpBox, MessageType.Info);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f5d299eb05d633847b9327742901f749
@@ -0,0 +1,417 @@
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Experimental.Rendering.Universal;
using UnityEngine.Rendering.Universal;
using System.Collections.Generic;
using System.Reflection;
namespace UnityEditor.Rendering.Universal
{
/// <summary>
/// Editor script for the <c>RenderObjects</c> renderer feature.
/// </summary>
[CustomEditor(typeof(RenderObjects), true)]
public class ScriptableRendererFeatureEditor : Editor
{
/// <inheritdoc/>
public override void OnInspectorGUI()
{
DrawPropertiesExcluding(serializedObject, "m_Script");
}
}
}
namespace UnityEditor.Experimental.Rendering.Universal
{
[CustomPropertyDrawer(typeof(RenderObjects.RenderObjectsSettings), true)]
internal class RenderObjectsPassFeatureEditor : PropertyDrawer
{
internal class Styles
{
public static float defaultLineSpace = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
public static GUIContent callback = new GUIContent("Event", "Choose at which point this render pass is executed in the frame.");
//Headers
public static GUIContent filtersHeader = new GUIContent("Filters", "Settings that control which objects should be rendered.");
public static GUIContent renderHeader = new GUIContent("Overrides", "Different parts of the rendering that you can choose to override.");
//Filters
public static GUIContent renderQueueFilter = new GUIContent("Queue", "Only render objects in the selected render queue range.");
public static GUIContent layerMask = new GUIContent("Layer Mask", "Only render objects in a layer that match the given layer mask.");
public static GUIContent shaderPassFilter = new GUIContent("LightMode Tags", "Controls which shader passes to render by filtering by LightMode tag.");
//Render Options
public static GUIContent overrideMaterial = new GUIContent("Material", "Choose an override material, every renderer will be rendered with this material.");
public static GUIContent overrideMaterialPass = new GUIContent("Pass Index", "The pass index for the override material to use.");
public static GUIContent overrideShader = new GUIContent("Shader", "Choose an override shader, every renderer will be renderered with this shader and it's current material properties");
public static GUIContent overrideShaderPass = new GUIContent("Pass Index", "The pass index for the override shader to use.");
public static GUIContent overrideMode = new GUIContent("Override Mode", "Choose the material override mode. Material: override the material and all properties. Shader: override the shader and maintain current properties.");
//Depth Settings
public static GUIContent overrideDepth = new GUIContent("Depth", "Select this option to specify how this Renderer Feature affects or uses the values in the Depth buffer.");
public static GUIContent writeDepth = new GUIContent("Write Depth", "Choose to write depth to the screen.");
public static GUIContent depthState = new GUIContent("Depth Test", "Choose a new depth test function.");
public static GUIContent depthInputAttachment = new GUIContent("Set As Input Attachment", "Enable depth input attachment for efficient tile-based depth reading (DX12/Vulkan only). Depth will be read-only.");
//Camera Settings
public static GUIContent overrideCamera = new GUIContent("Camera", "Override camera matrices. Toggling this setting will make camera use perspective projection.");
public static GUIContent cameraFOV = new GUIContent("Field Of View", "The camera's view angle measured in degrees along vertical axis.");
public static GUIContent positionOffset = new GUIContent("Position Offset", "Position offset to apply to the original camera's position.");
public static GUIContent restoreCamera = new GUIContent("Restore", "Restore to the original camera matrices after the execution of the render passes added by this feature.");
}
//Headers and layout
private HeaderBool m_FiltersFoldout;
private int m_FilterLines = 3;
private HeaderBool m_RenderFoldout;
private int m_MaterialLines = 2;
private int m_DepthLines = 3;
private int m_CameraLines = 4;
// Serialized Properties
private SerializedProperty m_Callback;
private SerializedProperty m_PassTag;
//Filter props
private SerializedProperty m_FilterSettings;
private SerializedProperty m_RenderQueue;
private SerializedProperty m_LayerMask;
private SerializedProperty m_ShaderPasses;
//Render props
private SerializedProperty m_OverrideMaterial;
private SerializedProperty m_OverrideMaterialPass;
private SerializedProperty m_OverrideShader;
private SerializedProperty m_OverrideShaderPass;
private SerializedProperty m_OverrideMode;
//Depth props
private SerializedProperty m_OverrideDepth;
private SerializedProperty m_WriteDepth;
private SerializedProperty m_DepthState;
private SerializedProperty m_DepthInputAttachment;
//Stencil props
private SerializedProperty m_StencilSettings;
//Caemra props
private SerializedProperty m_CameraSettings;
private SerializedProperty m_OverrideCamera;
private SerializedProperty m_FOV;
private SerializedProperty m_CameraOffset;
private SerializedProperty m_RestoreCamera;
private List<SerializedObject> m_properties = new List<SerializedObject>();
static bool FilterRenderPassEvent(int evt) =>
// Return all events higher or equal than before rendering prepasses
evt >= (int)RenderPassEvent.BeforeRenderingPrePasses &&
// filter obsolete events
typeof(RenderPassEvent).GetField(Enum.GetName(typeof(RenderPassEvent), evt))?.GetCustomAttribute(typeof(ObsoleteAttribute)) == null;
// Return all render pass event names that match filterRenderPassEvent
private GUIContent[] m_EventOptionNames = Enum.GetValues(typeof(RenderPassEvent)).Cast<int>()
.Where(FilterRenderPassEvent)
.Select(x => new GUIContent(Enum.GetName(typeof(RenderPassEvent), x))).ToArray();
// Return all render pass event options that match filterRenderPassEvent
private int[] m_EventOptionValues = Enum.GetValues(typeof(RenderPassEvent)).Cast<int>()
.Where(FilterRenderPassEvent).ToArray();
private void Init(SerializedProperty property)
{
//Header bools
var key = $"{this.ToString().Split('.').Last()}.{property.serializedObject.targetObject.name}";
m_FiltersFoldout = new HeaderBool($"{key}.FiltersFoldout", true);
m_RenderFoldout = new HeaderBool($"{key}.RenderFoldout");
m_Callback = property.FindPropertyRelative("Event");
m_PassTag = property.FindPropertyRelative("passTag");
//Filter props
m_FilterSettings = property.FindPropertyRelative("filterSettings");
m_RenderQueue = m_FilterSettings.FindPropertyRelative("RenderQueueType");
m_LayerMask = m_FilterSettings.FindPropertyRelative("LayerMask");
m_ShaderPasses = m_FilterSettings.FindPropertyRelative("PassNames");
//Render options
m_OverrideMaterial = property.FindPropertyRelative("overrideMaterial");
m_OverrideMaterialPass = property.FindPropertyRelative("overrideMaterialPassIndex");
m_OverrideShader = property.FindPropertyRelative("overrideShader");
m_OverrideShaderPass = property.FindPropertyRelative("overrideShaderPassIndex");
m_OverrideMode = property.FindPropertyRelative("overrideMode");
//Depth props
m_OverrideDepth = property.FindPropertyRelative("overrideDepthState");
m_WriteDepth = property.FindPropertyRelative("enableWrite");
m_DepthState = property.FindPropertyRelative("depthCompareFunction");
m_DepthInputAttachment = property.FindPropertyRelative("depthInputAttachment");
//Stencil
m_StencilSettings = property.FindPropertyRelative("stencilSettings");
//Camera
m_CameraSettings = property.FindPropertyRelative("cameraSettings");
m_OverrideCamera = m_CameraSettings.FindPropertyRelative("overrideCamera");
m_FOV = m_CameraSettings.FindPropertyRelative("cameraFieldOfView");
m_CameraOffset = m_CameraSettings.FindPropertyRelative("offset");
m_RestoreCamera = m_CameraSettings.FindPropertyRelative("restoreCamera");
m_properties.Add(property.serializedObject);
}
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
rect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.BeginChangeCheck();
EditorGUI.BeginProperty(rect, label, property);
if (!m_properties.Contains(property.serializedObject))
{
Init(property);
}
var passName = property.serializedObject.FindProperty("m_Name").stringValue;
if (passName != m_PassTag.stringValue)
{
m_PassTag.stringValue = passName;
property.serializedObject.ApplyModifiedProperties();
}
//Forward Callbacks
EditorGUI.BeginChangeCheck();
int selectedValue = EditorGUI.IntPopup(rect, Styles.callback, m_Callback.intValue, m_EventOptionNames, m_EventOptionValues);
if (EditorGUI.EndChangeCheck())
m_Callback.intValue = selectedValue;
rect.y += Styles.defaultLineSpace;
// Validate Event is compatible with Depth Input Attachment
// Depth is only available after opaque rendering
if (m_OverrideDepth.boolValue && m_DepthInputAttachment.boolValue)
{
// AfterRenderingOpaques = 250
if (m_Callback.intValue < (int)RenderPassEvent.AfterRenderingOpaques)
{
Rect helpBoxRect = rect;
helpBoxRect.height = EditorGUIUtility.singleLineHeight * 2;
EditorGUI.HelpBox(helpBoxRect, "Depth Input Attachment requires Event to be set to 'AfterRenderingOpaques' or later. Depth is only available after the opaque pass.", MessageType.Error);
rect.y += helpBoxRect.height + EditorGUIUtility.standardVerticalSpacing;
}
}
DoFilters(ref rect);
m_RenderFoldout.value = EditorGUI.Foldout(rect, m_RenderFoldout.value, Styles.renderHeader, true);
SaveHeaderBool(m_RenderFoldout);
rect.y += Styles.defaultLineSpace;
if (m_RenderFoldout.value)
{
EditorGUI.indentLevel++;
//Override material
DoMaterialOverride(ref rect);
rect.y += Styles.defaultLineSpace;
//Override depth
DoDepthOverride(ref rect);
rect.y += Styles.defaultLineSpace;
//Override stencil
//Hide override stencil checkbox when depth input attachment is enabled.
if (!m_DepthInputAttachment.boolValue)
{
EditorGUI.PropertyField(rect, m_StencilSettings);
rect.y += EditorGUI.GetPropertyHeight(m_StencilSettings);
}
//Override camera
DoCameraOverride(ref rect);
rect.y += Styles.defaultLineSpace;
EditorGUI.indentLevel--;
}
EditorGUI.EndProperty();
if (EditorGUI.EndChangeCheck())
property.serializedObject.ApplyModifiedProperties();
}
void DoFilters(ref Rect rect)
{
m_FiltersFoldout.value = EditorGUI.Foldout(rect, m_FiltersFoldout.value, Styles.filtersHeader, true);
SaveHeaderBool(m_FiltersFoldout);
rect.y += Styles.defaultLineSpace;
if (m_FiltersFoldout.value)
{
EditorGUI.indentLevel++;
//Render queue filter
EditorGUI.PropertyField(rect, m_RenderQueue, Styles.renderQueueFilter);
rect.y += Styles.defaultLineSpace;
//Layer mask
EditorGUI.PropertyField(rect, m_LayerMask, Styles.layerMask);
rect.y += Styles.defaultLineSpace;
//Shader pass list
EditorGUI.PropertyField(rect, m_ShaderPasses, Styles.shaderPassFilter, true);
rect.y += EditorGUI.GetPropertyHeight(m_ShaderPasses);
EditorGUI.indentLevel--;
}
}
void DoMaterialOverride(ref Rect rect)
{
EditorGUI.PropertyField(rect, m_OverrideMode, Styles.overrideMode);
EditorGUI.indentLevel++;
switch (m_OverrideMode.intValue)
{
case (int)RenderObjects.RenderObjectsSettings.OverrideMaterialMode.None:
m_MaterialLines = 1;
break;
case (int)RenderObjects.RenderObjectsSettings.OverrideMaterialMode.Material:
m_MaterialLines = 3;
rect.y += Styles.defaultLineSpace;
EditorGUI.PropertyField(rect, m_OverrideMaterial, Styles.overrideMaterial);
rect.y += Styles.defaultLineSpace;
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(rect, m_OverrideMaterialPass, Styles.overrideMaterialPass);
if (EditorGUI.EndChangeCheck())
m_OverrideMaterialPass.intValue = Mathf.Max(0, m_OverrideMaterialPass.intValue);
break;
case (int)RenderObjects.RenderObjectsSettings.OverrideMaterialMode.Shader:
m_MaterialLines = 3;
rect.y += Styles.defaultLineSpace;
EditorGUI.PropertyField(rect, m_OverrideShader, Styles.overrideShader);
rect.y += Styles.defaultLineSpace;
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(rect, m_OverrideShaderPass, Styles.overrideShaderPass);
if (EditorGUI.EndChangeCheck())
m_OverrideShaderPass.intValue = Mathf.Max(0, m_OverrideShaderPass.intValue);
break;
}
EditorGUI.indentLevel--;
}
void DoDepthOverride(ref Rect rect)
{
EditorGUI.PropertyField(rect, m_OverrideDepth, Styles.overrideDepth);
if (m_OverrideDepth.boolValue)
{
rect.y += Styles.defaultLineSpace;
EditorGUI.indentLevel++;
// Add depth input attachment checkbox first (nested under Override Depth)
EditorGUI.PropertyField(rect, m_DepthInputAttachment, Styles.depthInputAttachment);
rect.y += Styles.defaultLineSpace;
// Show help box when enabled
if (m_DepthInputAttachment.boolValue)
{
Rect helpBoxRect = EditorGUI.IndentedRect(rect);
helpBoxRect.height = EditorGUIUtility.singleLineHeight * 2;
EditorGUI.HelpBox(helpBoxRect, "Depth Input Attachment will ignore Depth and Stencil overrides.", MessageType.Info);
rect.y += helpBoxRect.height + EditorGUIUtility.standardVerticalSpacing;
}
// Hide write depth checkbox when depth input attachment is enabled.
if (!m_DepthInputAttachment.boolValue)
{
EditorGUI.PropertyField(rect, m_WriteDepth, Styles.writeDepth);
rect.y += Styles.defaultLineSpace;
}
EditorGUI.PropertyField(rect, m_DepthState, Styles.depthState);
EditorGUI.indentLevel--;
}
}
void DoCameraOverride(ref Rect rect)
{
EditorGUI.PropertyField(rect, m_OverrideCamera, Styles.overrideCamera);
if (m_OverrideCamera.boolValue)
{
rect.y += Styles.defaultLineSpace;
EditorGUI.indentLevel++;
//FOV
EditorGUI.Slider(rect, m_FOV, 4f, 179f, Styles.cameraFOV);
rect.y += Styles.defaultLineSpace;
//Offset vector
var offset = m_CameraOffset.vector4Value;
EditorGUI.BeginChangeCheck();
var newOffset = EditorGUI.Vector3Field(rect, Styles.positionOffset, new Vector3(offset.x, offset.y, offset.z));
if (EditorGUI.EndChangeCheck())
m_CameraOffset.vector4Value = new Vector4(newOffset.x, newOffset.y, newOffset.z, 0f);
rect.y += Styles.defaultLineSpace;
//Restore prev camera projections
EditorGUI.PropertyField(rect, m_RestoreCamera, Styles.restoreCamera);
rect.y += Styles.defaultLineSpace;
EditorGUI.indentLevel--;
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float height = Styles.defaultLineSpace;
Init(property);
height += Styles.defaultLineSpace * (m_FiltersFoldout.value ? m_FilterLines : 1);
height += m_FiltersFoldout.value ? EditorGUI.GetPropertyHeight(m_ShaderPasses) : 0;
height += Styles.defaultLineSpace; // add line for Event dropdown
// Add height for Event validation error when Input Attachment is enabled with incompatible Event
if (m_OverrideDepth.boolValue && m_DepthInputAttachment.boolValue)
{
if (m_Callback.intValue < (int)RenderPassEvent.AfterRenderingOpaques)
{
height += (EditorGUIUtility.singleLineHeight * 2) + EditorGUIUtility.standardVerticalSpacing;
}
}
if (m_RenderFoldout.value)
{
height += Styles.defaultLineSpace * m_MaterialLines;
int depthLines = 1;
if (m_OverrideDepth.boolValue)
{
depthLines = m_DepthLines;
if (m_DepthInputAttachment.boolValue)
{
// Add help box height (2 line + spacing)
height += (EditorGUIUtility.singleLineHeight) * 2 + EditorGUIUtility.standardVerticalSpacing;
// Write depth is hidden
depthLines = depthLines - 1;
}
}
height += Styles.defaultLineSpace * (m_OverrideDepth.boolValue ? depthLines : 1);
if (!m_DepthInputAttachment.boolValue)
height += EditorGUI.GetPropertyHeight(m_StencilSettings);
height += Styles.defaultLineSpace * (m_OverrideCamera.boolValue ? m_CameraLines : 1);
}
return height;
}
private void SaveHeaderBool(HeaderBool boolObj)
{
EditorPrefs.SetBool(boolObj.key, boolObj.value);
}
class HeaderBool
{
public string key;
public bool value;
public HeaderBool(string _key, bool _default = false)
{
key = _key;
if (EditorPrefs.HasKey(key))
value = EditorPrefs.GetBool(key);
else
value = _default;
EditorPrefs.SetBool(key, value);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5714328aff96462894a2e15ecb5d503
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,324 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(ScreenSpaceAmbientOcclusion))]
internal class ScreenSpaceAmbientOcclusionEditor : Editor, IOwningRendererDataConsumer
{
#region Serialized Properties
private SerializedProperty m_AOMethod;
private SerializedProperty m_Downsample;
private SerializedProperty m_AfterOpaque;
private SerializedProperty m_Source;
private SerializedProperty m_NormalQuality;
private SerializedProperty m_Intensity;
private SerializedProperty m_DirectLightingStrength;
private SerializedProperty m_Radius;
private SerializedProperty m_Falloff;
private SerializedProperty m_Samples;
private SerializedProperty m_BlurQuality;
#endregion
private bool m_IsInitialized = false;
private HeaderBool m_ShowQualitySettings;
private HeaderBool m_ShowDeprecatedSettings;
private bool m_ShowAfterOpaqueTileOnlyError;
private static readonly string k_AfterOpaqueIncompatibleWithTileOnlyMode = L10n.Tr("'After Opaque' is incompatible with the enabled 'Tile-Only Mode'. Disable After Opaque.");
/// <summary>
/// The renderer data that owns the feature when the inspector is drawn.
/// </summary>
public ScriptableRendererData owningRendererData { get; set; }
class HeaderBool
{
private string key;
public bool value;
internal HeaderBool(string _key, bool _default = false)
{
key = _key;
if (EditorPrefs.HasKey(key))
value = EditorPrefs.GetBool(key);
else
value = _default;
EditorPrefs.SetBool(key, value);
}
internal void SetValue(bool newValue)
{
value = newValue;
EditorPrefs.SetBool(key, value);
}
}
// Structs
private struct Styles
{
public static GUIContent AOMethod = EditorGUIUtility.TrTextContent("Method", "The noise method to use when calculating the Ambient Occlusion value.");
public static GUIContent Intensity = EditorGUIUtility.TrTextContent("Intensity", "The degree of darkness that Ambient Occlusion adds.");
public static GUIContent Radius = EditorGUIUtility.TrTextContent("Radius", "The radius around a given point, where Unity calculates and applies the effect.");
public static GUIContent Falloff = EditorGUIUtility.TrTextContent("Falloff Distance", "The distance from the camera where Ambient Occlusion should be visible.");
public static GUIContent DirectLightingStrength = EditorGUIUtility.TrTextContent("Direct Lighting Strength", "Controls how much the ambient occlusion affects direct lighting.");
public static GUIContent Quality = EditorGUIUtility.TrTextContent("Quality", "");
public static GUIContent Source = EditorGUIUtility.TrTextContent("Source", "The source of the normal vector values.\nDepth Normals: the feature uses the values generated in the Depth Normal prepass.\nDepth: the feature reconstructs the normal values using the depth buffer.\nIn the Deferred rendering path, the feature uses the G-buffer normals texture.");
public static GUIContent NormalQuality = new GUIContent("Normal Quality", "The number of depth texture samples that Unity takes when computing the normals. Low:1 sample, Medium: 5 samples, High: 9 samples.");
public static GUIContent Downsample = EditorGUIUtility.TrTextContent("Downsample", "With this option enabled, Unity downsamples the SSAO effect texture to improve performance. Each dimension of the texture is reduced by a factor of 2.");
public static GUIContent AfterOpaque = EditorGUIUtility.TrTextContent("After Opaque", "With this option enabled, Unity calculates and apply SSAO after the opaque pass to improve performance on mobile platforms with tiled-based GPU architectures. This is not physically correct.");
public static GUIContent BlurQuality = EditorGUIUtility.TrTextContent("Blur Quality", "High: Bilateral, Medium: Gaussian. Low: Kawase (Single Pass).");
public static GUIContent Samples = EditorGUIUtility.TrTextContent("Samples", "The number of samples that Unity takes when calculating the obscurance value. Low:4 samples, Medium: 8 samples, High: 12 samples.");
}
private void Init()
{
m_ShowQualitySettings = new HeaderBool($"SSAO.QualityFoldout", false);
m_ShowDeprecatedSettings = new HeaderBool("SSAO.DeprecatedFoldout", false);
SerializedProperty settings = serializedObject.FindProperty("m_Settings");
m_AOMethod = settings.FindPropertyRelative("AOMethod");
m_Intensity = settings.FindPropertyRelative("Intensity");
m_Radius = settings.FindPropertyRelative("Radius");
m_Falloff = settings.FindPropertyRelative("Falloff");
m_DirectLightingStrength = settings.FindPropertyRelative("DirectLightingStrength");
m_Source = settings.FindPropertyRelative("Source");
m_NormalQuality = settings.FindPropertyRelative("NormalSamples");
m_Downsample = settings.FindPropertyRelative("Downsample");
m_AfterOpaque = settings.FindPropertyRelative("AfterOpaque");
m_BlurQuality = settings.FindPropertyRelative("BlurQuality");
m_Samples = settings.FindPropertyRelative("Samples");
m_IsInitialized = true;
}
public override void OnInspectorGUI()
{
if (!m_IsInitialized)
Init();
#if MODERN_SSAO
bool volumeActive = SceneHasActiveSSAOVolumeOverride();
if (volumeActive)
{
EditorGUILayout.HelpBox(
"A Screen Space Ambient Occlusion Volume Override is active in the scene and controls all SSAO settings. " +
"The settings below are kept as fallback only and will not take effect while the Volume Override is present.",
MessageType.Info);
}
else
{
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
EditorGUILayout.LabelField(
new GUIContent(
"Configuring SSAO via the SSAO Renderer Feature is deprecated. Use the new Screen Space Ambient Occlusion Volume Override instead.",
EditorGUIUtility.GetHelpIcon(MessageType.Info)),
EditorStyles.wordWrappedLabel);
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (GUILayout.Button("Add Volume Override"))
MigrateSettingsToVolume();
}
}
}
EditorGUILayout.Space(5);
m_ShowDeprecatedSettings.SetValue(EditorGUILayout.Foldout(m_ShowDeprecatedSettings.value, "Settings (Deprecated)"));
EditorGUI.BeginDisabledGroup(volumeActive);
if (m_ShowDeprecatedSettings.value)
{
EditorGUI.indentLevel++;
DrawSsaoSettingsGUI();
EditorGUI.indentLevel--;
}
EditorGUI.EndDisabledGroup();
#else
DrawSsaoSettingsGUI();
#endif
}
void DrawSsaoSettingsGUI()
{
EditorGUILayout.PropertyField(m_AOMethod, Styles.AOMethod);
EditorGUILayout.PropertyField(m_Intensity, Styles.Intensity);
EditorGUILayout.PropertyField(m_Radius, Styles.Radius);
EditorGUILayout.PropertyField(m_Falloff, Styles.Falloff);
m_DirectLightingStrength.floatValue = EditorGUILayout.Slider(Styles.DirectLightingStrength, m_DirectLightingStrength.floatValue, 0f, 1f);
// Make sure these fields are never below 0.0...
m_Intensity.floatValue = Mathf.Max(m_Intensity.floatValue, 0f);
m_Radius.floatValue = Mathf.Max(m_Radius.floatValue, 0f);
m_Falloff.floatValue = Mathf.Max(m_Falloff.floatValue, 0f);
m_ShowQualitySettings.SetValue(EditorGUILayout.Foldout(m_ShowQualitySettings.value, Styles.Quality));
if (m_ShowQualitySettings.value)
{
bool isDeferredRenderingMode = RendererIsDeferred();
EditorGUI.indentLevel++;
// Selecting source is not available for Deferred Rendering...
using (new EditorGUI.DisabledScope(isDeferredRenderingMode))
EditorGUILayout.PropertyField(m_Source, Styles.Source);
// We only enable this field when depth source is selected...
using (new EditorGUI.DisabledScope(isDeferredRenderingMode || m_Source.enumValueIndex != (int)ScreenSpaceAmbientOcclusionSettings.DepthSource.Depth))
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_NormalQuality, Styles.NormalQuality);
EditorGUI.indentLevel--;
}
EditorGUILayout.PropertyField(m_Downsample, Styles.Downsample);
EditorGUILayout.PropertyField(m_AfterOpaque, Styles.AfterOpaque);
if (Event.current.type == EventType.Layout)
{
var rendererData = (this as IOwningRendererDataConsumer).owningRendererData as UniversalRendererData;
bool tileOnlyMode = rendererData != null && rendererData.tileOnlyMode;
bool afterOpaque = m_AfterOpaque.boolValue;
m_ShowAfterOpaqueTileOnlyError = tileOnlyMode && afterOpaque;
}
if (m_ShowAfterOpaqueTileOnlyError)
EditorGUILayout.HelpBox(k_AfterOpaqueIncompatibleWithTileOnlyMode, MessageType.Error, true);
EditorGUILayout.PropertyField(m_BlurQuality, Styles.BlurQuality);
EditorGUILayout.PropertyField(m_Samples, Styles.Samples);
EditorGUI.indentLevel--;
}
}
#if MODERN_SSAO
static bool SceneHasActiveSSAOVolumeOverride()
{
var stack = VolumeManager.instance.stack;
if (stack == null)
return false;
var ssaoVolume = stack.GetComponent<ScreenSpaceAmbientOcclusionVolumeOverride>();
return ssaoVolume != null && ssaoVolume.AnyPropertiesIsOverridden();
}
static void CreateSSAOGlobalVolume(out Volume volume, out ScreenSpaceAmbientOcclusionVolumeOverride ssaoOverride)
{
var go = new GameObject("SSAO Global Volume");
Undo.RegisterCreatedObjectUndo(go, "Create SSAO Global Volume");
volume = go.AddComponent<Volume>();
volume.isGlobal = true;
Scene scene = go.scene;
var profile = VolumeProfileFactory.CreateVolumeProfile(scene, "SSAO Volume Profile");
volume.sharedProfile = profile;
// AnyPropertiesIsOverridden() must return true for the runtime volume takeover path to activate.
ssaoOverride = profile.Add<ScreenSpaceAmbientOcclusionVolumeOverride>(overrides: true);
AssetDatabase.AddObjectToAsset(ssaoOverride, profile);
}
void MigrateSettingsToVolume()
{
if (SceneHasActiveSSAOVolumeOverride())
{
bool proceed = EditorUtility.DisplayDialog(
"SSAO Volume Already Exists",
"An SSAO Volume Override already exists in the scene. " +
"A new global volume will be created which may conflict with the existing one. Continue?",
"Create Anyway", "Cancel");
if (!proceed)
return;
}
CreateSSAOGlobalVolume(out var volume, out var ssaoOverride);
Undo.RecordObject(ssaoOverride, "Migrate SSAO Settings to Volume");
var feature = (ScreenSpaceAmbientOcclusion)target;
#pragma warning disable CS0618
ref var settings = ref feature.settings;
#pragma warning restore CS0618
ssaoOverride.mode = ScreenSpaceAmbientOcclusionMode.Standard;
ssaoOverride.quality = ScreenSpaceAmbientOcclusionQuality.Custom;
ssaoOverride.intensity = settings.Intensity;
ssaoOverride.radius = settings.Radius;
ssaoOverride.falloffDistance = settings.Falloff;
ssaoOverride.directLightingStrength = settings.DirectLightingStrength;
ssaoOverride.downsample = settings.Downsample;
ssaoOverride.afterOpaque = settings.AfterOpaque;
ssaoOverride.method = settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.BlueNoise
? ScreenSpaceAmbientOcclusionNoiseMethod.BlueNoise
: ScreenSpaceAmbientOcclusionNoiseMethod.InterleavedGradient;
ssaoOverride.depthSource = (ScreenSpaceAmbientOcclusionDepthSource)(int)settings.Source;
ssaoOverride.normalQuality = (ScreenSpaceAmbientOcclusionNormalQuality)(int)settings.NormalSamples;
ssaoOverride.blurQuality = settings.BlurQuality switch
{
ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.High => ScreenSpaceAmbientOcclusionBlurQuality.High,
ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Medium => ScreenSpaceAmbientOcclusionBlurQuality.Medium,
_ => ScreenSpaceAmbientOcclusionBlurQuality.Low
};
ssaoOverride.sampleCount = settings.Samples switch
{
ScreenSpaceAmbientOcclusionSettings.AOSampleOption.High => ScreenSpaceAmbientOcclusionSampleCount.High,
ScreenSpaceAmbientOcclusionSettings.AOSampleOption.Medium => ScreenSpaceAmbientOcclusionSampleCount.Medium,
_ => ScreenSpaceAmbientOcclusionSampleCount.Low
};
EditorUtility.SetDirty(ssaoOverride);
EditorUtility.SetDirty(volume.sharedProfile);
AssetDatabase.SaveAssets();
string profilePath = AssetDatabase.GetAssetPath(volume.sharedProfile);
var volumeGo = volume.gameObject;
EditorApplication.delayCall += () =>
{
if (volumeGo == null)
return;
Selection.activeGameObject = volumeGo;
EditorGUIUtility.PingObject(volumeGo);
};
}
#endif
private bool RendererIsDeferred()
{
ScreenSpaceAmbientOcclusion ssaoFeature = (ScreenSpaceAmbientOcclusion) target;
UniversalRenderPipelineAsset pipelineAsset = (UniversalRenderPipelineAsset) GraphicsSettings.currentRenderPipeline;
if (ssaoFeature == null || pipelineAsset == null)
return false;
// We have to find the renderer related to the SSAO feature, then test if it is in deferred mode.
var rendererDataList = pipelineAsset.m_RendererDataList;
for (int rendererIndex = 0; rendererIndex < rendererDataList.Length; ++rendererIndex)
{
var rendererData = rendererDataList[rendererIndex] as UniversalRendererData;
if (rendererData == null)
continue;
if (!rendererData.usesDeferredLighting)
continue;
var rendererFeatures = rendererData.rendererFeatures;
foreach (var feature in rendererFeatures)
if (feature is ScreenSpaceAmbientOcclusion occlusion && occlusion == ssaoFeature)
return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b4f00de1d40f4b4988c4f3cb7f4dcb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,32 @@
#if URP_SCREEN_SPACE_REFLECTION
using System;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(ScreenSpaceReflectionRendererFeature))]
internal class ScreenSpaceReflectionRendererFeatureEditor : Editor
{
SerializedProperty m_AfterOpaque;
public void OnEnable()
{
m_AfterOpaque = serializedObject.FindProperty(nameof(ScreenSpaceReflectionRendererFeature.afterOpaque));
}
public override void OnInspectorGUI()
{
#if UNITY_WEBGL
GraphicsDeviceType[] graphicsApis = PlayerSettings.GetGraphicsAPIs(BuildTarget.WebGL);
if (Array.FindIndex(graphicsApis, x => x == GraphicsDeviceType.WebGPU) == -1)
EditorGUILayout.HelpBox("WebGL is not supported for Screen Space Reflection.", MessageType.Warning);
#endif
EditorGUILayout.PropertyField(m_AfterOpaque);
EditorGUILayout.Space();
EditorGUILayout.HelpBox("Additional settings for Screen Space Reflection can be found in the Screen Space Reflection volume override on your Volume Profile.", MessageType.Info);
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76586561fc958cb488c6bbede8bf83c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,36 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(ScreenSpaceShadows))]
internal class ScreenSpaceShadowsEditor : Editor
{
#region Serialized Properties
private SerializedProperty m_SettingsProp;
#endregion
private bool m_IsInitialized = false;
static class Styles
{
public static readonly string k_NoSettingsHelpBox = L10n.Tr("This feature resolves the cascaded shadows in screen space, so there is no options now. It might have additional settings later.");
}
private void Init()
{
m_SettingsProp = serializedObject.FindProperty("m_Settings");
m_IsInitialized = true;
}
public override void OnInspectorGUI()
{
if (!m_IsInitialized)
{
Init();
}
EditorGUILayout.HelpBox(Styles.k_NoSettingsHelpBox, MessageType.Info);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d79f23692575f9d4f894c5b5a4b0ccad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,83 @@
#if SURFACE_CACHE
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(SurfaceCacheGIRendererFeature))]
internal class SurfaceCacheGIEditor : Editor
{
private bool m_IsInitialized;
// Debug parameters
private SerializedProperty _debugEnabled;
private SerializedProperty _debugViewMode;
private SerializedProperty _debugShowSamplePosition;
private struct TextContent
{
public static GUIContent DebugEnabled = EditorGUIUtility.TrTextContent("Debug Enabled", "Enable debug visualization.");
public static GUIContent DebugViewMode = EditorGUIUtility.TrTextContent("Debug View Mode", "Debug visualization mode.");
public static GUIContent DebugShowSamplePosition = EditorGUIUtility.TrTextContent("Debug Show Sample Position", "Show sample positions in debug view.");
}
private void Init()
{
m_IsInitialized = true;
SerializedProperty paramSets = serializedObject.FindProperty("_parameterSet");
_debugEnabled = paramSets.FindPropertyRelative("DebugEnabled");
_debugViewMode = paramSets.FindPropertyRelative("DebugViewMode");
_debugShowSamplePosition = paramSets.FindPropertyRelative("DebugShowSamplePosition");
}
private static bool SceneHasSurfaceCacheGIVolume()
{
Volume[] volumes = Object.FindObjectsByType<Volume>(FindObjectsInactive.Exclude);
for (int i = 0; i < volumes.Length; i++)
{
if (volumes[i].sharedProfile != null && volumes[i].sharedProfile.Has<SurfaceCacheGIVolumeOverride>())
return true;
}
return false;
}
public override void OnInspectorGUI()
{
if (!m_IsInitialized)
Init();
if (PlayerSettings.GetStaticBatchingForPlatform(EditorUserBuildSettings.activeBuildTarget))
{
var surfaceCacheFeature = (SurfaceCacheGIRendererFeature)target;
EditorGUILayout.HelpBox(SurfaceCacheGIRendererFeature.k_StaticBatchingErrorMesssage, surfaceCacheFeature.isActive ? MessageType.Error : MessageType.Warning);
}
else if (SceneView.lastActiveSceneView && !SceneView.lastActiveSceneView.sceneViewState.alwaysRefreshEnabled)
{
EditorGUILayout.HelpBox("Enable \"Always Refresh\" in the Scene View to see realtime updates in the Scene View.", MessageType.Info);
}
// Info box explaining volume-based control — only shown when no volume in the scene has the override
if (!SceneHasSurfaceCacheGIVolume())
{
EditorGUILayout.HelpBox("Many Surface Cache settings are controlled via the Volume system. Add a 'Surface Cache Global Illumination' volume override to your scene to adjust these settings per-scene.", MessageType.Info);
}
EditorGUILayout.Space();
// Debug settings
EditorGUILayout.LabelField("Debugging", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_debugEnabled, TextContent.DebugEnabled);
EditorGUILayout.PropertyField(_debugViewMode, TextContent.DebugViewMode);
EditorGUILayout.PropertyField(_debugShowSamplePosition, TextContent.DebugShowSamplePosition);
serializedObject.ApplyModifiedProperties();
}
}
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d5f6a7ce5f9e41eb8f3b1910acaacd49
timeCreated: 1733488061