Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,16 @@
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEditor.Rendering.Universal
{
internal static class CreateDecalProjector
{
[MenuItem("GameObject/Rendering/URP Decal Projector", priority = CoreUtils.Priorities.gameObjectMenuPriority)]
public static void CreateDecal(MenuCommand menuCommand)
{
var go = CoreEditorUtils.CreateGameObject("Decal Projector", menuCommand.context);
go.AddComponent<DecalProjector>();
go.transform.RotateAround(go.transform.position, go.transform.right, 90);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b18b0fc0f8fa024bad93dc11774b8f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
using System;
using UnityEditor.ShaderGraph;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Universal.ShaderGraph
{
internal static class CreateDecalShaderGraph
{
[MenuItem("Assets/Create/Shader Graph/URP/Decal Shader Graph", priority = CoreUtils.Sections.section4 + CoreUtils.Priorities.assetsCreateShaderMenuPriority + 1)]
public static void CreateLitGraph()
{
var target = (UniversalTarget)Activator.CreateInstance(typeof(UniversalTarget));
target.TrySetActiveSubTarget(typeof(UniversalDecalSubTarget));
var blockDescriptors = new[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.NormalTS,
UniversalBlockFields.SurfaceDescription.NormalAlpha,
BlockFields.SurfaceDescription.Metallic,
BlockFields.SurfaceDescription.Occlusion,
BlockFields.SurfaceDescription.Smoothness,
UniversalBlockFields.SurfaceDescription.MAOSAlpha,
};
GraphUtil.CreateNewGraphWithOutputs(new[] { target }, blockDescriptors);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7db8784515f96cf459209aeab8ad7ce3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,212 @@
Pass
{
$splice(PassName)
Tags
{
$splice(LightMode)
}
// Render State
$splice(RenderState)
// Debug
$splice(Debug)
// --------------------------------------------------
// Pass
HLSLPROGRAM
// Pragmas
$splice(PassPragmas)
// Keywords
$splice(PassKeywords)
$splice(GraphKeywords)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// Defines
$Attributes.normalOS: #define ATTRIBUTES_NEED_NORMAL
$Attributes.tangentOS: #define ATTRIBUTES_NEED_TANGENT
$Attributes.uv0: #define ATTRIBUTES_NEED_TEXCOORD0
$Attributes.uv1: #define ATTRIBUTES_NEED_TEXCOORD1
$Attributes.uv2: #define ATTRIBUTES_NEED_TEXCOORD2
$Attributes.uv3: #define ATTRIBUTES_NEED_TEXCOORD3
$Attributes.uv4: #define ATTRIBUTES_NEED_TEXCOORD4
$Attributes.uv5: #define ATTRIBUTES_NEED_TEXCOORD5
$Attributes.uv6: #define ATTRIBUTES_NEED_TEXCOORD6
$Attributes.uv7: #define ATTRIBUTES_NEED_TEXCOORD7
$Attributes.color: #define ATTRIBUTES_NEED_COLOR
$Varyings.positionWS: #define VARYINGS_NEED_POSITION_WS
$Varyings.normalWS: #define VARYINGS_NEED_NORMAL_WS
$Varyings.viewDirectionWS: #define VARYINGS_NEED_VIEWDIRECTION_WS
$Varyings.tangentWS: #define VARYINGS_NEED_TANGENT_WS
$Varyings.texCoord0: #define VARYINGS_NEED_TEXCOORD0
$Varyings.texCoord1: #define VARYINGS_NEED_TEXCOORD1
$Varyings.texCoord2: #define VARYINGS_NEED_TEXCOORD2
$Varyings.texCoord3: #define VARYINGS_NEED_TEXCOORD3
$Varyings.texCoord4: #define VARYINGS_NEED_TEXCOORD4
$Varyings.texCoord5: #define VARYINGS_NEED_TEXCOORD5
$Varyings.texCoord6: #define VARYINGS_NEED_TEXCOORD6
$Varyings.texCoord7: #define VARYINGS_NEED_TEXCOORD7
$Varyings.color: #define VARYINGS_NEED_COLOR
$Varyings.fogFactorAndVertexLight: #define VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
$Varyings.sh: #define VARYINGS_NEED_SH
$Varyings.staticLightmapUV: #define VARYINGS_NEED_STATIC_LIGHTMAP_UV
$Varyings.dynamicLightmapUV: #define VARYINGS_NEED_DYNAMIC_LIGHTMAP_UV
$Varyings.shadowCoord: #define VARYINGS_NEED_SHADOW_COORD
$features.graphVertex: #define HAVE_MESH_MODIFICATION
$SurfaceDescriptionInputs.FaceSign: // Define when IsFontFaceNode is included in ShaderGraph
$SurfaceDescriptionInputs.FaceSign: #define VARYINGS_NEED_CULLFACE
$splice(GraphDefines)
// Includes
$splice(PreGraphIncludes)
// -- Properties used by ScenePickingPass
#ifdef SCENEPICKINGPASS
float4 _SelectionID;
#endif
#if _RENDER_PASS_ENABLED
#define GBUFFER3 0
FRAMEBUFFER_INPUT_X_FLOAT(GBUFFER3);
#define GBUFFER4 1
FRAMEBUFFER_INPUT_X_UINT(GBUFFER4);
#endif
// --------------------------------------------------
// Structs and Packing
$splice(PassStructs)
$splice(InterpolatorPack)
// --------------------------------------------------
// Graph
// Graph Properties
$splice(GraphProperties)
// Graph Includes
$splice(GraphIncludes)
// Graph Functions
$splice(GraphFunctions)
// Graph Vertex
$splice(GraphVertex)
// Graph Pixel
$splice(GraphPixel)
// --------------------------------------------------
// Build Graph Inputs
$features.graphVertex: $include("VertexAnimation.template.hlsl")
$features.graphPixel: $include("SharedCode.template.hlsl")
$features.graphPixel: $include("BuildSurfaceDescriptionInputs.template.hlsl")
// --------------------------------------------------
// Build Surface Data
// With XYZ normal map encoding we sporadically sample normals with near-zero length that would result in NaN (see NormalizeNormalPerPixel).
half3 DecalSafeNormalize(half3 n, half3 fallback)
{
#if defined(UNITY_NO_DXT5nm)
half lenSq = dot(n, n);
return lenSq > HALF_MIN ? n * rsqrt(lenSq) : fallback;
#else
return normalize(n);
#endif
}
void GetSurfaceData(Varyings input, float4 positionCS, float angleFadeFactor, out DecalSurfaceData surfaceData)
{
#if (SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_FORWARD_EMISSIVE_PROJECTOR) || (SHADERPASS == SHADERPASS_DECAL_SCREEN_SPACE_PROJECTOR) || (SHADERPASS == SHADERPASS_DECAL_GBUFFER_PROJECTOR)
half4x4 normalToWorld = UNITY_ACCESS_INSTANCED_PROP(Decal, _NormalToWorld);
half fadeFactor = clamp(normalToWorld[0][3], 0.0f, 1.0f) * angleFadeFactor;
float2 scale = float2(normalToWorld[3][0], normalToWorld[3][1]);
float2 offset = float2(normalToWorld[3][2], normalToWorld[3][3]);
$Varyings.texCoord0: input.texCoord0.xy = input.texCoord0.xy * scale + offset;
$Varyings.texCoord1: input.texCoord1.xy = input.texCoord1.xy * scale + offset;
$Varyings.texCoord2: input.texCoord2.xy = input.texCoord2.xy * scale + offset;
$Varyings.texCoord3: input.texCoord3.xy = input.texCoord3.xy * scale + offset;
$Varyings.texCoord4: input.texCoord4.xy = input.texCoord4.xy * scale + offset;
$Varyings.texCoord5: input.texCoord5.xy = input.texCoord5.xy * scale + offset;
$Varyings.texCoord6: input.texCoord6.xy = input.texCoord6.xy * scale + offset;
$Varyings.texCoord7: input.texCoord7.xy = input.texCoord7.xy * scale + offset;
half3 normalWS = TransformObjectToWorldDir(half3(0, 1, 0));
half3 tangentWS = TransformObjectToWorldDir(half3(1, 0, 0));
half3 bitangentWS = TransformObjectToWorldDir(half3(0, 0, 1));
half sign = dot(cross(normalWS, tangentWS), bitangentWS) > 0 ? 1 : -1;
$Varyings.normalWS: input.normalWS.xyz = normalWS;
$Varyings.tangentWS: input.tangentWS.xyzw = half4(tangentWS, sign);
#else
#if defined(LOD_FADE_CROSSFADE) && USE_UNITY_CROSSFADE
LODFadeCrossFade(positionCS);
#endif
half fadeFactor = half(1.0);
#endif
SurfaceDescriptionInputs surfaceDescriptionInputs = BuildSurfaceDescriptionInputs(input);
SurfaceDescription surfaceDescription = SurfaceDescriptionFunction(surfaceDescriptionInputs);
// setup defaults -- these are used if the graph doesn't output a value
ZERO_INITIALIZE(DecalSurfaceData, surfaceData);
surfaceData.occlusion = half(1.0);
surfaceData.smoothness = half(0);
#ifdef _MATERIAL_AFFECTS_NORMAL
surfaceData.normalWS.w = half(1.0);
#else
surfaceData.normalWS.w = half(0.0);
#endif
$SurfaceDescription.Emission: surfaceData.emissive.rgb = half3(surfaceDescription.Emission.rgb * fadeFactor);
// copy across graph values, if defined
$SurfaceDescription.BaseColor: surfaceData.baseColor.xyz = half3(surfaceDescription.BaseColor);
$SurfaceDescription.Alpha: surfaceData.baseColor.w = half(surfaceDescription.Alpha * fadeFactor);
#if (SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_DECAL_SCREEN_SPACE_PROJECTOR) || (SHADERPASS == SHADERPASS_DECAL_GBUFFER_PROJECTOR)
#if defined(_MATERIAL_AFFECTS_NORMAL)
$SurfaceDescription.NormalTS: surfaceData.normalWS.xyz = DecalSafeNormalize(mul((half3x3)normalToWorld, surfaceDescription.NormalTS.xyz), normalize(normalToWorld[2].xyz));
#else
surfaceData.normalWS.xyz = normalize(normalToWorld[2].xyz);
#endif
#elif (SHADERPASS == SHADERPASS_DBUFFER_MESH) || (SHADERPASS == SHADERPASS_DECAL_SCREEN_SPACE_MESH) || (SHADERPASS == SHADERPASS_DECAL_GBUFFER_MESH)
#if defined(_MATERIAL_AFFECTS_NORMAL)
float sgn = input.tangentWS.w; // should be either +1 or -1
float3 bitangent = sgn * cross(input.normalWS.xyz, input.tangentWS.xyz);
half3x3 tangentToWorld = half3x3(input.tangentWS.xyz, bitangent.xyz, input.normalWS.xyz);
// We need to normalize as we use mikkt tangent space and this is expected (tangent space is not normalize)
$SurfaceDescription.NormalTS: surfaceData.normalWS.xyz = DecalSafeNormalize(TransformTangentToWorld(surfaceDescription.NormalTS, tangentToWorld), normalize(half3(input.normalWS)));
#else
surfaceData.normalWS.xyz = normalize(half3(input.normalWS)); // Default to vertex normal
#endif
#endif
$SurfaceDescription.NormalAlpha: surfaceData.normalWS.w = surfaceDescription.NormalAlpha * fadeFactor;
// In case of Smoothness / AO / Metal, all the three are always computed but color mask can change
$SurfaceDescription.Metallic: surfaceData.metallic = half(surfaceDescription.Metallic);
$SurfaceDescription.Occlusion: surfaceData.occlusion = half(surfaceDescription.Occlusion);
$SurfaceDescription.Smoothness: surfaceData.smoothness = half(surfaceDescription.Smoothness);
$SurfaceDescription.MAOSAlpha: surfaceData.MAOSAlpha = half(surfaceDescription.MAOSAlpha * fadeFactor);
}
// --------------------------------------------------
// Main
$splice(PostGraphIncludes)
ENDHLSL
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 39262bb9f1f65f040aefacd75fbd0e47
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,31 @@
using UnityEngine;
namespace UnityEditor.Rendering.Universal
{
partial class DecalProjectorEditor
{
const string k_EditShapePreservingUVTooltip = "Modifies the projector boundaries and crops/tiles the decal to fill them.";
const string k_EditShapeWithoutPreservingUVTooltip = "Modifies the projector boundaries and stretches the decal to fill them.";
const string k_EditUVTooltip = "Modify the UV and the pivot position without moving the projection box. It can alter Transform.";
static readonly GUIContent k_ScaleMode = EditorGUIUtility.TrTextContent("Scale Mode", "Specifies the scaling mode to apply to decals that use this Decal Projector.");
static readonly GUIContent k_WidthContent = EditorGUIUtility.TrTextContent("Width", "Sets the width of the projection plan.");
static readonly GUIContent k_HeightContent = EditorGUIUtility.TrTextContent("Height", "Sets the height of the projection plan.");
static readonly GUIContent k_ProjectionDepthContent = EditorGUIUtility.TrTextContent("Projection Depth", "Sets the projection depth of the projector.");
static readonly GUIContent k_MaterialContent = EditorGUIUtility.TrTextContent("Material", "Specifies the Material this component projects as a decal.");
static readonly GUIContent k_RenderingLayerMaskContent = EditorGUIUtility.TrTextContent("Rendering Layers", "Specify the rendering layer mask for this projector. Unity renders decals on all meshes where at least one Rendering Layer value matches.");
static readonly GUIContent k_DistanceContent = EditorGUIUtility.TrTextContent("Draw Distance", "Sets the distance from the Camera at which URP stop rendering the decal.");
static readonly GUIContent k_FadeScaleContent = EditorGUIUtility.TrTextContent("Start Fade", "Controls the distance from the Camera at which this component begins to fade the decal out.");
static readonly GUIContent k_AngleFadeContent = EditorGUIUtility.TrTextContent("Angle Fade", "Controls the fade out range of the decal based on the angle between the Decal backward direction and the vertex normal of the receiving surface. Requires 'Decal Layers' to be enabled in the URP Asset and Frame Settings.");
static readonly GUIContent k_UVScaleContent = EditorGUIUtility.TrTextContent("Tilling", "Sets the scale for the decal Material. Scales the decal along its UV axes.");
static readonly GUIContent k_UVBiasContent = EditorGUIUtility.TrTextContent("Offset", "Sets the offset for the decal Material. Moves the decal along its UV axes.");
static readonly GUIContent k_OpacityContent = EditorGUIUtility.TrTextContent("Opacity", "Controls the transparency of the decal.");
static readonly GUIContent k_Offset = EditorGUIUtility.TrTextContent("Pivot", "Controls the position of the pivot point of the decal.");
static readonly GUIContent k_NewMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new decal Material asset template.");
static readonly string k_BaseSceneEditingToolText = "<color=grey>Decal Scene Editing Mode:</color> ";
static readonly string k_EditShapeWithoutPreservingUVName = k_BaseSceneEditingToolText + "Scale";
static readonly string k_EditShapePreservingUVName = k_BaseSceneEditingToolText + "Crop";
static readonly string k_EditUVAndPivotName = k_BaseSceneEditingToolText + "Pivot / UV";
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c91e96badf0e2d4439afbed8e4befceb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,872 @@
using System;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using UnityEditor.ShaderGraph;
using UnityEditor.ShortcutManagement;
using UnityEditorInternal;
using UnityEditor.EditorTools;
using UnityEditor.Rendering.Utilities;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.RenderPipelines.Core;
using UnityEngine.Rendering.Universal;
using static UnityEditorInternal.EditMode;
namespace UnityEditor.Rendering.Universal
{
[CustomEditor(typeof(DecalProjector))]
[CanEditMultipleObjects]
partial class DecalProjectorEditor : Editor
{
const float k_Limit = 100000f;
const float k_LimitInv = 1f / k_Limit;
static readonly GUIContent k_NewDecalMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new Decal material.");
static readonly string k_NewDecalText = "URP Decal";
static readonly string k_NewSGDecalText = "ShaderGraph Decal";
static readonly string k_NewSGDecalFromTemplateText = "ShaderGraph Decal from Template";
static readonly string k_DefaultDecalShaderGraphTemplatePath = "Packages/com.unity.render-pipelines.universal/Shaders/Decal.shadergraph";
static Color fullColor
{
get
{
Color c = s_LastColor;
c.a = 1f;
return c;
}
}
static Color s_LastColor;
static void UpdateColorsInHandlesIfRequired()
{
Color c = DecalPreferences.decalGizmoColor;
if (c != s_LastColor)
{
if (s_BoxHandle != null && !s_BoxHandle.Equals(null))
s_BoxHandle = null;
if (s_uvHandles != null && !s_uvHandles.Equals(null))
s_uvHandles.baseColor = c;
s_LastColor = c;
}
}
MaterialEditor m_MaterialEditor = null;
SerializedProperty m_MaterialProperty;
SerializedProperty m_DrawDistanceProperty;
SerializedProperty m_FadeScaleProperty;
SerializedProperty m_StartAngleFadeProperty;
SerializedProperty m_EndAngleFadeProperty;
SerializedProperty m_UVScaleProperty;
SerializedProperty m_UVBiasProperty;
SerializedProperty m_ScaleMode;
SerializedProperty m_Size;
SerializedProperty[] m_SizeValues;
SerializedProperty m_Offset;
SerializedProperty[] m_OffsetValues;
SerializedProperty m_FadeFactor;
SerializedProperty m_RenderingLayerMask;
int layerMask => (target as Component).gameObject.layer;
bool layerMaskHasMultipleValues
{
get
{
if (targets.Length < 2)
return false;
int layerMask = (targets[0] as Component).gameObject.layer;
for (int index = 1; index < targets.Length; ++index)
{
if ((targets[index] as Component).gameObject.layer != layerMask)
return true;
}
return false;
}
}
static HierarchicalBox s_BoxHandle;
static HierarchicalBox boxHandle
{
get
{
if (s_BoxHandle == null || s_BoxHandle.Equals(null))
{
Color c = fullColor;
s_BoxHandle = new HierarchicalBox(s_LastColor, new[] { c, c, c, c, c, c });
s_BoxHandle.SetBaseColor(s_LastColor);
s_BoxHandle.monoHandle = false;
}
return s_BoxHandle;
}
}
static DisplacableRectHandles s_uvHandles;
static DisplacableRectHandles uvHandles
{
get
{
if (s_uvHandles == null || s_uvHandles.Equals(null))
s_uvHandles = new DisplacableRectHandles(s_LastColor);
return s_uvHandles;
}
}
static readonly BoxBoundsHandle s_AreaLightHandle =
new BoxBoundsHandle { axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y };
const SceneViewEditMode k_EditShapeWithoutPreservingUV = (SceneViewEditMode)90;
const SceneViewEditMode k_EditShapePreservingUV = (SceneViewEditMode)91;
const SceneViewEditMode k_EditUVAndPivot = (SceneViewEditMode)92;
static readonly SceneViewEditMode[] k_EditVolumeModes = new SceneViewEditMode[]
{
k_EditShapeWithoutPreservingUV,
k_EditShapePreservingUV,
k_EditUVAndPivot,
};
static Func<Vector3, Quaternion, Vector3> s_DrawPivotHandle;
static List<DecalProjectorEditor> s_Instances = new List<DecalProjectorEditor>();
static DecalProjectorEditor FindEditorFromSelection()
{
GameObject[] selection = Selection.gameObjects;
DecalProjector[] selectionTargets = Selection.GetFiltered<DecalProjector>(SelectionMode.Unfiltered);
foreach (DecalProjectorEditor editor in s_Instances)
{
if (selectionTargets.Length != editor.targets.Length)
continue;
bool allOk = true;
foreach (DecalProjector selectionTarget in selectionTargets)
{
if (!Array.Find(editor.targets, t => t == selectionTarget))
{
allOk = false;
break;
}
}
if (!allOk)
continue;
return editor;
}
return null;
}
private void OnEnable()
{
s_Instances.Add(this);
// Create an instance of the MaterialEditor
UpdateMaterialEditor();
// Fetch serialized properties
m_MaterialProperty = serializedObject.FindProperty("m_Material");
m_DrawDistanceProperty = serializedObject.FindProperty("m_DrawDistance");
m_FadeScaleProperty = serializedObject.FindProperty("m_FadeScale");
m_StartAngleFadeProperty = serializedObject.FindProperty("m_StartAngleFade");
m_EndAngleFadeProperty = serializedObject.FindProperty("m_EndAngleFade");
m_UVScaleProperty = serializedObject.FindProperty("m_UVScale");
m_UVBiasProperty = serializedObject.FindProperty("m_UVBias");
m_ScaleMode = serializedObject.FindProperty("m_ScaleMode");
m_Size = serializedObject.FindProperty("m_Size");
m_SizeValues = new[]
{
m_Size.FindPropertyRelative("x"),
m_Size.FindPropertyRelative("y"),
m_Size.FindPropertyRelative("z"),
};
m_Offset = serializedObject.FindProperty("m_Offset");
m_OffsetValues = new[]
{
m_Offset.FindPropertyRelative("x"),
m_Offset.FindPropertyRelative("y"),
m_Offset.FindPropertyRelative("z"),
};
m_FadeFactor = serializedObject.FindProperty("m_FadeFactor");
m_RenderingLayerMask = serializedObject.FindProperty("m_RenderingLayerMask");
ReinitSavedRatioSizePivotPosition();
}
private void OnDisable()
{
s_Instances.Remove(this);
}
private void OnDestroy() =>
DestroyImmediate(m_MaterialEditor);
public bool HasFrameBounds()
{
return true;
}
public Bounds OnGetFrameBounds()
{
DecalProjector decalProjector = target as DecalProjector;
return new Bounds(decalProjector.transform.position, boxHandle.size);
}
public void UpdateMaterialEditor()
{
int validMaterialsCount = 0;
for (int index = 0; index < targets.Length; ++index)
{
DecalProjector decalProjector = (targets[index] as DecalProjector);
if ((decalProjector != null) && (decalProjector.material != null))
validMaterialsCount++;
}
// Update material editor with the new material
UnityEngine.Object[] materials = new UnityEngine.Object[validMaterialsCount];
validMaterialsCount = 0;
for (int index = 0; index < targets.Length; ++index)
{
DecalProjector decalProjector = (targets[index] as DecalProjector);
if ((decalProjector != null) && (decalProjector.material != null))
materials[validMaterialsCount++] = (targets[index] as DecalProjector).material;
}
m_MaterialEditor = (MaterialEditor)CreateEditor(materials);
}
void OnSceneGUI()
{
//called on each targets
DrawHandles();
}
void DrawBoxTransformationHandles(DecalProjector decalProjector)
{
Vector3 scale = decalProjector.effectiveScale;
using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, scale)))
{
Vector3 centerStart = decalProjector.pivot;
boxHandle.center = centerStart;
boxHandle.size = decalProjector.size;
Vector3 boundsSizePreviousOS = boxHandle.size;
Vector3 boundsMinPreviousOS = boxHandle.size * -0.5f + boxHandle.center;
EditorGUI.BeginChangeCheck();
boxHandle.DrawHandle();
if (EditorGUI.EndChangeCheck())
{
// Adjust decal transform if handle changed.
Undo.RecordObject(decalProjector, "Decal Projector Change");
bool xChangeIsValid = scale.x != 0f;
bool yChangeIsValid = scale.y != 0f;
bool zChangeIsValid = scale.z != 0f;
// Preserve serialized state for axes with scale 0.
decalProjector.size = new Vector3(
xChangeIsValid ? boxHandle.size.x : decalProjector.size.x,
yChangeIsValid ? boxHandle.size.y : decalProjector.size.y,
zChangeIsValid ? boxHandle.size.z : decalProjector.size.z);
decalProjector.pivot = new Vector3(
xChangeIsValid ? boxHandle.center.x : decalProjector.pivot.x,
yChangeIsValid ? boxHandle.center.y : decalProjector.pivot.y,
zChangeIsValid ? boxHandle.center.z : decalProjector.pivot.z);
Vector3 boundsSizeCurrentOS = boxHandle.size;
Vector3 boundsMinCurrentOS = boxHandle.size * -0.5f + boxHandle.center;
if (editMode == k_EditShapePreservingUV)
{
// Treat decal projector bounds as a crop tool, rather than a scale tool.
// Compute a new uv scale and bias terms to pin decal projection pixels in world space, irrespective of projector bounds.
// Preserve serialized state for axes with scale 0.
Vector2 uvScale = decalProjector.uvScale;
Vector2 uvBias = decalProjector.uvBias;
if (xChangeIsValid)
{
uvScale.x *= Mathf.Max(k_LimitInv, boundsSizeCurrentOS.x) / Mathf.Max(k_LimitInv, boundsSizePreviousOS.x);
uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(k_LimitInv, boundsSizeCurrentOS.x) * uvScale.x;
}
if (yChangeIsValid)
{
uvScale.y *= Mathf.Max(k_LimitInv, boundsSizeCurrentOS.y) / Mathf.Max(k_LimitInv, boundsSizePreviousOS.y);
uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(k_LimitInv, boundsSizeCurrentOS.y) * uvScale.y;
}
decalProjector.uvScale = uvScale;
decalProjector.uvBias = uvBias;
}
if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector))
{
PrefabUtility.RecordPrefabInstancePropertyModifications(decalProjector);
}
}
}
}
void DrawPivotHandles(DecalProjector decalProjector)
{
Vector3 scale = decalProjector.effectiveScale;
Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale);
Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale);
using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(Vector3.zero, decalProjector.transform.rotation, Vector3.one)))
{
EditorGUI.BeginChangeCheck();
Vector3 newPosition = ProjectedTransform.DrawHandles(decalProjector.transform.position, .5f * scaledSize.z - scaledPivot.z, decalProjector.transform.rotation);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObjects(new UnityEngine.Object[] { decalProjector, decalProjector.transform }, "Decal Projector Change");
scaledPivot += Quaternion.Inverse(decalProjector.transform.rotation) * (decalProjector.transform.position - newPosition);
decalProjector.pivot = new Vector3(
scale.x != 0f ? scaledPivot.x / scale.x : decalProjector.pivot.x,
scale.y != 0f ? scaledPivot.y / scale.y : decalProjector.pivot.y,
scale.z != 0f ? scaledPivot.z / scale.z : decalProjector.pivot.z);
decalProjector.transform.position = newPosition;
ReinitSavedRatioSizePivotPosition();
}
}
}
void DrawUVHandles(DecalProjector decalProjector)
{
Vector3 scale = decalProjector.effectiveScale;
Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale);
Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale);
using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position + decalProjector.transform.rotation * (scaledPivot - .5f * scaledSize), decalProjector.transform.rotation, scale)))
{
Vector2 uvScale = decalProjector.uvScale;
Vector2 uvBias = decalProjector.uvBias;
Vector2 uvSize = new Vector2(
(uvScale.x > k_Limit || uvScale.x < -k_Limit) ? 0f : decalProjector.size.x / uvScale.x,
(uvScale.y > k_Limit || uvScale.y < -k_Limit) ? 0f : decalProjector.size.y / uvScale.y
);
Vector2 uvCenter = uvSize * .5f - new Vector2(uvBias.x * uvSize.x, uvBias.y * uvSize.y);
uvHandles.center = uvCenter;
uvHandles.size = uvSize;
EditorGUI.BeginChangeCheck();
uvHandles.DrawHandle();
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(decalProjector, "Decal Projector Change");
for (int channel = 0; channel < 2; channel++)
{
// Preserve serialized state for axes with the scaled size 0.
if (scaledSize[channel] != 0f)
{
float handleSize = uvHandles.size[channel];
float minusNewUVStart = .5f * handleSize - uvHandles.center[channel];
float decalSize = decalProjector.size[channel];
float limit = k_LimitInv * decalSize;
if (handleSize > limit || handleSize < -limit)
{
uvScale[channel] = decalSize / handleSize;
uvBias[channel] = minusNewUVStart / handleSize;
}
else
{
// TODO: Decide if uvHandles.size should ever have negative value. It can't currently.
uvScale[channel] = k_Limit * Mathf.Sign(handleSize);
uvBias[channel] = k_Limit * minusNewUVStart / decalSize;
}
}
}
decalProjector.uvScale = uvScale;
decalProjector.uvBias = uvBias;
}
}
}
void DrawHandles()
{
DecalProjector decalProjector = target as DecalProjector;
if (editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV)
DrawBoxTransformationHandles(decalProjector);
else if (editMode == k_EditUVAndPivot)
{
DrawPivotHandles(decalProjector);
DrawUVHandles(decalProjector);
}
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoType)
{
float lod = Gizmos.CalculateLOD(decalProjector.transform.position, decalProjector.size.magnitude * 0.25f);
// skip drawing anything if it will be too small or behind the camera on screen
if (lod < 0.1f)
return;
UpdateColorsInHandlesIfRequired();
const float k_DotLength = 5f;
// Draw them with scale applied to size and pivot instead of the matrix to keep the proportions of the arrow and lines.
using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one)))
{
Vector3 scale = decalProjector.effectiveScale;
Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale);
Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale);
boxHandle.center = scaledPivot;
boxHandle.size = scaledSize;
bool isVolumeEditMode = editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV;
bool isPivotEditMode = editMode == k_EditUVAndPivot;
if (lod > 0.5f)
{
boxHandle.DrawHull(isVolumeEditMode);
}
else
Handles.DrawWireCube(scaledPivot, scaledSize); // simplify the drawing if too small on screen
if (lod == 1.0f) // only draw when big enough on screen to be useable
{
Vector3 pivot = Vector3.zero;
Vector3 projectedPivot = new Vector3(0, 0, scaledPivot.z - .5f * scaledSize.z);
if (isPivotEditMode)
{
Handles.DrawDottedLines(new[] { projectedPivot, pivot }, k_DotLength);
}
else
{
float arrowSize = scaledSize.z * 0.25f;
Handles.ArrowHandleCap(0, projectedPivot, Quaternion.identity, arrowSize, EventType.Repaint);
}
//draw UV and bolder edges
using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position + decalProjector.transform.rotation * new Vector3(scaledPivot.x, scaledPivot.y, scaledPivot.z - .5f * scaledSize.z), decalProjector.transform.rotation, Vector3.one)))
{
Vector2 UVSize = new Vector2(
(decalProjector.uvScale.x > k_Limit || decalProjector.uvScale.x < -k_Limit) ? 0f : scaledSize.x / decalProjector.uvScale.x,
(decalProjector.uvScale.y > k_Limit || decalProjector.uvScale.y < -k_Limit) ? 0f : scaledSize.y / decalProjector.uvScale.y
);
Vector2 UVCenter = UVSize * .5f - new Vector2(decalProjector.uvBias.x * UVSize.x, decalProjector.uvBias.y * UVSize.y) - (Vector2)scaledSize * .5f;
uvHandles.center = UVCenter;
uvHandles.size = UVSize;
uvHandles.DrawRect(dottedLine: true, screenSpaceSize: k_DotLength);
uvHandles.center = default;
uvHandles.size = scaledSize;
uvHandles.DrawRect(dottedLine: false, thickness: 3f);
}
}
}
}
static Func<Bounds> GetBoundsGetter(DecalProjector decalProjector)
{
return () =>
{
var bounds = new Bounds();
var decalTransform = decalProjector.transform;
bounds.Encapsulate(decalTransform.position);
return bounds;
};
}
// Temporarily save ratio between size and pivot position while editing in inspector.
// null or NaN is used to say that there is no saved ratio.
// Aim is to keep proportion while sliding the value to 0 in Inspector and then go back to something else.
// Current solution only works for the life of this editor, but is enough in most cases.
// Which means if you go to there, selection something else and go back on it, pivot position is thus null.
Dictionary<DecalProjector, Vector3> ratioSizePivotPositionSaved = null;
void ReinitSavedRatioSizePivotPosition()
{
ratioSizePivotPositionSaved = null;
}
void UpdateSize(int axe, float newSize)
{
void UpdateSizeOfOneTarget(DecalProjector currentTarget)
{
//lazy init on demand as targets array cannot be accessed from OnSceneGUI so in edit mode.
if (ratioSizePivotPositionSaved == null)
{
ratioSizePivotPositionSaved = new Dictionary<DecalProjector, Vector3>();
foreach (DecalProjector projector in targets)
ratioSizePivotPositionSaved[projector] = new Vector3(float.NaN, float.NaN, float.NaN);
}
// Save old ratio if not registered
// Either or are NaN or no one, check only first
Vector3 saved = ratioSizePivotPositionSaved[currentTarget];
if (float.IsNaN(saved[axe]))
{
float oldSize = currentTarget.m_Size[axe];
saved[axe] = Mathf.Abs(oldSize) <= Mathf.Epsilon ? 0f : currentTarget.m_Offset[axe] / oldSize;
ratioSizePivotPositionSaved[currentTarget] = saved;
}
currentTarget.m_Size[axe] = newSize;
currentTarget.m_Offset[axe] = saved[axe] * newSize;
// refresh DecalProjector to update projection
currentTarget.OnValidate();
}
// Manually register Undo as we work directly on the target
Undo.RecordObjects(targets, "Change DecalProjector Size or Depth");
// Apply any change on target first
serializedObject.ApplyModifiedProperties();
// update each target
foreach (DecalProjector decalProjector in targets)
{
UpdateSizeOfOneTarget(decalProjector);
// Fix for UUM-29105 (Changes made to Decal Project Prefab in the Inspector are not saved)
// This editor doesn't use serializedObject to modify the target objects, explicitly mark the prefab
// asset dirty to ensure the new data is saved.
if (PrefabUtility.IsPartOfPrefabAsset(decalProjector))
EditorUtility.SetDirty(decalProjector);
}
// update again serialize object to register change in targets
serializedObject.Update();
// change was not tracked by SerializeReference so force repaint the scene views and game views
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
// strange: we need to force it throu serialization to update multiple differente value state (value are right but still detected as different)
if (m_SizeValues[axe].hasMultipleDifferentValues)
m_SizeValues[axe].floatValue = newSize;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
bool materialChanged = false;
bool isDefaultMaterial = false;
bool isValidDecalMaterial = true;
bool isDecalSupported = DecalProjector.isSupported;
if (!isDecalSupported)
EditorUtils.FeatureHelpBox("The current renderer has no Decal Renderer Feature added.", MessageType.Warning);
EditorGUI.BeginChangeCheck();
{
EditorGUILayout.PropertyField(m_ScaleMode, k_ScaleMode);
bool negativeScale = false;
foreach (var target in targets)
{
var decalProjector = target as DecalProjector;
float combinedScale = decalProjector.transform.lossyScale.x * decalProjector.transform.lossyScale.y * decalProjector.transform.lossyScale.z;
negativeScale |= combinedScale < 0 && decalProjector.scaleMode == DecalScaleMode.InheritFromHierarchy;
}
if (negativeScale)
{
EditorGUILayout.HelpBox("Does not work with negative odd scaling (When there are odd number of scale components)", MessageType.Warning);
}
var widthRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(widthRect, k_WidthContent, m_SizeValues[0]);
EditorGUI.BeginChangeCheck();
float newSizeX = EditorGUI.FloatField(widthRect, k_WidthContent, m_SizeValues[0].floatValue);
if (EditorGUI.EndChangeCheck())
UpdateSize(0, Mathf.Max(0, newSizeX));
EditorGUI.EndProperty();
var heightRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(heightRect, k_HeightContent, m_SizeValues[1]);
EditorGUI.BeginChangeCheck();
float newSizeY = EditorGUI.FloatField(heightRect, k_HeightContent, m_SizeValues[1].floatValue);
if (EditorGUI.EndChangeCheck())
UpdateSize(1, Mathf.Max(0, newSizeY));
EditorGUI.EndProperty();
var projectionRect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(projectionRect, k_ProjectionDepthContent, m_SizeValues[2]);
EditorGUI.BeginChangeCheck();
float newSizeZ = EditorGUI.FloatField(projectionRect, k_ProjectionDepthContent, m_SizeValues[2].floatValue);
if (EditorGUI.EndChangeCheck())
UpdateSize(2, Mathf.Max(0, newSizeZ));
EditorGUI.EndProperty();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_Offset, k_Offset);
if (EditorGUI.EndChangeCheck())
ReinitSavedRatioSizePivotPosition();
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
MaterialFieldWithButton(m_MaterialProperty, k_MaterialContent);
materialChanged = EditorGUI.EndChangeCheck();
EditorGUILayout.PropertyField(m_RenderingLayerMask, k_RenderingLayerMaskContent);
foreach (var target in targets)
{
var decalProjector = target as DecalProjector;
var mat = decalProjector.material;
isDefaultMaterial |= decalProjector.material == DecalProjector.defaultMaterial;
isValidDecalMaterial &= decalProjector.IsValid();
}
if (m_MaterialEditor && !isValidDecalMaterial)
{
CoreEditorUtils.DrawFixMeBox("Decal only work with Decal Material. Use default material or create from decal shader graph sub target.", () =>
{
m_MaterialProperty.objectReferenceValue = DecalProjector.defaultMaterial;
materialChanged = true;
});
}
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_UVScaleProperty, k_UVScaleContent);
EditorGUILayout.PropertyField(m_UVBiasProperty, k_UVBiasContent);
EditorGUILayout.PropertyField(m_FadeFactor, k_OpacityContent);
EditorGUI.indentLevel--;
bool angleFadeSupport = false;
foreach (var decalProjector in targets)
{
var mat = (decalProjector as DecalProjector).material;
if (mat == null)
continue;
angleFadeSupport = mat.HasProperty("_DecalAngleFadeSupported");
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_DrawDistanceProperty, k_DistanceContent);
if (EditorGUI.EndChangeCheck() && m_DrawDistanceProperty.floatValue < 0f)
m_DrawDistanceProperty.floatValue = 0f;
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_FadeScaleProperty, k_FadeScaleContent);
EditorGUI.indentLevel--;
using (new EditorGUI.DisabledScope(!angleFadeSupport))
{
float angleFadeMinValue = m_StartAngleFadeProperty.floatValue;
float angleFadeMaxValue = m_EndAngleFadeProperty.floatValue;
EditorGUI.BeginChangeCheck();
EditorGUILayout.MinMaxSlider(k_AngleFadeContent, ref angleFadeMinValue, ref angleFadeMaxValue, 0.0f, 180.0f);
if (EditorGUI.EndChangeCheck())
{
m_StartAngleFadeProperty.floatValue = angleFadeMinValue;
m_EndAngleFadeProperty.floatValue = angleFadeMaxValue;
}
}
if (!angleFadeSupport && isValidDecalMaterial)
{
EditorGUILayout.HelpBox($"Decal Angle Fade is not enabled in Shader. In ShaderGraph enable Angle Fade option.", MessageType.Info);
}
EditorGUILayout.Space();
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (materialChanged)
UpdateMaterialEditor();
if (layerMaskHasMultipleValues || layerMask != (target as Component).gameObject.layer)
{
foreach (var decalProjector in targets)
{
(decalProjector as DecalProjector).OnValidate();
}
}
if (m_MaterialEditor != null)
{
// We need to prevent the user to edit default decal materials
if (isValidDecalMaterial)
{
using (new DecalProjectorScope())
{
using (new EditorGUI.DisabledGroupScope(isDefaultMaterial))
{
// Draw the material's foldout and the material shader field
// Required to call m_MaterialEditor.OnInspectorGUI ();
m_MaterialEditor.DrawHeader();
// Draw the material properties
// Works only if the foldout of m_MaterialEditor.DrawHeader () is open
m_MaterialEditor.OnInspectorGUI();
}
}
}
}
}
internal void MaterialFieldWithButton(SerializedProperty prop, GUIContent label)
{
const int k_NewFieldWidth = 70;
var rect = EditorGUILayout.GetControlRect();
rect.xMax -= k_NewFieldWidth + 2;
EditorGUI.PropertyField(rect, prop, label);
var newFieldRect = rect;
newFieldRect.x = rect.xMax + 2;
newFieldRect.width = k_NewFieldWidth;
if (!EditorGUI.DropdownButton(newFieldRect, k_NewDecalMaterialButtonText, FocusType.Keyboard))
return;
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent(k_NewDecalText), false, () => CreateDefaultDecalMaterial(targets));
menu.AddItem(new GUIContent(k_NewSGDecalText), false, () => CreateDecalMaterialFromTemplate(targets, k_DefaultDecalShaderGraphTemplatePath));
menu.AddItem(new GUIContent(k_NewSGDecalFromTemplateText), false, () => CreateDecalMaterialFromTemplate(targets));
menu.DropDown(newFieldRect);
}
static void CreateDecalMaterialFromTemplate(UnityEngine.Object[] decalProjectors, string templatePath = null)
{
CreateShaderGraph.CreateGraphAndMaterialFromTemplate((material) =>
{
SetDecalMaterial(decalProjectors, material);
},
templatePath,
$"New {k_NewSGDecalText}",
null,
"shadergraph.material=decal");
}
static void CreateDefaultDecalMaterial(UnityEngine.Object[] decalProjectors)
{
string materialName = "New " + k_NewDecalText;
AssetCreationUtil.CreateMaterial(
materialName,
(material) =>
{
SetDecalMaterial(decalProjectors, material);
},
DecalProjector.defaultMaterial.shader
);
}
static void SetDecalMaterial(UnityEngine.Object[] decalProjectors, Material material)
{
var selection = new List<GameObject>();
foreach (DecalProjector decalProjector in decalProjectors)
{
decalProjector.material = material;
EditorUtility.SetDirty(decalProjector);
selection.Add(decalProjector.gameObject);
}
Selection.objects = selection.ToArray();
}
[Shortcut("URP/Decal: Handle changing size stretching UV", typeof(SceneView), KeyCode.Keypad1, ShortcutModifiers.Action)]
static void EnterEditModeWithoutPreservingUV(ShortcutArguments args)
{
//If editor is not there, then the selected GameObject does not contains a DecalProjector
DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent<DecalProjector>();
if (activeDecalProjector == null || activeDecalProjector.Equals(null))
return;
ChangeEditMode(k_EditShapeWithoutPreservingUV, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection());
}
[Shortcut("URP/Decal: Handle changing size cropping UV", typeof(SceneView), KeyCode.Keypad2, ShortcutModifiers.Action)]
static void EnterEditModePreservingUV(ShortcutArguments args)
{
//If editor is not there, then the selected GameObject does not contains a DecalProjector
DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent<DecalProjector>();
if (activeDecalProjector == null || activeDecalProjector.Equals(null))
return;
ChangeEditMode(k_EditShapePreservingUV, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection());
}
[Shortcut("URP/Decal: Handle changing pivot position and UVs", typeof(SceneView), KeyCode.Keypad3, ShortcutModifiers.Action)]
static void EnterEditModePivotPreservingUV(ShortcutArguments args)
{
//If editor is not there, then the selected GameObject does not contains a DecalProjector
DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent<DecalProjector>();
if (activeDecalProjector == null || activeDecalProjector.Equals(null))
return;
ChangeEditMode(k_EditUVAndPivot, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection());
}
[Shortcut("URP/Decal: Handle swap between cropping and stretching UV", typeof(SceneView), KeyCode.Keypad4, ShortcutModifiers.Action)]
static void SwappingEditUVMode(ShortcutArguments args)
{
//If editor is not there, then the selected GameObject does not contains a DecalProjector
DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent<DecalProjector>();
if (activeDecalProjector == null || activeDecalProjector.Equals(null))
return;
SceneViewEditMode targetMode = SceneViewEditMode.None;
switch (editMode)
{
case k_EditShapePreservingUV:
case k_EditUVAndPivot:
targetMode = k_EditShapeWithoutPreservingUV;
break;
case k_EditShapeWithoutPreservingUV:
targetMode = k_EditShapePreservingUV;
break;
}
if (targetMode != SceneViewEditMode.None)
ChangeEditMode(targetMode, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection());
}
[Shortcut("URP/Decal: Stop Editing", typeof(SceneView), KeyCode.Keypad0, ShortcutModifiers.Action)]
static void ExitEditMode(ShortcutArguments args)
{
//If editor is not there, then the selected GameObject does not contains a DecalProjector
DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent<DecalProjector>();
if (activeDecalProjector == null || activeDecalProjector.Equals(null))
return;
QuitEditMode();
}
[EditorTool(Description, typeof(DecalProjector), toolPriority = (int)Mode)]
internal class DecalProjectorModifyScaleTool : GenericEditorTool<DecalProjector>
{
private const string Description = DecalProjectorEditor.k_EditShapeWithoutPreservingUVTooltip;
private const EditMode.SceneViewEditMode Mode = DecalProjectorEditor.k_EditShapeWithoutPreservingUV;
private const string IconName = "ScaleTool";
protected DecalProjectorModifyScaleTool() : base(Description, Mode, IconName) { }
}
[EditorTool(Description, typeof(DecalProjector), toolPriority = (int)Mode)]
internal class DecalProjectorEditShapeTool : GenericEditorTool<DecalProjector>
{
private const string Description = DecalProjectorEditor.k_EditShapePreservingUVTooltip;
private const EditMode.SceneViewEditMode Mode = DecalProjectorEditor.k_EditShapePreservingUV;
private const string IconName = "RectTool";
protected DecalProjectorEditShapeTool() : base(Description, Mode, IconName) { }
}
[EditorTool(Description, typeof(DecalProjector), toolPriority = (int)Mode)]
internal class DecalProjectorEditTool : GenericEditorTool<DecalProjector>
{
private const string Description = DecalProjectorEditor.k_EditUVTooltip;
private const EditMode.SceneViewEditMode Mode = DecalProjectorEditor.k_EditUVAndPivot;
private const string IconName = "MoveTool";
protected DecalProjectorEditTool() : base(Description, Mode, IconName) { }
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e95fca79248379e42bece9300ebf44ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,199 @@
using System;
using UnityEditor.ShaderGraph;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.Universal.Internal;
namespace UnityEditor.Rendering.Universal
{
/// <summary>
/// Scope that indicates start of <see cref="DecalProjector"/> GUI.
/// </summary>
internal class DecalProjectorScope : GUI.Scope
{
public DecalProjectorScope()
{
DecalShaderGraphGUI.isDecalProjectorGUI = true;
}
protected override void CloseScope()
{
DecalShaderGraphGUI.isDecalProjectorGUI = false;
}
}
/// <summary>
/// Represents the GUI for Decal Shader Graph materials.
/// </summary>
internal class DecalShaderGraphGUI : UnityEditor.ShaderGUI
{
internal class Styles
{
public static GUIContent inputs = new GUIContent("Inputs");
public static GUIContent advancedOptions = new GUIContent("Advanced Options");
public static GUIContent meshDecalBiasType = new GUIContent("Mesh Bias Type", "Set the type of bias that is applied to the mesh decal. Depth Bias applies a bias to the final depth value, while View bias applies a world space bias (in meters) alongside the view vector.");
public static GUIContent meshDecalDepthBiasText = new GUIContent("Depth Bias", "Sets a depth bias to stop the decal's Mesh from overlapping with other Meshes.");
public static GUIContent meshDecalViewBiasText = new GUIContent("View Bias", "Sets a world-space bias alongside the view vector to stop the decal's Mesh from overlapping with other Meshes. The unit is meters.");
public static GUIContent drawOrderText = new GUIContent("Priority", "Controls the draw order of Decal Projectors. URP draws decals with lower values first.");
}
protected enum Expandable
{
Inputs = 1 << 0,
Advanced = 1 << 1,
}
public static bool isDecalProjectorGUI { get; set; }
const string kDecalMeshBiasType = "_DecalMeshBiasType";
const string kDecalMeshDepthBias = "_DecalMeshDepthBias";
const string kDecalViewDepthBias = "_DecalMeshViewBias";
const string kDrawOrder = "_DrawOrder";
readonly MaterialHeaderScopeList m_MaterialScopeList = new MaterialHeaderScopeList(uint.MaxValue & ~((uint)Expandable.Advanced));
MaterialEditor m_MaterialEditor;
MaterialProperty[] m_Properties;
MaterialProperty decalMeshBiasType;
MaterialProperty decalMeshDepthBias;
MaterialProperty decalMeshViewBias;
MaterialProperty drawOrder;
public DecalShaderGraphGUI()
{
m_MaterialScopeList.RegisterHeaderScope(Styles.inputs, Expandable.Inputs, DrawExposedProperties);
m_MaterialScopeList.RegisterHeaderScope(Styles.advancedOptions, Expandable.Advanced, DrawSortingProperties);
}
/// <summary>
/// Override this function to implement your custom GUI. To display a user interface similar to HDRP shaders, use a MaterialUIBlockList.
/// </summary>
/// <param name="materialEditor">The current material editor.</param>
/// <param name="props">The list of properties the material has.</param>
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
{
DecalMeshWarning();
m_MaterialEditor = materialEditor;
FindProperties(props);
Material material = materialEditor.target as Material;
using (var changed = new EditorGUI.ChangeCheckScope())
{
m_MaterialScopeList.DrawHeaders(materialEditor, material);
}
// We should always do this call at the end
materialEditor.serializedObject.ApplyModifiedProperties();
}
private void FindProperties(MaterialProperty[] properties)
{
decalMeshBiasType = FindProperty(kDecalMeshBiasType, properties);
decalMeshViewBias = FindProperty(kDecalViewDepthBias, properties);
decalMeshDepthBias = FindProperty(kDecalMeshDepthBias, properties);
drawOrder = FindProperty(kDrawOrder, properties);
m_Properties = properties;
}
private void DrawExposedProperties(Material material)
{
MaterialProperty[] properties = m_Properties;
MaterialEditor materialEditor = m_MaterialEditor;
// TODO: scope
var fieldWidth = EditorGUIUtility.fieldWidth;
var labelWidth = EditorGUIUtility.labelWidth;
// Copy of MaterialEditor.PropertiesDefaultGUI that excludes properties of PerRendererData
materialEditor.SetDefaultGUIWidths();
for (var i = 0; i < properties.Length; i++)
{
if ((properties[i].propertyFlags & (ShaderPropertyFlags.HideInInspector | ShaderPropertyFlags.PerRendererData)) != 0)
continue;
float h = materialEditor.GetPropertyHeight(properties[i], properties[i].displayName);
Rect r = EditorGUILayout.GetControlRect(true, h, EditorStyles.layerMaskField);
materialEditor.ShaderProperty(r, properties[i], properties[i].displayName);
}
EditorGUIUtility.fieldWidth = fieldWidth;
EditorGUIUtility.labelWidth = labelWidth;
}
private void DrawSortingProperties(Material material)
{
MaterialEditor materialEditor = m_MaterialEditor;
materialEditor.EnableInstancingField();
DrawOrder();
materialEditor.ShaderProperty(decalMeshBiasType, Styles.meshDecalBiasType);
DecalMeshDepthBiasType decalBias = (DecalMeshDepthBiasType)decalMeshBiasType.floatValue;
EditorGUI.indentLevel++;
switch (decalBias)
{
case DecalMeshDepthBiasType.DepthBias:
materialEditor.ShaderProperty(decalMeshDepthBias, Styles.meshDecalDepthBiasText);
break;
case DecalMeshDepthBiasType.ViewBias:
materialEditor.ShaderProperty(decalMeshViewBias, Styles.meshDecalViewBiasText);
break;
}
EditorGUI.indentLevel--;
}
private void DrawOrder()
{
MaterialEditor materialEditor = m_MaterialEditor;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = drawOrder.hasMixedValue;
var queue = EditorGUILayout.IntSlider(Styles.drawOrderText, (int)drawOrder.floatValue, -50, 50);
if (EditorGUI.EndChangeCheck())
{
foreach (var target in materialEditor.targets)
{
var material = target as Material;
material.renderQueue = 2000 + queue;
}
drawOrder.floatValue = queue;
}
EditorGUI.showMixedValue = false;
}
private void DecalMeshWarning()
{
if (isDecalProjectorGUI)
return;
var urp = UniversalRenderPipeline.asset;
if (urp == null)
return;
bool hasDecalScreenSpace = false;
var renderers = urp.m_RendererDataList;
foreach (var renderer in renderers)
{
if (renderer.TryGetRendererFeature(out DecalRendererFeature decalRendererFeature))
{
var technique = decalRendererFeature.GetTechnique(renderer);
if (technique == DecalTechnique.ScreenSpace || technique == DecalTechnique.GBuffer)
{
hasDecalScreenSpace = true;
break;
}
}
}
if (hasDecalScreenSpace)
EditorGUILayout.HelpBox("Decals with Screen Space technique only support rendering with DecalProjector component.", MessageType.Warning);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4470a4bb8b24974a828f392bdcd4d0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,296 @@
using System;
using System.Reflection;
using UnityEngine;
namespace UnityEditor.Rendering.Universal
{
// Copy of UnityEditor.Rendering.HighDefinition.DisplacableRectHandles
class DisplacableRectHandles
{
const float k_HandleSizeCoef = 0.05f;
enum NamedEdge { Right, Top, Left, Bottom, None }
int[] m_ControlIDs = new int[4] { 0, 0, 0, 0 };
Color m_MonochromeHandleColor;
Color m_WireframeColor;
Color m_WireframeColorBehind;
/// <summary>The position of the center of the box in Handle.matrix space. On plane z=0.</summary>
public Vector2 center { get; set; }
/// <summary>The size of the box in Handle.matrix space. On plane z=0.</summary>
public Vector2 size { get; set; }
//Note: Handles.Slider not allow to use a specific ControlID.
//Thus Slider1D is used (with reflection)
static Type k_Slider1D = Type.GetType("UnityEditorInternal.Slider1D, UnityEditor");
static MethodInfo k_Slider1D_Do = k_Slider1D
.GetMethod(
"Do",
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
null,
CallingConventions.Any,
new[] { typeof(int), typeof(Vector3), typeof(Vector3), typeof(float), typeof(Handles.CapFunction), typeof(float) },
null);
static void Slider1D(int controlID, ref Vector3 handlePosition, Vector3 handleOrientation, float snapScale)
{
handlePosition = (Vector3)k_Slider1D_Do.Invoke(null, new object[]
{
controlID,
handlePosition,
handleOrientation,
HandleUtility.GetHandleSize(handlePosition) * k_HandleSizeCoef,
new Handles.CapFunction(Handles.DotHandleCap),
snapScale
});
}
/// <summary>The baseColor used to draw the rect.</summary>
public Color baseColor
{
get { return m_MonochromeHandleColor; }
set
{
m_MonochromeHandleColor = GizmoUtility.GetHandleColor(value);
m_WireframeColor = GizmoUtility.GetWireframeColor(value);
m_WireframeColorBehind = GizmoUtility.GetWireframeColorBehindObjects(value);
}
}
public DisplacableRectHandles(Color baseColor)
{
this.baseColor = baseColor;
}
/// <summary>Draw the rect.</summary>
public void DrawRect(bool dottedLine = false, float thickness = .0f, float screenSpaceSize = 5f)
{
Vector2 start = center - size * .5f;
Vector3[] positions = new Vector3[]
{
start,
start + size * Vector2.right,
start + size,
start + size * Vector2.up
};
Vector3[] edges = new Vector3[]
{
positions[0], positions[1],
positions[1], positions[2],
positions[2], positions[3],
positions[3], positions[0],
};
void Draw()
{
if (dottedLine)
Handles.DrawDottedLines(edges, screenSpaceSize);
else
{
Handles.DrawLine(positions[0], positions[1], thickness);
Handles.DrawLine(positions[1], positions[2], thickness);
Handles.DrawLine(positions[2], positions[3], thickness);
Handles.DrawLine(positions[3], positions[0], thickness);
}
}
Color previousColor = Handles.color;
Handles.color = m_WireframeColor;
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
Draw();
Handles.color = m_WireframeColorBehind;
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
Draw();
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
Handles.color = previousColor;
}
NamedEdge DrawSliders(ref Vector3 leftPosition, ref Vector3 rightPosition, ref Vector3 topPosition, ref Vector3 bottomPosition)
{
NamedEdge theChangedEdge = NamedEdge.None;
using (new Handles.DrawingScope(m_MonochromeHandleColor))
{
EditorGUI.BeginChangeCheck();
Slider1D(m_ControlIDs[(int)NamedEdge.Left], ref leftPosition, Vector3.left, EditorSnapSettings.scale);
if (EditorGUI.EndChangeCheck())
theChangedEdge = NamedEdge.Left;
EditorGUI.BeginChangeCheck();
Slider1D(m_ControlIDs[(int)NamedEdge.Right], ref rightPosition, Vector3.right, EditorSnapSettings.scale);
if (EditorGUI.EndChangeCheck())
theChangedEdge = NamedEdge.Right;
EditorGUI.BeginChangeCheck();
Slider1D(m_ControlIDs[(int)NamedEdge.Top], ref topPosition, Vector3.up, EditorSnapSettings.scale);
if (EditorGUI.EndChangeCheck())
theChangedEdge = NamedEdge.Top;
EditorGUI.BeginChangeCheck();
Slider1D(m_ControlIDs[(int)NamedEdge.Bottom], ref bottomPosition, Vector3.down, EditorSnapSettings.scale);
if (EditorGUI.EndChangeCheck())
theChangedEdge = NamedEdge.Bottom;
}
return theChangedEdge;
}
void EnsureEdgeFacesOutsideForHomothety(NamedEdge theChangedEdge, ref Vector3 leftPosition, ref Vector3 rightPosition, ref Vector3 topPosition, ref Vector3 bottomPosition)
{
switch (theChangedEdge)
{
case NamedEdge.Left:
if (rightPosition.x < leftPosition.x)
leftPosition.x = rightPosition.x;
if (topPosition.y < bottomPosition.y)
topPosition.y = bottomPosition.y = center.y;
break;
case NamedEdge.Right:
if (rightPosition.x < leftPosition.x)
rightPosition.x = leftPosition.x;
if (topPosition.y < bottomPosition.y)
topPosition.y = bottomPosition.y = center.y;
break;
case NamedEdge.Top:
if (topPosition.y < bottomPosition.y)
topPosition.y = bottomPosition.y;
if (rightPosition.x < leftPosition.x)
rightPosition.x = leftPosition.x = center.x;
break;
case NamedEdge.Bottom:
if (topPosition.y < bottomPosition.y)
bottomPosition.y = topPosition.y;
if (rightPosition.x < leftPosition.x)
rightPosition.x = leftPosition.x = center.x;
break;
}
}
void EnsureEdgeFacesOutsideForSymetry(NamedEdge theChangedEdge, ref Vector3 leftPosition, ref Vector3 rightPosition, ref Vector3 topPosition, ref Vector3 bottomPosition)
{
switch (theChangedEdge)
{
case NamedEdge.Left:
case NamedEdge.Right:
if (rightPosition.x < leftPosition.x)
rightPosition.x = leftPosition.x = center.x;
break;
case NamedEdge.Top:
case NamedEdge.Bottom:
if (topPosition.y < bottomPosition.y)
topPosition.y = bottomPosition.y = center.y;
break;
}
}
void EnsureEdgeFacesOutsideForOtherTransformation(ref Vector2 max, ref Vector2 min)
{
for (int axis = 0; axis < 2; ++axis)
{
if (min[axis] > max[axis])
{
// Control IDs in m_ControlIDs[0-1] are for positive axes
if (GUIUtility.hotControl == m_ControlIDs[axis])
max[axis] = min[axis];
else
min[axis] = max[axis];
}
}
}
/// <summary>Draw the manipulable handles</summary>
public void DrawHandle()
{
Event evt = Event.current;
bool useHomothety = evt.shift;
bool useSymetry = evt.alt || evt.command;
// Note: snapping is handled natively on ctrl for each Slider1D
for (int i = 0, count = m_ControlIDs.Length; i < count; ++i)
m_ControlIDs[i] = GUIUtility.GetControlID("DisplacableRectHandles".GetHashCode() + i, FocusType.Passive);
Vector3 leftPosition = center + size.x * .5f * Vector2.left;
Vector3 rightPosition = center + size.x * .5f * Vector2.right;
Vector3 topPosition = center + size.y * .5f * Vector2.up;
Vector3 bottomPosition = center + size.y * .5f * Vector2.down;
var theChangedEdge = NamedEdge.None;
EditorGUI.BeginChangeCheck();
theChangedEdge = DrawSliders(ref leftPosition, ref rightPosition, ref topPosition, ref bottomPosition);
if (EditorGUI.EndChangeCheck())
{
float delta = 0f;
switch (theChangedEdge)
{
case NamedEdge.Left: delta = ((Vector2)leftPosition - center - size.x * .5f * Vector2.left).x; break;
case NamedEdge.Right: delta = -((Vector2)rightPosition - center - size.x * .5f * Vector2.right).x; break;
case NamedEdge.Top: delta = -((Vector2)topPosition - center - size.y * .5f * Vector2.up).y; break;
case NamedEdge.Bottom: delta = ((Vector2)bottomPosition - center - size.y * .5f * Vector2.down).y; break;
}
if (useHomothety && useSymetry)
{
var tempSize = size - Vector2.one * delta;
//ensure that the rect edges are still facing outside
for (int axis = 0; axis < 3; ++axis)
{
if (tempSize[axis] < 0)
{
delta += tempSize[axis];
tempSize = size - Vector2.one * delta;
}
}
size = tempSize;
}
else
{
if (useSymetry)
{
switch (theChangedEdge)
{
case NamedEdge.Left: rightPosition.x -= delta; break;
case NamedEdge.Right: leftPosition.x += delta; break;
case NamedEdge.Top: bottomPosition.y += delta; break;
case NamedEdge.Bottom: topPosition.y -= delta; break;
}
EnsureEdgeFacesOutsideForSymetry(theChangedEdge, ref leftPosition, ref rightPosition, ref topPosition, ref bottomPosition);
}
if (useHomothety)
{
float halfDelta = delta * 0.5f;
switch (theChangedEdge)
{
case NamedEdge.Left:
case NamedEdge.Right:
bottomPosition.y += halfDelta;
topPosition.y -= halfDelta;
break;
case NamedEdge.Top:
case NamedEdge.Bottom:
rightPosition.x -= halfDelta;
leftPosition.x += halfDelta;
break;
}
EnsureEdgeFacesOutsideForHomothety(theChangedEdge, ref leftPosition, ref rightPosition, ref topPosition, ref bottomPosition);
}
var max = new Vector2(rightPosition.x, topPosition.y);
var min = new Vector2(leftPosition.x, bottomPosition.y);
if (!useSymetry && !useHomothety)
EnsureEdgeFacesOutsideForOtherTransformation(ref max, ref min);
center = (max + min) * .5f;
size = max - min;
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed534566ab68d00408f22fdba23b0848
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,248 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEditor;
namespace UnityEngine.Rendering.Universal
{
// Copy of UnityEditor.Rendering.HighDefinition.DisplacableRectHandles
class ProjectedTransform
{
struct PositionHandleIds
{
static int s_xAxisMoveHandleHash = "xAxisDecalPivot".GetHashCode();
static int s_yAxisMoveHandleHash = "yAxisDecalPivot".GetHashCode();
static int s_zAxisMoveHandleHash = "zAxisDecalPivot".GetHashCode();
static int s_xyAxisMoveHandleHash = "xyAxisDecalPivot".GetHashCode();
public static PositionHandleIds @default
{
get
{
return new PositionHandleIds(
GUIUtility.GetControlID(s_xAxisMoveHandleHash, FocusType.Passive),
GUIUtility.GetControlID(s_yAxisMoveHandleHash, FocusType.Passive),
GUIUtility.GetControlID(s_zAxisMoveHandleHash, FocusType.Passive),
GUIUtility.GetControlID(s_xyAxisMoveHandleHash, FocusType.Passive)
);
}
}
public readonly int x, y, z, xy;
public int this[int index]
{
get
{
switch (index)
{
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return xy;
}
return -1;
}
}
public bool Has(int id)
{
return x == id
|| y == id
|| z == id
|| xy == id;
}
public PositionHandleIds(int x, int y, int z, int xy)
{
this.x = x;
this.y = y;
this.z = z;
this.xy = xy;
}
public override int GetHashCode()
{
return x ^ y ^ z ^ xy;
}
public override bool Equals(object obj)
{
if (!(obj is PositionHandleIds o))
return false;
return o.x == x && o.y == y && o.z == z && o.xy == xy;
}
}
struct PositionHandleParam
{
public static PositionHandleParam defaultHandleXY = new PositionHandleParam(
Handle.X | Handle.Y | Handle.XY,
Vector3.zero, Vector3.one, Vector3.zero, Vector3.one * .25f,
Orientation.Signed, Orientation.Camera);
public static PositionHandleParam defaultHandleZ = new PositionHandleParam(
Handle.Z,
Vector3.zero, Vector3.one, Vector3.zero, Vector3.one * .25f,
Orientation.Signed, Orientation.Camera);
[Flags]
public enum Handle
{
None = 0,
X = 1 << 0,
Y = 1 << 1,
Z = 1 << 2,
XY = 1 << 3,
All = ~None
}
public enum Orientation
{
Signed,
Camera
}
public readonly Vector3 axisOffset;
public readonly Vector3 axisSize;
public readonly Vector3 planeOffset;
public readonly Vector3 planeSize;
public readonly Handle handles;
public readonly Orientation axesOrientation;
public readonly Orientation planeOrientation;
public bool ShouldShow(int axis)
{
return (handles & (Handle)(1 << axis)) != 0;
}
public bool ShouldShow(Handle handle)
{
return (handles & handle) != 0;
}
public PositionHandleParam(
Handle handles,
Vector3 axisOffset,
Vector3 axisSize,
Vector3 planeOffset,
Vector3 planeSize,
Orientation axesOrientation,
Orientation planeOrientation)
{
this.axisOffset = axisOffset;
this.axisSize = axisSize;
this.planeOffset = planeOffset;
this.planeSize = planeSize;
this.handles = handles;
this.axesOrientation = axesOrientation;
this.planeOrientation = planeOrientation;
}
}
static PositionHandleParam paramXY = PositionHandleParam.defaultHandleXY;
static PositionHandleParam paramZ = PositionHandleParam.defaultHandleZ;
static PositionHandleIds ids = PositionHandleIds.@default;
static int[] s_DoPositionHandle_Internal_NextIndex = { 1, 2, 0 };
static int[] s_DoPositionHandle_Internal_PrevIndex = { 2, 0, 1 };
static Vector3[] verts = { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };
static Func<bool> s_IsGridSnappingActive;
static ProjectedTransform()
{
//We need to know if grid snaping is active or not in Editor. Sadly this is internal so we must grab it by reflection.
Type gridSnappingType = typeof(Handles).Assembly.GetType("UnityEditor.GridSnapping");
PropertyInfo activePropertyInfo = gridSnappingType.GetProperty("active", BindingFlags.Public | BindingFlags.Static);
MethodCallExpression activePropertyGetCall = Expression.Call(null, activePropertyInfo.GetGetMethod());
var activeGetLambda = Expression.Lambda<Func<bool>>(activePropertyGetCall);
s_IsGridSnappingActive = activeGetLambda.Compile();
}
static bool IsHovering(int controlID, Event evt)
{
return controlID == HandleUtility.nearestControl && GUIUtility.hotControl == 0 && !Tools.viewToolActive;
}
public static Vector3 DrawHandles(Vector3 position, float zProjectionDistance, Quaternion rotation)
{
var isHot = ids.Has(GUIUtility.hotControl);
var planeSize = isHot ? paramXY.planeSize + paramXY.planeOffset : paramXY.planeSize;
var planarSize = Mathf.Max(planeSize[0], planeSize[s_DoPositionHandle_Internal_NextIndex[0]]);
Vector3 sliderRotatedWorldPos = Quaternion.Inverse(rotation) * position;
var size1D = HandleUtility.GetHandleSize(sliderRotatedWorldPos);
var size2D = HandleUtility.GetHandleSize(sliderRotatedWorldPos - new Vector3(0, 0, zProjectionDistance)) * planarSize * .5f;
Vector3 depthSlider = sliderRotatedWorldPos;
EditorGUI.BeginChangeCheck();
{
// dot offset = transform position seen as a sphere
EditorGUI.BeginChangeCheck();
depthSlider = Handles.Slider(depthSlider, Vector3.forward, size1D * .1f, Handles.SphereHandleCap, -1);
if (EditorGUI.EndChangeCheck())
sliderRotatedWorldPos.z = depthSlider.z;
// 2D slider: square xy-axis
Vector3 sliderFaceProjected = sliderRotatedWorldPos - new Vector3(0, 0, zProjectionDistance);
sliderFaceProjected.x += size2D;
sliderFaceProjected.y += size2D;
using (new Handles.DrawingScope(Handles.zAxisColor))
{
verts[0] = sliderFaceProjected + (Vector3.right + Vector3.up) * size2D;
verts[1] = sliderFaceProjected + (-Vector3.right + Vector3.up) * size2D;
verts[2] = sliderFaceProjected + (-Vector3.right - Vector3.up) * size2D;
verts[3] = sliderFaceProjected + (Vector3.right - Vector3.up) * size2D;
int id = GUIUtility.GetControlID(ids.xy, FocusType.Passive);
float faceOpacity = 0.8f;
if (GUIUtility.hotControl == id)
Handles.color = Handles.selectedColor;
else if (IsHovering(id, Event.current))
faceOpacity = 0.4f;
else
faceOpacity = 0.1f;
Color faceColor = new Color(Handles.zAxisColor.r, Handles.zAxisColor.g, Handles.zAxisColor.b, Handles.zAxisColor.a * faceOpacity);
Handles.DrawSolidRectangleWithOutline(verts, faceColor, Color.clear);
EditorGUI.BeginChangeCheck();
sliderFaceProjected = Handles.Slider2D(id, sliderFaceProjected, Vector3.forward, Vector3.right, Vector3.up, size2D, Handles.RectangleHandleCap, s_IsGridSnappingActive() ? Vector2.zero : new Vector2(EditorSnapSettings.move[0], EditorSnapSettings.move[1]), false);
if (EditorGUI.EndChangeCheck())
{
sliderRotatedWorldPos.x = sliderFaceProjected.x;
sliderRotatedWorldPos.y = sliderFaceProjected.y;
}
}
sliderFaceProjected.x -= size2D;
sliderFaceProjected.y -= size2D;
// 2D slider: x-axis
EditorGUI.BeginChangeCheck();
using (new Handles.DrawingScope(Handles.xAxisColor))
sliderFaceProjected = Handles.Slider(sliderFaceProjected, Vector3.right);
if (EditorGUI.EndChangeCheck())
sliderRotatedWorldPos.x = sliderFaceProjected.x;
// 2D slider: y-axis
EditorGUI.BeginChangeCheck();
using (new Handles.DrawingScope(Handles.yAxisColor))
sliderFaceProjected = Handles.Slider(sliderFaceProjected, Vector3.up);
if (EditorGUI.EndChangeCheck())
sliderRotatedWorldPos.y = sliderFaceProjected.y;
// depth: z-axis
EditorGUI.BeginChangeCheck();
using (new Handles.DrawingScope(Handles.zAxisColor))
depthSlider = Handles.Slider(depthSlider, Vector3.forward);
if (EditorGUI.EndChangeCheck())
sliderRotatedWorldPos.z = depthSlider.z;
}
if (EditorGUI.EndChangeCheck())
{
position = rotation * sliderRotatedWorldPos;
}
return position;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11a1c63a9dcda4740920a8e98e4ee672
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3522f385657caf14b8c18df878a3c65b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
fileFormatVersion: 2
guid: 9ba98ca4f0fc0754caca09e38af0cc0a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
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
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant: