This commit is contained in:
2024-09-20 20:30:10 +02:00
commit 4fabf1a6fd
29169 changed files with 1706941 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c667ca46d23aa3468b6c4243b135b0d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[VolumeParameterDrawer(typeof(BoolParameter))]
sealed class BoolParameterDrawer : VolumeParameterDrawer
{
private enum BoolEnum
{
Disabled = 0,
Enabled = 1
}
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Boolean)
return false;
var o = parameter.GetObjectRef<BoolParameter>();
if (o.displayType == BoolParameter.DisplayType.EnumPopup)
{
var enumValue = value.boolValue ? BoolEnum.Enabled: BoolEnum.Disabled;
enumValue = (BoolEnum) EditorGUILayout.EnumPopup(title, enumValue);
value.boolValue = enumValue == BoolEnum.Enabled;
}
else
{
EditorGUILayout.PropertyField(value, title);
}
return true;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e60eb64f07904667887976b2ec8cffed
timeCreated: 1664276387

View File

@@ -0,0 +1,25 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[VolumeParameterDrawer(typeof(ColorParameter))]
sealed class ColorParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Color)
return false;
var o = parameter.GetObjectRef<ColorParameter>();
var rect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(rect, title, value);
value.colorValue = EditorGUI.ColorField(rect, title, value.colorValue, o.showEyeDropper, o.showAlpha, o.hdr);
EditorGUI.EndProperty();
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34ad702e46732ff438113b62a10ae80e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,146 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[VolumeParameterDrawer(typeof(MinFloatParameter))]
sealed class MinFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<MinFloatParameter>();
EditorGUILayout.PropertyField(value, title);
value.floatValue = Mathf.Max(value.floatValue, o.min);
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpMinFloatParameter))]
sealed class NoInterpMinFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<NoInterpMinFloatParameter>();
EditorGUILayout.PropertyField(value, title);
value.floatValue = Mathf.Max(value.floatValue, o.min);
return true;
}
}
[VolumeParameterDrawer(typeof(MaxFloatParameter))]
sealed class MaxFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<MaxFloatParameter>();
EditorGUILayout.PropertyField(value, title);
value.floatValue = Mathf.Min(value.floatValue, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpMaxFloatParameter))]
sealed class NoInterpMaxFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<NoInterpMaxFloatParameter>();
EditorGUILayout.PropertyField(value, title);
value.floatValue = Mathf.Min(value.floatValue, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(ClampedFloatParameter))]
sealed class ClampedFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<ClampedFloatParameter>();
EditorGUILayout.Slider(value, o.min, o.max, title);
value.floatValue = Mathf.Clamp(value.floatValue, o.min, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpClampedFloatParameter))]
sealed class NoInterpClampedFloatParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Float)
return false;
var o = parameter.GetObjectRef<NoInterpClampedFloatParameter>();
EditorGUILayout.Slider(value, o.min, o.max, title);
value.floatValue = Mathf.Clamp(value.floatValue, o.min, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(FloatRangeParameter))]
sealed class FloatRangeParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Vector2)
return false;
var o = parameter.GetObjectRef<FloatRangeParameter>();
var v = value.vector2Value;
// The layout system breaks alignement when mixing inspector fields with custom layouted
// 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 = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
lineRect.xMin += 4f;
lineRect.y += 2f;
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.BeginProperty(lineRect, title, value);
EditorGUI.PrefixLabel(labelRect, title);
v.x = EditorGUI.FloatField(floatFieldLeft, v.x);
EditorGUI.MinMaxSlider(sliderRect, ref v.x, ref v.y, o.min, o.max);
v.y = EditorGUI.FloatField(floatFieldRight, v.y);
EditorGUI.EndProperty();
value.vector2Value = v;
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9816364c4bdf314db38db52fc67a3f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,168 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditorInternal;
namespace UnityEditor.Rendering
{
[VolumeParameterDrawer(typeof(MinIntParameter))]
sealed class MinIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<MinIntParameter>();
EditorGUILayout.PropertyField(value, title);
value.intValue = Mathf.Max(value.intValue, o.min);
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpMinIntParameter))]
sealed class NoInterpMinIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<NoInterpMinIntParameter>();
EditorGUILayout.PropertyField(value, title);
value.intValue = Mathf.Max(value.intValue, o.min);
return true;
}
}
[VolumeParameterDrawer(typeof(MaxIntParameter))]
sealed class MaxIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<MaxIntParameter>();
EditorGUILayout.PropertyField(value, title);
value.intValue = Mathf.Min(value.intValue, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpMaxIntParameter))]
sealed class NoInterpMaxIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<NoInterpMaxIntParameter>();
EditorGUILayout.PropertyField(value, title);
value.intValue = Mathf.Min(value.intValue, o.max);
return true;
}
}
[VolumeParameterDrawer(typeof(ClampedIntParameter))]
sealed class ClampedIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<ClampedIntParameter>();
var lineRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(lineRect, title, value);
EditorGUI.IntSlider(lineRect, value, o.min, o.max, title);
value.intValue = Mathf.Clamp(value.intValue, o.min, o.max);
EditorGUI.EndProperty();
return true;
}
}
[VolumeParameterDrawer(typeof(NoInterpClampedIntParameter))]
sealed class NoInterpClampedIntParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Integer)
return false;
var o = parameter.GetObjectRef<NoInterpClampedIntParameter>();
var lineRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(lineRect, title, value);
EditorGUI.IntSlider(lineRect, value, o.min, o.max, title);
value.intValue = Mathf.Clamp(value.intValue, o.min, o.max);
EditorGUI.EndProperty();
return true;
}
}
[VolumeParameterDrawer(typeof(LayerMaskParameter))]
sealed class LayerMaskParameterDrawer : VolumeParameterDrawer
{
private static int FieldToLayerMask(int field)
{
int mask = 0;
var layers = InternalEditorUtility.layers;
bool everything = true;
for (int c = 0; c < layers.Length; c++)
{
if ((field & (1 << c)) != 0)
mask |= 1 << LayerMask.NameToLayer(layers[c]);
else
{
mask &= ~(1 << LayerMask.NameToLayer(layers[c]));
everything = false;
}
}
return everything ? -1 : mask;
}
private static int LayerMaskToField(int mask)
{
int field = 0;
var layers = InternalEditorUtility.layers;
bool everything = true;
for (int c = 0; c < layers.Length; c++)
{
if ((mask & (1 << LayerMask.NameToLayer(layers[c]))) != 0)
field |= 1 << c;
else
everything = false;
}
return everything ? -1 : field;
}
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.LayerMask)
return false;
var lineRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(lineRect, title, value);
value.intValue = FieldToLayerMask(
EditorGUI.MaskField(lineRect, title, LayerMaskToField(value.intValue), InternalEditorUtility.layers));
EditorGUI.EndProperty();
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d2f589334fbc8444b30925a405106d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,193 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
namespace UnityEditor.Rendering
{
internal static class TextureParameterHelper
{
static readonly Type k_ObjectFieldValidator = Type.GetType("UnityEditor.EditorGUI+ObjectFieldValidator,UnityEditor");
internal static Func<Object[], Type, SerializedProperty, int, Object> ValidateObjectFieldAssignment;
static Func<Rect, Rect, int, Object, Object, Type, Type, SerializedProperty, Delegate, bool, GUIStyle, Object> k_DoObjectField;
internal delegate Object ObjectFieldValidator(Object[] references, Type objType, SerializedProperty property, int options);
static TextureParameterHelper()
{
Type ObjectFieldValidatorOptions_Type = Type.GetType("UnityEditor.EditorGUI+ObjectFieldValidatorOptions,UnityEditor");
var typeParameter = Expression.Parameter(typeof(Type), "type");
var propertyParameter = Expression.Parameter(typeof(SerializedProperty), "property");
var intParameter = Expression.Parameter(typeof(int), "int");
// ValidateObjectFieldAssignment
MethodInfo validateObjectFieldAssignment_Info = Type.GetType("UnityEditor.EditorGUI,UnityEditor").GetMethod("ValidateObjectFieldAssignment", BindingFlags.Static | BindingFlags.NonPublic);
var referencesParameter = Expression.Parameter(typeof(Object[]), "references");
var optionsVariable = Expression.Parameter(ObjectFieldValidatorOptions_Type, "options");
var validateObjectFieldAssignment_Block = Expression.Block(
new[] { optionsVariable },
Expression.Assign(optionsVariable, Expression.Convert(intParameter, ObjectFieldValidatorOptions_Type)),
Expression.Call(validateObjectFieldAssignment_Info, referencesParameter, typeParameter, propertyParameter, optionsVariable)
);
var validateObjectFieldAssignment_Lambda = Expression.Lambda<Func<Object[], Type, SerializedProperty, int, Object>>(
validateObjectFieldAssignment_Block, referencesParameter, typeParameter, propertyParameter, intParameter);
ValidateObjectFieldAssignment = validateObjectFieldAssignment_Lambda.Compile();
// ObjectField
MethodInfo doObjectField_Info = Type.GetType("UnityEditor.EditorGUI,UnityEditor").GetMethod("DoObjectField", BindingFlags.Static | BindingFlags.NonPublic, null,
new Type[] { typeof(Rect), typeof(Rect), typeof(int), typeof(Object), typeof(Object), typeof(Type), typeof(Type), typeof(SerializedProperty), k_ObjectFieldValidator, typeof(bool), typeof(GUIStyle) }, null);
var positionParameter = Expression.Parameter(typeof(Rect), "position");
var rectParameter = Expression.Parameter(typeof(Rect), "rect");
var objectParameter = Expression.Parameter(typeof(Object), "object");
var unusedParameter = Expression.Parameter(typeof(Object), "unused");
var type2Parameter = Expression.Parameter(typeof(Type), "type2");
var boolParameter = Expression.Parameter(typeof(bool), "allowSceneObject");
var styleParameter = Expression.Parameter(typeof(GUIStyle), "style");
var validatorParameter = Expression.Parameter(typeof(Delegate), "validator");
var validatorVariable = Expression.Parameter(k_ObjectFieldValidator, "validator");
var doObjectField_Block = Expression.Block(
new[] { validatorVariable },
Expression.Assign(validatorVariable, Expression.Convert(validatorParameter, k_ObjectFieldValidator)),
Expression.Call(doObjectField_Info, positionParameter, rectParameter, intParameter, objectParameter, unusedParameter, typeParameter, type2Parameter, propertyParameter, validatorVariable, boolParameter, styleParameter)
);
var doObjectField_Lambda = Expression.Lambda<Func<Rect, Rect, int, Object, Object, Type, Type, SerializedProperty, Delegate, bool, GUIStyle, Object>>(
doObjectField_Block, positionParameter, rectParameter, intParameter, objectParameter, unusedParameter, typeParameter, type2Parameter, propertyParameter, validatorParameter, boolParameter, styleParameter);
k_DoObjectField = doObjectField_Lambda.Compile();
}
internal static Delegate CastValidator(ObjectFieldValidator validator)
{
return DelegateUtility.Cast(validator, k_ObjectFieldValidator);
}
internal static void DoObjectField(SerializedProperty property, GUIContent label, Type type1, Type type2, Delegate validator)
{
Rect r = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight);
DoObjectField(r, property, label, type1, type2, validator);
}
internal static void DoObjectField(Rect r, SerializedProperty property, GUIContent label, Type type1, Type type2, Delegate validator)
{
int id = GUIUtility.GetControlID(FocusType.Keyboard, r);
r = EditorGUI.PrefixLabel(r, id, label);
k_DoObjectField(r, r, id, null, null, type1, type2, property, validator, false, EditorStyles.objectField);
}
}
[VolumeParameterDrawer(typeof(TextureParameter))]
sealed class TextureParameterDrawer : VolumeParameterDrawer
{
internal static bool HasGenuineNullSelection(Object[] references)
{
bool genuineNullSelection = true;
for (int i = 0; i < references.Length; ++i)
{
genuineNullSelection &= (references[i] == null);
}
return genuineNullSelection;
}
static Delegate validator = TextureParameterHelper.CastValidator((Object[] references, Type objType, SerializedProperty property, int options) =>
{
if (HasGenuineNullSelection(references)) return null;
// Accept RenderTextures of correct dimensions
Texture validated = (RenderTexture)TextureParameterHelper.ValidateObjectFieldAssignment(references, typeof(RenderTexture), property, options);
if (validated != null)
{
if (objType == typeof(Texture2D) && validated.dimension != TextureDimension.Tex2D) validated = null;
if (objType == typeof(Texture3D) && validated.dimension != TextureDimension.Tex3D) validated = null;
if (objType == typeof(Cubemap) && validated.dimension != TextureDimension.Cube) validated = null;
}
// Accept textures of correct type
if (validated == null)
validated = (Texture)TextureParameterHelper.ValidateObjectFieldAssignment(references, objType, property, options);
return validated ? validated : property.objectReferenceValue;
});
internal static bool TextureField(SerializedProperty property, GUIContent title, TextureDimension dimension)
{
if (property.propertyType != SerializedPropertyType.ObjectReference)
return false;
var rect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(rect, title, property);
switch (dimension)
{
case TextureDimension.Tex2D:
TextureParameterHelper.DoObjectField(rect, property, title, typeof(Texture2D), typeof(RenderTexture), validator);
break;
case TextureDimension.Tex3D:
TextureParameterHelper.DoObjectField(rect, property, title, typeof(Texture3D), typeof(RenderTexture), validator);
break;
case TextureDimension.Cube:
TextureParameterHelper.DoObjectField(rect, property, title, typeof(Cubemap), typeof(RenderTexture), validator);
break;
default:
EditorGUI.PropertyField(rect, property, title);
break;
}
EditorGUI.EndProperty();
return true;
}
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
var dimension = parameter.GetObjectRef<TextureParameter>().dimension;
return TextureField(value, title, dimension);
}
}
[VolumeParameterDrawer(typeof(Texture2DParameter))]
sealed class Texture2DParameterDrawer : VolumeParameterDrawer
{
/// <summary>Draws the parameter in the editor.</summary>
/// <param name="parameter">The parameter to draw.</param>
/// <param name="title">The label and tooltip of the parameter.</param>
/// <returns><c>true</c> if the input parameter is valid, <c>false</c> otherwise</returns>
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
return TextureParameterDrawer.TextureField(parameter.value, title, TextureDimension.Tex2D);
}
}
[VolumeParameterDrawer(typeof(Texture3DParameter))]
sealed class Texture3DParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
return TextureParameterDrawer.TextureField(parameter.value, title, TextureDimension.Tex3D);
}
}
[VolumeParameterDrawer(typeof(CubemapParameter))]
sealed class CubemapParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
return TextureParameterDrawer.TextureField(parameter.value, title, TextureDimension.Cube);
}
}
[VolumeParameterDrawer(typeof(NoInterpCubemapParameter))]
sealed class NoInterpCubemapParameterDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
return TextureParameterDrawer.TextureField(parameter.value, title, TextureDimension.Cube);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 476c38cf01c741143abe491ba6a97a3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[VolumeParameterDrawer(typeof(Vector4Parameter))]
sealed class Vector4ParametrDrawer : VolumeParameterDrawer
{
public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
{
var value = parameter.value;
if (value.propertyType != SerializedPropertyType.Vector4)
return false;
value.vector4Value = EditorGUILayout.Vector4Field(title, value.vector4Value);
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c51e2ea627a393478d0b5c2a086136d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0a1b3bf427e8c2246a076c46a94e3793
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,121 @@
fileFormatVersion: 2
guid: 188dfe7e559f13248ba2c41eb5a59328
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,123 @@
fileFormatVersion: 2
guid: f20112bdeec2e8d4d9f80e8390e37263
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 8
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEngine.Assertions;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// A serialization wrapper for <see cref="VolumeParameter{T}"/>.
/// </summary>
public sealed class SerializedDataParameter
{
/// <summary>
/// The serialized property for <see cref="VolumeParameter.overrideState"/>.
/// </summary>
public SerializedProperty overrideState { get; private set; }
/// <summary>
/// The serialized property for <see cref="VolumeParameter{T}.value"/>
/// </summary>
public SerializedProperty value { get; private set; }
/// <summary>
/// A pre-fetched list of all the attributes applied on the <see cref="VolumeParameter{T}"/>.
/// </summary>
public Attribute[] attributes { get; private set; }
/// <summary>
/// The actual type of the serialized <see cref="VolumeParameter{T}"/>.
/// </summary>
public Type referenceType { get; private set; }
SerializedProperty m_BaseProperty;
object m_ReferenceValue;
/// <summary>
/// The generated display name of the <see cref="VolumeParameter{T}"/> for the inspector.
/// </summary>
public string displayName => m_BaseProperty.displayName;
internal SerializedDataParameter(SerializedProperty property)
{
// Find the actual property type, optional attributes & reference
var path = property.propertyPath.Split('.');
object obj = property.serializedObject.targetObject;
FieldInfo field = null;
foreach (var p in path)
{
field = obj.GetType().GetField(p, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
obj = field.GetValue(obj);
}
Assert.IsNotNull(field);
m_BaseProperty = property.Copy();
overrideState = m_BaseProperty.FindPropertyRelative("m_OverrideState");
value = m_BaseProperty.FindPropertyRelative("m_Value");
attributes = field.GetCustomAttributes(false).Cast<Attribute>().ToArray();
referenceType = obj.GetType();
m_ReferenceValue = obj;
}
/// <summary>
/// Gets and casts an attribute applied on the base <see cref="VolumeParameter{T}"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T GetAttribute<T>()
where T : Attribute
{
return (T)attributes.FirstOrDefault(x => x is T);
}
/// <summary>
/// Gets and casts the underlying reference of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type to cast to</typeparam>
/// <returns>The reference to the serialized <see cref="VolumeParameter{T}"/> type</returns>
public T GetObjectRef<T>()
{
return (T)m_ReferenceValue;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abf61146103c4444290de1048016607b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// Interface to add additional gizmo renders for a <see cref="IVolume"/>
/// </summary>
public interface IVolumeAdditionalGizmo
{
/// <summary>
/// The type that overrides this additional gizmo
/// </summary>
Type type { get; }
/// <summary>
/// Additional gizmo draw for <see cref="BoxCollider"/>
/// </summary>
/// <param name="scr">The <see cref="IVolume"/></param>
/// <param name="c">The <see cref="BoxCollider"/></param>
void OnBoxColliderDraw(IVolume scr, BoxCollider c);
/// <summary>
/// Additional gizmo draw for <see cref="SphereCollider"/>
/// </summary>
/// <param name="scr">The <see cref="IVolume"/></param>
/// <param name="c">The <see cref="SphereCollider"/></param>
void OnSphereColliderDraw(IVolume scr, SphereCollider c);
/// <summary>
/// Additional gizmo draw for <see cref="MeshCollider"/>
/// </summary>
/// <param name="scr">The <see cref="IVolume"/></param>
/// <param name="c">The <see cref="MeshCollider"/></param>
void OnMeshColliderDraw(IVolume scr, MeshCollider c);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec83f2a0a0da1f0499e433a0070dfdb4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,832 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.AnimatedValues;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// A custom editor class that draws a <see cref="VolumeComponent"/> in the Inspector. If you do not
/// provide a custom editor for a <see cref="VolumeComponent"/>, Unity uses the default one.
/// You must use a <see cref="CustomEditor"/> to let the editor know which
/// component this drawer is for.
/// </summary>
/// <example>
/// Below is an example of a custom <see cref="VolumeComponent"/>:
/// <code>
/// using UnityEngine.Rendering;
///
/// [Serializable, VolumeComponentMenu("Custom/Example Component")]
/// public class ExampleComponent : VolumeComponent
/// {
/// public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
/// }
/// </code>
/// And its associated editor:
/// <code>
/// using UnityEditor.Rendering;
///
/// [CustomEditor(typeof(ExampleComponent))]
/// class ExampleComponentEditor : VolumeComponentEditor
/// {
/// SerializedDataParameter m_Intensity;
///
/// public override void OnEnable()
/// {
/// var o = new PropertyFetcher&lt;ExampleComponent&gt;(serializedObject);
/// m_Intensity = Unpack(o.Find(x => x.intensity));
/// }
///
/// public override void OnInspectorGUI()
/// {
/// PropertyField(m_Intensity);
/// }
/// }
/// </code>
/// </example>
/// <seealso cref="CustomEditor"/>
[CustomEditor(typeof(VolumeComponent), true)]
public class VolumeComponentEditor : Editor
{
const string k_KeyPrefix = "CoreRP:VolumeComponent:UI_State:";
EditorPrefBool m_EditorPrefBool;
/// <summary>
/// If the editor for this <see cref="VolumeComponent"/> is expanded or not in the inspector
/// </summary>
public bool expanded
{
get => m_EditorPrefBool.value;
set => m_EditorPrefBool.value = value;
}
internal Type[] m_PipelineTypes;
internal Type[] pipelineTypes
{
get
{
if (m_PipelineTypes == null)
{
var supportedOn = volumeComponent.GetType().GetCustomAttribute<VolumeComponentMenuForRenderPipeline>();
if(supportedOn != null)
m_PipelineTypes = supportedOn.pipelineTypes;
else
m_PipelineTypes = Array.Empty<Type>();
}
return m_PipelineTypes;
}
}
internal bool visible
{
get
{
if (RenderPipelineManager.currentPipeline == null)
return false;
if (!pipelineTypes.Any())
return true;
return pipelineTypes.Contains(RenderPipelineManager.currentPipeline.GetType());
}
}
class Styles
{
public static GUIContent overrideSettingText { get; } = EditorGUIUtility.TrTextContent("", "Override this setting for this volume.");
public static GUIContent allText { get; } = EditorGUIUtility.TrTextContent("ALL", "Toggle all overrides on. To maximize performances you should only toggle overrides that you actually need.");
public static GUIContent noneText { get; } = EditorGUIUtility.TrTextContent("NONE", "Toggle all overrides off.");
public static string toggleAllText { get; } = L10n.Tr("Toggle All");
public const int overrideCheckboxWidth = 14;
public const int overrideCheckboxOffset = 9;
}
Vector2? m_OverrideToggleSize;
internal Vector2 overrideToggleSize
{
get
{
if (!m_OverrideToggleSize.HasValue)
m_OverrideToggleSize = CoreEditorStyles.smallTickbox.CalcSize(Styles.overrideSettingText);
return m_OverrideToggleSize.Value;
}
}
/// <summary>
/// Specifies the <see cref="VolumeComponent"/> this editor is drawing.
/// </summary>
public VolumeComponent volumeComponent => target as VolumeComponent;
/// <summary>
/// The copy of the serialized property of the <see cref="VolumeComponent"/> being
/// inspected. Unity uses this to track whether the editor is collapsed in the Inspector or not.
/// </summary>
[Obsolete("Please use expanded property instead. #from(2022.2)", false)]
public SerializedProperty baseProperty { get; internal set; }
/// <summary>
/// The serialized property of <see cref="VolumeComponent.active"/> for the component being
/// inspected.
/// </summary>
public SerializedProperty activeProperty { get; internal set; }
#region Additional Properties
AnimFloat m_AdditionalPropertiesAnimation;
EditorPrefBool m_ShowAdditionalProperties;
List<VolumeParameter> m_VolumeNotAdditionalParameters = new List<VolumeParameter>();
/// <summary>
/// Override this property if your editor makes use of the "Additional Properties" feature.
/// </summary>
public virtual bool hasAdditionalProperties => volumeComponent.parameterList.Count != m_VolumeNotAdditionalParameters.Count;
/// <summary>
/// Set to true to show additional properties.
/// </summary>
public bool showAdditionalProperties
{
get => m_ShowAdditionalProperties.value;
set
{
if (value && !m_ShowAdditionalProperties.value)
{
m_AdditionalPropertiesAnimation.value = 1.0f;
m_AdditionalPropertiesAnimation.target = 0.0f;
}
SetAdditionalPropertiesPreference(value);
}
}
/// <summary>
/// Start a scope for additional properties.
/// This will handle the highlight of the background when toggled on and off.
/// </summary>
/// <returns>True if the additional content should be drawn.</returns>
protected bool BeginAdditionalPropertiesScope()
{
if (hasAdditionalProperties && showAdditionalProperties)
{
CoreEditorUtils.BeginAdditionalPropertiesHighlight(m_AdditionalPropertiesAnimation);
return true;
}
else
{
return false;
}
}
/// <summary>
/// End a scope for additional properties.
/// </summary>
protected void EndAdditionalPropertiesScope()
{
if (hasAdditionalProperties && showAdditionalProperties)
{
CoreEditorUtils.EndAdditionalPropertiesHighlight();
}
}
#endregion
/// <summary>
/// A reference to the parent editor in the Inspector.
/// </summary>
protected Editor m_Inspector;
/// <summary>
/// A reference to the parent editor in the Inspector.
/// </summary>
internal Editor inspector
{
get => m_Inspector;
set => m_Inspector = value;
}
/// <summary>
/// Obtains the <see cref="Volume"/> that is being edited from this volume component
/// </summary>
protected Volume volume => inspector?.target as Volume;
List<(GUIContent displayName, int displayOrder, SerializedDataParameter param)> m_Parameters;
static Dictionary<Type, VolumeParameterDrawer> s_ParameterDrawers;
static VolumeComponentEditor()
{
s_ParameterDrawers = new Dictionary<Type, VolumeParameterDrawer>();
ReloadDecoratorTypes();
}
[Callbacks.DidReloadScripts]
static void OnEditorReload()
{
ReloadDecoratorTypes();
}
static void ReloadDecoratorTypes()
{
s_ParameterDrawers.Clear();
// Look for all the valid parameter drawers
var types = CoreUtils.GetAllTypesDerivedFrom<VolumeParameterDrawer>()
.Where(t => t.IsDefined(typeof(VolumeParameterDrawerAttribute), false) && !t.IsAbstract);
// Store them
foreach (var type in types)
{
var attr = (VolumeParameterDrawerAttribute)type.GetCustomAttributes(typeof(VolumeParameterDrawerAttribute), false)[0];
var decorator = (VolumeParameterDrawer)Activator.CreateInstance(type);
s_ParameterDrawers.Add(attr.parameterType, decorator);
}
}
/// <summary>
/// Triggers an Inspector repaint event.
/// </summary>
public new void Repaint()
{
inspector?.Repaint();
// Volume Component Editors can be shown in the ProjectSettings window (default volume profile)
// This will force a repaint of the whole window, otherwise, additional properties highlight animation does not work properly.
SettingsService.RepaintAllSettingsWindow();
base.Repaint();
}
internal static string GetAdditionalPropertiesPreferenceKey(Type type)
{
return $"UI_Show_Additional_Properties_{type}";
}
internal void InitAdditionalPropertiesPreference()
{
string key = GetAdditionalPropertiesPreferenceKey(GetType());
m_ShowAdditionalProperties = new EditorPrefBool(key);
}
internal void SetAdditionalPropertiesPreference(bool value)
{
m_ShowAdditionalProperties.value = value;
}
internal void Init()
{
activeProperty = serializedObject.FindProperty("active");
var inspectorKey = inspector != null ? inspector.GetType().Name : string.Empty;
m_EditorPrefBool = new EditorPrefBool(k_KeyPrefix + inspectorKey + volumeComponent.GetType().Name, true);
InitAdditionalPropertiesPreference();
m_AdditionalPropertiesAnimation = new AnimFloat(0, Repaint)
{
speed = CoreEditorConstants.additionalPropertiesHightLightSpeed
};
InitParameters();
OnEnable();
}
void InitParameters()
{
VolumeComponent.FindParameters(target, m_VolumeNotAdditionalParameters, field => field.GetCustomAttribute<AdditionalPropertyAttribute>() == null);
}
void GetFields(object o, List<(FieldInfo, SerializedProperty)> infos, SerializedProperty prop = null)
{
if (o == null)
return;
var fields = o.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
if (field.FieldType.IsSubclassOf(typeof(VolumeParameter)))
{
if ((field.GetCustomAttributes(typeof(HideInInspector), false).Length == 0) &&
((field.GetCustomAttributes(typeof(SerializeField), false).Length > 0) ||
(field.IsPublic && field.GetCustomAttributes(typeof(NonSerializedAttribute), false).Length == 0)))
infos.Add((field, prop == null ?
serializedObject.FindProperty(field.Name) : prop.FindPropertyRelative(field.Name)));
}
else if (!field.FieldType.IsArray && field.FieldType.IsClass)
GetFields(field.GetValue(o), infos, prop == null ?
serializedObject.FindProperty(field.Name) : prop.FindPropertyRelative(field.Name));
}
}
/// <summary>
/// Unity calls this method when the object loads.
/// </summary>
/// <remarks>
/// You can safely override this method and not call <c>base.OnEnable()</c> unless you want
/// Unity to display all the properties from the <see cref="VolumeComponent"/> automatically.
/// </remarks>
public virtual void OnEnable()
{
// Grab all valid serializable field on the VolumeComponent
// TODO: Should only be done when needed / on demand as this can potentially be wasted CPU when a custom editor is in use
var fields = new List<(FieldInfo, SerializedProperty)>();
GetFields(target, fields);
m_Parameters = fields
.Select(t =>
{
var name = "";
var order = 0;
var (fieldInfo, serializedProperty) = t;
var attr = (DisplayInfoAttribute[])fieldInfo.GetCustomAttributes(typeof(DisplayInfoAttribute), true);
if (attr.Length != 0)
{
name = attr[0].name;
order = attr[0].order;
}
var parameter = new SerializedDataParameter(t.Item2);
return (EditorGUIUtility.TrTextContent(name), order, parameter);
})
.OrderBy(t => t.order)
.ToList();
}
/// <summary>
/// Unity calls this method when the object goes out of scope.
/// </summary>
public virtual void OnDisable()
{
}
internal void OnInternalInspectorGUI()
{
serializedObject.Update();
using (new EditorGUILayout.VerticalScope())
{
TopRowFields();
OnInspectorGUI();
EditorGUILayout.Space();
}
serializedObject.ApplyModifiedProperties();
}
/// <summary>
/// Unity calls this method each time it re-draws the Inspector.
/// </summary>
/// <remarks>
/// You can safely override this method and not call <c>base.OnInspectorGUI()</c> unless you
/// want Unity to display all the properties from the <see cref="VolumeComponent"/>
/// automatically.
/// </remarks>
public override void OnInspectorGUI()
{
// Display every field as-is
foreach (var parameter in m_Parameters)
{
if (!string.IsNullOrEmpty(parameter.displayName.text))
PropertyField(parameter.param, parameter.displayName);
else
PropertyField(parameter.param);
}
}
/// <summary>
/// Sets the label for the component header. Override this method to provide
/// a custom label. If you don't, Unity automatically obtains one from the class name.
/// </summary>
/// <returns>A label to display in the component header.</returns>
public virtual GUIContent GetDisplayTitle()
{
var targetType = target.GetType();
string title = string.IsNullOrEmpty(volumeComponent.displayName) ? ObjectNames.NicifyVariableName(volumeComponent.GetType().Name) : volumeComponent.displayName;
string tooltip = targetType.GetCustomAttribute(typeof(VolumeComponentMenuForRenderPipeline), false) is VolumeComponentMenuForRenderPipeline supportedOn
? string.Join(", ", supportedOn.pipelineTypes.Select(t => ObjectNames.NicifyVariableName(t.Name)))
: string.Empty;
return EditorGUIUtility.TrTextContent(title, tooltip);
}
void AddToogleState(GUIContent content, bool state)
{
bool allOverridesSameState = AreOverridesTo(state);
if (GUILayout.Toggle(allOverridesSameState, content, CoreEditorStyles.miniLabelButton, GUILayout.ExpandWidth(false)) && !allOverridesSameState)
SetOverridesTo(state);
}
void TopRowFields()
{
using (new EditorGUILayout.HorizontalScope())
{
AddToogleState(Styles.allText, true);
AddToogleState(Styles.noneText, false);
}
}
/// <summary>
/// Checks if all the visible parameters have the given state
/// </summary>
/// <param name="state">The state to check</param>
internal bool AreOverridesTo(bool state)
{
if (hasAdditionalProperties && showAdditionalProperties)
return AreAllOverridesTo(state);
for (int i = 0; i < m_VolumeNotAdditionalParameters.Count; ++i)
{
if (m_VolumeNotAdditionalParameters[i].overrideState != state)
return false;
}
return true;
}
/// <summary>
/// Sets the given state to all the visible parameters
/// </summary>
/// <param name="state">The state to check</param>
internal void SetOverridesTo(bool state)
{
if (hasAdditionalProperties && showAdditionalProperties)
SetAllOverridesTo(state);
else
{
Undo.RecordObject(target, Styles.toggleAllText);
volumeComponent.SetOverridesTo(m_VolumeNotAdditionalParameters, state);
serializedObject.Update();
}
}
internal bool AreAllOverridesTo(bool state)
{
for (int i = 0; i < volumeComponent.parameterList.Count; ++i)
{
if (volumeComponent.parameterList[i].overrideState != state)
return false;
}
return true;
}
internal void SetAllOverridesTo(bool state)
{
Undo.RecordObject(target, Styles.toggleAllText);
volumeComponent.SetAllOverridesTo(state);
serializedObject.Update();
}
/// <summary>
/// Generates and auto-populates a <see cref="SerializedDataParameter"/> from a serialized
/// <see cref="VolumeParameter{T}"/>.
/// </summary>
/// <param name="property">A serialized property holding a <see cref="VolumeParameter{T}"/>
/// </param>
/// <returns></returns>
protected SerializedDataParameter Unpack(SerializedProperty property)
{
Assert.IsNotNull(property);
return new SerializedDataParameter(property);
}
/// <summary>
/// Draws a given <see cref="SerializedDataParameter"/> in the editor.
/// </summary>
/// <param name="property">The property to draw in the editor</param>
/// <returns>true if the property field has been rendered</returns>
protected bool PropertyField(SerializedDataParameter property)
{
var title = EditorGUIUtility.TrTextContent(property.displayName,
property.GetAttribute<TooltipAttribute>()?.tooltip); // avoid property from getting the tooltip of another one with the same name
return PropertyField(property, title);
}
static readonly Dictionary<string, GUIContent> s_HeadersGuiContents = new Dictionary<string, GUIContent>();
/// <summary>
/// Draws a header into the inspector with the given title
/// </summary>
/// <param name="header">The title for the header</param>
protected void DrawHeader(string header)
{
if (!s_HeadersGuiContents.TryGetValue(header, out GUIContent content))
{
content = EditorGUIUtility.TrTextContent(header);
s_HeadersGuiContents.Add(header, content);
}
var rect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight));
EditorGUI.LabelField(rect, content, EditorStyles.miniLabel);
}
/// <summary>
/// Handles unity built-in decorators (Space, Header, Tooltips, ...) from <see cref="SerializedDataParameter"/> attributes
/// </summary>
/// <param name="property">The property to obtain the attributes and handle the decorators</param>
/// <param name="title">A custom label and/or tooltip that might be updated by <see cref="TooltipAttribute"/> and/or by <see cref="InspectorNameAttribute"/></param>
void HandleDecorators(SerializedDataParameter property, GUIContent title)
{
foreach (var attr in property.attributes)
{
if (!(attr is PropertyAttribute))
continue;
switch (attr)
{
case SpaceAttribute spaceAttribute:
EditorGUILayout.GetControlRect(false, spaceAttribute.height);
break;
case HeaderAttribute headerAttribute:
DrawHeader(headerAttribute.header);
break;
case TooltipAttribute tooltipAttribute:
if (string.IsNullOrEmpty(title.tooltip))
title.tooltip = tooltipAttribute.tooltip;
break;
case InspectorNameAttribute inspectorNameAttribute:
title.text = inspectorNameAttribute.displayName;
break;
}
}
}
/// <summary>
/// Get indentation from Indent attribute
/// </summary>
/// <param name="property">The property to obtain the attributes</param>
/// <returns>The relative indent level change</returns>
int HandleRelativeIndentation(SerializedDataParameter property)
{
foreach (var attr in property.attributes)
{
if (attr is VolumeComponent.Indent indent)
return indent.relativeAmount;
}
return 0;
}
/// <summary>
/// Draws a given <see cref="SerializedDataParameter"/> in the editor using a custom label
/// and tooltip.
/// </summary>
/// <param name="property">The property to draw in the editor.</param>
/// <param name="title">A custom label and/or tooltip.</param>
/// <returns>true if the property field has been rendered</returns>
protected bool PropertyField(SerializedDataParameter property, GUIContent title)
{
if (VolumeParameter.IsObjectParameter(property.referenceType))
return DrawEmbeddedField(property, title);
else
return DrawPropertyField(property, title);
}
/// <summary>
/// Draws a given <see cref="SerializedDataParameter"/> in the editor using a custom label
/// and tooltip.
/// </summary>
/// <param name="property">The property to draw in the editor.</param>
/// <param name="title">A custom label and/or tooltip.</param>
private bool DrawPropertyField(SerializedDataParameter property, GUIContent title)
{
using (var scope = new OverridablePropertyScope(property, title, this))
{
if (!scope.displayed)
return false;
// Custom drawer
if (scope.drawer?.OnGUI(property, title) ?? false)
return true;
// Standard Unity drawer
EditorGUILayout.PropertyField(property.value, title);
}
return true;
}
/// <summary>
/// Draws a given <see cref="SerializedDataParameter"/> in the editor using a custom label
/// and tooltip. This variant is only for embedded class / struct
/// </summary>
/// <param name="property">The property to draw in the editor.</param>
/// <param name="title">A custom label and/or tooltip.</param>
private bool DrawEmbeddedField(SerializedDataParameter property, GUIContent title)
{
bool isAdditionalProperty = property.GetAttribute<AdditionalPropertyAttribute>() != null;
bool displayed = !isAdditionalProperty || BeginAdditionalPropertiesScope();
if (!displayed)
return false;
// Custom parameter drawer
s_ParameterDrawers.TryGetValue(property.referenceType, out VolumeParameterDrawer drawer);
if (drawer != null && !drawer.IsAutoProperty())
if (drawer.OnGUI(property, title))
{
if (isAdditionalProperty)
EndAdditionalPropertiesScope();
return true;
}
// Standard Unity drawer
using (new IndentLevelScope())
{
bool expanded = property?.value?.isExpanded ?? true;
expanded = EditorGUILayout.Foldout(expanded, title, true);
if (expanded)
{
// Not the fastest way to do it but that'll do just fine for now
var it = property.value.Copy();
var end = it.GetEndProperty();
bool first = true;
while (it.Next(first) && !SerializedProperty.EqualContents(it, end))
{
PropertyField(Unpack(it));
first = false;
}
}
property.value.isExpanded = expanded;
}
if (isAdditionalProperty)
EndAdditionalPropertiesScope();
return true;
}
/// <summary>
/// Draws the override checkbox used by a property in the editor.
/// </summary>
/// <param name="property">The property to draw the override checkbox for</param>
protected void DrawOverrideCheckbox(SerializedDataParameter property)
{
// Create a rect the height + vspacing of the property that is being overriden
float height = EditorGUI.GetPropertyHeight(property.value) + EditorGUIUtility.standardVerticalSpacing;
var overrideRect = GUILayoutUtility.GetRect(Styles.allText, CoreEditorStyles.miniLabelButton, GUILayout.Height(height), GUILayout.Width(Styles.overrideCheckboxWidth + Styles.overrideCheckboxOffset), GUILayout.ExpandWidth(false));
// also center vertically the checkbox
overrideRect.yMin += height * 0.5f - overrideToggleSize.y * 0.5f;
overrideRect.xMin += Styles.overrideCheckboxOffset;
property.overrideState.boolValue = GUI.Toggle(overrideRect, property.overrideState.boolValue, Styles.overrideSettingText, CoreEditorStyles.smallTickbox);
}
/// <summary>
/// Scope for property that handle:
/// - Layout decorator (Space, Header)
/// - Naming decorator (Tooltips, InspectorName)
/// - Overridable checkbox if parameter IsAutoProperty
/// - disabled GUI if Overridable checkbox (case above) is unchecked
/// - additional property scope
/// This is automatically used inside PropertyField method
/// </summary>
protected struct OverridablePropertyScope : IDisposable
{
bool isAdditionalProperty;
VolumeComponentEditor editor;
IDisposable disabledScope;
IDisposable indentScope;
internal bool haveCustomOverrideCheckbox { get; private set; }
internal VolumeParameterDrawer drawer { get; private set; }
/// <summary>
/// Either the content property will be displayed or not (can varry with additional property settings)
/// </summary>
public bool displayed { get; private set; }
/// <summary>
/// The title modified regarding attribute used on the field
/// </summary>
public GUIContent label { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="property">The property that will be drawn</param>
/// <param name="label">The label of this property</param>
/// <param name="editor">The editor that will draw it</param>
public OverridablePropertyScope(SerializedDataParameter property, GUIContent label, VolumeComponentEditor editor)
{
disabledScope = null;
indentScope = null;
haveCustomOverrideCheckbox = false;
drawer = null;
displayed = false;
isAdditionalProperty = false;
this.label = label;
this.editor = editor;
Init(property, label, editor);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="property">The property that will be drawn</param>
/// <param name="label">The label of this property</param>
/// <param name="editor">The editor that will draw it</param>
public OverridablePropertyScope(SerializedDataParameter property, string label, VolumeComponentEditor editor)
{
disabledScope = null;
indentScope = null;
haveCustomOverrideCheckbox = false;
drawer = null;
displayed = false;
isAdditionalProperty = false;
this.label = EditorGUIUtility.TrTextContent(label);
this.editor = editor;
Init(property, this.label, editor);
}
void Init(SerializedDataParameter property, GUIContent label, VolumeComponentEditor editor)
{
// Below, 3 is horizontal spacing and there is one between label and field and another between override checkbox and label
EditorGUIUtility.labelWidth -= Styles.overrideCheckboxWidth + Styles.overrideCheckboxOffset + 3 + 3;
isAdditionalProperty = property.GetAttribute<AdditionalPropertyAttribute>() != null;
displayed = !isAdditionalProperty || editor.BeginAdditionalPropertiesScope();
s_ParameterDrawers.TryGetValue(property.referenceType, out VolumeParameterDrawer vpd);
drawer = vpd;
//never draw override for embedded class/struct
haveCustomOverrideCheckbox = (displayed && !(drawer?.IsAutoProperty() ?? true))
|| VolumeParameter.IsObjectParameter(property.referenceType);
if (displayed)
{
editor.HandleDecorators(property, label);
int relativeIndentation = editor.HandleRelativeIndentation(property);
if (relativeIndentation != 0)
indentScope = new IndentLevelScope(relativeIndentation * 15);
if (!haveCustomOverrideCheckbox)
{
EditorGUILayout.BeginHorizontal();
editor.DrawOverrideCheckbox(property);
disabledScope = new EditorGUI.DisabledScope(!property.overrideState.boolValue);
}
}
}
/// <summary>
/// Dispose of the class
/// </summary>
void IDisposable.Dispose()
{
disabledScope?.Dispose();
indentScope?.Dispose();
if (!haveCustomOverrideCheckbox && displayed)
EditorGUILayout.EndHorizontal();
if (isAdditionalProperty)
editor.EndAdditionalPropertiesScope();
EditorGUIUtility.labelWidth += Styles.overrideCheckboxWidth + Styles.overrideCheckboxOffset + 3 + 3;
}
}
/// <summary>
/// Like EditorGUI.IndentLevelScope but this one will also indent the override checkboxes.
/// </summary>
protected class IndentLevelScope : GUI.Scope
{
int m_Offset;
/// <summary>
/// Constructor
/// </summary>
/// <param name="offset">[optional] Change the indentation offset</param>
public IndentLevelScope(int offset = 15)
{
m_Offset = offset;
// When using EditorGUI.indentLevel++, the clicking on the checkboxes does not work properly due to some issues on the C++ side.
// This scope is a work-around for this issue.
GUILayout.BeginHorizontal();
EditorGUILayout.Space(offset, false);
GUIStyle style = new GUIStyle();
GUILayout.BeginVertical(style);
EditorGUIUtility.labelWidth -= m_Offset;
}
/// <summary>
/// Closes the scope
/// </summary>
protected override void CloseScope()
{
EditorGUIUtility.labelWidth += m_Offset;
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6bb22372ebe2bc42a227c8f8c1795ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,495 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// Unity uses this class to draw the user interface for all the settings
/// contained in a <see cref="VolumeProfile"/> in the Inspector.
/// </summary>
/// <example>
/// A minimal example of how to write a custom editor that displays the content of a profile
/// in the inspector:
/// <code>
/// using UnityEngine.Rendering;
///
/// [CustomEditor(typeof(VolumeProfile))]
/// public class CustomVolumeProfileEditor : Editor
/// {
/// VolumeComponentListEditor m_ComponentList;
///
/// void OnEnable()
/// {
/// m_ComponentList = new VolumeComponentListEditor(this);
/// m_ComponentList.Init(target as VolumeProfile, serializedObject);
/// }
///
/// void OnDisable()
/// {
/// if (m_ComponentList != null)
/// m_ComponentList.Clear();
/// }
///
/// public override void OnInspectorGUI()
/// {
/// serializedObject.Update();
/// m_ComponentList.OnGUI();
/// serializedObject.ApplyModifiedProperties();
/// }
/// }
/// </code>
/// </example>
public sealed class VolumeComponentListEditor
{
/// <summary>
/// A direct reference to the <see cref="VolumeProfile"/> this editor displays.
/// </summary>
public VolumeProfile asset { get; private set; }
/// <summary>
/// Obtains if all the volume components are visible
/// </summary>
internal bool hasHiddenVolumeComponents => m_Editors.Count != asset.components.Count;
Editor m_BaseEditor;
SerializedObject m_SerializedObject;
SerializedProperty m_ComponentsProperty;
List<VolumeComponentEditor> m_Editors = new List<VolumeComponentEditor>();
/// <summary>
/// Creates a new instance of <see cref="VolumeComponentListEditor"/> to use in an
/// existing editor.
/// </summary>
/// <param name="editor">A reference to the parent editor instance</param>
public VolumeComponentListEditor(Editor editor)
{
Assert.IsNotNull(editor);
m_BaseEditor = editor;
}
/// <summary>
/// Initializes the editor.
/// </summary>
/// <param name="asset">A direct reference to the profile Asset.</param>
/// <param name="serializedObject">An instance of the <see cref="SerializedObject"/>
/// provided by the parent editor.</param>
public void Init(VolumeProfile asset, SerializedObject serializedObject)
{
Assert.IsNotNull(asset);
Assert.IsNotNull(serializedObject);
this.asset = asset;
m_SerializedObject = serializedObject;
RefreshEditors();
// Keep track of undo/redo to redraw the inspector when that happens
Undo.undoRedoPerformed += OnUndoRedoPerformed;
}
void OnUndoRedoPerformed()
{
asset.isDirty = true;
// Dumb hack to make sure the serialized object is up to date on undo (else there'll be
// a state mismatch when this class is used in a GameObject inspector).
if (m_SerializedObject != null
&& !m_SerializedObject.Equals(null)
&& m_SerializedObject.targetObject != null
&& !m_SerializedObject.targetObject.Equals(null))
{
m_SerializedObject.Update();
m_SerializedObject.ApplyModifiedProperties();
}
// Seems like there's an issue with the inspector not repainting after some undo events
// This will take care of that
m_BaseEditor.Repaint();
}
// index is only used when we need to re-create a component in a specific spot (e.g. reset)
void CreateEditor(VolumeComponent component, SerializedProperty property, int index = -1, bool forceOpen = false)
{
var editor = (VolumeComponentEditor)Editor.CreateEditor(component);
editor.inspector = m_BaseEditor;
editor.Init();
if (forceOpen)
editor.expanded = true;
if (index < 0)
m_Editors.Add(editor);
else
m_Editors[index] = editor;
}
int m_CurrentHashCode;
void ClearEditors()
{
if (m_Editors?.Any() ?? false)
{
// Disable all editors first
foreach (var editor in m_Editors)
UnityEngine.Object.DestroyImmediate(editor);
// Remove them
m_Editors.Clear();
}
}
void RefreshEditors()
{
ClearEditors();
// Refresh the ref to the serialized components in case the asset got swapped or another
// script is editing it while it's active in the inspector
m_SerializedObject.Update();
m_ComponentsProperty = m_SerializedObject.Find((VolumeProfile x) => x.components);
Assert.IsNotNull(m_ComponentsProperty);
// Recreate editors for existing settings, if any
var components = asset.components;
for (int i = 0; i < components.Count; i++)
CreateEditor(components[i], m_ComponentsProperty.GetArrayElementAtIndex(i));
m_CurrentHashCode = asset.GetComponentListHashCode();
}
/// <summary>
/// Cleans up the editor and individual <see cref="VolumeComponentEditor"/> instances. You
/// must call this when the parent editor is disabled or destroyed.
/// </summary>
public void Clear()
{
ClearEditors();
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
}
/// <summary>
/// Draws the editor.
/// </summary>
public void OnGUI()
{
if (asset == null)
return;
// Even if the asset is not dirty, the list of component may have been changed by another inspector.
// In this case, only the hash will tell us that we need to refresh.
if (asset.isDirty || asset.GetComponentListHashCode() != m_CurrentHashCode)
{
RefreshEditors();
asset.isDirty = false;
}
bool isEditable = !VersionControl.Provider.isActive
|| AssetDatabase.IsOpenForEdit(asset, StatusQueryOptions.UseCachedIfPossible);
using (new EditorGUI.DisabledScope(!isEditable))
{
for (int i = 0; i < m_Editors.Count; i++)
{
var editor = m_Editors[i];
if (!editor.visible)
continue;
var title = editor.GetDisplayTitle();
int id = i; // Needed for closure capture below
CoreEditorUtils.DrawSplitter();
bool displayContent = CoreEditorUtils.DrawHeaderToggleFoldout(
title,
editor.expanded,
editor.activeProperty,
pos => OnContextClick(pos, editor, id),
editor.hasAdditionalProperties ? () => editor.showAdditionalProperties : (Func<bool>)null,
() => editor.showAdditionalProperties ^= true,
Help.GetHelpURLForObject(editor.volumeComponent)
);
if (displayContent ^ editor.expanded)
editor.expanded = displayContent;
if (editor.expanded)
{
using (new EditorGUI.DisabledScope(!editor.activeProperty.boolValue))
editor.OnInternalInspectorGUI();
}
}
if (m_Editors.Count > 0)
CoreEditorUtils.DrawSplitter();
else
EditorGUILayout.HelpBox("This Volume Profile contains no overrides.", MessageType.Info);
EditorGUILayout.Space();
using (var hscope = new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(EditorGUIUtility.TrTextContent("Add Override"), EditorStyles.miniButton))
{
var r = hscope.rect;
var pos = new Vector2(r.x + r.width / 2f, r.yMax + 18f);
FilterWindow.Show(pos, new VolumeComponentProvider(asset, this));
}
}
}
}
void OnContextClick(Vector2 position, VolumeComponentEditor targetEditor, int id)
{
var targetComponent = targetEditor.volumeComponent;
var menu = new GenericMenu();
menu.AddItem(EditorGUIUtility.TrTextContent("Move to Top"), false, () => MoveComponent(id, Move.Top));
menu.AddItem(EditorGUIUtility.TrTextContent("Move Up"), false, () => MoveComponent(id, Move.Up));
menu.AddItem(EditorGUIUtility.TrTextContent("Move Down"), false, () => MoveComponent(id, Move.Down));
menu.AddItem(EditorGUIUtility.TrTextContent("Move to Bottom"), false, () => MoveComponent(id, Move.Bottom));
menu.AddSeparator(string.Empty);
menu.AddItem(EditorGUIUtility.TrTextContent("Collapse All"), false, () => CollapseComponents());
menu.AddItem(EditorGUIUtility.TrTextContent("Expand All"), false, () => ExpandComponents());
menu.AddSeparator(string.Empty);
menu.AddItem(EditorGUIUtility.TrTextContent("Reset"), false, () => ResetComponent(targetComponent.GetType(), id));
menu.AddItem(EditorGUIUtility.TrTextContent("Remove"), false, () => RemoveComponent(id));
menu.AddSeparator(string.Empty);
if (targetEditor.hasAdditionalProperties)
menu.AddItem(EditorGUIUtility.TrTextContent("Show Additional Properties"), targetEditor.showAdditionalProperties, () => targetEditor.showAdditionalProperties ^= true);
else
menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Show Additional Properties"));
menu.AddItem(EditorGUIUtility.TrTextContent("Show All Additional Properties..."), false, () => CoreRenderPipelinePreferences.Open());
menu.AddSeparator(string.Empty);
menu.AddItem(EditorGUIUtility.TrTextContent("Copy Settings"), false, () => CopySettings(targetComponent));
if (CanPaste(targetComponent))
menu.AddItem(EditorGUIUtility.TrTextContent("Paste Settings"), false, () => PasteSettings(targetComponent));
else
menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Paste Settings"));
menu.AddSeparator(string.Empty);
menu.AddItem(EditorGUIUtility.TrTextContent("Toggle All"), false, () => m_Editors[id].SetAllOverridesTo(true));
menu.AddItem(EditorGUIUtility.TrTextContent("Toggle None"), false, () => m_Editors[id].SetAllOverridesTo(false));
menu.DropDown(new Rect(position, Vector2.zero));
}
VolumeComponent CreateNewComponent(Type type)
{
var effect = (VolumeComponent)ScriptableObject.CreateInstance(type);
effect.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
effect.name = type.Name;
return effect;
}
internal void AddComponent(Type type)
{
m_SerializedObject.Update();
var component = CreateNewComponent(type);
Undo.RegisterCreatedObjectUndo(component, "Add Volume Override");
// Store this new effect as a subasset so we can reference it safely afterwards
// Only when we're not dealing with an instantiated asset
if (EditorUtility.IsPersistent(asset))
AssetDatabase.AddObjectToAsset(component, asset);
// Grow the list first, then add - that's how serialized lists work in Unity
m_ComponentsProperty.arraySize++;
var componentProp = m_ComponentsProperty.GetArrayElementAtIndex(m_ComponentsProperty.arraySize - 1);
componentProp.objectReferenceValue = component;
// Create & store the internal editor object for this effect
CreateEditor(component, componentProp, forceOpen: true);
m_SerializedObject.ApplyModifiedProperties();
// Force save / refresh
if (EditorUtility.IsPersistent(asset))
{
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssets();
}
}
internal void RemoveComponent(int id)
{
// Remove from the cached editors list
UnityEngine.Object.DestroyImmediate(m_Editors[id]);
m_Editors.RemoveAt(id);
m_SerializedObject.Update();
var property = m_ComponentsProperty.GetArrayElementAtIndex(id);
var component = property.objectReferenceValue;
// Unassign it (should be null already but serialization does funky things
property.objectReferenceValue = null;
// ...and remove the array index itself from the list
m_ComponentsProperty.DeleteArrayElementAtIndex(id);
m_SerializedObject.ApplyModifiedProperties();
// Destroy the setting object after ApplyModifiedProperties(). If we do it before, redo
// actions will be in the wrong order and the reference to the setting object in the
// list will be lost.
Undo.DestroyObjectImmediate(component);
// Force save / refresh
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssets();
}
// Reset is done by deleting and removing the object from the list and adding a new one in
// the same spot as it was before
internal void ResetComponent(Type type, int id)
{
// Remove from the cached editors list
UnityEngine.Object.DestroyImmediate(m_Editors[id]);
m_Editors[id] = null;
m_SerializedObject.Update();
var property = m_ComponentsProperty.GetArrayElementAtIndex(id);
var prevComponent = property.objectReferenceValue;
// Unassign it but down remove it from the array to keep the index available
property.objectReferenceValue = null;
// Create a new object
var newComponent = CreateNewComponent(type);
Undo.RegisterCreatedObjectUndo(newComponent, "Reset Volume Overrides");
// Store this new effect as a subasset so we can reference it safely afterwards
AssetDatabase.AddObjectToAsset(newComponent, asset);
// Put it in the reserved space
property.objectReferenceValue = newComponent;
// Create & store the internal editor object for this effect
CreateEditor(newComponent, property, id);
m_SerializedObject.ApplyModifiedProperties();
// Same as RemoveComponent, destroy at the end so it's recreated first on Undo to make
// sure the GUID exists before undoing the list state
Undo.DestroyObjectImmediate(prevComponent);
// Force save / refresh
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssets();
}
internal enum Move
{
Up,
Down,
Top,
Bottom
}
internal void MoveComponent(int id, Move move)
{
m_SerializedObject.Update();
int newIndex = id;
// Find the index based on the visible editor
switch(move)
{
case Move.Up:
{
do
{
newIndex--;
}
while (newIndex >= 0 && !m_Editors[newIndex].visible);
}
break;
case Move.Down:
{
do
{
newIndex++;
}
while (newIndex < m_Editors.Count && !m_Editors[newIndex].visible);
}
break;
case Move.Top:
newIndex = 0;
break;
case Move.Bottom:
newIndex = m_Editors.Count - 1;
break;
}
newIndex = Mathf.Clamp(newIndex, 0, m_Editors.Count - 1);
m_ComponentsProperty.MoveArrayElement(id, newIndex);
m_SerializedObject.ApplyModifiedProperties();
if (!m_Editors.TrySwap(id, newIndex, out var error))
Debug.LogException(error);
}
internal void CollapseComponents()
{
// Move components
m_SerializedObject.Update();
int numEditors = m_Editors.Count;
for (int i = 0; i < numEditors; ++i)
{
m_Editors[i].expanded = false;
}
m_SerializedObject.ApplyModifiedProperties();
}
internal void ExpandComponents()
{
// Move components
m_SerializedObject.Update();
int numEditors = m_Editors.Count;
for (int i = 0; i < numEditors; ++i)
{
m_Editors[i].expanded = true;
}
m_SerializedObject.ApplyModifiedProperties();
}
static bool CanPaste(VolumeComponent targetComponent)
{
if (string.IsNullOrWhiteSpace(EditorGUIUtility.systemCopyBuffer))
return false;
string clipboard = EditorGUIUtility.systemCopyBuffer;
int separator = clipboard.IndexOf('|');
if (separator < 0)
return false;
return targetComponent.GetType().AssemblyQualifiedName == clipboard.Substring(0, separator);
}
static void CopySettings(VolumeComponent targetComponent)
{
string typeName = targetComponent.GetType().AssemblyQualifiedName;
string typeData = JsonUtility.ToJson(targetComponent);
EditorGUIUtility.systemCopyBuffer = $"{typeName}|{typeData}";
}
static void PasteSettings(VolumeComponent targetComponent)
{
string clipboard = EditorGUIUtility.systemCopyBuffer;
string typeData = clipboard.Substring(clipboard.IndexOf('|') + 1);
Undo.RecordObject(targetComponent, "Paste Settings");
JsonUtility.FromJsonOverwrite(typeData, targetComponent);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f3ec0801d05bcb24c8a404d62f357d9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
using IProvider = FilterWindow.IProvider;
using Element = FilterWindow.Element;
using GroupElement = FilterWindow.GroupElement;
class VolumeComponentProvider : IProvider
{
class VolumeComponentElement : Element
{
public Type type;
public VolumeComponentElement(int level, string label, Type type)
{
this.level = level;
this.type = type;
// TODO: Add support for custom icons
content = new GUIContent(label);
}
}
class PathNode : IComparable<PathNode>
{
public List<PathNode> nodes = new List<PathNode>();
public string name;
public Type type;
public int CompareTo(PathNode other)
{
return name.CompareTo(other.name);
}
}
public Vector2 position { get; set; }
VolumeProfile m_Target;
VolumeComponentListEditor m_TargetEditor;
public VolumeComponentProvider(VolumeProfile target, VolumeComponentListEditor targetEditor)
{
m_Target = target;
m_TargetEditor = targetEditor;
}
public void CreateComponentTree(List<Element> tree)
{
var currentPipeline = RenderPipelineManager.currentPipeline;
if (currentPipeline == null)
{
tree.Add(new GroupElement(0, "No SRP in use"));
return;
}
tree.Add(new GroupElement(0, "Volume Overrides"));
var volumeComponentTypesFiltered =
VolumeManager.GetSupportedVolumeComponents(currentPipeline.GetType());
if (volumeComponentTypesFiltered.Any())
{
var rootNode = new PathNode();
foreach (var (path, t) in volumeComponentTypesFiltered)
{
// Skip components that have already been added to the volume
if (m_Target.Has(t))
continue;
// Prep the categories & types tree
AddNode(rootNode, path, t);
}
// Recursively add all elements to the tree
Traverse(rootNode, 1, tree);
}
}
public bool GoToChild(Element element, bool addIfComponent)
{
if (element is VolumeComponentElement volumeComponentElement)
{
m_TargetEditor.AddComponent(volumeComponentElement.type);
return true;
}
return false;
}
void AddNode(PathNode root, string path, Type type)
{
var current = root;
var parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
{
var child = current.nodes.Find(x => x.name == part);
if (child == null)
{
child = new PathNode { name = part, type = type };
current.nodes.Add(child);
}
current = child;
}
}
void Traverse(PathNode node, int depth, List<Element> tree)
{
node.nodes.Sort();
foreach (var n in node.nodes)
{
if (n.nodes.Count > 0) // Group
{
tree.Add(new GroupElement(depth, n.name));
Traverse(n, depth + 1, tree);
}
else // Element
{
tree.Add(new VolumeComponentElement(depth, n.name, n.type));
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d7e09e271ad3fd4c9ceb1873a5fb59e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,304 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor.Rendering.Analytics;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[CustomEditor(typeof(Volume))]
sealed class VolumeEditor : Editor
{
static class Styles
{
public static readonly GUIContent mode = EditorGUIUtility.TrTextContent("Mode", "This property defines whether the Volume is Global or Local. Global: Volumes affect the Camera everywhere in the Scene. Local: Volumes affect the Camera if the Camera is within the bounds of the Collider.");
public static readonly GUIContent[] modes = { EditorGUIUtility.TrTextContent("Global"), EditorGUIUtility.TrTextContent("Local") };
public static readonly GUIContent addBoxCollider = EditorGUIUtility.TrTextContent("Add a Box Collider");
public static readonly GUIContent sphereBoxCollider = EditorGUIUtility.TrTextContent("Add a Sphere Collider");
public static readonly GUIContent capsuleBoxCollider = EditorGUIUtility.TrTextContent("Add a Capsule Collider");
public static readonly GUIContent meshBoxCollider = EditorGUIUtility.TrTextContent("Add a Mesh Collider");
public static readonly GUIContent addColliderFixMessage = EditorGUIUtility.TrTextContentWithIcon("Add a Collider to this GameObject to set boundaries for the local Volume.", CoreEditorStyles.iconWarn);
public static readonly GUIContent disableColliderFixMessage = EditorGUIUtility.TrTextContentWithIcon("Global Volumes do not need a collider. Disable or remove the collider.", CoreEditorStyles.iconWarn);
public static readonly GUIContent enableColliderFixMessage = EditorGUIUtility.TrTextContentWithIcon("Local Volumes need a collider enabled. Enable the collider.", CoreEditorStyles.iconWarn);
public static readonly GUIContent profileInstance = EditorGUIUtility.TrTextContent("Profile (Instance)", "A Volume Profile is a Scriptable Object which contains properties that Volumes use to determine how to render the Scene environment for Cameras they affect.");
public static readonly GUIContent profile = EditorGUIUtility.TrTextContent("Profile", "A Volume Profile is a Scriptable Object which contains properties that Volumes use to determine how to render the Scene environment for Cameras they affect.");
public static readonly GUIContent newLabel = EditorGUIUtility.TrTextContent("New", "Create a new profile.");
public static readonly GUIContent saveLabel = EditorGUIUtility.TrTextContent("Save", "Save the instantiated profile");
public static readonly GUIContent cloneLabel = EditorGUIUtility.TrTextContent("Clone", "Create a new profile and copy the content of the currently assigned profile.");
public static readonly string noVolumeMessage = L10n.Tr("Please select or create a new Volume profile to begin applying effects to the scene.");
}
SerializedProperty m_IsGlobal;
SerializedProperty m_BlendRadius;
SerializedProperty m_Weight;
SerializedProperty m_Priority;
SerializedProperty m_Profile;
VolumeComponentListEditor m_ComponentList;
Volume actualTarget => target as Volume;
VolumeProfile profileRef => actualTarget.HasInstantiatedProfile() ? actualTarget.profile : actualTarget.sharedProfile;
void OnEnable()
{
var o = new PropertyFetcher<Volume>(serializedObject);
m_IsGlobal = o.Find(x => x.isGlobal);
m_BlendRadius = o.Find(x => x.blendDistance);
m_Weight = o.Find(x => x.weight);
m_Priority = o.Find(x => x.priority);
m_Profile = o.Find(x => x.sharedProfile);
m_ComponentList = new VolumeComponentListEditor(this);
RefreshEffectListEditor(actualTarget.sharedProfile);
}
void OnDisable()
{
m_ComponentList?.Clear();
}
void RefreshEffectListEditor(VolumeProfile asset)
{
m_ComponentList.Clear();
if (asset != null)
{
asset.Sanitize();
m_ComponentList.Init(asset, new SerializedObject(asset));
}
}
private void AddOverride()
{
var menu = new GenericMenu();
menu.AddItem(Styles.addBoxCollider, false, () => Undo.AddComponent<BoxCollider>(actualTarget.gameObject));
menu.AddItem(Styles.sphereBoxCollider, false, () => Undo.AddComponent<SphereCollider>(actualTarget.gameObject));
menu.AddItem(Styles.capsuleBoxCollider, false, () => Undo.AddComponent<CapsuleCollider>(actualTarget.gameObject));
menu.AddItem(Styles.meshBoxCollider, false, () => Undo.AddComponent<MeshCollider>(actualTarget.gameObject));
menu.ShowAsContext();
}
[MenuItem("CONTEXT/Volume/Remove All Overrides")]
private static void RemoveAllOverrides(MenuCommand command)
{
if (command.context is Volume volumeComponent)
{
volumeComponent.profile.components.Clear();
}
}
private static void SetVolumeOverridesActiveState(List<VolumeComponent> components, bool activeState)
{
foreach (var v in components)
{
v.active = activeState;
}
}
[MenuItem("CONTEXT/Volume/Disable All Overrides")]
private static void DisableAllOverrides(MenuCommand command)
{
if (command.context is Volume volumeComponent)
SetVolumeOverridesActiveState(volumeComponent.profile.components, false);
}
[MenuItem("CONTEXT/Volume/Enable All Overrides")]
private static void EnableAllOverrides(MenuCommand command)
{
if (command.context is Volume volumeComponent)
SetVolumeOverridesActiveState(volumeComponent.profile.components, true);
}
public override void OnInspectorGUI()
{
serializedObject.Update();
Rect lineRect = EditorGUILayout.GetControlRect();
int isGlobal = m_IsGlobal.boolValue ? 0 : 1;
using (new EditorGUI.PropertyScope(lineRect, Styles.mode, m_IsGlobal))
{
EditorGUI.BeginChangeCheck();
isGlobal = EditorGUI.Popup(lineRect, Styles.mode, isGlobal, Styles.modes);
if (EditorGUI.EndChangeCheck())
m_IsGlobal.boolValue = isGlobal == 0;
}
if (isGlobal != 0) // Blend radius is not needed for global volumes
{
if (actualTarget.TryGetComponent<Collider>(out var collider))
{
if (!collider.enabled)
CoreEditorUtils.DrawFixMeBox(Styles.enableColliderFixMessage, () => collider.enabled = true);
}
else
{
CoreEditorUtils.DrawFixMeBox(Styles.addColliderFixMessage, AddOverride);
}
EditorGUILayout.PropertyField(m_BlendRadius);
m_BlendRadius.floatValue = Mathf.Max(m_BlendRadius.floatValue, 0f);
}
else
{
if (actualTarget.TryGetComponent<Collider>(out var collider))
{
if (collider.enabled)
CoreEditorUtils.DrawFixMeBox(Styles.disableColliderFixMessage, () => collider.enabled = false);
}
}
EditorGUILayout.PropertyField(m_Weight);
bool priorityHasChanged = false;
using (var scope = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(m_Priority);
priorityHasChanged = scope.changed;
}
bool assetHasChanged = false;
bool showCopy = m_Profile.objectReferenceValue != null;
bool multiEdit = m_Profile.hasMultipleDifferentValues;
// The layout system breaks alignment when mixing inspector fields with custom layout'd
// fields, do the layout manually instead
int buttonWidth = showCopy ? 45 : 60;
float indentOffset = EditorGUI.indentLevel * 15f;
lineRect = EditorGUILayout.GetControlRect();
var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset - 3, lineRect.height);
var fieldRect = new Rect(labelRect.xMax + 5, lineRect.y, lineRect.width - labelRect.width - buttonWidth * (showCopy ? 2 : 1) - 5, lineRect.height);
var buttonNewRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height);
var buttonCopyRect = new Rect(buttonNewRect.xMax, lineRect.y, buttonWidth, lineRect.height);
using (var scope = new EditorGUI.ChangeCheckScope())
{
var isProfileInstance = actualTarget.HasInstantiatedProfile();
VolumeProfile editedProfile;
if (isProfileInstance)
{
var prevMixedValueState = EditorGUI.showMixedValue;
EditorGUI.showMixedValue = m_Profile.hasMultipleDifferentValues;
EditorGUI.PrefixLabel(labelRect, Styles.profileInstance);
editedProfile = (VolumeProfile)EditorGUI.ObjectField(fieldRect, actualTarget.profile, typeof(VolumeProfile), false);
EditorGUI.showMixedValue = prevMixedValueState;
}
else
{
fieldRect = new Rect(labelRect.x, labelRect.y, labelRect.width + fieldRect.width, fieldRect.height);
EditorGUI.ObjectField(fieldRect, m_Profile, Styles.profile);
editedProfile = (VolumeProfile)m_Profile.objectReferenceValue;
}
if (scope.changed)
{
assetHasChanged = true;
if (isProfileInstance)
// Clear the instantiated profile, from now on we're using shared again
actualTarget.profile = null;
else
m_Profile.objectReferenceValue = editedProfile;
}
}
using (new EditorGUI.DisabledScope(multiEdit))
{
if (GUI.Button(buttonNewRect, Styles.newLabel, showCopy ? EditorStyles.miniButtonLeft : EditorStyles.miniButton))
{
// By default, try to put assets in a folder next to the currently active
// scene file. If the user isn't a scene, put them in root instead.
var targetName = actualTarget.name + " Profile";
var scene = actualTarget.gameObject.scene;
var asset = VolumeProfileFactory.CreateVolumeProfile(scene, targetName);
m_Profile.objectReferenceValue = asset;
actualTarget.profile = null; // Make sure we're not using an instantiated profile anymore
assetHasChanged = true;
}
GUIContent guiContent = actualTarget.HasInstantiatedProfile() ? Styles.saveLabel : Styles.cloneLabel;
if (showCopy && GUI.Button(buttonCopyRect, guiContent, EditorStyles.miniButtonRight))
{
// Duplicate the currently assigned profile and save it as a new profile
var origin = profileRef;
var path = AssetDatabase.GetAssetPath(m_Profile.objectReferenceValue);
path = CoreEditorUtils.IsAssetInReadOnlyPackage(path)
// We may be in a read only package, in that case we need to clone the volume profile in an
// editable area, such as the root of the project.
? AssetDatabase.GenerateUniqueAssetPath(Path.Combine("Assets", Path.GetFileName(path)))
// Otherwise, duplicate next to original asset.
: AssetDatabase.GenerateUniqueAssetPath(path);
var asset = Instantiate(origin);
asset.components.Clear();
AssetDatabase.CreateAsset(asset, path);
foreach (var item in origin.components)
{
var itemCopy = Instantiate(item);
itemCopy.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
itemCopy.name = item.name;
asset.components.Add(itemCopy);
AssetDatabase.AddObjectToAsset(itemCopy, asset);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
m_Profile.objectReferenceValue = asset;
actualTarget.profile = null; // Make sure we're not using an instantiated profile anymore
assetHasChanged = true;
}
}
EditorGUILayout.Space();
if (m_Profile.objectReferenceValue == null && !actualTarget.HasInstantiatedProfile())
{
if (assetHasChanged)
m_ComponentList.Clear(); // Asset wasn't null before, do some cleanup
}
else
{
if (assetHasChanged || profileRef != m_ComponentList.asset)
{
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
RefreshEffectListEditor(profileRef);
}
if (!multiEdit)
{
m_ComponentList.OnGUI();
EditorGUILayout.Space();
}
}
if (actualTarget.sharedProfile == null && m_Profile.objectReferenceValue != null)
{
if (Event.current.type != EventType.Layout)
{
actualTarget.sharedProfile = (VolumeProfile)m_Profile.objectReferenceValue;
if (actualTarget.HasInstantiatedProfile())
actualTarget.profile = null;
RefreshEffectListEditor(actualTarget.sharedProfile);
}
}
serializedObject.ApplyModifiedProperties();
if (assetHasChanged)
VolumeProfileUsageAnalytic.Send(actualTarget, (VolumeProfile)m_Profile.objectReferenceValue);
if (priorityHasChanged)
VolumePriorityUsageAnalytic.Send(actualTarget);
if (m_Profile.objectReferenceValue == null)
EditorGUILayout.HelpBox(Styles.noVolumeMessage, MessageType.Info);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a033a261241d6e48af8ca011ab7c5c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class VolumeGizmoDrawer
{
#region GizmoCallbacks
static readonly Dictionary<Type, IVolumeAdditionalGizmo> s_AdditionalGizmoCallbacks = new();
[InitializeOnLoadMethod]
static void InitVolumeGizmoCallbacks()
{
foreach (var additionalGizmoCallback in TypeCache.GetTypesDerivedFrom<IVolumeAdditionalGizmo>())
{
if (additionalGizmoCallback.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) == null)
continue;
var instance = Activator.CreateInstance(additionalGizmoCallback) as IVolumeAdditionalGizmo;
s_AdditionalGizmoCallbacks.Add(instance.type, instance);
}
}
#endregion
[DrawGizmo(GizmoType.Active | GizmoType.Selected | GizmoType.NonSelected)]
static void OnDrawGizmos(IVolume scr, GizmoType gizmoType)
{
if (scr is not MonoBehaviour monoBehaviour)
return;
if (!monoBehaviour.enabled)
return;
if (scr.isGlobal || scr.colliders == null)
return;
// Store the computation of the lossyScale
var lossyScale = monoBehaviour.transform.lossyScale;
Gizmos.matrix = Matrix4x4.TRS(monoBehaviour.transform.position, monoBehaviour.transform.rotation, lossyScale);
Gizmos.color = VolumesPreferences.volumeGizmoColor;
s_AdditionalGizmoCallbacks.TryGetValue(scr.GetType(), out var callback);
// Draw a separate gizmo for each collider
foreach (var collider in scr.colliders)
{
if (!collider || !collider.enabled)
continue;
// We'll just use scaling as an approximation for volume skin. It's far from being
// correct (and is completely wrong in some cases). Ultimately we'd use a distance
// field or at least a tesselate + push modifier on the collider's mesh to get a
// better approximation, but the current Gizmo system is a bit limited and because
// everything is dynamic in Unity and can be changed at anytime, it's hard to keep
// track of changes in an elegant way (which we'd need to implement a nice cache
// system for generated volume meshes).
switch (collider)
{
case BoxCollider c:
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireCube(c.center, c.size);
if (VolumesPreferences.drawSolid)
Gizmos.DrawCube(c.center, c.size);
callback?.OnBoxColliderDraw(scr, c);
break;
case SphereCollider c:
Matrix4x4 oldMatrix = Gizmos.matrix;
// For sphere the only scale that is used is the transform.x
Gizmos.matrix = Matrix4x4.TRS(monoBehaviour.transform.position, monoBehaviour.transform.rotation, Vector3.one * lossyScale.x);
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireSphere(c.center, c.radius);
if (VolumesPreferences.drawSolid)
Gizmos.DrawSphere(c.center, c.radius);
callback?.OnSphereColliderDraw(scr, c);
Gizmos.matrix = oldMatrix;
break;
case MeshCollider c:
// Only convex mesh m_Colliders are allowed
if (!c.convex)
c.convex = true;
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireMesh(c.sharedMesh);
if (VolumesPreferences.drawSolid)
// Mesh pivot should be centered or this won't work
Gizmos.DrawMesh(c.sharedMesh);
callback?.OnMeshColliderDraw(scr, c);
break;
default:
// Nothing for capsule (DrawCapsule isn't exposed in Gizmo), terrain, wheel and
// other m_Colliders...
break;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0cd3688d1b5f3194780d5edc0da54e7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
static class VolumeMenuItems
{
[MenuItem("GameObject/Volume/Global Volume", priority = CoreUtils.Priorities.gameObjectMenuPriority)]
static void CreateGlobalVolume(MenuCommand menuCommand)
{
var go = CoreEditorUtils.CreateGameObject("Global Volume", menuCommand.context);
var volume = go.AddComponent<Volume>();
volume.isGlobal = true;
}
[MenuItem("GameObject/Volume/Box Volume", priority = CoreUtils.Sections.section1 + CoreUtils.Priorities.gameObjectMenuPriority)]
static void CreateBoxVolume(MenuCommand menuCommand)
{
var go = CoreEditorUtils.CreateGameObject("Box Volume", menuCommand.context);
var collider = go.AddComponent<BoxCollider>();
collider.isTrigger = true;
var volume = go.AddComponent<Volume>();
volume.isGlobal = false;
volume.blendDistance = 1f;
}
[MenuItem("GameObject/Volume/Sphere Volume", priority = CoreUtils.Sections.section1 + CoreUtils.Priorities.gameObjectMenuPriority + 1)]
static void CreateSphereVolume(MenuCommand menuCommand)
{
var go = CoreEditorUtils.CreateGameObject("Sphere Volume", menuCommand.context);
var collider = go.AddComponent<SphereCollider>();
collider.isTrigger = true;
var volume = go.AddComponent<Volume>();
volume.isGlobal = false;
volume.blendDistance = 1f;
}
[MenuItem("GameObject/Volume/Convex Mesh Volume", priority = CoreUtils.Sections.section1 + CoreUtils.Priorities.gameObjectMenuPriority + 2)]
static void CreateConvexMeshVolume(MenuCommand menuCommand)
{
var go = CoreEditorUtils.CreateGameObject("Convex Mesh Volume", menuCommand.context);
var collider = go.AddComponent<MeshCollider>();
collider.convex = true;
collider.isTrigger = true;
var volume = go.AddComponent<Volume>();
volume.isGlobal = false;
volume.blendDistance = 1f;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: acfc3acab7bb76944b99725933c0ad45
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
/// <summary>
/// This attributes tells an <see cref="VolumeParameterDrawer"/> class which type of
/// <see cref="VolumeParameter"/> it's an editor for.
/// When you make a custom drawer for a parameter, you need add this attribute to the drawer
/// class.
/// </summary>
/// <seealso cref="VolumeParameterDrawer"/>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class VolumeParameterDrawerAttribute : Attribute
{
/// <summary>
/// A type derived from <see cref="VolumeParameter{T}"/>.
/// </summary>
public readonly Type parameterType;
/// <summary>
/// Creates a new <see cref="VolumeParameterDrawerAttribute"/> instance.
/// </summary>
/// <param name="parameterType">A type derived from <see cref="VolumeParameter{T}"/>.</param>
public VolumeParameterDrawerAttribute(Type parameterType)
{
this.parameterType = parameterType;
}
}
/// <summary>
/// A base class to implement to draw custom editors for custom <see cref="VolumeParameter"/>.
/// You must use a <see cref="VolumeParameterDrawerAttribute"/> to let the editor know which
/// parameter this drawer is for.
/// </summary>
/// <remarks>
/// If you do not provide a custom editor for a <see cref="VolumeParameter"/>, Unity uses the buil-in property drawers to draw the
/// property as-is.
/// </remarks>
/// <example>
/// Here's an example about how <see cref="ClampedFloatParameter"/> is implemented:
/// <code>
/// [VolumeParameterDrawer(typeof(ClampedFloatParameter))]
/// class ClampedFloatParameterDrawer : VolumeParameterDrawer
/// {
/// public override bool OnGUI(SerializedDataParameter parameter, GUIContent title)
/// {
/// var value = parameter.value;
///
/// if (value.propertyType != SerializedPropertyType.Float)
/// return false;
///
/// var o = parameter.GetObjectRef&lt;ClampedFloatParameter&gt;();
/// EditorGUILayout.Slider(value, o.min, o.max, title);
/// value.floatValue = Mathf.Clamp(value.floatValue, o.min, o.max);
/// return true;
/// }
/// }
/// </code>
/// </example>
/// <seealso cref="VolumeParameterDrawerAttribute"/>
public abstract class VolumeParameterDrawer
{
// Override this and return false if you want to customize the override checkbox position,
// else it'll automatically draw it and put the property content in a horizontal scope.
/// <summary>
/// Override this and return <c>false</c> if you want to customize the position of the override
/// checkbox. If you don't, Unity automatically draws the checkbox and puts the property content in a
/// horizontal scope.
/// </summary>
/// <returns><c>false</c> if the override checkbox position is customized, <c>true</c>
/// otherwise</returns>
public virtual bool IsAutoProperty() => true;
/// <summary>
/// Draws the parameter in the editor. If the input parameter is invalid you should return
/// <c>false</c> so that Unity displays the default editor for this parameter.
/// </summary>
/// <param name="parameter">The parameter to draw.</param>
/// <param name="title">The label and tooltip of the parameter.</param>
/// <returns><c>true</c> if the input parameter is valid, <c>false</c> otherwise in which
/// case Unity will revert to the default editor for this parameter</returns>
public abstract bool OnGUI(SerializedDataParameter parameter, GUIContent title);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8ce10b4215bd81438b65f7e23ac0946
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
[CustomEditor(typeof(VolumeProfile))]
sealed class VolumeProfileEditor : Editor
{
VolumeComponentListEditor m_ComponentList;
void OnEnable()
{
m_ComponentList = new VolumeComponentListEditor(this);
m_ComponentList.Init(target as VolumeProfile, serializedObject);
}
void OnDisable()
{
if (m_ComponentList != null)
m_ComponentList.Clear();
}
public override void OnInspectorGUI()
{
serializedObject.Update();
m_ComponentList.OnGUI();
EditorGUILayout.Space();
if (m_ComponentList.hasHiddenVolumeComponents)
EditorGUILayout.HelpBox("There are Volume Components that are hidden in this asset because they are incompatible with the current active Render Pipeline. Change the active Render Pipeline to see them.", MessageType.Info);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77e4433a29bc5b547a429fcd8552c691
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using UnityEngine;
using UnityEditor.ProjectWindowCallback;
using System.IO;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
namespace UnityEditor.Rendering
{
/// <summary>
/// A utility class to create Volume Profiles and components.
/// </summary>
public static class VolumeProfileFactory
{
[MenuItem("Assets/Create/Volume Profile", priority = 201)]
static void CreateVolumeProfile()
{
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(
0,
ScriptableObject.CreateInstance<DoCreatePostProcessProfile>(),
"New Volume Profile.asset",
null,
null
);
}
/// <summary>
/// Creates a <see cref="VolumeProfile"/> Asset and saves it at the given path.
/// </summary>
/// <param name="path">The path to save the Asset to, relative to the Project folder.</param>
/// <returns>The newly created <see cref="VolumeProfile"/>.</returns>
public static VolumeProfile CreateVolumeProfileAtPath(string path)
{
var profile = ScriptableObject.CreateInstance<VolumeProfile>();
profile.name = Path.GetFileName(path);
AssetDatabase.CreateAsset(profile, path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return profile;
}
/// <summary>
/// Creates a <see cref="VolumeProfile"/> Asset and saves it in a folder next to the Scene.
/// </summary>
/// <param name="scene">The Scene to save the Profile next to.</param>
/// <param name="targetName">A name to use for the Asset filename.</param>
/// <returns>The newly created <see cref="VolumeProfile"/>.</returns>
public static VolumeProfile CreateVolumeProfile(Scene scene, string targetName)
{
return CoreEditorUtils.CreateAssetAt<VolumeProfile>(scene, targetName);
}
/// <summary>
/// Creates a <see cref="VolumeComponent"/> in an existing <see cref="VolumeProfile"/>.
/// </summary>
/// <typeparam name="T">A type of <see cref="VolumeComponent"/>.</typeparam>
/// <param name="profile">The profile to store the new component in.</param>
/// <param name="overrides">specifies whether to override the parameters in the component or not.</param>
/// <param name="saveAsset">Specifies whether to save the Profile Asset or not. This is useful when you need to
/// create several components in a row and only want to save the Profile Asset after adding the last one,
/// because saving Assets to disk can be slow.</param>
/// <returns></returns>
public static T CreateVolumeComponent<T>(VolumeProfile profile, bool overrides = false, bool saveAsset = true)
where T : VolumeComponent
{
var comp = profile.Add<T>(overrides);
comp.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
AssetDatabase.AddObjectToAsset(comp, profile);
if (saveAsset)
{
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
return comp;
}
}
class DoCreatePostProcessProfile : EndNameEditAction
{
public override void Action(int instanceId, string pathName, string resourceFile)
{
var profile = VolumeProfileFactory.CreateVolumeProfileAtPath(pathName);
ProjectWindowUtil.ShowCreatedAsset(profile);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: da75d0a7610da4245824752899c20db4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using RuntimeSRPPreferences = UnityEngine.Rendering.CoreRenderPipelinePreferences;
namespace UnityEditor.Rendering
{
/// <summary>
/// Preferences for Volumes
/// </summary>
public class VolumesPreferences : ICoreRenderPipelinePreferencesProvider
{
static class Keys
{
internal const string volumeGizmosVisibility = "General.VolumeGizmosVisibility";
}
/// <summary>
/// Specifies how the gizmos for volumes are being drawn
/// </summary>
[Flags]
public enum VolumeGizmoVisibility
{
/// <summary> Wireframe </summary>
Wireframe = 1,
/// <summary> Solid </summary>
Solid = 2,
/// <summary> Solid with Wireframe </summary>
Everything = Wireframe | Solid
}
class Styles
{
public static readonly GUIContent volumeGizmosVisibilityLabel = EditorGUIUtility.TrTextContent("Gizmo Visibility", "Specifies how Gizmos for Volumes are being rendered");
}
static VolumeGizmoVisibility s_VolumeGizmosVisibilityOption = VolumeGizmoVisibility.Solid;
static VolumesPreferences()
{
GetColorPrefVolumeGizmoColor = RuntimeSRPPreferences.RegisterPreferenceColor("Scene/Volume Gizmo", s_VolumeGizmoColorDefault);
if (EditorPrefs.HasKey(Keys.volumeGizmosVisibility))
s_VolumeGizmosVisibilityOption = (VolumeGizmoVisibility)EditorPrefs.GetInt(Keys.volumeGizmosVisibility);
}
/// <summary>
/// Returns the current <see cref="VolumeGizmoVisibility"/>
/// </summary>
public static VolumeGizmoVisibility volumeGizmosVisibilityOption
{
get => s_VolumeGizmosVisibilityOption;
set
{
s_VolumeGizmosVisibilityOption = value;
EditorPrefs.SetInt(Keys.volumeGizmosVisibility, (int)s_VolumeGizmosVisibilityOption);
}
}
/// <summary>
/// Returns if the Volume Gizmos should render the wireframe edges
/// </summary>
public static bool drawWireFrame => (volumeGizmosVisibilityOption & VolumeGizmoVisibility.Wireframe) == VolumeGizmoVisibility.Wireframe;
/// <summary>
/// Returns if the Volume Gizmos should render the solid faces
/// </summary>
public static bool drawSolid => (volumeGizmosVisibilityOption & VolumeGizmoVisibility.Solid) == VolumeGizmoVisibility.Solid;
static Color s_VolumeGizmoColorDefault = new Color(0.2f, 0.8f, 0.1f, 0.125f);
private static Func<Color> GetColorPrefVolumeGizmoColor;
/// <summary>
/// Returns the user defined color for rendering volume gizmos
/// </summary>
public static Color volumeGizmoColor => GetColorPrefVolumeGizmoColor();
static List<string> s_SearchKeywords = new() { "Gizmo", "Wireframe", "Visibility" };
/// <summary>
/// The list of keywords for user search
/// </summary>
public List<string> keywords => s_SearchKeywords;
/// <summary>
/// The header of the panel
/// </summary>
public GUIContent header { get; } = EditorGUIUtility.TrTextContent("Volumes");
/// <summary>
/// Renders the Preferences UI for this provider
/// </summary>
public void PreferenceGUI()
{
EditorGUI.BeginChangeCheck();
var newValue = EditorGUILayout.EnumPopup(Styles.volumeGizmosVisibilityLabel, volumeGizmosVisibilityOption);
if (EditorGUI.EndChangeCheck())
{
volumeGizmosVisibilityOption = (VolumeGizmoVisibility)newValue;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 27f2759742fe50d4fa55a384fd18e06b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: