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,8 @@
fileFormatVersion: 2
guid: d51fac0e1a1a7074ab4397427e551ea5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,369 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Pool;
namespace UnityEditor.Rendering
{
/// <summary>
/// Set of utilities for analytics
/// </summary>
public static class AnalyticsUtils
{
const string k_VendorKey = "unity.srp";
internal static void SendData(IAnalytic analytic)
{
EditorAnalytics.SendAnalytic(analytic);
}
/// <summary>
/// Gets a list of the serializable fields of the given type
/// </summary>
/// <param name="type">The type to get fields that are serialized.</param>
/// <param name="removeObsolete">If obsolete fields are taken into account</param>
/// <returns>The collection of <see cref="FieldInfo"/> that are serialized for this type</returns>
public static IEnumerable<FieldInfo> GetSerializableFields(this Type type, bool removeObsolete = false)
{
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (type.BaseType != null && type.BaseType != typeof(object))
{
foreach (FieldInfo field in type.BaseType.GetSerializableFields())
{
yield return field;
}
}
foreach (var member in members)
{
if (member.MemberType != MemberTypes.Field && member.MemberType != MemberTypes.Property)
{
continue;
}
if (member.DeclaringType != type || member is not FieldInfo field)
{
continue;
}
if (removeObsolete && member.GetCustomAttribute<ObsoleteAttribute>() != null)
continue;
if (field.IsPublic)
{
if (member.GetCustomAttribute<NonSerializedAttribute>() != null)
continue;
yield return field;
}
else
{
if (member.GetCustomAttribute<SerializeField>() != null)
yield return field;
}
}
}
static bool AreArraysDifferent(IList a, IList b)
{
if ((a == null) && (b == null))
return false;
if ((a == null) ^ (b == null))
return true;
if (a.Count != b.Count)
return true;
for (int i = 0; i < a.Count; i++)
{
if (!a[i].Equals(b[i]))
return true;
}
return false;
}
static string DumpValues(this IList list)
{
using (ListPool<string>.Get(out var tempList))
{
for (int i = 0; i < list.Count; i++)
{
tempList.Add(list[i] != null ? list[i].ToString() : "null");
}
var arrayValues = string.Join(",", tempList);
return $"[{arrayValues}]";
}
}
static Dictionary<string, string> DumpValues(Type type, object current)
{
var diff = new Dictionary<string, string>();
foreach (var field in type.GetSerializableFields(removeObsolete: true))
{
var t = field.FieldType;
try
{
if (typeof(ScriptableObject).IsAssignableFrom(t))
continue;
var valueCurrent = current != null ? field.GetValue(current) : null;
if (t == typeof(string))
{
var stringCurrent = (string)valueCurrent;
diff[field.Name] = stringCurrent;
}
else if (t.IsPrimitive || t.IsEnum)
{
diff[field.Name] = ConvertPrimitiveWithInvariants(valueCurrent);
}
else if (t.IsArray && valueCurrent is IList valueCurrentList)
{
diff[field.Name] = valueCurrentList.DumpValues();
}
else if (t.IsClass || t.IsValueType)
{
if (valueCurrent is IEnumerable ea)
continue; // List<T> not supported
var subDiff = DumpValues(t, valueCurrent);
foreach (var d in subDiff)
{
diff[field.Name + "." + d.Key] = d.Value;
}
}
}
catch (Exception ex)
{
Debug.LogError($"Exception found while parsing {field}, {ex}");
}
}
return diff;
}
static Dictionary<string, string> GetDiffAsDictionary(Type type, object current, object defaults)
{
var diff = new Dictionary<string, string>();
foreach (var field in type.GetSerializableFields())
{
var fieldType = field.FieldType;
if (!IsFieldIgnored(fieldType))
AddDiff(current, defaults, field, fieldType, diff);
}
return diff;
}
private static void AddDiff(object current, object defaults, FieldInfo field, Type fieldType, Dictionary<string, string> diff)
{
try
{
var valueCurrent = current != null ? field.GetValue(current) : null;
var valueDefault = defaults != null ? field.GetValue(defaults) : null;
AddIfDifferent(field, fieldType, diff, valueCurrent, valueDefault);
}
catch (Exception ex)
{
Debug.LogError($"Exception found while parsing {field}, {ex}");
}
}
private static void AddIfDifferent(FieldInfo field, Type fieldType, Dictionary<string, string> diff, object valueCurrent, object valueDefault)
{
if (!AreValuesEqual(fieldType, valueCurrent, valueDefault))
{
if (IsComplexType(fieldType))
{
var subDiff = GetDiffAsDictionary(fieldType, valueCurrent, valueDefault);
foreach (var d in subDiff)
{
diff[$"{field.Name}.{d.Key}"] = d.Value;
}
}
else
{
diff[field.Name] = ConvertValueToString(valueCurrent);
}
}
}
static bool IsFieldIgnored(Type fieldType)
{
return fieldType.GetCustomAttribute<ObsoleteAttribute>() != null || typeof(ScriptableObject).IsAssignableFrom(fieldType);
}
internal static bool AreValuesEqual(Type fieldType, object valueCurrent, object valueDefault)
{
if (fieldType == typeof(string))
return (string)valueCurrent == (string)valueDefault;
if (fieldType.IsPrimitive || fieldType.IsEnum)
return valueCurrent.Equals(valueDefault);
if (fieldType.IsArray && valueCurrent is IList currentList)
return !AreArraysDifferent(currentList, valueDefault as IList);
if (valueCurrent == null && valueDefault == null)
return true;
return valueDefault?.Equals(valueCurrent) ?? valueCurrent?.Equals(null) ?? false;
}
internal static bool IsComplexType(Type fieldType)
{
// Primitive types and enums are not considered complex
if (fieldType.IsPrimitive || fieldType.IsEnum)
return false;
// String is considered a primitive type for our purposes
if (fieldType == typeof(string))
return false;
// Arrays can be converted to string easy without sub-elements
if (fieldType.IsArray)
return false;
// Value types (structs) that are not primitive are considered complex
// Classes are considered complex types
return fieldType.IsValueType || fieldType.IsClass;
}
static string ConvertValueToString(object value)
{
if (value == null) return null;
if (value is IList list) return list.DumpValues();
return ConvertPrimitiveWithInvariants(value);
}
static string ConvertPrimitiveWithInvariants(object obj)
{
if (obj is IConvertible convertible)
return convertible.ToString(CultureInfo.InvariantCulture);
return obj.ToString();
}
static string[] ToStringArray(Dictionary<string, string> diff, string format = null)
{
var changedSettings = new string[diff.Count];
if (string.IsNullOrEmpty(format))
format = @"{{""{0}"":""{1}""}}";
int i = 0;
foreach (var d in diff)
changedSettings[i++] = string.Format(format, d.Key, d.Value);
return changedSettings;
}
private static string[] EnumerableToNestedColumn<T>([DisallowNull] this IEnumerable collection)
{
using (ListPool<string>.Get(out var tmp))
{
foreach (var element in collection)
{
string[] elementColumns = ToStringArray(DumpValues(element.GetType(), element), @"""{0}"":""{1}""");
tmp.Add("{" + string.Join(", ", elementColumns) + "}");
}
return tmp.ToArray();
}
}
private static string[] ToNestedColumnSimplify<T>([DisallowNull] this T current)
where T : new()
{
var type = current.GetType();
if (typeof(UnityEngine.Object).IsAssignableFrom(typeof(T)))
{
var instance = ScriptableObject.CreateInstance(type);
ToStringArray(GetDiffAsDictionary(type, current, instance));
ScriptableObject.DestroyImmediate(instance);
}
return ToStringArray(GetDiffAsDictionary(type, current, new T()));
}
/// <summary>
/// Obtains the Serialized fields and values in form of nested columns for BigQuery
/// https://cloud.google.com/bigquery/docs/nested-repeated
/// </summary>
/// <typeparam name="T">The given type</typeparam>
/// <param name="current">The current object to obtain the fields and values.</param>
/// <param name="compareAndSimplifyWithDefault">If a comparison against the default value must be done.</param>
/// <returns>The nested columns in form of {key.nestedKey : value} </returns>
/// <exception cref="ArgumentNullException">Throws an exception if current parameter is null.</exception>
public static string[] ToNestedColumn<T>([DisallowNull] this T current, bool compareAndSimplifyWithDefault = false)
where T : new()
{
if (current == null)
throw new ArgumentNullException(nameof(current));
if (current is IEnumerable currentAsEnumerable)
return EnumerableToNestedColumn<T>(currentAsEnumerable);
if (compareAndSimplifyWithDefault)
return ToNestedColumnSimplify(current);
return ToStringArray(DumpValues(current.GetType(), current));
}
/// <summary>
/// Obtains the Serialized fields and values in form of nested columns for BigQuery
/// https://cloud.google.com/bigquery/docs/nested-repeated
/// </summary>
/// <typeparam name="T">The given type</typeparam>
/// <param name="current">The current object to obtain the fields and values.</param>
/// <param name="defaultInstance">The default instance to compare values</param>
/// <returns>The nested columns in form of {key.nestedKey : value} </returns>
/// <exception cref="ArgumentNullException">Throws an exception if the current or defaultInstance parameters are null.</exception>
public static string[] ToNestedColumn<T>([DisallowNull] this T current, T defaultInstance)
{
if (current == null)
throw new ArgumentNullException(nameof(current));
if (defaultInstance == null)
throw new ArgumentNullException(nameof(defaultInstance));
var type = current.GetType();
Dictionary<string, string> diff = GetDiffAsDictionary(type, current, defaultInstance);
return ToStringArray(diff);
}
/// <summary>
/// Obtains the Serialized fields and values in form of nested columns for BigQuery
/// https://cloud.google.com/bigquery/docs/nested-repeated
/// </summary>
/// <typeparam name="T">The given type</typeparam>
/// <param name="current">The current object to obtain the fields and values.</param>
/// <param name="defaultObject">The default object</param>
/// <param name="compareAndSimplifyWithDefault">If a comparison against the default value must be done.</param>
/// <returns>The nested columns in form of {key.nestedKey : value} </returns>
/// <exception cref="ArgumentNullException">Throws an exception if the current parameter is null.</exception>
public static string[] ToNestedColumnWithDefault<T>([DisallowNull] this T current, [DisallowNull] T defaultObject, bool compareAndSimplifyWithDefault = false)
{
if (current == null)
throw new ArgumentNullException(nameof(current));
var type = current.GetType();
Dictionary<string, string> diff = (compareAndSimplifyWithDefault) ?
GetDiffAsDictionary(type, current, defaultObject) : DumpValues(type, current);
return ToStringArray(diff);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed711ee78a4b6e74896cbc8dbf636441
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,66 @@
using JetBrains.Annotations;
using System;
using System.Diagnostics.CodeAnalysis;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
internal class BuildTargetAnalytic : IPostprocessBuildWithReport
{
public int callbackOrder => int.MaxValue;
[AnalyticInfo(eventName: "uBuildTargetAnalytic", vendorKey: "unity.srp", maxEventsPerHour: 10, maxNumberOfElements: 1000)]
internal class Analytic : IAnalytic
{
[MustUseReturnValue]
public bool TryGatherData([NotNullWhen(true)] out IAnalytic.IData data, [NotNullWhen(false)] out Exception error)
{
var activeBuildTarget = EditorUserBuildSettings.activeBuildTarget;
var activeBuildTargetGroup = BuildPipeline.GetBuildTargetGroup(activeBuildTarget);
var activeBuildTargetGroupName = NamedBuildTarget.FromBuildTargetGroup(activeBuildTargetGroup).TargetName;
error = null;
var assetType = GraphicsSettings.currentRenderPipeline == null ? "Built-In Render Pipeline" : GraphicsSettings.currentRenderPipeline.GetType().ToString();
data = new BuildTargetAnalyticData()
{
build_target = activeBuildTarget.ToString(),
quality_levels = QualitySettings.GetActiveQualityLevelsForPlatformCount(activeBuildTargetGroupName),
render_pipeline_asset_type = assetType,
total_quality_levels_on_project = QualitySettings.count
};
return true;
}
};
[System.Diagnostics.DebuggerDisplay("{render_pipeline_asset_type} - {quality_levels}/{total_quality_levels_on_project}")]
[Serializable]
internal struct BuildTargetAnalyticData : IAnalytic.IData
{
// Naming convention for analytics data
public string build_target;
public string render_pipeline_asset_type;
public int quality_levels;
public int total_quality_levels_on_project;
};
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport _)
{
SendAnalytic();
}
[MenuItem("internal:Edit/Rendering/Analytics/Send BuildTargetAnalytic ", priority = 0)]
static void SendAnalytic()
{
Analytic analytic = new Analytic();
EditorAnalytics.SendAnalytic(analytic);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f249a7110f8dd14ca061023fb8aa6e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,70 @@
using System;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uRenderGraphViewerSessionCreated_v1
// taxonomy = editor.analytics.uRenderGraphViewerSessionCreated.v1
internal class RenderGraphViewerSessionCreatedAnalytic
{
const int k_MaxEventsPerHour = 1000;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
const string k_EventName = "uRenderGraphViewerSessionCreated";
public enum SessionType
{
Local = 0,
Remote = 1
}
[AnalyticInfo(eventName: k_EventName, vendorKey: k_VendorKey, maxEventsPerHour: k_MaxEventsPerHour, maxNumberOfElements: k_MaxNumberOfElements)]
class Analytic : IAnalytic
{
public Analytic(SessionType sessionType, DebugMessageHandler.AnalyticsPayload payload)
{
using (GenericPool<Data>.Get(out var data))
{
data.session_type = sessionType.ToString();
data.graphics_device_type = payload.graphicsDeviceType.ToString();
data.device_type = payload.deviceType.ToString();
data.device_model = payload.deviceModel;
data.gpu_vendor = payload.gpuVendor;
data.gpu_name = payload.gpuName;
m_Data = data;
}
}
[Serializable]
class Data : IAnalytic.IData
{
// Naming convention for analytics data
public string session_type;
public string graphics_device_type;
public string device_type;
public string device_model;
public string gpu_vendor;
public string gpu_name;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
data = m_Data;
error = null;
return true;
}
Data m_Data;
};
public static void Send(SessionType sessionType, DebugMessageHandler.AnalyticsPayload payload)
{
Analytic analytic = new Analytic(sessionType, payload);
AnalyticsUtils.SendData(analytic);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a22b1f2645743e0b78bd9fd651a38c8
timeCreated: 1746442904
@@ -0,0 +1,67 @@
using System;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class RenderPipelineGraphicsSettingsAnalytics : IPostprocessBuildWithReport
{
const int k_MaxEventsPerHour = 1000;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
const string k_EventName = "uRenderPipelineGraphicsSettingsUsage";
[AnalyticInfo(eventName: k_EventName, vendorKey: k_VendorKey, maxEventsPerHour: k_MaxEventsPerHour, maxNumberOfElements: k_MaxNumberOfElements)]
public class Analytic : IAnalytic
{
[Serializable]
public struct AnalyticsData : IAnalytic.IData
{
public string settings;
public string[] usage;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
data = GatherDataToBeSent();
error = null;
return true;
}
public static IAnalytic.DataList<AnalyticsData> GatherDataToBeSent()
{
using (ListPool<AnalyticsData>.Get(out var tmp))
{
GraphicsSettings.ForEach(settings =>
{
var settingsType = settings.GetType();
var usage = settings.ToNestedColumn(Activator.CreateInstance(settingsType));
if (usage.Length != 0)
tmp.Add(new AnalyticsData() { settings = settingsType.FullName, usage = usage });
});
return new IAnalytic.DataList<AnalyticsData>(tmp.ToArray());
}
}
}
static void SendUniversalEvent()
{
//The event shouldn't be able to report if this is disabled but if we know we're not going to report
//Lets early out and not waste time gathering all the data
if (!EditorAnalytics.enabled)
return;
Analytic analytic = new Analytic();
EditorAnalytics.SendAnalytic(analytic);
}
public int callbackOrder { get; }
public void OnPostprocessBuild(BuildReport report)
{
SendUniversalEvent();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 24edf9d94fc418047a951393fca40966
@@ -0,0 +1,66 @@
using System;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
using static UnityEngine.Analytics.IAnalytic;
using Scene = UnityEditor.SearchService.SceneSearch;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumePriorityUsageAnalyticData_v2
// taxonomy = editor.analytics.uVolumePriorityUsageAnalyticData.v2
internal class VolumePriorityUsageAnalytic
{
[AnalyticInfo(eventName: "uVolumePriorityUsageAnalyticData", version: 2, vendorKey: "unity.srp")]
class Analytic : IAnalytic
{
public Analytic(Volume volume, string guid)
{
using (GenericPool<Data>.Get(out var data))
{
data.volume_name = Hash128.Compute(volume.name).ToString();
data.scene_name = guid;
data.priority = volume.priority;
m_Data = data;
}
}
[System.Diagnostics.DebuggerDisplay("{volume_name} - {scene_name} - {priority}")]
[Serializable]
class Data : IAnalytic.IData
{
// Naming convention for analytics data
public string volume_name;
public string scene_name;
public float priority;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
data = m_Data;
error = null;
return true;
}
Data m_Data;
};
public static void Send(Volume volume)
{
if (volume == null)
return;
var sceneGUID = EditorSceneManager.GetActiveScene().GetGUID();
GUID guid = new GUID(sceneGUID);
if (guid.Empty())
return;
Analytic analytic = new Analytic(volume, sceneGUID);
AnalyticsUtils.SendData(analytic);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b29e0569eca4bc54da7a07d64b33e1b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,95 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using System.Diagnostics.CodeAnalysis;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Analytics;
using System;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumeProfileOverridesAnalytic_v2
// taxonomy = editor.analytics.uVolumeProfileOverridesAnalytic.v2
internal class VolumeProfileOverridesAnalytic : IPostprocessBuildWithReport
{
public int callbackOrder => int.MaxValue;
[AnalyticInfo(eventName: "uVolumeProfileOverridesAnalytic", version: 2, maxEventsPerHour:1000, vendorKey: "unity.srp")]
public class Analytic : IAnalytic
{
public Analytic(string asset_guid, string type, string[] p)
{
m_Data = new Data
{
volume_profile_asset_guid = asset_guid,
component_type = type,
overrided_parameters = p
};
}
[System.Diagnostics.DebuggerDisplay("{volume_profile_asset_guid} - {component_type} - {overrided_parameters.Length}")]
[Serializable]
struct Data : IAnalytic.IData
{
// Naming convention for analytics data
public string volume_profile_asset_guid;
public string component_type;
public string[] overrided_parameters;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
data = m_Data;
error = null;
return true;
}
Data m_Data;
}
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport _)
{
SendAnalytic();
}
private static readonly string[] k_SearchFolders = new[] { "Assets" };
[MustUseReturnValue]
static bool TryGatherData([NotNullWhen(true)] out List<IAnalytic> datas, [NotNullWhen(false)] out string warning)
{
warning = string.Empty;
datas = new List<IAnalytic>();
var volumeProfileGUIDs = AssetDatabase.FindAssets($"t:{nameof(VolumeProfile)} glob:\"**/*.asset\"", k_SearchFolders);
foreach (var guid in volumeProfileGUIDs)
{
var volumeProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(AssetDatabase.GUIDToAssetPath(guid));
if (volumeProfile == null)
continue;
foreach (var volumeComponent in volumeProfile.components)
{
var volumeComponentType = volumeComponent.GetType();
var defaultVolumeComponent = (VolumeComponent) ScriptableObject.CreateInstance(volumeComponentType);
var overrideParameters = volumeComponent.ToNestedColumnWithDefault(defaultVolumeComponent, true);
if (overrideParameters.Length == 0)
continue;
datas.Add(new Analytic(guid, volumeComponent.GetType().Name, overrideParameters));
}
}
return true;
}
[MenuItem("internal:Edit/Rendering/Analytics/Send VolumeProfileOverridesAnalytic ", priority = 1)]
static void SendAnalytic()
{
if (!TryGatherData(out var data, out var warning))
Debug.Log(warning);
data.ForEach(d => AnalyticsUtils.SendData(d));
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e30261210b9c0040baf9d684f0b3e8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,55 @@
using System;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumeProfileUsageAnalytic_v4
// taxonomy = editor.analytics.uVolumeProfileUsageAnalytic.v4
internal class VolumeProfileUsageAnalytic
{
[AnalyticInfo(eventName: "uVolumeProfileUsageAnalytic", version: 4, vendorKey: "unity.srp" )]
class Analytic : IAnalytic
{
public Analytic(Volume volume, VolumeProfile volumeProfile)
{
using (GenericPool<Data>.Get(out var data))
{
data.volume_name = Hash128.Compute(volume.name).ToString();
data.scene_name = EditorSceneManager.GetActiveScene().GetGUID();
data.volume_profile_asset_guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(volumeProfile.GetEntityId()));
m_Data = data;
}
}
[System.Diagnostics.DebuggerDisplay("{volume_name} - {scene_name}- {volume_profile_asset_guid}")]
[Serializable]
class Data : IAnalytic.IData
{
// Naming convention for analytics data
public string volume_name;
public string scene_name;
public string volume_profile_asset_guid;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
data = m_Data;
error = null;
return true;
}
Data m_Data;
};
public static void Send(Volume volume, VolumeProfile volumeProfile)
{
if (volume == null || volumeProfile == null)
return;
Analytic analytic = new Analytic(volume, volumeProfile);
AnalyticsUtils.SendData(analytic);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e7e0182f8c41fea4aaebcffa2915a381
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Shared")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.HighDefinition.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Universal.Editor.Tests")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")]
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfa722e189cafe743b7884ff1953f0b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Rendering
{
/// <summary> Set of helpers for AssetDatabase operations. </summary>
public static class AssetDatabaseHelper
{
/// <summary>
/// Finds all assets of type T in the project.
/// </summary>
/// <param name="extension">Asset type extension i.e ".mat" for materials. Specifying extension make this faster.</param>
/// <typeparam name="T">The type of asset you are looking for</typeparam>
/// <returns>An IEnumerable off all assets found.</returns>
public static IEnumerable<T> FindAssets<T>(string extension = null)
where T : Object
{
string query = BuildQueryToFindAssets<T>(extension);
foreach (var guid in AssetDatabase.FindAssets(query))
{
var asset = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(guid));
if (asset is T castAsset)
yield return castAsset;
}
}
/// <summary>
/// Finds all assets paths of type T in the project.
/// </summary>
/// <param name="extension">Asset type extension i.e ".mat" for materials. Specifying extension make this faster.</param>
/// <typeparam name="T">The type of asset you are looking for</typeparam>
/// <returns>An IEnumerable off all assets paths found.</returns>
public static IEnumerable<string> FindAssetPaths<T>(string extension = null)
where T : Object
{
string query = BuildQueryToFindAssets<T>(extension);
foreach (var guid in AssetDatabase.FindAssets(query))
yield return AssetDatabase.GUIDToAssetPath(guid);
}
static string BuildQueryToFindAssets<T>(string extension = null)
where T : Object
{
string typeName = typeof(T).ToString();
int i = typeName.LastIndexOf('.');
if (i != -1)
{
typeName = typeName.Substring(i+1, typeName.Length - i-1);
}
return string.IsNullOrEmpty(extension) ? $"t:{typeName}" : $"t:{typeName} glob:\"**/*{extension}\"";
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ecc2633973414f6d8bbab97cf0c937b4
timeCreated: 1693402114
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d846ae44708583940a0e44aa66cff1c9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// Contains a set of needed data for building.
/// This might also being called when building Asset Bundles
/// </summary>
public class CoreBuildData : IDisposable
{
static CoreBuildData m_Instance = null;
/// <summary>
/// Instance to the current <see cref="CoreBuildData"/>.
/// </summary>
public static CoreBuildData instance => m_Instance ??= CreateInstance();
/// <summary>
/// If the target build has an SRP configured
/// </summary>
public bool buildingPlayerForRenderPipeline { get; private set; } = false;
/// <summary>
/// A valid type of <see cref="RenderPipelineAsset"/>, that the build is targeting,
/// </summary>
public Type currentRenderPipelineAssetType { get; private set; } = null;
/// <summary>
/// A list of <see cref="RenderPipelineAsset"/>, all of them of the same type.
/// </summary>
public List<RenderPipelineAsset> renderPipelineAssets { get; private set; } = new();
/// <summary>
/// Whether the current build's managed code variant has <c>UNITY_ENABLE_CHECKS</c> defined
/// (Debug or Checked variant).
/// </summary>
/// <remarks>
/// Use this to gate inclusion of diagnostic shaders, resources, and other build-time decisions
/// that mirror C# code paths compiled under <c>#if UNITY_ENABLE_CHECKS</c>.
/// </remarks>
public bool useDiagnosticChecks
{
get
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
return PlayerSettings.GetManagedCodeVariant(GetNamedBuildTarget(buildTarget)) <= ManagedCodeVariant.Checked;
}
}
/// <summary>
/// Obsolete. Always returns <c>false</c>.
/// </summary>
[Obsolete("developmentBuild is no longer populated and always returns false. Use useDiagnosticChecks for stripping decisions that mirror UNITY_ENABLE_CHECKS-gated C# code.")]
public bool developmentBuild => false;
internal Dictionary<EntityId, ComputeShader> computeShaderCache { get; private set; } = new();
internal bool pipelineSupportGPUResidentDrawer { get; private set; } = false;
internal bool playerNeedGPUResidentDrawer { get; private set; } = false;
private CoreBuildData(BuildTarget buildTarget)
{
m_Instance = this;
if (!buildTarget.TryGetRenderPipelineAssets(renderPipelineAssets))
return;
buildingPlayerForRenderPipeline = true;
//We can check only the first as we don't support multiple pipeline type in player
var asset = renderPipelineAssets[0];
currentRenderPipelineAssetType = asset.GetType();
CheckGPUResidentDrawerUsage();
}
private static CoreBuildData CreateInstance()
=> new(EditorUserBuildSettings.activeBuildTarget);
// NamedBuildTarget for buildTarget under the active subtarget (Player vs Server for Standalone).
private static NamedBuildTarget GetNamedBuildTarget(BuildTarget buildTarget)
{
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
if (buildTargetGroup == BuildTargetGroup.Standalone &&
EditorUserBuildSettings.standaloneBuildSubtarget == StandaloneBuildSubtarget.Server)
{
return NamedBuildTarget.Server;
}
return NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
}
private void CheckGPUResidentDrawerUsage()
{
foreach (var renderPipelineAsset in renderPipelineAssets)
{
if (renderPipelineAsset is IGPUResidentRenderPipeline gpuResidentPipelineAsset
&& gpuResidentPipelineAsset.IsGPUResidentDrawerSupportedBySRP())
{
// Record if any pipeline supports the GPU resident drawer
pipelineSupportGPUResidentDrawer = true;
// If any pipeline already has GPU resident drawer enabled, then record this and also early out
if (gpuResidentPipelineAsset.gpuResidentDrawerSettings.mode != GPUResidentDrawerMode.Disabled)
{
playerNeedGPUResidentDrawer = true;
break;
}
}
}
if (!playerNeedGPUResidentDrawer)
return;
#pragma warning disable 618 // Todo(@daniel.andersen): Remove deprecated API usage
GraphicsSettings.GetRenderPipelineSettings<GPUResidentDrawerResources>()
.ForEachFieldOfType<ComputeShader>(computeShader => computeShaderCache.Add(computeShader.GetEntityId(), computeShader));
#pragma warning restore 618
}
/// <summary>
/// Dispose all the gathered data for building
/// </summary>
public void Dispose()
{
renderPipelineAssets?.Clear();
computeShaderCache?.Clear();
m_Instance = null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 77db4492d35e8db4fb0fe2936a0879e2
@@ -0,0 +1,25 @@
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace UnityEditor.Rendering
{
//Make CoreBuildData constructed and kept till end of build
class CorePreprocessBuild : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
int IOrderedCallback.callbackOrder => int.MinValue + 50;
private static CoreBuildData m_BuildData = null;
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
{
m_BuildData?.Dispose();
m_BuildData = CoreBuildData.instance;
}
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
{
m_BuildData?.Dispose();
m_BuildData = null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2ae707d91841f5849935209a93425289
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f9e0abec186274f4f8a49394c1fef24b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class GPUResidentDrawerResourcesStripper : IRenderPipelineGraphicsSettingsStripper<GPUResidentDrawerResources>
{
public bool active => true;
public bool CanRemoveSettings(GPUResidentDrawerResources settings) => !CoreBuildData.instance.pipelineSupportGPUResidentDrawer || !CoreBuildData.instance.playerNeedGPUResidentDrawer;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: efeaffd0d0bd818459953697384fc1d9
@@ -0,0 +1,11 @@
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class RenderingDebuggerRuntimeResourcesStripper : IRenderPipelineGraphicsSettingsStripper<RenderingDebuggerRuntimeResources>
{
public bool active => true;
public bool CanRemoveSettings(RenderingDebuggerRuntimeResources settings) => !CoreBuildData.instance.useDiagnosticChecks;
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b0efad93b2507274daeaf8cc7306a312
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using UnityEngine;
namespace UnityEditor.Rendering
{
class SRPDisabledComputeShaderVariantStripper : IComputeShaderVariantStripper
{
public bool active => !CoreBuildData.instance.buildingPlayerForRenderPipeline;
#pragma warning disable 618 // Todo(@daniel.andersen): Remove deprecated API usage
public bool CanRemoveVariant([DisallowNull] ComputeShader shader, string _, ShaderCompilerData __)
=> CoreBuildData.instance.computeShaderCache.ContainsKey(shader.GetEntityId());
#pragma warning restore 618
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9f2d47f6376246d49bf978c4dbbe3686
@@ -0,0 +1,111 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using UnityEditor.Build;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// Extensions for <see cref="BuildTarget"/>
/// </summary>
public static class BuildTargetExtensions
{
static bool NeedsToBeIncludedInBuildBylabel(RenderPipelineAsset asset, string label)
{
var labelList = AssetDatabase.GetLabels(asset);
foreach (string item in labelList)
{
if (item == label)
return true;
}
return false;
}
static void AddAdditionalRenderPipelineAssetsIncludedForBuild<T>(HashSet<T> assetsList)
where T : RenderPipelineAsset
{
var includer = GraphicsSettings.GetRenderPipelineSettings<IncludeAdditionalRPAssets>();
if (includer == null)
return;
bool includeSceneDependencies = includer.includeReferencedInScenes;
bool includeAssetsWithLabel = includer.includeAssetsByLabel;
string labelToInclude = includer.labelToInclude;
if (!includeSceneDependencies && !includeAssetsWithLabel)
return;
using (ListPool<string>.Get(out var assetsPaths))
{
assetsPaths.AddRange(AssetDatabaseHelper.FindAssetPaths<T>(".asset"));
if (includeSceneDependencies)
{
using (ListPool<string>.Get(out var scenesPaths))
{
foreach (var scene in EditorBuildSettings.scenes)
if (scene.enabled)
scenesPaths.Add(scene.path);
// Get all enabled scenes path in the build settings.
HashSet<string> depsHash = new HashSet<string>(AssetDatabase.GetDependencies(scenesPaths.ToArray()));
for (int i = 0; i < assetsPaths.Count; ++i)
{
var assetPath = assetsPaths[i];
if (depsHash.Contains(assetPath))
assetsList.Add(AssetDatabase.LoadAssetAtPath<T>(assetPath));
}
}
}
if (includeAssetsWithLabel)
{
for (int i = 0; i < assetsPaths.Count; ++i)
{
// Add the assets that are labeled to be included
var asset = AssetDatabase.LoadAssetAtPath<T>(assetsPaths[i]);
if (NeedsToBeIncludedInBuildBylabel(asset, labelToInclude))
assetsList.Add(asset);
}
}
}
}
/// <summary>
/// Obtains a list of the <see cref="RenderPipelineAsset"/> that are references into the settings either on <see cref="QualitySettings"/> or in <see cref="GraphicsSettings"/>
/// </summary>
/// <typeparam name="T">The type of <see cref="RenderPipelineAsset"/></typeparam>
/// <param name="buildTarget">The <see cref="BuildTarget"/> to obtain the assets.</param>
/// <param name="srpAssets">The output list of <see cref="RenderPipelineAsset"/> that are referenced by the platform.</param>
/// <returns>false if there was an error fetching the <see cref="RenderPipelineAsset"/> for this <see cref="BuildTarget"/></returns>
[MustUseReturnValue]
public static bool TryGetRenderPipelineAssets<T>([DisallowNull] this BuildTarget buildTarget, List<T> srpAssets)
where T : RenderPipelineAsset
{
if (srpAssets == null)
return false;
var activeBuildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
var namedBuildTarget = NamedBuildTarget.FromBuildTargetGroup(activeBuildTargetGroup);
QualitySettings.GetRenderPipelineAssetsForPlatform<T>(namedBuildTarget.TargetName, out var buildPipelineAssets, out var allQualityLevelsAreOverriden);
bool noQualityLevels = QualitySettings.GetActiveQualityLevelsForPlatformCount(namedBuildTarget.TargetName) == 0;
if (noQualityLevels || !allQualityLevelsAreOverriden)
{
// We need to check the fallback cases
if (GraphicsSettings.defaultRenderPipeline is T srpAsset)
buildPipelineAssets.Add(srpAsset);
}
if (buildPipelineAssets.Count != 0)
AddAdditionalRenderPipelineAssetsIncludedForBuild(buildPipelineAssets);
srpAssets.AddRange(buildPipelineAssets);
return srpAssets.Count != 0;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e78621c9df5d0b4d884d48b1ded36c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 234fa6c8645c73d4e8857414e1823942
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,171 @@
using System.Linq;
using UnityEngine;
namespace UnityEditor.Rendering
{
/// <summary> Camera UI Shared Properties among SRP</summary>
public static partial class CameraUI
{
/// <summary>Camera Projection type</summary>
public enum ProjectionType
{
/// <summary> Perspective</summary>
Perspective,
/// <summary> Orthographic</summary>
Orthographic
}
/// <summary>Camera Projection matrix mode</summary>
public enum ProjectionMatrixMode
{
/// <summary> Explicit</summary>
Explicit,
/// <summary> Implicit</summary>
Implicit,
/// <summary> PhysicalPropertiesBased</summary>
PhysicalPropertiesBased,
}
static bool s_FovChanged;
static float s_FovLastValue;
static ProjectionType DrawerProjectionType(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
ProjectionType projectionType;
Rect perspectiveRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(perspectiveRect, Styles.projectionContent, cam.orthographic);
{
projectionType = cam.orthographic.boolValue ? ProjectionType.Orthographic : ProjectionType.Perspective;
EditorGUI.BeginChangeCheck();
projectionType = (ProjectionType)EditorGUI.EnumPopup(perspectiveRect, Styles.projectionContent, projectionType);
if (EditorGUI.EndChangeCheck())
cam.orthographic.boolValue = (projectionType == ProjectionType.Orthographic);
}
EditorGUI.EndProperty();
return projectionType;
}
static void DrawerOrthographicType(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.orthographicSize, Styles.sizeContent);
Drawer_FieldClippingPlanes(p, owner);
}
static void DrawerPerspectiveType(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
var targets = p.serializedObject.targetObjects;
var camera0 = targets[0] as Camera;
float fovCurrentValue;
bool multipleDifferentFovValues = false;
bool isPhysicalCamera = p.projectionMatrixMode.intValue == (int)ProjectionMatrixMode.PhysicalPropertiesBased;
var rect = EditorGUILayout.GetControlRect();
var guiContent = EditorGUI.BeginProperty(rect, Styles.FOVAxisModeContent, cam.fovAxisMode);
EditorGUI.showMixedValue = cam.fovAxisMode.hasMultipleDifferentValues;
CoreEditorUtils.DrawEnumPopup<Camera.FieldOfViewAxis>(rect, guiContent, cam.fovAxisMode);
bool fovAxisVertical = cam.fovAxisMode.intValue == 0;
if (!fovAxisVertical && !cam.fovAxisMode.hasMultipleDifferentValues)
{
float aspectRatio = isPhysicalCamera ? cam.sensorSize.vector2Value.x / cam.sensorSize.vector2Value.y : camera0.aspect;
// camera.aspect is not serialized so we have to check all targets.
fovCurrentValue = Camera.VerticalToHorizontalFieldOfView(camera0.fieldOfView, aspectRatio);
if (targets.Cast<Camera>().Any(camera => camera.fieldOfView != fovCurrentValue))
multipleDifferentFovValues = true;
}
else
{
fovCurrentValue = cam.verticalFOV.floatValue;
multipleDifferentFovValues = cam.fovAxisMode.hasMultipleDifferentValues;
}
EditorGUI.showMixedValue = multipleDifferentFovValues;
var content = EditorGUI.BeginProperty(EditorGUILayout.BeginHorizontal(), Styles.fieldOfViewContent, cam.verticalFOV);
EditorGUI.BeginDisabledGroup(p.projectionMatrixMode.hasMultipleDifferentValues || isPhysicalCamera && (cam.sensorSize.hasMultipleDifferentValues || cam.fovAxisMode.hasMultipleDifferentValues));
EditorGUI.BeginChangeCheck();
s_FovLastValue = EditorGUILayout.Slider(content, fovCurrentValue, 0.00001f, 179f);
s_FovChanged = EditorGUI.EndChangeCheck();
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
EditorGUI.EndProperty();
EditorGUI.showMixedValue = false;
Drawer_FieldClippingPlanes(p, owner);
content = EditorGUI.BeginProperty(EditorGUILayout.BeginHorizontal(), Styles.physicalCameraContent, p.projectionMatrixMode);
EditorGUI.showMixedValue = p.projectionMatrixMode.hasMultipleDifferentValues;
EditorGUI.BeginChangeCheck();
isPhysicalCamera = EditorGUILayout.Toggle(content, isPhysicalCamera);
if (EditorGUI.EndChangeCheck())
{
p.projectionMatrixMode.intValue = isPhysicalCamera ? (int)ProjectionMatrixMode.PhysicalPropertiesBased : (int)ProjectionMatrixMode.Implicit;
s_FovChanged = true;
}
EditorGUILayout.EndHorizontal();
EditorGUI.EndProperty();
EditorGUI.showMixedValue = false;
if (s_FovChanged)
{
if (!isPhysicalCamera || p.projectionMatrixMode.hasMultipleDifferentValues)
{
cam.verticalFOV.floatValue = fovAxisVertical
? s_FovLastValue
: Camera.HorizontalToVerticalFieldOfView(s_FovLastValue, camera0.aspect);
}
else if (!p.projectionMatrixMode.hasMultipleDifferentValues)
{
cam.verticalFOV.floatValue = fovAxisVertical
? s_FovLastValue
: Camera.HorizontalToVerticalFieldOfView(s_FovLastValue, camera0.aspect);
}
}
}
/// <summary>Draws projection related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Projection(ISerializedCamera p, Editor owner)
{
// Most of this is replicated from CameraEditor.DrawProjection as we don't want to draw
// it the same way it's done in non-SRP cameras. Unfortunately, because a lot of the
// code is internal, we have to copy/paste some stuff from the editor code :(
var projectionType = DrawerProjectionType(p, owner);
if (p.baseCameraSettings.orthographic.hasMultipleDifferentValues)
return;
using (new EditorGUI.IndentLevelScope())
{
if (projectionType == ProjectionType.Orthographic)
{
DrawerOrthographicType(p, owner);
}
else
{
DrawerPerspectiveType(p, owner);
}
}
}
static void Drawer_FieldClippingPlanes(ISerializedCamera p, Editor owner)
{
CoreEditorUtils.DrawMultipleFields(
Styles.clippingPlaneMultiFieldTitle,
new[] { p.baseCameraSettings.nearClippingPlane, p.baseCameraSettings.farClippingPlane },
new[] { Styles.nearPlaneContent, Styles.farPlaneContent });
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0d2633fc585aec4a8a89a6014bd7640
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
/// <summary>
/// Environment Section
/// </summary>
public static partial class Environment
{
/// <summary>Draws layer mask planes related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Environment_VolumeLayerMask(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.volumeLayerMask, Styles.volumeLayerMask);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 40b2b7ce6c436184b91d2d7ea4ef35ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
public static partial class Environment
{
/// <summary>
/// Styles
/// </summary>
public static class Styles
{
/// <summary>
/// Header of the section
/// </summary>
public static readonly GUIContent header = EditorGUIUtility.TrTextContent("Environment", "These settings control what the camera background looks like.");
/// <summary>
/// Volume layer mask content
/// </summary>
public static readonly GUIContent volumeLayerMask = EditorGUIUtility.TrTextContent("Volume Mask", "This camera will only be affected by volumes in the selected scene-layers.");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c94bc25276e67ea429b40e3228a39b05
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,47 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
/// <summary>
/// Output Section
/// </summary>
public static partial class Output
{
/// <summary>Draws Allow Dynamic Resolution related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
/// <param name="customLabel">Override property name</param>
public static void Drawer_Output_AllowDynamicResolution(ISerializedCamera p, Editor owner, GUIContent customLabel = null)
{
EditorGUILayout.PropertyField(p.allowDynamicResolution, customLabel ?? Styles.allowDynamicResolution);
p.baseCameraSettings.allowDynamicResolution.boolValue = p.allowDynamicResolution.boolValue;
}
/// <summary>Draws Normalized ViewPort related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Output_NormalizedViewPort(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.normalizedViewPortRect, Styles.viewport);
}
/// <summary>Draws Depth related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Output_Depth(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.depth, Styles.depth);
}
/// <summary>Draws Render Target related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Output_RenderTarget(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.targetTexture);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c77d1122a4e2ed448966b1535f9f1130
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,43 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
public static partial class Output
{
/// <summary>
/// Styles
/// </summary>
public static class Styles
{
/// <summary>
/// Header of the section
/// </summary>
public static readonly GUIContent header = EditorGUIUtility.TrTextContent("Output", "These settings control how the camera output is formatted.");
#if ENABLE_MULTIPLE_DISPLAYS
/// <summary>
/// Target display content
/// </summary>
public static readonly GUIContent targetDisplay = EditorGUIUtility.TrTextContent("Target Display");
#endif
/// <summary>
/// Viewport
/// </summary>
public static readonly GUIContent viewport = EditorGUIUtility.TrTextContent("Viewport Rect", "Four values that indicate where on the screen HDRP draws this Camera view. Measured in Viewport Coordinates (values in the range of [0, 1]).");
/// <summary>
/// Allow dynamic resolution content
/// </summary>
public static readonly GUIContent allowDynamicResolution = EditorGUIUtility.TrTextContent("Allow Dynamic Resolution", "Whether to support dynamic resolution.");
/// <summary>
/// Depth content
/// </summary>
public static readonly GUIContent depth = EditorGUIUtility.TrTextContent("Depth");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f82f0aee4a6afa04f86310b233ea3d66
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,286 @@
using System;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
/// <summary>
/// Physical camera related drawers
/// </summary>
public static partial class PhysicalCamera
{
// Saves the value of the sensor size when the user switches from "custom" size to a preset per camera.
// We use a ConditionalWeakTable instead of a Dictionary to avoid keeping alive (with strong references) deleted cameras
static ConditionalWeakTable<Camera, object> s_PerCameraSensorSizeHistory = new ConditionalWeakTable<Camera, object>();
/// <summary>Draws Body Sensor related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_CameraBody_Sensor(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
EditorGUI.BeginChangeCheck();
int oldFilmGateIndex = Array.IndexOf(Styles.apertureFormatValues, new Vector2((float)Math.Round(cam.sensorSize.vector2Value.x, 3), (float)Math.Round(cam.sensorSize.vector2Value.y, 3)));
// If it is not one of the preset sizes, set it to custom
oldFilmGateIndex = (oldFilmGateIndex == -1) ? Styles.customPresetIndex : oldFilmGateIndex;
// Get the new user selection
int newFilmGateIndex = EditorGUILayout.Popup(Styles.sensorType, oldFilmGateIndex, Styles.apertureFormatNames);
if (EditorGUI.EndChangeCheck())
{
// Retrieve the previous custom size value, if one exists for this camera
object previousCustomValue;
s_PerCameraSensorSizeHistory.TryGetValue((Camera)p.serializedObject.targetObject, out previousCustomValue);
// When switching from custom to a preset, update the last custom value (to display again, in case the user switches back to custom)
if (oldFilmGateIndex == Styles.customPresetIndex)
{
if (previousCustomValue == null)
{
s_PerCameraSensorSizeHistory.Add((Camera)p.serializedObject.targetObject, cam.sensorSize.vector2Value);
}
else
{
previousCustomValue = cam.sensorSize.vector2Value;
}
}
if (newFilmGateIndex < Styles.customPresetIndex)
{
cam.sensorSize.vector2Value = Styles.apertureFormatValues[newFilmGateIndex];
}
else
{
// The user switched back to custom, so display by deafulr the previous custom value
if (previousCustomValue != null)
{
cam.sensorSize.vector2Value = (Vector2)previousCustomValue;
}
else
{
cam.sensorSize.vector2Value = new Vector2(36.0f, 24.0f); // this is the value new cameras are created with
}
}
}
EditorGUILayout.PropertyField(cam.sensorSize, Styles.sensorSize);
}
/// <summary>Draws Gate fit related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_CameraBody_GateFit(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
using (var horizontal = new EditorGUILayout.HorizontalScope())
using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Styles.gateFit, cam.gateFit))
using (var checkScope = new EditorGUI.ChangeCheckScope())
{
int gateValue = (int)(Camera.GateFitMode)EditorGUILayout.EnumPopup(propertyScope.content, (Camera.GateFitMode)cam.gateFit.intValue);
if (checkScope.changed)
cam.gateFit.intValue = gateValue;
}
}
/// <summary>Draws Focal Length related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_Lens_FocalLength(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
using (var horizontal = new EditorGUILayout.HorizontalScope())
using (new EditorGUI.PropertyScope(horizontal.rect, Styles.focalLength, cam.focalLength))
using (var checkScope = new EditorGUI.ChangeCheckScope())
{
bool isPhysical = p.projectionMatrixMode.intValue == (int)CameraUI.ProjectionMatrixMode.PhysicalPropertiesBased;
// We need to update the focal length if the camera is physical and the FoV has changed.
bool focalLengthIsDirty = (s_FovChanged && isPhysical);
float sensorLength = cam.fovAxisMode.intValue == 0 ? cam.sensorSize.vector2Value.y : cam.sensorSize.vector2Value.x;
float focalLengthVal = focalLengthIsDirty ? Camera.FieldOfViewToFocalLength(s_FovLastValue, sensorLength) : cam.focalLength.floatValue;
focalLengthVal = EditorGUILayout.FloatField(Styles.focalLength, focalLengthVal);
if (checkScope.changed || focalLengthIsDirty)
cam.focalLength.floatValue = focalLengthVal;
}
}
/// <summary>Draws Lens Shift related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_Lens_Shift(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.lensShift, Styles.shift);
}
/// <summary>Draws Focus Distance related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_FocusDistance(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
EditorGUILayout.PropertyField(cam.focusDistance, Styles.focusDistance);
}
/// <summary>Draws ISO related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_CameraBody_ISO(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
EditorGUILayout.PropertyField(cam.iso, Styles.ISO);
}
static EditorPrefBoolFlags<ShutterSpeedUnit> m_ShutterSpeedState = new EditorPrefBoolFlags<ShutterSpeedUnit>($"HDRP:{nameof(CameraUI)}:ShutterSpeedState");
enum ShutterSpeedUnit
{
[InspectorName("Second")]
Second,
[InspectorName("1 \u2215 Second")] // Don't use a slash here else Unity will auto-create a submenu...
OneOverSecond
}
/// <summary>Draws Shutter Speed related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_CameraBody_ShutterSpeed(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
// Custom layout for shutter speed
const int k_UnitMenuWidth = 90;
const int k_OffsetPerIndent = 15;
const int k_LabelFieldSeparator = 2;
const int k_Offset = 1;
int oldIndentLevel = EditorGUI.indentLevel;
// Don't take into account the indentLevel when rendering the units field
EditorGUI.indentLevel = 0;
var lineRect = EditorGUILayout.GetControlRect();
var fieldRect = new Rect(k_OffsetPerIndent + k_LabelFieldSeparator + k_Offset, lineRect.y, lineRect.width - k_UnitMenuWidth, lineRect.height);
var unitMenu = new Rect(fieldRect.xMax + k_LabelFieldSeparator, lineRect.y, k_UnitMenuWidth - k_LabelFieldSeparator, lineRect.height);
// We cannot had the shutterSpeedState as this is not a serialized property but a global edition mode.
// This imply that it will never go bold nor can be reverted in prefab overrides
m_ShutterSpeedState.value = (ShutterSpeedUnit)EditorGUI.EnumPopup(unitMenu, m_ShutterSpeedState.value);
// Reset the indent level
EditorGUI.indentLevel = oldIndentLevel;
EditorGUI.BeginProperty(fieldRect, Styles.shutterSpeed, cam.shutterSpeed);
{
// if we we use (1 / second) units, then change the value for the display and then revert it back
if (m_ShutterSpeedState.value == ShutterSpeedUnit.OneOverSecond && cam.shutterSpeed.floatValue > 0)
cam.shutterSpeed.floatValue = 1.0f / cam.shutterSpeed.floatValue;
EditorGUI.PropertyField(fieldRect, cam.shutterSpeed, Styles.shutterSpeed);
if (m_ShutterSpeedState.value == ShutterSpeedUnit.OneOverSecond && cam.shutterSpeed.floatValue > 0)
cam.shutterSpeed.floatValue = 1.0f / cam.shutterSpeed.floatValue;
}
EditorGUI.EndProperty();
}
/// <summary>Draws Lens Aperture related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_Lens_Aperture(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
// Custom layout for aperture
var rect = EditorGUILayout.BeginHorizontal();
{
// Magic values/offsets to get the UI look consistent
const float textRectSize = 80;
const float textRectPaddingRight = 62;
const float unitRectPaddingRight = 97;
const float sliderPaddingLeft = 2;
const float sliderPaddingRight = 77;
var labelRect = rect;
labelRect.width = EditorGUIUtility.labelWidth;
labelRect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.LabelField(labelRect, Styles.aperture);
GUI.SetNextControlName("ApertureSlider");
var sliderRect = rect;
sliderRect.x += labelRect.width + sliderPaddingLeft;
sliderRect.width = rect.width - labelRect.width - sliderPaddingRight;
float newVal = GUI.HorizontalSlider(sliderRect, cam.aperture.floatValue, Camera.kMinAperture, Camera.kMaxAperture);
// keep only 2 digits of precision, like the otehr editor fields
newVal = Mathf.Floor(100 * newVal) / 100.0f;
if (cam.aperture.floatValue != newVal)
{
cam.aperture.floatValue = newVal;
// Note: We need to move the focus when the slider changes, otherwise the textField will not update
GUI.FocusControl("ApertureSlider");
}
var unitRect = rect;
unitRect.x += rect.width - unitRectPaddingRight;
unitRect.width = textRectSize;
unitRect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.LabelField(unitRect, "f /", EditorStyles.label);
var textRect = rect;
textRect.x = rect.width - textRectPaddingRight;
textRect.width = textRectSize;
textRect.height = EditorGUIUtility.singleLineHeight;
string newAperture = EditorGUI.TextField(textRect, cam.aperture.floatValue.ToString());
if (float.TryParse(newAperture, out float parsedValue))
cam.aperture.floatValue = Mathf.Clamp(parsedValue, Camera.kMinAperture, Camera.kMaxAperture);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(EditorGUIUtility.singleLineHeight);
}
/// <summary>Draws Aperture Shape related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_PhysicalCamera_ApertureShape(ISerializedCamera p, Editor owner)
{
var cam = p.baseCameraSettings;
EditorGUILayout.PropertyField(cam.bladeCount, Styles.bladeCount);
using (var horizontal = new EditorGUILayout.HorizontalScope())
using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Styles.curvature, cam.curvature))
{
var v = cam.curvature.vector2Value;
// The layout system breaks alignment when mixing inspector fields with custom layout'd
// fields as soon as a scrollbar is needed in the inspector, so we'll do the layout
// manually instead
const int kFloatFieldWidth = 50;
const int kSeparatorWidth = 5;
float indentOffset = EditorGUI.indentLevel * 15f;
var lineRect = EditorGUILayout.GetControlRect();
var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y, lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height);
var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height);
EditorGUI.PrefixLabel(labelRect, propertyScope.content);
v.x = EditorGUI.FloatField(floatFieldLeft, v.x);
EditorGUI.MinMaxSlider(sliderRect, ref v.x, ref v.y, Camera.kMinAperture, Camera.kMaxAperture);
v.y = EditorGUI.FloatField(floatFieldRight, v.y);
cam.curvature.vector2Value = v;
}
EditorGUILayout.PropertyField(cam.barrelClipping, Styles.barrelClipping);
EditorGUILayout.PropertyField(cam.anamorphism, Styles.anamorphism);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7fbad490dc4ecc46b2936be42e9c71f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,116 @@
using System.Linq;
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
public static partial class PhysicalCamera
{
/// <summary>
/// Styles
/// </summary>
public static class Styles
{
// Camera Body
/// <summary>
/// Camera Body content
/// </summary>
public static readonly GUIContent cameraBody = EditorGUIUtility.TrTextContent("Camera Body");
/// <summary>
/// Sensor type content
/// </summary>
public static readonly GUIContent sensorType = EditorGUIUtility.TrTextContent("Sensor Type", "Common sensor sizes. Choose an item to set Sensor Size, or edit Sensor Size for your custom settings.");
/// <summary>
/// Aperture format names
/// </summary>
public static readonly string[] apertureFormatNames = CameraEditor.Settings.ApertureFormatNames.ToArray();
/// <summary>
/// Aperture format values
/// </summary>
public static readonly Vector2[] apertureFormatValues = CameraEditor.Settings.ApertureFormatValues.ToArray();
/// <summary>
/// Custom preset index
/// </summary>
public static readonly int customPresetIndex = apertureFormatNames.Length - 1;
/// <summary>
/// Sensor size
/// </summary>
public static readonly GUIContent sensorSize = EditorGUIUtility.TrTextContent("Sensor Size", "The size of the camera sensor in millimeters.");
/// <summary>
/// Gate Fit
/// </summary>
public static readonly GUIContent gateFit = EditorGUIUtility.TrTextContent("Gate Fit", "Determines how the rendered area (resolution gate) fits into the sensor area (film gate).");
// Lens
/// <summary>
/// Lens content
/// </summary>
public static readonly GUIContent lens = EditorGUIUtility.TrTextContent("Lens");
/// <summary>
/// Focal Length content
/// </summary>
public static readonly GUIContent focalLength = EditorGUIUtility.TrTextContent("Focal Length", "The simulated distance between the lens and the sensor of the physical camera. Larger values give a narrower field of view.");
/// <summary>
/// Shift content
/// </summary>
public static readonly GUIContent shift = EditorGUIUtility.TrTextContent("Shift", "Offset from the camera sensor. Use these properties to simulate a shift lens. Measured as a multiple of the sensor size.");
/// <summary>
/// ISO content
/// </summary>
public static readonly GUIContent ISO = EditorGUIUtility.TrTextContent("ISO", "Sets the light sensitivity of the Camera sensor. This property affects Exposure if you set its Mode to Use Physical Camera.");
/// <summary>
/// Shutter Speed content
/// </summary>
public static readonly GUIContent shutterSpeed = EditorGUIUtility.TrTextContent("Shutter Speed", "The amount of time the Camera sensor is capturing light.");
/// <summary>
/// Aperture content
/// </summary>
public static readonly GUIContent aperture = EditorGUIUtility.TrTextContent("Aperture", "The f-stop (f-number) of the lens. Lower values give a wider lens aperture.");
/// <summary>
/// Focus Distance content
/// </summary>
public static readonly GUIContent focusDistance = EditorGUIUtility.TrTextContent("Focus Distance", "The distance from the camera where objects appear sharp when Depth Of Field is enabled.");
// Aperture Shape
/// <summary>
/// Aperture Shape content
/// </summary>
public static readonly GUIContent apertureShape = EditorGUIUtility.TrTextContent("Aperture Shape", "Common sensor sizes. Choose an item to set Sensor Size, or edit Sensor Size for your custom settings.");
/// <summary>
/// Blade Count content
/// </summary>
public static readonly GUIContent bladeCount = EditorGUIUtility.TrTextContent("Blade Count", "The number of blades in the lens aperture. Higher values give a rounder aperture shape.");
/// <summary>
/// Curvature content
/// </summary>
public static readonly GUIContent curvature = EditorGUIUtility.TrTextContent("Curvature", "Controls the curvature of the lens aperture blades. The minimum value results in fully-curved, perfectly-circular bokeh, and the maximum value results in visible aperture blades.");
/// <summary>
/// Barrel Clipping content
/// </summary>
public static readonly GUIContent barrelClipping = EditorGUIUtility.TrTextContent("Barrel Clipping", "Controls the self-occlusion of the lens, creating a cat's eye effect.");
/// <summary>
/// Anamorphism content
/// </summary>
public static readonly GUIContent anamorphism = EditorGUIUtility.TrTextContent("Anamorphism", "Use the slider to stretch the sensor to simulate an anamorphic look.");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e978521b37d51146b2cc9750ebfa16c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
public static partial class Rendering
{
/// <summary>Draws Stop NaNs related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Rendering_StopNaNs(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.stopNaNs, Styles.stopNaNs);
}
/// <summary>Draws Dithering related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Rendering_Dithering(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.dithering, Styles.dithering);
}
/// <summary>Draws Culling mask related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Rendering_CullingMask(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.cullingMask, Styles.cullingMask);
}
/// <summary>Draws occlusion Culling related fields on the inspector</summary>
/// <param name="p"><see cref="ISerializedCamera"/> The serialized camera</param>
/// <param name="owner"><see cref="Editor"/> The editor owner calling this drawer</param>
public static void Drawer_Rendering_OcclusionCulling(ISerializedCamera p, Editor owner)
{
EditorGUILayout.PropertyField(p.baseCameraSettings.occlusionCulling, Styles.occlusionCulling);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6cf20b5e989565749903509e13e351f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
/// <summary>
/// Rendering section
/// </summary>
public static partial class Rendering
{
/// <summary>
/// Styles
/// </summary>
public static class Styles
{
/// <summary>
/// Header of the section
/// </summary>
public static readonly GUIContent header = EditorGUIUtility.TrTextContent("Rendering", "These settings control for the specific rendering features for this camera.");
/// <summary>
/// antialiasing content
/// </summary>
public static readonly GUIContent antialiasing = EditorGUIUtility.TrTextContent("Post Anti-aliasing", "The postprocess anti-aliasing method to use.");
/// <summary>
/// dithering content
/// </summary>
public static readonly GUIContent dithering = EditorGUIUtility.TrTextContent("Dithering", "Applies 8-bit dithering to the final render to reduce color banding.");
/// <summary>
/// stopNaNs content
/// </summary>
public static readonly GUIContent stopNaNs = EditorGUIUtility.TrTextContent("Stop NaNs", "Automatically replaces NaN/Inf in shaders by a black pixel to avoid breaking some effects. This will slightly affect performances and should only be used if you experience NaN issues that you can't fix.");
/// <summary>
/// cullingMask content
/// </summary>
public static readonly GUIContent cullingMask = EditorGUIUtility.TrTextContent("Culling Mask");
/// <summary>
/// occlusionCulling content
/// </summary>
public static readonly GUIContent occlusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling");
/// <summary>
/// renderingPath content
/// </summary>
public static readonly GUIContent renderingPath = EditorGUIUtility.TrTextContent("Custom Frame Settings", "Define the custom Frame Settings for this Camera to use.");
/// <summary>
/// exposureTarget content
/// </summary>
public static readonly GUIContent exposureTarget = EditorGUIUtility.TrTextContent("Exposure Target", "The object used as a target for centering the Exposure's Procedural Mask metering mode when target object option is set (See Exposure Volume Component).");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96acda4e859ca224986250b52266e0c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,63 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
public static partial class CameraUI
{
/// <summary>
/// Styles
/// </summary>
public static class Styles
{
/// <summary>
/// Projection section header
/// </summary>
public static GUIContent projectionSettingsHeaderContent { get; } = EditorGUIUtility.TrTextContent("Projection");
/// <summary>
/// Clipping planes content
/// </summary>
public static GUIContent clippingPlaneMultiFieldTitle = EditorGUIUtility.TrTextContent("Clipping Planes");
/// <summary>
/// Projection Content
/// </summary>
public static readonly GUIContent projectionContent = EditorGUIUtility.TrTextContent("Projection", "How the Camera renders perspective.\n\nChoose Perspective to render objects with perspective.\n\nChoose Orthographic to render objects uniformly, with no sense of perspective.");
/// <summary>
/// Size content
/// </summary>
public static readonly GUIContent sizeContent = EditorGUIUtility.TrTextContent("Size");
/// <summary>
/// FOV content
/// </summary>
public static readonly GUIContent fieldOfViewContent = EditorGUIUtility.TrTextContent("Field of View", "The height of the Camera's view angle, measured in degrees along the specified axis.");
/// <summary>
/// FOV Axis content
/// </summary>
public static readonly GUIContent FOVAxisModeContent = EditorGUIUtility.TrTextContent("Field of View Axis", "The axis the Camera's view angle is measured along.");
/// <summary>
/// Physical camera content
/// </summary>
public static readonly GUIContent physicalCameraContent = EditorGUIUtility.TrTextContent("Physical Camera", "Enables Physical camera mode for FOV calculation. When checked, the field of view is calculated from properties for simulating physical attributes (focal length, sensor size, and lens shift).");
/// <summary>
/// Near plane content
/// </summary>
public static readonly GUIContent nearPlaneContent = EditorGUIUtility.TrTextContent("Near", "The closest point relative to the camera that drawing occurs.");
/// <summary>
/// Far plane content
/// </summary>
public static readonly GUIContent farPlaneContent = EditorGUIUtility.TrTextContent("Far", "The furthest point relative to the camera that drawing occurs.");
/// <summary>
/// Message displayed about unsupported fields for Camera Presets
/// </summary>
public static readonly string unsupportedPresetPropertiesMessage = L10n.Tr("When using Preset of Camera Component, only a subset of properties are supported. Unsupported properties are hidden.");
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e26c221569d1d284a9d21434b3a4b277
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,42 @@
namespace UnityEditor.Rendering
{
/// <summary>
/// Interface to be implemented by each pipeline to hold the <see cref="SerializedObject"/> for a Camera Editor
/// </summary>
public interface ISerializedCamera
{
/// <summary>The camera serialized</summary>
SerializedObject serializedObject { get; }
/// <summary>The additional camera data serialized</summary>
SerializedObject serializedAdditionalDataObject { get; }
/// <summary>The base camera settings</summary>
CameraEditor.Settings baseCameraSettings { get; }
// This one is internal in UnityEditor for whatever reason...
/// <summary>The projection matrix mode</summary>
SerializedProperty projectionMatrixMode { get; }
// Common properties
/// <summary>Dithering property</summary>
SerializedProperty dithering { get; }
/// <summary>Stop NaNs property</summary>
SerializedProperty stopNaNs { get; }
/// <summary>Allow Dynamic resolution property</summary>
SerializedProperty allowDynamicResolution { get; }
/// <summary>Volume layer mask property</summary>
SerializedProperty volumeLayerMask { get; }
/// <summary>Clear Depth property property</summary>
SerializedProperty clearDepth { get; }
/// <summary>Anti aliasing property</summary>
SerializedProperty antialiasing { get; }
/// <summary>Method that updates the <see cref="SerializedObject"/> of the Camera and the Additional Camera Data</summary>
void Update();
/// <summary>Applies the modified properties to the <see cref="SerializedObject"/> of the Camera and the Additional Camera Data</summary>
void Apply();
/// <summary>Refreshes the <see cref="SerializedProperty"/> of the <see cref="SerializedObject"/> of the Camera and the Additional Camera Data</summary>
void Refresh();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55ef358f023224145a079dd70d4692b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,123 @@
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.Rendering
{
/// <summary>
/// Utility functions for cameras in the editor.
/// </summary>
public static class CameraEditorUtils
{
/// <summary>Delegate that must give an initialized preview camera</summary>
/// <param name="sourceCamera">The initial Camera we want a preview from</param>
/// <param name="previewSize">The size of the preview</param>
/// <returns>The Preview camera, initialized</returns>
public delegate Camera GetPreviewCamera(Camera sourceCamera, Vector2 previewSize);
const float k_PreviewNormalizedSize = 0.2f;
internal static Material s_GUITextureBlit2SRGBMaterial;
/// <summary>
/// The material used to display a texture into SRGB
/// </summary>
public static Material GUITextureBlit2SRGBMaterial
{
get
{
if (!s_GUITextureBlit2SRGBMaterial)
{
Shader shader = EditorGUIUtility.LoadRequired("SceneView/GUITextureBlit2SRGB.shader") as Shader;
s_GUITextureBlit2SRGBMaterial = new Material(shader);
s_GUITextureBlit2SRGBMaterial.hideFlags = HideFlags.HideAndDontSave;
}
s_GUITextureBlit2SRGBMaterial.SetFloat("_ManualTex2SRGB", QualitySettings.activeColorSpace == ColorSpace.Linear ? 1.0f : 0.0f);
return s_GUITextureBlit2SRGBMaterial;
}
}
/// <summary>
/// Draw the overlay of a Camera
/// </summary>
/// <param name="target">The Camera that we want a preview</param>
/// <param name="sceneView">The scene view where to draw it</param>
/// <param name="previewCameraGetter">The way to get the preview camera corresponding to the target</param>
public static void DrawCameraSceneViewOverlay(Object target, SceneView sceneView, GetPreviewCamera previewCameraGetter)
{
if (target == null) return;
// cache some deep values
var c = (Camera)target;
var previewSize = Handles.GetMainGameViewSize();
if (previewSize.x < 0f)
{
// Fallback to Scene View of not a valid game view size
previewSize.x = sceneView.position.width;
previewSize.y = sceneView.position.height;
}
// Apply normalizedviewport rect of camera
var normalizedViewPortRect = c.rect;
previewSize.x *= Mathf.Max(normalizedViewPortRect.width, 0f);
previewSize.y *= Mathf.Max(normalizedViewPortRect.height, 0f);
// Prevent using invalid previewSize
if (previewSize.x <= 0f || previewSize.y <= 0f)
return;
var aspect = previewSize.x / previewSize.y;
// Scale down (fit to scene view)
previewSize.y = k_PreviewNormalizedSize * sceneView.position.height;
previewSize.x = previewSize.y * aspect;
if (previewSize.y > sceneView.position.height * 0.5f)
{
previewSize.y = sceneView.position.height * 0.5f;
previewSize.x = previewSize.y * aspect;
}
if (previewSize.x > sceneView.position.width * 0.5f)
{
previewSize.x = sceneView.position.width * 0.5f;
previewSize.y = previewSize.x / aspect;
}
// Get and reserve rect
Rect cameraRect = GUILayoutUtility.GetRect(previewSize.x, previewSize.y);
if (Event.current.type == EventType.Repaint)
{
var previewCamera = previewCameraGetter(c, previewSize);
if (previewCamera.targetTexture == null)
{
Debug.LogError("The preview camera must render in a render target");
return;
}
bool drawGizmo = sceneView.drawGizmos;
sceneView.drawGizmos = false;
previewCamera.Render();
sceneView.drawGizmos = drawGizmo;
Graphics.DrawTexture(cameraRect, previewCamera.targetTexture, new Rect(0, 0, 1, 1), 0, 0, 0, 0, GUI.color, GUITextureBlit2SRGBMaterial);
// We set target texture to null after this call otherwise if both sceneview and gameview are visible and we have a preview camera wwe
// get this error: "Releasing render texture that is set as Camera.targetTexture!"
previewCamera.targetTexture = null;
}
}
/// <summary>
/// Check if the view port rect have a positive size
/// </summary>
/// <param name="normalizedViewPortRect">The rect to check</param>
/// <returns>True: the rect have positive size</returns>
public static bool IsViewPortRectValidToRender(Rect normalizedViewPortRect)
{
if (normalizedViewPortRect.width <= 0f || normalizedViewPortRect.height <= 0f)
return false;
if (normalizedViewPortRect.x >= 1f || normalizedViewPortRect.xMax <= 0f)
return false;
if (normalizedViewPortRect.y >= 1f || normalizedViewPortRect.yMax <= 0f)
return false;
return true;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c9fabbcdc8ab50c44a8112c70c67735c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef6e93ebaf391ed43a0bdcc1aa77ee74
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ee4775791ff6f8448490ba9f74d2f5b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,470 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class CommandBufferGenerator
{
// When adding new functions to the core command buffer and you want to expose them to the rendergraph command buffers please
// add them to the appropriate lists below.
// Functions going in all command buffers
static List<FunctionInfo> baseFunctions = new List<FunctionInfo> {
new FunctionInfo("SetGlobalFloat", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalInt", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalInteger", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalVector", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalColor", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalMatrix", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalFloatArray", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalVectorArray", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalMatrixArray", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalTexture", textureArg: "value", modifiesGlobalState: true),
new FunctionInfo("SetGlobalBuffer", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetGlobalConstantBuffer", textureArg: "", modifiesGlobalState: true),
"SetLateLatchProjectionMatrices",
"MarkLateLatchMatrixShaderPropertyID",
"UnmarkLateLatchMatrix",
new FunctionInfo("EnableShaderKeyword", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("EnableKeyword", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("DisableShaderKeyword", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("DisableKeyword", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetKeyword", textureArg: "", modifiesGlobalState: true),
"SetShadowSamplingMode",
"SetSinglePassStereo",
"IssuePluginEvent",
"IssuePluginEventAndData",
"IssuePluginCustomBlit",
"IssuePluginCustomTextureUpdateV2",
"SetInvertCulling",
"EnableScissorRect",
"DisableScissorRect",
"SetViewport",
"SetGlobalDepthBias",
"BeginSample",
"EndSample",
"IncrementUpdateCount",
"SetViewProjectionMatrices",
"SetupCameraProperties",
"InvokeOnRenderObjectCallbacks"
};
// Functions for compute only
static List<FunctionInfo> computeFunctions = new List<FunctionInfo> {
"SetComputeParamsFromMaterial",
"SetComputeFloatParam",
"SetComputeIntParam",
"SetComputeVectorArrayParam",
"SetComputeMatrixParam",
"SetComputeMatrixArrayParam",
"SetComputeFloatParams",
"SetComputeIntParams",
new FunctionInfo("SetComputeTextureParam", textureArg: "rt"),
"SetComputeBufferParam",
"SetComputeConstantBufferParam",
"SetComputeVectorParam",
"DispatchCompute",
"BuildRayTracingAccelerationStructure",
"SetRayTracingAccelerationStructure",
"SetRayTracingBufferParam",
"SetRayTracingConstantBufferParam",
new FunctionInfo("SetRayTracingTextureParam", textureArg: "rt"),
"SetRayTracingFloatParam",
"SetRayTracingFloatParams",
"SetRayTracingIntParam",
"SetRayTracingIntParams",
"SetRayTracingVectorParam",
"SetRayTracingVectorArrayParam",
"SetRayTracingMatrixParam",
"SetRayTracingMatrixArrayParam",
"SetRayTracingShaderPass",
"DispatchRays",
"SetBufferData",
"SetBufferCounterValue",
"CopyCounterValue"
};
// Functions for raster (native render passes) only
static List<FunctionInfo> rasterFunctions = new List<FunctionInfo> {
new FunctionInfo("DrawMesh", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawMultipleMeshes", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawRenderer", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawRendererList", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawProcedural", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawProceduralIndirect", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawMeshInstanced", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawMeshInstancedProcedural", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawMeshInstancedIndirect", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("DrawOcclusionMesh", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("SetInstanceMultiplier", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("ClearRenderTarget", textureArg : "", modifiesGlobalState : false, triggersRasterization: true),
new FunctionInfo("SetFoveatedRenderingMode", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("ConfigureFoveatedRendering", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetWireframe", textureArg: "", modifiesGlobalState: true),
new FunctionInfo("SetShadingRateFragmentSize", textureArg: "", modifiesGlobalState: false),
new FunctionInfo("SetShadingRateCombiner", textureArg: "", modifiesGlobalState: false),
};
// Functions for unsafe (wrapper around Commandbuffer) only
static List<FunctionInfo> unsafeFunctions = new List<FunctionInfo> {
"SetRenderTarget",
"Clear",
"RequestAsyncReadbackIntoNativeArray",
"RequestAsyncReadback",
"ClearRandomWriteTargets",
"SetRandomWriteTarget",
"CopyTexture",
"GenerateMips",
// Next APIs are already available in UnsafeCommandBuffer through compute or base functions lists,
// but the added overloads below relax safety rules to support texture parameters without texture handle usage.
new FunctionInfo("SetGlobalTexture", textureArg: "", modifiesGlobalState: true),
"SetRayTracingTextureParam",
"SetComputeTextureParam",
// End of added unsafe overloads
};
// Generated file header
static string preamble =
@"
using System;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine.Profiling;
using Unity.Profiling;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Experimental.Rendering;
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
//
// This file is automatically generated by reflection on the UnityEngine.Rendering.CommandBuffer type.
// If you changed the command buffer and want to expose the changes here please open and SRP project
// ""Edit/Rendering/Generate Core CommandBuffers"" menu option.
// This will generate the new command buffer C# files in the project root.
//
// Note that while automated,this doesn't mean you won't have to think. Please consider any new methods on the command
// buffer if they are safe to be executed on the async compute queue or not, if they can be executed inside a
// native render pass or not,... and add the function to the appropriate lists in CommandBufferGenerator.cs in the
// com.unity.render-pipelines.core\Editor\CommandBuffers\CommandBufferGenerator\CommandBufferGenerator.cs.
// If you are unsure please ask the RenderGraph package owners for advise.
//
// Once generated, review the generated file and move the approved files into:
// <unity root>\Packages\com.unity.render-pipelines.core\Runtime\CommandBuffers\
//
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
namespace UnityEngine.Rendering
{
";
// Generated class header
static string classPreamble =
@"
/// <summary>
/// @docString@
/// </summary>
public class @type_name@ : @base_type@
{
// @type_name@ is not created by users. The render graph creates them and passes them to the execute callback of the graph pass.
internal @type_name@(CommandBuffer wrapped, RenderGraphPass executingPass, bool isAsync) : base(wrapped, executingPass, isAsync) { }
";
// Generated interface header
static string interfacePeamble =
@"
/// <summary>
/// @docString@
/// </summary>
public interface @type_name@ @base_type@
{
";
// Generated file footer
static string postamble =
@"
}
}
";
// Generated individual function template
static string functionTemplate =
@"
/// <summary>Wraps [{0}](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.{0}.html) on a CommandBuffer.</summary>
{1}
public void {0}{5}({2}) {6} {{ {4} m_WrappedCommandBuffer.{0}({3}); }}
";
// Generated individual function template
static string interfaceFunctionTemplate =
@"
/// <summary>Wraps [{0}](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.{0}.html) on a CommandBuffer.</summary>
{1}
public void {0}{5}({2}) {6};
";
static string paramDocTemplate =
@" /// <param name=""{0}"">[See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.{1}.html)</param>";
static string typeParamDocTemplate =
@" /// <typeparam name=""{0}"">[See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.{1}.html)</typeparam>";
struct FunctionInfo
{
public FunctionInfo(string name, string textureArg, bool modifiesGlobalState = false, bool triggersRasterization = false)
{
this.name = name;
this.textureArgs = textureArg;
this.modifiesGlobalState = modifiesGlobalState;
this.triggersRasterization = triggersRasterization;
}
public static implicit operator FunctionInfo(string value)
{
return new FunctionInfo(value, "", false);
}
// Name of the function to expose, all overloads are exposed with it.
public string name;
// Name of a texture pointer argument. This will receive extra validation for the Rendergraph.
public string textureArgs;
// Indicate if the function modifies global render state.
public bool modifiesGlobalState;
// Indicate if the function actually triggers rasterization and may thus cause pixel shader invocations.
public bool triggersRasterization;
}
/// <summary>
/// Generate a commandbuffer type exposing only certain methods of the base commandbuffer class
/// </summary>
/// <param name="className">Name of the new class</param>
/// <param name="docString">Description of the class</param>
/// <param name="baseType">Classes from which this new class inherits</param>
/// <param name="isInterface">Whether or not the new class is an interface</param>
/// <param name="validateRaster">Whether or not the functions in this class should validate that a raster commandbuffer has any render targets</param>
/// <param name="functionList">List of functions on commandbuffer to expose</param>
static void GenerateCommandBufferType(string className, string docString, string baseType, bool isInterface, bool validateRaster, IEnumerable<FunctionInfo> functionList)
{
StringBuilder result = new StringBuilder();
result.Append(preamble);
var str = (isInterface) ? interfacePeamble : classPreamble;
str = str.Replace("@type_name@", className);
str = str.Replace("@base_type@", baseType);
str = str.Replace("@docString@", docString);
result.Append(str);
Type commandBufferType = typeof(CommandBuffer);
//To restrict return properties. If all properties are required don't provide flag.
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var methods = commandBufferType.GetMethods(flags);
var allowedFuncInfoMethodList = new List<Tuple<FunctionInfo, MethodInfo>>();
// Filtering function list to only keep the ones existing in CommandBuffer
foreach (var method in methods)
{
foreach (var fn in functionList)
{
if (fn.name == method.Name)
allowedFuncInfoMethodList.Add(new Tuple<FunctionInfo, MethodInfo>(fn, method));
}
}
// Generating function list, we can have duplicates due to overloads in methods and different support in the different functionLists (TextureHandle overload or not)
foreach (var allowedFuncInfoMethod in allowedFuncInfoMethodList)
{
StringBuilder argList = new StringBuilder();
StringBuilder typedArgList = new StringBuilder();
StringBuilder argDocList = new StringBuilder();
StringBuilder validationCode = new StringBuilder();
StringBuilder genericArgList = new StringBuilder();
StringBuilder genericConstraints = new StringBuilder();
var info = allowedFuncInfoMethod.Item1;
var method = allowedFuncInfoMethod.Item2;
if (info.modifiesGlobalState)
{
validationCode.Append("ThrowIfGlobalStateNotAllowed(); ");
}
if (validateRaster && info.triggersRasterization)
{
validationCode.Append("ThrowIfRasterNotAllowed(); ");
}
var arguments = method.GetParameters();
bool separator = false;
foreach (var arg in arguments)
{
if (separator)
{
argList.Append(", ");
typedArgList.Append(", ");
argDocList.Append("\n");
}
separator = true;
// Comma separated argument lists
argList.Append(arg.Name);
// Typed, comma separated argument lists
// Texture args are replace to take a texture handle so we can do extra validation on them
if (arg.Name == info.textureArgs)
{
typedArgList.Append("TextureHandle");
}
else
{
typedArgList.Append(DecorateArgumentTypeString(arg));
}
typedArgList.Append(" ");
typedArgList.Append(arg.Name);
// Parameter docs
argDocList.AppendFormat(paramDocTemplate, arg.Name, method.Name);
if (arg.Name == info.textureArgs)
{
validationCode.Append("ValidateTextureHandle(" + arg.Name + "); ");
}
}
if (method.ContainsGenericParameters)
{
// Hack: The current command buffer only includes very simple single generic functions. We just hard code these but in the future we might need reflection on the generic arguments if needed.
genericArgList.Append("<T>");
genericConstraints.Append("where T : struct");
argDocList.Append("\n");
argDocList.AppendFormat(typeParamDocTemplate, "T", method.Name);
}
result.AppendFormat((isInterface) ? interfaceFunctionTemplate : functionTemplate, method.Name, argDocList.ToString(), typedArgList.ToString(), argList.ToString(), validationCode.ToString(), genericArgList.ToString(), genericConstraints.ToString());
}
result.Append(postamble);
var outputFile = className + ".cs";
File.WriteAllText(outputFile, result.ToString());
Debug.Log("Wrote generated file to: " + Path.GetFullPath(outputFile) + " please review it, and if approved, move it to the 'com.unity.render-pipelines.core/Runtime/CommandBuffers/' folder.");
}
// Replace CLI types with c# shorthands for cleaner code...
static string CSharpFlavour(Type type)
{
if (type == typeof(int))
{
return "int";
}
else if (type == typeof(uint))
{
return "uint";
}
else if (type == typeof(float))
{
return "float";
}
else if (type == typeof(string))
{
return "string";
}
else if (type == typeof(float))
{
return "float";
}
else if (type == typeof(byte))
{
return "byte";
}
else if (type == typeof(char))
{
return "float";
}
else if (type == typeof(bool))
{
return "bool";
}
return type.Name;
}
// Return A c# code string for a given parameter. Works for most common cases
// and simple generics.
static string DecorateArgumentTypeString(ParameterInfo arg)
{
var t = arg.ParameterType;
if (t.HasElementType)
{
// Determine whether the type is an array.
if (t.IsArray)
{
string prefix = "";
if (arg.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0)
{
prefix = "params ";
}
return prefix + CSharpFlavour(t.GetElementType()) + "[]";
}
// Determine whether the type is an 'in' argument,
else if (arg.IsIn)
{
return "in " + CSharpFlavour(t.GetElementType());
}
// Determine whether the type is a reference. 'in' is also a reference but this was already handled above.
else if (t.IsByRef)
{
return "ref " + CSharpFlavour(t.GetElementType());
}
else
{
throw new NotImplementedException("Implement special type handling for " + t.Name);
}
}
else
{
// Is this an undefined generic
if (t.ContainsGenericParameters)
{
//The current command buffer only includes very simple single generic functions. We just hard code these but in the future we might need reflection on the generic arguments if needed.
// We strip the last two chars at the name is normally something like MyClass`1 for generics.
var types = t.GenericTypeArguments;
if (types.Length > 1) throw new NotImplementedException("Implement generic handling for more than 1 argument");
return t.Name.Substring(0, t.Name.Length - 2) + "<T>";
}
// This is a defined generic like List<int>
else if (t.IsConstructedGenericType)
{
var types = t.GenericTypeArguments;
if (types.Length > 1) throw new NotImplementedException("Implement generic handling for more than 1 argument");
return t.Name.Substring(0, t.Name.Length - 2) + "<" + CSharpFlavour(types[0]) + ">";
}
else
{
return CSharpFlavour(t);
}
}
}
[MenuItem("Edit/Rendering/Generate Core CommandBuffers")]
static void GenerateCommandBufferTypes()
{
GenerateCommandBufferType("IBaseCommandBuffer", "This interface declares functions shared by several command buffer types.", "", true, false, baseFunctions);
GenerateCommandBufferType("IRasterCommandBuffer", "This interface declares functions that are specific to a rasterization command buffer.", ": IBaseCommandBuffer", true, false, rasterFunctions);
GenerateCommandBufferType("IComputeCommandBuffer", "This interface declares functions that are specific to a compute command buffer.", ": IBaseCommandBuffer", true, false, computeFunctions);
GenerateCommandBufferType("IUnsafeCommandBuffer", "This interface declares functions that are specific to an unsafe command buffer.", ": IBaseCommandBuffer, IRasterCommandBuffer, IComputeCommandBuffer", true, false, unsafeFunctions);
GenerateCommandBufferType("RasterCommandBuffer", "A command buffer that is used with a rasterization render graph pass.", "BaseCommandBuffer, IRasterCommandBuffer", false, true, baseFunctions.Concat(rasterFunctions));
GenerateCommandBufferType("ComputeCommandBuffer", "A command buffer that is used with a compute render graph pass.", "BaseCommandBuffer, IComputeCommandBuffer", false, false, baseFunctions.Concat(computeFunctions));
GenerateCommandBufferType("UnsafeCommandBuffer", "A command buffer that is used with an unsafe render graph pass.", "BaseCommandBuffer, IUnsafeCommandBuffer", false, false, baseFunctions.Concat(unsafeFunctions).Concat(rasterFunctions).Concat(computeFunctions));
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a059bee53a757a408e35c70e82ac2fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,18 @@
using UnityEngine;
namespace UnityEditor.Rendering
{
/// <summary>
/// Helper methods for overriding contextual menus
/// </summary>
static class ContextualMenuDispatcher
{
[MenuItem("CONTEXT/ReflectionProbe/Remove Component")]
[MenuItem("CONTEXT/Light/Remove Component")]
[MenuItem("CONTEXT/Camera/Remove Component")]
static void RemoveComponentWithAdditionalData(MenuCommand command)
{
RemoveComponentUtils.RemoveComponent(command.context as Component);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b55ea781ffec78245a85c7b70fefee48
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 19a8f70f36adc46b8a4ebd0954643553
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,292 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Rendering
{
[UxmlElement]
internal partial class ToggleDropdown : VisualElement
{
const string k_StylesheetPathFormat = "Packages/com.unity.render-pipelines.core/Editor/Controls/ToggleDropdown.uss";
const string k_MainClass = "toggle-dropdown";
const string k_ToggleButtonClass = k_MainClass + "__toggle-button";
const string k_DropdownButtonClass = k_MainClass + "__dropdown-button";
const string k_SeparatorClass = k_MainClass + "__separator";
const string k_EnabledClass = k_MainClass + "--enabled";
private Button m_ToggleButton;
private Button m_DropdownButton;
private VisualElement m_DropdownArrow;
private VisualElement m_Separator;
private List<string> m_Options = new List<string>();
private HashSet<int> m_SelectedIndices = new HashSet<int>();
private int m_SelectedIndex = 0;
private bool m_IsEnabled = false;
private string m_Text = "Toggle Dropdown";
[UxmlAttribute]
public string text
{
get => m_Text;
set
{
if (m_Text == value)
return;
m_Text = value;
m_ToggleButton.text = m_Text;
}
}
[UxmlAttribute]
private string options { get; set; } = "";
[UxmlAttribute("selected-index")]
private int selectedIndex
{
get => m_SelectedIndex;
set
{
if (m_SelectedIndex == value || value < 0)
return;
m_SelectedIndex = value;
}
}
[UxmlAttribute("selected-indices")]
public string selectedIndices
{
get
{
var indices = new List<string>();
foreach (int index in m_SelectedIndices)
{
indices.Add(index.ToString());
}
return string.Join(",", indices.ToArray());
}
set
{
m_SelectedIndices.Clear();
if (!string.IsNullOrEmpty(value))
{
var indices = value.Split(',');
foreach (var indexStr in indices)
{
if (int.TryParse(indexStr.Trim(), out int index) && index >= 0)
{
m_SelectedIndices.Add(index);
}
}
}
}
}
[UxmlAttribute]
public bool value
{
get => m_IsEnabled;
set
{
if (m_IsEnabled == value)
return;
m_IsEnabled = value;
UpdateEnabledState();
}
}
/// <summary>Get the currently selected option text (first selected)</summary>
public string selectedOption
{
get
{
foreach (int index in m_SelectedIndices)
{
if (index < m_Options.Count)
return m_Options[index];
}
return "";
}
}
/// <summary>Get all selected options</summary>
public string[] selectedOptions
{
get
{
var result = new List<string>();
foreach (int index in m_SelectedIndices)
{
if (index < m_Options.Count)
result.Add(m_Options[index]);
}
return result.ToArray();
}
}
/// <summary>Get all selected indices</summary>
public int[] GetSelectedIndices()
{
var result = new int[m_SelectedIndices.Count];
int i = 0;
foreach (int index in m_SelectedIndices)
{
result[i++] = index;
}
return result;
}
/// <summary>Event fired when selection changes</summary>
public event System.Action<int[]> selectionChanged;
/// <summary>Event fired when toggle state changes</summary>
public event System.Action<bool> toggleChanged;
/// <summary>Constructor</summary>
public ToggleDropdown()
{
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylesheetPathFormat));
AddToClassList(k_MainClass);
RegisterCallback<AttachToPanelEvent>(DelayedInit);
m_ToggleButton = new Button(OnToggleClicked);
m_ToggleButton.AddToClassList(k_ToggleButtonClass);
Add(m_ToggleButton);
m_DropdownButton = new Button(ShowCustomDropdown);
m_DropdownButton.AddToClassList(k_DropdownButtonClass);
m_DropdownArrow = new VisualElement();
m_DropdownArrow.AddToClassList("unity-toolbar-menu__arrow");
m_DropdownButton.Add(m_DropdownArrow);
m_Separator = new VisualElement();
m_Separator.AddToClassList(k_SeparatorClass);
Add(m_Separator);
Add(m_DropdownButton);
}
void DelayedInit(AttachToPanelEvent evt)
{
if (!string.IsNullOrEmpty(options))
{
var optionArray = options.Split(',');
for (int i = 0; i < optionArray.Length; i++)
{
optionArray[i] = optionArray[i].Trim();
}
SetOptions(optionArray);
}
if (selectedIndex >= 0)
{
m_SelectedIndices.Add(selectedIndex);
}
m_IsEnabled = value;
m_ToggleButton.text = m_Text;
UpdateEnabledState();
}
/// <summary>Set the available options for the dropdown</summary>
public void SetOptions(string[] newOptions)
{
m_Options.Clear();
if (newOptions != null)
m_Options.AddRange(newOptions);
if (m_SelectedIndex >= m_Options.Count)
m_SelectedIndex = 0;
}
/// <summary>Set the selected indices for multi-select</summary>
public void SetSelectedIndices(int[] indices)
{
m_SelectedIndices.Clear();
if (indices != null)
{
foreach (int index in indices)
{
if (index >= 0 && index < m_Options.Count)
{
m_SelectedIndices.Add(index);
}
}
}
selectionChanged?.Invoke(GetSelectedIndices());
}
/// <summary>Toggle selection of a specific index</summary>
public void ToggleSelection(int index)
{
if (index >= 0 && index < m_Options.Count)
{
if (m_SelectedIndices.Contains(index))
{
m_SelectedIndices.Remove(index);
}
else
{
m_SelectedIndices.Add(index);
}
selectionChanged?.Invoke(GetSelectedIndices());
}
}
/// <summary>Check if an index is selected</summary>
public bool IsSelected(int index)
{
return m_SelectedIndices.Contains(index);
}
/// <summary>Set the enabled state</summary>
public new void SetEnabled(bool enabled)
{
if (enabled != m_IsEnabled)
{
m_IsEnabled = enabled;
UpdateEnabledState();
toggleChanged?.Invoke(enabled);
}
}
void OnToggleClicked()
{
SetEnabled(!m_IsEnabled);
}
void UpdateEnabledState()
{
if (m_IsEnabled)
{
AddToClassList(k_EnabledClass);
}
else
{
RemoveFromClassList(k_EnabledClass);
}
MarkDirtyRepaint();
}
void ShowCustomDropdown()
{
var menu = new GenericMenu();
for (int i = 0; i < m_Options.Count; i++)
{
int index = i;
string optionName = m_Options[i];
bool isSelected = m_SelectedIndices.Contains(index);
menu.AddItem(new GUIContent(optionName), isSelected, () => {
ToggleSelection(index);
});
}
var rect = this.worldBound;
menu.DropDown(rect);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 37f63294a089b441eb9b5a8b6dea5114
@@ -0,0 +1,111 @@
.toggle-dropdown {
flex-direction: row;
height: 19px;
margin: 0;
}
.toggle-dropdown__toggle-button {
margin: 0;
padding: 3px 8px;
border-radius: 2px 0 0 2px;
border-width: 0px 1px 0px 0px;
border-right-width: 0;
font-size: 12px;
min-width: 85px;
-unity-text-align: middle-left;
flex-shrink: 0;
height: 19px;
}
.toggle-dropdown__separator {
width: 1px;
height: 11px;
align-self: center;
flex-shrink: 0;
}
.toggle-dropdown__dropdown-button {
margin: 0;
border-radius: 0 2px 2px 0;
border-width: 0px 1px 0px 0px;
border-left-width: 0;
min-width: 18px;
max-width: 18px;
padding: 0;
flex-shrink: 0;
height: 19px;
justify-content: center;
align-items: center;
}
.unity-toolbar .toggle-dropdown {
height: 19px;
margin: 0 1px;
}
.unity-toolbar .toggle-dropdown__toggle-button {
height: 19px;
padding: 2px 8px;
font-size: 12px;
}
.unity-toolbar .toggle-dropdown__separator {
height: 11px;
width: 1px;
}
.unity-toolbar .toggle-dropdown__dropdown-button {
height: 19px;
min-width: 16px;
max-width: 16px;
}
.unity-toolbar-menu__arrow{
width: 12px;
height: 12px;
-unity-background-image-tint-color: var(--unity-colors-dropdown-text);
background-image: resource('d_dropdown');
}
.toggle-dropdown .toggle-dropdown__toggle-button {
background-color: var(--unity-colors-toolbar-background);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown .toggle-dropdown__toggle-button:hover {
background-color: var(--unity-colors-toolbar_button-background-hover);
}
.toggle-dropdown .toggle-dropdown__toggle-button:active {
background-color: var(--unity-colors-toolbar-background);
}
.toggle-dropdown .toggle-dropdown__dropdown-button {
background-color: var(--unity-colors-toolbar-background);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown .toggle-dropdown__dropdown-button:hover {
background-color: var(--unity-colors-toolbar_button-background-hover);
}
.toggle-dropdown .toggle-dropdown__dropdown-button:active {
background-color: var(--unity-colors-toolbar-background);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__toggle-button {
background-color: var(--unity-colors-toolbar_button-background-checked);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__toggle-button:active {
background-color: var(--unity-colors-toolbar_button-background-checked);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__toggle-button:hover {
background-color: var(--unity-colors-toolbar_button-background-hover);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__dropdown-button {
background-color: var(--unity-colors-toolbar_button-background-checked);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__dropdown-button:active {
background-color: var(--unity-colors-toolbar_button-background-checked);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__dropdown-button:hover {
background-color: var(--unity-colors-toolbar_button-background-hover);
border-color: var(--unity-colors-toolbar-border);
}
.toggle-dropdown.toggle-dropdown--enabled .toggle-dropdown__separator {
background-color: var(--unity-colors-toolbar_button-border);
}
.toggle-dropdown.toggle-dropdown .toggle-dropdown__separator {
background-color: var(--unity-colors-toolbar_button-border);
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ff83f8997b534409b1595a0ea6750db
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e9fe0ff34cd022408422f6b92ad7df6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,243 @@
using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using Object = UnityEngine.Object;
namespace UnityEditor.Rendering
{
/// <summary>Class containing constants</summary>
public static class CoreEditorConstants
{
/// <summary>Speed of additional properties highlight.</summary>
public static readonly float additionalPropertiesHightLightSpeed = 0.3f;
/// <summary>Standard UI spacing</summary>
public static float standardHorizontalSpacing => 5f;
}
/// <summary>Class containing style definition</summary>
public static class CoreEditorStyles
{
#region Styles
static System.Lazy<GUIStyle> m_SmallTickbox = new(() => new GUIStyle("ShurikenToggle"));
/// <summary>Style for a small checkbox</summary>
public static GUIStyle smallTickbox => m_SmallTickbox.Value;
static System.Lazy<GUIStyle> m_SmallMixedTickbox = new(() => new GUIStyle("ShurikenToggleMixed"));
/// <summary>Style for a small checkbox in mixed state</summary>
public static GUIStyle smallMixedTickbox => m_SmallMixedTickbox.Value;
static GUIStyle m_MiniLabelButton;
/// <summary>Style for a minilabel button</summary>
public static GUIStyle miniLabelButton
{
get
{
if (m_MiniLabelButton == null)
{
m_MiniLabelButton = new GUIStyle(EditorStyles.miniLabel)
{
normal = new GUIStyleState
{
background = m_TransparentTexture,
scaledBackgrounds = null,
textColor = EditorGUIUtility.isProSkin ? Color.grey : Color.darkGray
}
};
var activeState = new GUIStyleState
{
background = m_TransparentTexture,
scaledBackgrounds = null,
textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black
};
m_MiniLabelButton.active = activeState;
m_MiniLabelButton.onNormal = activeState;
m_MiniLabelButton.onActive = activeState;
return m_MiniLabelButton;
}
return m_MiniLabelButton;
}
}
static System.Lazy<GUIStyle> m_ContextMenuStyle = new(() => new GUIStyle("IconButton"));
/// <summary>Context Menu button style</summary>
public static GUIStyle contextMenuStyle => m_ContextMenuStyle.Value;
static System.Lazy<GUIStyle> m_AdditionalPropertiesHighlightStyle = new(() => new GUIStyle { normal = { background = Texture2D.whiteTexture } });
/// <summary>Style of a additional properties highlighted background.</summary>
public static GUIStyle additionalPropertiesHighlightStyle => m_AdditionalPropertiesHighlightStyle.Value;
/// <summary>Help icon style</summary>
public static GUIStyle iconHelpStyle => GUI.skin.FindStyle("IconButton") ?? EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("IconButton");
static System.Lazy<GUIStyle> m_SectionHeaderStyle = new(() => new GUIStyle(EditorStyles.largeLabel) { richText = true, fontSize = 18, fixedHeight = 42 });
/// <summary>Style of Section Headers.</summary>
public static GUIStyle sectionHeaderStyle => m_SectionHeaderStyle.Value;
static System.Lazy<GUIStyle> m_SubSectionHeaderStyle = new(() => new GUIStyle(EditorStyles.boldLabel));
/// <summary>Style of Sub-Section Headers.</summary>
public static GUIStyle subSectionHeaderStyle => m_SubSectionHeaderStyle.Value;
static System.Lazy<GUIStyle> m_HelpBox = new(() =>
{
var style = new GUIStyle()
{
imagePosition = ImagePosition.ImageLeft,
fontSize = 10,
wordWrap = true,
alignment = TextAnchor.MiddleLeft
};
style.normal.textColor = EditorStyles.helpBox.normal.textColor;
return style;
});
internal static GUIStyle helpBox => m_HelpBox.Value;
#endregion
#region Textures 2D
static Texture2D m_TransparentTexture;
/// <summary><see cref="Texture2D"/> 1x1 pixel with red color</summary>
public static readonly Texture2D redTexture;
/// <summary><see cref="Texture2D"/> 1x1 pixel with green color</summary>
public static readonly Texture2D greenTexture;
/// <summary><see cref="Texture2D"/> 1x1 pixel with blue color</summary>
public static readonly Texture2D blueTexture;
/// <summary> PaneOption icon for dark skin</summary>
static readonly Texture2D paneOptionsIconDark;
/// <summary> PaneOption icon for light skin</summary>
static readonly Texture2D paneOptionsIconLight;
/// <summary> PaneOption icon </summary>
public static Texture2D paneOptionsIcon => EditorGUIUtility.isProSkin ? paneOptionsIconDark : paneOptionsIconLight;
/// <summary> Warning icon </summary>
public static readonly Texture2D iconWarn;
/// <summary> Info icon </summary>
public static readonly Texture2D iconInfo;
/// <summary> Help icon </summary>
public static readonly Texture2D iconHelp;
/// <summary> Fail icon </summary>
public static readonly Texture2D iconFail;
/// <summary> Success icon </summary>
public static readonly Texture2D iconSuccess;
/// <summary> Complete icon </summary>
public static readonly Texture2D iconComplete;
/// <summary> Pending icon </summary>
public static readonly Texture2D iconPending;
/// <summary>RenderPipeline Global Settings icon</summary>
public static readonly Texture2D globalSettingsIcon;
/// <summary>
/// Gets the icon that describes the <see cref="MessageType"/>
/// </summary>
/// <param name="messageType">The <see cref="MessageType"/> to obtain the icon from</param>
/// <returns>a <see cref="Texture2D"/> with the icon for the <see cref="MessageType"/></returns>
internal static Texture2D GetMessageTypeIcon(MessageType messageType)
{
switch (messageType)
{
case MessageType.None:
return null;
case MessageType.Info:
return iconInfo;
case MessageType.Warning:
return iconWarn;
case MessageType.Error:
return iconFail;
default:
throw new ArgumentOutOfRangeException(nameof(messageType), messageType, null);
}
}
#endregion
#region Colors
static readonly Color m_LightThemeBackgroundColor;
static readonly Color m_LightThemeBackgroundHighlightColor;
static readonly Color m_DarkThemeBackgroundColor;
static readonly Color m_DarkThemeBackgroundHighlightColor;
/// <summary>Regular background color.</summary>
public static Color backgroundColor => EditorGUIUtility.isProSkin ? m_DarkThemeBackgroundColor : m_LightThemeBackgroundColor;
/// <summary>Hightlited background color.</summary>
public static Color backgroundHighlightColor => EditorGUIUtility.isProSkin ? m_DarkThemeBackgroundHighlightColor : m_LightThemeBackgroundHighlightColor;
#endregion
#region GUIContents
/// <summary>Context Menu button icon</summary>
public static readonly GUIContent contextMenuIcon;
/// <summary>Reset Content</summary>
public static readonly GUIContent resetButtonLabel = EditorGUIUtility.TrTextContent("Reset");
/// <summary>Reset All content</summary>
public static readonly GUIContent resetAllButtonLabel = EditorGUIUtility.TrTextContent("Reset All");
/// <summary>
/// Empty space content in case that you want to keep the indentation but have nothing to write
/// </summary>
public static readonly GUIContent empty = EditorGUIUtility.TrTextContent(" ");
#endregion
static CoreEditorStyles()
{
m_TransparentTexture = new Texture2D(1, 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None)
{
name = "transparent"
};
m_TransparentTexture.SetPixel(0, 0, Color.clear);
m_TransparentTexture.Apply();
paneOptionsIconDark = CoreEditorUtils.LoadIcon("Builtin Skins/DarkSkin/Images", "pane options", ".png");
paneOptionsIconDark.name = "pane options dark skin";
paneOptionsIconLight = CoreEditorUtils.LoadIcon("Builtin Skins/LightSkin/Images", "pane options", ".png");
paneOptionsIconLight.name = "pane options light skin";
m_LightThemeBackgroundColor = new Color(0.7843138f, 0.7843138f, 0.7843138f, 1.0f);
m_LightThemeBackgroundHighlightColor = new Color32(174, 174, 174, 255);
m_DarkThemeBackgroundColor = new Color(0.2196079f, 0.2196079f, 0.2196079f, 1.0f);
m_DarkThemeBackgroundHighlightColor = new Color32(77, 77, 77, 255);
const string contextTooltip = ""; // To be defined (see with UX)
contextMenuIcon = new GUIContent(paneOptionsIcon, contextTooltip);
redTexture = CoreEditorUtils.CreateColoredTexture2D(Color.red, "Red 1x1");
greenTexture = CoreEditorUtils.CreateColoredTexture2D(Color.green, "Green 1x1");
blueTexture = CoreEditorUtils.CreateColoredTexture2D(Color.blue, "Blue 1x1");
iconHelp = CoreEditorUtils.LoadIcon("icons", "_Help", ".png");
iconInfo = CoreEditorUtils.LoadIcon("icons", "console.infoicon", ".png");
iconWarn = CoreEditorUtils.LoadIcon("icons", "console.warnicon", ".png");
iconFail = CoreEditorUtils.LoadIcon("icons", "console.erroricon", ".png");
iconSuccess = EditorGUIUtility.FindTexture("TestPassed");
iconComplete = CoreEditorUtils.LoadIcon("icons", "GreenCheckmark", ".png");
iconPending = EditorGUIUtility.FindTexture("Toolbar Minus");
globalSettingsIcon = EditorGUIUtility.FindTexture("ScriptableObject Icon");
// Make sure that textures are unloaded on domain reloads.
void OnBeforeAssemblyReload()
{
Object.DestroyImmediate(redTexture);
Object.DestroyImmediate(greenTexture);
Object.DestroyImmediate(blueTexture);
Object.DestroyImmediate(m_TransparentTexture);
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
}
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 106fd77ef6b30234597e56c849578bad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 744ceabda269e6c469964dda8c490d0d
timeCreated: 1507109827
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// Core Render Pipeline preferences.
/// </summary>
public static class CoreRenderPipelinePreferences
{
/// <summary>
/// Path to the Render Pipeline Preferences
/// </summary>
public static readonly string corePreferencePath = "Preferences/Graphics";
private static readonly List<ICoreRenderPipelinePreferencesProvider> s_Providers = new();
[InitializeOnLoadMethod]
static void InitPreferenceProviders()
{
foreach (var provider in TypeCache.GetTypesDerivedFrom<ICoreRenderPipelinePreferencesProvider>())
{
if (provider.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) == null)
continue;
s_Providers.Add(Activator.CreateInstance(provider) as ICoreRenderPipelinePreferencesProvider);
}
s_Providers.Sort((x, y) => GetDisplayInfoOrder(x.GetType()).CompareTo(GetDisplayInfoOrder(y.GetType())));
}
static int GetDisplayInfoOrder(Type type)
{
var attribute = type.GetCustomAttribute<DisplayInfoAttribute>();
return attribute?.order ?? int.MaxValue;
}
[SettingsProvider]
static SettingsProvider PreferenceGUI()
{
var provider = new SettingsProvider(corePreferencePath, SettingsScope.User)
{
guiHandler = searchContext =>
{
using (new SettingsProviderGUIScope())
{
foreach (var providers in s_Providers)
{
if (providers.header != null)
{
EditorGUILayout.LabelField(providers.header, EditorStyles.boldLabel);
providers.PreferenceGUI();
}
}
}
}
};
FillKeywords(provider);
return provider;
}
private static void FillKeywords(SettingsProvider provider)
{
List<string> keywords = new List<string>();
foreach (var providers in s_Providers)
keywords.AddRange(providers.keywords);
provider.keywords = keywords;
}
/// <summary>
/// Open the Core Rendering Pipeline preference window.
/// </summary>
public static void Open()
{
SettingsService.OpenUserPreferences(corePreferencePath);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c13e3f9217a6854ebb4d5d716b60103
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5415ef8821c020469ee7e810da8b3ff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
static class CoreMenuItems
{
[MenuItem("Assets/Create/Shader/Custom Render Texture", priority = CoreUtils.Priorities.assetsCreateShaderMenuPriority + 2)]
static void MenuCreateCustomRenderTextureShader()
{
string templatePath = $"{CoreUtils.GetCorePath()}/Editor/CustomRenderTexture/CustomRenderTextureShader.template";
ProjectWindowUtil.CreateScriptAssetFromTemplateFile(templatePath, "New Custom Render Texture.shader");
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e2d77127041cd24faf2847015043c6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
Shader "CustomRenderTexture/#NAME#"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex("InputTex", 2D) = "white" {}
}
SubShader
{
Blend One Zero
Pass
{
Name "#NAME#"
CGPROGRAM
#include "UnityCustomRenderTexture.cginc"
#pragma vertex CustomRenderTextureVertexShader
#pragma fragment frag
#pragma target 3.0
float4 _Color;
sampler2D _MainTex;
float4 frag(v2f_customrendertexture IN) : SV_Target
{
float2 uv = IN.localTexcoord.xy;
float4 color = tex2D(_MainTex, uv) * _Color;
// TODO: Replace this by actual code!
uint2 p = uv.xy * 256;
return countbits(~(p.x & p.y) + 1) % 2 * float4(uv, 1, 1) * color;
}
ENDCG
}
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6e1b69fb677bd95439f31bff8ca1c431
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25136a97d9136f440a76669b6dc5656f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,153 @@
#if ENABLE_UIELEMENTS_MODULE && UNITY_ENABLE_CHECKS
#define ENABLE_RENDERING_DEBUGGER_UI
#endif
using System;
using System.Collections.Generic;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
namespace UnityEditor.Rendering
{
internal class WidgetSearchData
{
public List<TextElement> textElements;
public string aggregatedAdditionalSearchText;
public WidgetSearchData(List<TextElement> textElements, string aggregatedAdditionalSearchText)
{
this.textElements = textElements;
this.aggregatedAdditionalSearchText = aggregatedAdditionalSearchText;
}
}
sealed partial class DebugWindow
{
#if ENABLE_RENDERING_DEBUGGER_UI
readonly Dictionary<DebugUI.Widget, WidgetSearchData> m_WidgetSearchElementCache = new();
readonly List<TextElement> m_PanelHeaderTextElements = new();
UIElementSearchFilter m_SearchFilter;
Label m_NoResultsLabel;
void BuildSearchCache()
{
m_WidgetSearchElementCache.Clear();
m_PanelHeaderTextElements.Clear();
m_NoResultsLabel = rootVisualElement.Q<Label>(name: "debug-window-no-results-label");
foreach (var panelElement in m_RightPaneElement.Children())
{
var headerLabel = panelElement.Q<Label>(className: "debug-window-search-filter-target");
if (headerLabel != null)
m_PanelHeaderTextElements.Add(headerLabel);
}
DebugManager.instance.ForEachWidget(widget =>
{
if (widget.m_VisualElement == null)
return;
List<TextElement> textElements = widget.m_VisualElement.Query()
.Descendents<TextElement>(classname: "debug-window-search-filter-target")
.ToList();
string aggregatedText = CollectAggregatedAdditionalSearchText(widget);
m_WidgetSearchElementCache[widget] = new WidgetSearchData(textElements, aggregatedText);
});
}
void InitializeSearchField()
{
m_SearchFilter = new UIElementSearchFilter(
rootVisualElement,
searchString =>
{
var visiblePanels = PerformSearch(m_WidgetSearchElementCache, searchString, hideRootElementIfNoMatch: true);
foreach (var headerLabel in m_PanelHeaderTextElements)
UIElementSearchFilter.ApplySearchAndHighlight(headerLabel, searchString, out _);
foreach (var panel in DebugManager.instance.panels)
{
var tab = m_LeftPaneElement.Q<VisualElement>(name: panel.displayName + "_Tab");
if (tab != null)
{
bool shouldShow = string.IsNullOrEmpty(searchString) || visiblePanels.Contains(panel.displayName);
tab.style.display = shouldShow ? DisplayStyle.Flex : DisplayStyle.None;
}
}
bool noResults = !string.IsNullOrEmpty(searchString) && visiblePanels.Count == 0;
m_NoResultsLabel.style.display = noResults ? DisplayStyle.Flex : DisplayStyle.None;
}
);
m_SearchFilter.InitializeSearchField("search-field");
}
internal static string CollectAggregatedAdditionalSearchText(DebugUI.Widget widget)
{
var parts = new List<string>();
if (!string.IsNullOrEmpty(widget.m_AdditionalSearchText))
parts.Add(widget.m_AdditionalSearchText);
if (widget is DebugUI.Container container)
{
foreach (var child in container.children)
{
string childAggregated = CollectAggregatedAdditionalSearchText(child);
if (!string.IsNullOrEmpty(childAggregated))
parts.Add(childAggregated);
}
}
return parts.Count > 0 ? string.Join(",", parts) : string.Empty;
}
internal static HashSet<string> PerformSearch(Dictionary<DebugUI.Widget, WidgetSearchData> elementCache, string searchString, bool hideRootElementIfNoMatch = false)
{
var panelsWithVisibleWidgets = new HashSet<string>();
foreach (var (widget, searchData) in elementCache)
{
bool anyDescendantMatchesSearch = false;
foreach (var elem in searchData.textElements)
{
UIElementSearchFilter.ApplySearchAndHighlight(elem, searchString, out bool matched);
if (matched)
anyDescendantMatchesSearch = true;
}
if (!string.IsNullOrEmpty(searchData.aggregatedAdditionalSearchText))
{
if (searchData.aggregatedAdditionalSearchText.Contains(searchString, StringComparison.CurrentCultureIgnoreCase))
anyDescendantMatchesSearch = true;
}
if (hideRootElementIfNoMatch)
{
if (searchString == string.Empty && searchData.textElements.Count == 0)
{
widget.m_IsHiddenBySearchFilter = false;
}
else
{
widget.m_IsHiddenBySearchFilter = !anyDescendantMatchesSearch;
}
}
else
{
widget.m_IsHiddenBySearchFilter = false;
}
if (!widget.m_IsHiddenBySearchFilter && widget.panel != null)
panelsWithVisibleWidgets.Add(widget.panel.displayName);
}
return panelsWithVisibleWidgets;
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e60528a842c858f469435e8e9683025a
@@ -0,0 +1,332 @@
#if ENABLE_UIELEMENTS_MODULE && UNITY_ENABLE_CHECKS
#define ENABLE_RENDERING_DEBUGGER_UI
#endif
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor.Rendering.Analytics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace UnityEditor.Rendering
{
struct WidgetChangedAction<T>
{
public string query_path;
public T previous_value;
public T new_value;
}
[CoreRPHelpURL("Rendering-Debugger")]
sealed partial class DebugWindow : EditorWindowWithHelpButton
#if ENABLE_RENDERING_DEBUGGER_UI
, IHasCustomMenu
#endif
{
internal static GUIContent s_TitleContent = EditorGUIUtility.TrTextContent("Rendering Debugger");
[MenuItem("Window/Analysis/Rendering Debugger", priority = 10005)]
static void Init()
{
var window = GetWindow<DebugWindow>();
window.titleContent = s_TitleContent;
window.minSize = new Vector2(800f, 300f);
}
[MenuItem("Window/Analysis/Rendering Debugger", validate = true)]
static bool ValidateMenuItem()
{
return RenderPipelineManager.currentPipeline != null;
}
public void CreateGUI()
{
#if ENABLE_RENDERING_DEBUGGER_UI
RecreateGUI();
#else
var helpBox = new HelpBox(
"UIElements Module is disabled. In order to use Rendering Debugger, enable the module in Package Manager > Built-in. ",
HelpBoxMessageType.Info);
helpBox.buttonText = "Open in Package Manager";
helpBox.onButtonClicked += () => PackageManager.UI.Window.Open("com.unity.modules.uielements");
rootVisualElement.Add(helpBox);
#endif
}
#if ENABLE_RENDERING_DEBUGGER_UI
[SerializeField]
string m_SelectedPanelName;
DebugUI.Panel m_SelectedPanel;
DebugUI.Panel selectedPanel
{
get => m_SelectedPanel;
set
{
m_SelectedPanel = value;
m_SelectedPanelName = m_SelectedPanel?.displayName;
}
}
VisualElement m_LeftPaneElement;
VisualElement m_RightPaneElement;
const string k_UssCommon = "Packages/com.unity.render-pipelines.core/Runtime/Debugging/Runtime UI Resources/DebugWindowCommon.uss";
const string k_Uss = "Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uss";
const string k_Uxml = "Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uxml";
void OnEnable()
{
DebugManager.instance.displayEditorUI = true;
hideFlags = HideFlags.HideAndDontSave;
autoRepaintOnSceneChange = true;
DebugManager.instance.onSetDirty += RequestRebuild;
DebugManager.instance.onRecreateDebugUI += RequestRebuild;
DebugManager.instance.onPanelSelectionRequested += SetSelectedPanel;
GraphicsToolLifetimeAnalytic.WindowOpened<DebugWindow>();
HookValueChangedAnalytics();
}
// We use reflection to hook analytics to the onWidgetValueChangedAnalytic callback. The callback itself is required here because
// GraphicsToolUsageAnalytic is in the editor assembly but all widgets are in runtime. Reflection is used because we want to
// also hook analytics for any custom user widgets derived from public DebugUI.Field<T>.
void HookValueChangedAnalytics()
{
var allFieldTypes = TypeCache.GetTypesDerivedFrom(typeof(DebugUI.Field<>));
foreach (var fieldType in allFieldTypes)
{
try
{
var genericArgs = fieldType.BaseType.GetGenericArguments();
if (fieldType.IsAbstract || genericArgs.Length == 0)
continue;
var field = fieldType.GetField(nameof(DebugUI.Field<int>.onWidgetValueChangedAnalytic), BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
var method = GetType().GetMethod(nameof(SendWidgetValueChangedAnalytic), BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
var genericArg = fieldType.BaseType.GetGenericArguments()[0];
var genericMethod = method.MakeGenericMethod(genericArg);
var delegateType = typeof(Action<,,>).MakeGenericType(typeof(string), genericArg, genericArg);
var callback = Delegate.CreateDelegate(delegateType, null, genericMethod);
field.SetValue(null, callback);
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to hook analytics for {fieldType}: {ex.Message}");
}
}
}
// Store timestamps to throttle event sending
static readonly Dictionary<string, float> s_SentAnalyticsTimestamps = new ();
static void SendWidgetValueChangedAnalytic<T>(string queryPath, T previousValue, T newValue)
{
if (queryPath == null)
return;
const float kMaxSendRateSeconds = 0.5f;
float now = (float)EditorApplication.timeSinceStartup;
if (s_SentAnalyticsTimestamps.TryGetValue(queryPath, out float lastSentAt) && now - lastSentAt < kMaxSendRateSeconds)
return;
s_SentAnalyticsTimestamps[queryPath] = now;
var analytic = new List<WidgetChangedAction<T>> { new()
{
query_path = queryPath,
previous_value = previousValue,
new_value = newValue
} };
GraphicsToolUsageAnalytic.ActionPerformed<DebugWindow>("Widget Value Changed", analytic.ToNestedColumn());
}
private void OnDisable()
{
DebugManager.instance.onSetDirty -= RequestRebuild;
DebugManager.instance.onRecreateDebugUI -= RequestRebuild;
DebugManager.instance.onPanelSelectionRequested -= SetSelectedPanel;
GraphicsToolLifetimeAnalytic.WindowClosed<DebugWindow>();
}
// Note: this won't get called if the window is opened when the editor itself is closed
void OnDestroy()
{
EditorApplication.delayCall += () =>
{
// Note: In the case where the window is maximized/unmaximized, OnEnable for the new window gets called *before* OnDestroy.
// Therefore you need to be careful with statics/globals. In this case, we only mark displayEditorUI as false if we are
// closing the only/last DebugWindow instance. The check is delayed because inside OnDestroy, the current window still exists.
var debugWindows = Resources.FindObjectsOfTypeAll(typeof(DebugWindow));
if (debugWindows.Length == 0)
DebugManager.instance.displayEditorUI = false;
};
}
bool m_NeedsRebuild;
void RequestRebuild()
{
m_NeedsRebuild = true;
}
void Update()
{
if (m_NeedsRebuild)
{
m_NeedsRebuild = false;
RecreateGUI();
}
}
private void RecreateGUI()
{
rootVisualElement.Clear();
var panels = DebugManager.instance.panels;
// Adding all panels that are not inactive in editor and have at least one active child
var activePanels = new List<DebugUI.Panel>();
foreach (var panel in panels)
{
if (!panel.isInactiveInEditor)
{
foreach (var child in panel.children)
{
if (!child.isInactiveInEditor)
{
activePanels.Add(panel);
break;
}
}
}
}
if (activePanels.Count == 0)
{
rootVisualElement.Add(new HelpBox("No debug items registered. Make sure a Render Pipeline Asset is assigned in Quality Settings.", HelpBoxMessageType.Info));
return;
}
var windowUxml = EditorGUIUtility.LoadRequired(k_Uxml) as VisualTreeAsset;
var commonUss = EditorGUIUtility.LoadRequired(k_UssCommon) as StyleSheet;
var windowUss = EditorGUIUtility.LoadRequired(k_Uss) as StyleSheet;
if (commonUss == null || windowUss == null || windowUxml == null)
throw new InvalidOperationException("Unable to find required UXML and USS files");
rootVisualElement.styleSheets.Add(commonUss);
rootVisualElement.styleSheets.Add(windowUss);
windowUxml.CloneTree(rootVisualElement);
m_LeftPaneElement = rootVisualElement.Q<VisualElement>(name: "tabs-insertion-element");
m_RightPaneElement = rootVisualElement.Q<VisualElement>(name: "panels-inspector-insertion-element");
if (m_LeftPaneElement == null || m_RightPaneElement == null)
throw new InvalidOperationException("Unable to find required insertion Visual Elements");
m_LeftPaneElement.Clear();
m_RightPaneElement.Clear();
var resetButton = rootVisualElement.Q<ToolbarButton>(name: "btn-reset");
resetButton.clicked -= ResetClicked;
resetButton.clicked += ResetClicked;
var uiPanels = DebugUIExtensions.CreatePanels(activePanels, DebugUI.Context.Editor);
foreach (var (tab, panel) in uiPanels)
{
panel.style.display = DisplayStyle.None;
tab.RegisterCallback<ClickEvent>(_ => SetSelectedPanel(tab.text));
m_LeftPaneElement.Add(tab);
m_RightPaneElement.Add(panel);
}
string selectedPanelName = m_SelectedPanelName;
if (string.IsNullOrEmpty(selectedPanelName) || m_LeftPaneElement.Q<Label>(name: m_SelectedPanelName + "_Tab") == null)
{
// No selected panel, or selected panel is not existing anymore, pick the first
if (m_LeftPaneElement.childCount > 0 && m_LeftPaneElement[0] is Label firstLabel)
selectedPanelName = firstLabel.text;
}
SetSelectedPanel(selectedPanelName);
// When the window is docked/undocked, this ensures the schedulers are re-enabled
rootVisualElement.RegisterCallback<AttachToPanelEvent>(_ =>
{
// The schedulers themselves are created in AttachToPanelEvent so we need to delay to ensure this has happened.
EditorApplication.delayCall += () => SetSelectedPanel(m_SelectedPanelName);
});
BuildSearchCache();
InitializeSearchField();
m_NeedsRebuild = false;
}
void ResetClicked()
{
DebugManager.instance.Reset();
RecreateGUI();
DebugDisplaySerializer.LoadFoldoutStates();
}
internal void SetSelectedPanel(string panelName) // internal for tests
{
if (string.IsNullOrEmpty(panelName))
return;
// UI elements may not be initialized yet if this is called before RecreateGUI
if (m_LeftPaneElement == null || m_RightPaneElement == null)
{
// Just update the selected panel name - RecreateGUI will apply it when it runs
m_SelectedPanelName = panelName;
return;
}
if (selectedPanel != null)
{
m_LeftPaneElement.Q<VisualElement>(name: $"{selectedPanel.displayName}_Tab")?.RemoveFromClassList("selected");
if (m_RightPaneElement.Q<VisualElement>(name: $"{selectedPanel.displayName}_Content") is { } previousContent)
previousContent.style.display = DisplayStyle.None;
DebugManager.instance.schedulerTracker.SetHierarchyEnabled(DebugUI.Context.Editor, selectedPanel, false);
}
selectedPanel = DebugManager.instance.GetPanel(panelName);
if (selectedPanel != null)
{
m_LeftPaneElement.Q<VisualElement>(name: $"{selectedPanel.displayName}_Tab")?.AddToClassList("selected");
if (m_RightPaneElement.Q<VisualElement>(name: $"{selectedPanel.displayName}_Content") is { } newContent)
newContent.style.display = DisplayStyle.Flex;
DebugManager.instance.schedulerTracker.SetHierarchyEnabled(DebugUI.Context.Editor, selectedPanel, true);
}
}
public void AddItemsToMenu(GenericMenu menu)
{
menu.AddItem(EditorGUIUtility.TrTextContent("Expand All"), false, () => SetExpanded(true));
menu.AddItem(EditorGUIUtility.TrTextContent("Collapse All"), false, () => SetExpanded(false));
}
void SetExpanded(bool expanded)
{
DebugManager.instance.ForEachWidget(widget =>
{
if (widget is DebugUI.Foldout foldout)
foldout.opened = expanded;
});
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41147144ff556e246b736135eb26f185
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,143 @@
:root {
}
.top-toolbar {
height: 22px;
}
#debug-window-tab-panel {
align-items: stretch;
min-width: 120px;
}
.debug-window-tab-item {
padding-bottom: 4px;
padding-left: 15px;
padding-top: 2px;
}
/* Main Tab Panel Content */
#debug-window-tab-container {
min-width: 300px;
align-items: stretch;
flex-wrap: nowrap;
flex-grow: 1;
}
.debug-window-tab-content {
padding-right: 5px;
margin-left: 0px;
margin-right: 0px;
}
/* Align content of the foldouts with the text */
.debug-window-foldout>.unity-foldout__content {
margin: 0px 4px 8px 6px;
}
.selected {
background-color: var(--unity-colors-highlight-background-inactive);
}
.selected:focus {
background-color: var(--unity-colors-highlight-background);
}
.debug-window-colorfield.debug-window-table-cell {
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
.debug-window-messagebox {
margin: 1px 0px;
}
/* Compensate from editor stylesheet, Z-input no margin-right, Vector4 needs no margin-right and add the lost margin-left*/
#unity-w-input.unity-composite-field__field {
margin-right: 0px;
margin-left: 4px;
}
/* Header Foldout */
.debug-window-foldout-header > .unity-foldout__toggle {
padding-top: 1px !important;
padding-bottom: 1px !important;
margin-top: 0px !important;
margin-bottom: 0px !important;
margin-left: -2px;
margin-right: -4px;
border-top-width: 1px;
border-top-color: var(--unity-colors-default-border);
border-bottom-width: 1px;
border-bottom-color: var(--unity-colors-default-border);
background-color: var(--unity-colors-inspector_titlebar-background);
}
.debug-window-foldout-header > .unity-foldout__toggle:hover {
background-color: var(--unity-colors-inspector_titlebar-background-hover);
}
.debug-window-foldout-header > .unity-foldout__toggle > .unity-toggle__input > .unity-toggle__checkmark
{
margin-left: 4px;
margin-right: 4px;
}
.debug-window-foldout-header .unity-foldout__text {
-unity-font-style: bold;
}
.debug-window-foldout > .unity-foldout__toggle {
padding-top: 1px !important;
padding-bottom: 1px !important;
margin-top: 0px !important;
margin-bottom: 0px !important;
}
.debug-window-foldout > .unity-foldout__toggle:hover {
background-color: var(--unity-colors-inspector_titlebar-background-hover);
}
.debug-window-foldout > .unity-foldout__toggle > .unity-toggle__input > .unity-toggle__checkmark
{
margin-left: 4px;
margin-right: 4px;
}
.debug-window-foldout .unity-foldout__text {
-unity-font-style: bold;
}
.more-options-button {
background-image: var(--unity-icons-pane_options);
}
.info-button,
.more-options-button {
background-color: transparent;
margin: 2px 2px 1px 3px;
padding: 0px 2px 0px 0px;
border-width: 0px;
border-radius: 2px 2px 2px 2px;
width: 20px;
height: 20px;
}
.info-button:hover,
.more-options-button:hover{
background-color: var(--unity-colors-button-background-hover);
}
.info-button:disabled
.info-button:disabled,
.more-options-button:disabled {
}
#debug-window-no-results-label {
display: none;
-unity-text-align: middle-center;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6015f12526b2ed04eb8a3943af5202da
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,23 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<uie:Toolbar class="top-toolbar">
<uie:ToolbarSpacer style="flex-grow: 1" />
<uie:ToolbarSearchField name="search-field"/>
<uie:ToolbarButton text="Reset" name="btn-reset" focusable="false" />
</uie:Toolbar>
<ui:TwoPaneSplitView fixed-pane-index="0" fixed-pane-initial-dimension="225" view-data-key="debug-window-split-view">
<ui:VisualElement name="debug-window-tab-panel">
<ui:ScrollView horizontal-scroller-visibility="Hidden" view-data-key="debug-window-tab-panel-scrollview">
<ui:VisualElement name="tabs-insertion-element"/>
<ui:VisualElement name="scroll-buffer"/>
</ui:ScrollView>
</ui:VisualElement>
<ui:VisualElement name="debug-window-tab-container" class="">
<ui:ScrollView horizontal-scroller-visibility="Hidden" view-data-key="debug-window-tab-container-scrollview">
<ui:VisualElement name="panels-inspector-insertion-element" />
<ui:Label name="debug-window-no-results-label" text="No results match your search." />
<ui:VisualElement name="scroll-buffer" />
</ui:ScrollView>
</ui:VisualElement>
</ui:TwoPaneSplitView>
</ui:UXML>
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5e5ba1167b7b68e4fb383ce19a13c5e7
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e199542932514047864b6e8dcd90aa0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,37 @@
using System;
namespace UnityEditor.Rendering
{
/// <summary>
/// Bool saved in EditorPref.
/// </summary>
public struct EditorPrefBool
{
readonly string m_Key;
/// <summary>
/// Value of the boolean in editor preferences.
/// </summary>
public bool value
{
get => EditorPrefs.GetBool(m_Key);
set => EditorPrefs.SetBool(m_Key, value);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="key">Key in the editor preferences.</param>
/// <param name="defaultValue">Default value of the preference.</param>
public EditorPrefBool(string key, bool defaultValue = false)
{
m_Key = key;
//register key if not already there
if (!EditorPrefs.HasKey(m_Key))
{
EditorPrefs.SetBool(m_Key, defaultValue);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a68889b608ba2d247920c6b4983df6f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,87 @@
using System;
namespace UnityEditor.Rendering
{
/// <summary>Bool flag saved in EditorPref</summary>
/// <typeparam name="T">Underlying enum type</typeparam>
public struct EditorPrefBoolFlags<T> : IEquatable<T>, IEquatable<EditorPrefBoolFlags<T>>
where T : struct, IConvertible
{
readonly string m_Key;
/// <summary>The value as the underlying enum type used</summary>
public T value
{ get => (T)(object)EditorPrefs.GetInt(m_Key); set => EditorPrefs.SetInt(m_Key, (int)(object)value); }
/// <summary>The raw value</summary>
public uint rawValue
{
get => (uint)EditorPrefs.GetInt(m_Key);
set => EditorPrefs.SetInt(m_Key, (int)value);
}
/// <summary>Constructor</summary>
/// <param name="key">Name of the Key in EditorPrefs to save the value</param>
public EditorPrefBoolFlags(string key)
{
m_Key = key;
}
/// <summary>Test if saved value is equal to the one given</summary>
/// <param name="other">Given value</param>
/// <returns>True if value are the same</returns>
public bool Equals(T other) => (int)(object)value == (int)(object)other;
/// <summary>Test if this EditorPrefBoolFlags is the same than the given one</summary>
/// <param name="other">Given EditorPrefBoolFlags</param>
/// <returns>True if they use the same value</returns>
public bool Equals(EditorPrefBoolFlags<T> other) => m_Key == other.m_Key;
/// <summary>Test if the given flags are set</summary>
/// <param name="v">Given flags</param>
/// <returns>True: all the given flags are set</returns>
public bool HasFlag(T v) => ((uint)(int)(object)v & rawValue) == (uint)(int)(object)v;
/// <summary>Set or unset the flags</summary>
/// <param name="f">Flags to edit</param>
/// <param name="v">Boolean value to set to the given flags</param>
public void SetFlag(T f, bool v)
{
if (v) rawValue |= (uint)(int)(object)f;
else rawValue &= ~(uint)(int)(object)f;
}
/// <summary>Explicit conversion operator to the underlying type</summary>
/// <param name="v">The EditorPrefBoolFlags to convert</param>
/// <returns>The converted value</returns>
public static explicit operator T(EditorPrefBoolFlags<T> v) => v.value;
/// <summary>Or operator between a EditorPrefBoolFlags and a value</summary>
/// <param name="l">The EditorPrefBoolFlags</param>
/// <param name="r">The value</param>
/// <returns>A EditorPrefBoolFlags with OR operator performed</returns>
public static EditorPrefBoolFlags<T> operator |(EditorPrefBoolFlags<T> l, T r)
{
l.rawValue |= (uint)(int)(object)r;
return l;
}
/// <summary>And operator between a EditorPrefBoolFlags and a value</summary>
/// <param name="l">The EditorPrefBoolFlags</param>
/// <param name="r">The value</param>
/// <returns>A EditorPrefBoolFlags with AND operator performed</returns>
public static EditorPrefBoolFlags<T> operator &(EditorPrefBoolFlags<T> l, T r)
{
l.rawValue &= (uint)(int)(object)r;
return l;
}
/// <summary>Xor operator between a EditorPrefBoolFlags and a value</summary>
/// <param name="l">The EditorPrefBoolFlags</param>
/// <param name="r">The value</param>
/// <returns>A EditorPrefBoolFlags with XOR operator performed</returns>
public static EditorPrefBoolFlags<T> operator ^(EditorPrefBoolFlags<T> l, T r)
{
l.rawValue ^= (uint)(int)(object)r;
return l;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f766cc928a2d60469867f03d60c9f01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,32 @@
using System;
using UnityEngine;
namespace UnityEditor.Rendering
{
/// <summary>Editor window that adds a button to browse the help url, specify <see cref="HelpURLAttribute"/> when defining your inherited class</summary>
public class EditorWindowWithHelpButton : EditorWindow
{
static Lazy<GUIContent> m_IconHelpGUIContent;
GUIContent iconHelpGUIContent => m_IconHelpGUIContent.Value;
static EditorWindowWithHelpButton()
{
m_IconHelpGUIContent = new Lazy<GUIContent>(() => new GUIContent(CoreEditorStyles.iconHelp));
}
/// <summary>Shows a button with help icon and opens the url defined by <see cref="HelpURLAttribute"/></summary>
/// <param name="r">The rect to show the button</param>
[Obsolete("This method will be removed soon. Please override OnHelpButtonClicked instead. #from(2023.1)")]
protected virtual void ShowButton(Rect r)
{
if (GUI.Button(r, iconHelpGUIContent, CoreEditorStyles.iconHelpStyle))
OnHelpButtonClicked();
}
/// <summary>What hapens when the help button is clicked onto. Default implementation use the <see cref="HelpURLAttribute"/> onto the window class.</summary>
protected virtual void OnHelpButtonClicked()
{
Help.ShowHelpForObject(this);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db823efdb635ec84d8ecae05788f8143
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More