From ae88f60915196a6cac50231c3d2afb5be5e64a82 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Tue, 5 May 2020 19:08:11 +0300 Subject: [PATCH 01/61] tt --- .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 2 +- .../UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader | 8 ++++---- .../UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 3569cf7..846ba0a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -475,7 +475,7 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti } // Set source texture as _MainTex to match Blit behavior. - _commandBuffer.SetGlobalTexture(_mainRtId, _source); + _commandBuffer.SetGlobalTexture(_mainRtId, _hPassRtId); // Set destination texture as render target. #if UNITY_2018_2_OR_NEWER diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader index 2febb62..8b5fab6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader @@ -29,8 +29,8 @@ Shader "UnityFx/Outline/HPass" int _Width; CBUFFER_END - UNITY_DECLARE_TEX2D(_MaskTex); - float2 _MaskTex_TexelSize; + UNITY_DECLARE_TEX2D(_MainTex); + float2 _MainTex_TexelSize; float _GaussSamples[32]; struct v2f @@ -51,13 +51,13 @@ Shader "UnityFx/Outline/HPass" float Frag(v2f i) : COLOR { - float TX_x = _MaskTex_TexelSize.x; + float TX_x = _MainTex_TexelSize.x; float intensity; int n = _Width; for (int k = -n; k <= n; k += 1) { - intensity += UNITY_SAMPLE_TEX2D(_MaskTex, i.uvs.xy + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uvs.xy + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; } return intensity; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader index dbf1a18..7ce520c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader @@ -35,10 +35,9 @@ Shader "UnityFx/Outline/VPassBlend" float4 _Color; CBUFFER_END + UNITY_DECLARE_TEX2D(_MainTex); + float2 _MainTex_TexelSize; UNITY_DECLARE_TEX2D(_MaskTex); - float2 _MaskTex_TexelSize; - UNITY_DECLARE_TEX2D(_HPassTex); - float2 _HPassTex_TexelSize; float _GaussSamples[32]; struct v2f @@ -64,13 +63,13 @@ Shader "UnityFx/Outline/VPassBlend" discard; } - float TX_y = _MaskTex_TexelSize.y; + float TX_y = _MainTex_TexelSize.y; float intensity; int n = _Width; for (int k = -n; k <= _Width; k += 1) { - intensity += UNITY_SAMPLE_TEX2D(_HPassTex, i.uvs.xy + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uvs.xy + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; } intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; From a3ae6bc2a5c37e143587a48af40175dbb009c025 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 6 May 2020 17:46:15 +0300 Subject: [PATCH 02/61] Changed shaders to use DrawProcedural if SM 3.5 is supported --- .../Runtime/Scripts/OutlineRenderer.cs | 33 ++++-- .../Runtime/Scripts/OutlineResources.cs | 2 +- .../Runtime/Shaders/OutlineCommon.hlsl | 51 +++++++++ .../Runtime/Shaders/OutlineCommon.hlsl.meta | 9 ++ .../Runtime/Shaders/OutlinePass1.shader | 84 ++++++++------- .../Runtime/Shaders/OutlinePass2.shader | 102 ++++++++++-------- .../Runtime/Shaders/OutlineRenderColor.shader | 18 +--- .../ProjectSettings/EditorBuildSettings.asset | 5 +- 8 files changed, 199 insertions(+), 105 deletions(-) create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 846ba0a..cd1a3e6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -224,10 +224,13 @@ public void Render(IList renderers, OutlineResources resources, IOutli throw new ArgumentNullException("settings"); } - Init(resources, settings); - RenderObject(resources, settings, renderers); - RenderHPass(resources, settings); - RenderVPassBlend(resources, settings); + if (renderers.Count > 0) + { + Init(resources, settings); + RenderObject(resources, settings, renderers); + RenderHPass(resources, settings); + RenderVPassBlend(resources, settings); + } } /// @@ -454,7 +457,16 @@ private void RenderHPass(OutlineResources resources, IOutlineSettings settings) #endif // Blit fullscreen triangle. - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, 0, props); + if (SystemInfo.graphicsShaderLevel >= 35) + { + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.HPassMaterial, -1, MeshTopology.Triangles, 3, 1, props); + } + else + { + _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, -1, props); + } + + //_commandBuffer.Blit(_maskRtId, _hPassRtId, resources.HPassMaterial); } private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings) @@ -485,7 +497,16 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti #endif // Blit fullscreen triangle. - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, 0, props); + if (SystemInfo.graphicsShaderLevel >= 35) + { + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.VPassBlendMaterial, -1, MeshTopology.Triangles, 3, 1, props); + } + else + { + _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, -1, props); + } + + //_commandBuffer.Blit(_hPassRtId, _destination, resources.VPassBlendMaterial); } #endregion diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 8d8f169..38c77a0 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -173,7 +173,7 @@ public Mesh FullscreenTriangleMesh { name = "Outline - FullscreenTriangle", hideFlags = HideFlags.HideAndDontSave, - vertices = new Vector3[] { new Vector3(-1f, -1f, 0f), new Vector3(-1f, 3f, 0f), new Vector3( 3f, -1f, 0f) }, + vertices = new Vector3[] { new Vector3(-1, -1, 0), new Vector3(3, -1, 0), new Vector3(-1, 3, 0) }, triangles = new int[] {0, 1, 2 } }; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl new file mode 100644 index 0000000..b49445a --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl @@ -0,0 +1,51 @@ +#ifndef OUTLINE_COMMON_INCLUDED +#define OUTLINE_COMMON_INCLUDED + +#include "UnityCG.cginc" + +#if SHADER_TARGET < 35 + +v2f_img vert(appdata_img v) +{ + v2f_img o; + UNITY_INITIALIZE_OUTPUT(v2f_img, o); + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); + o.uv = ComputeScreenPos(o.pos); + + return o; +} + +#else + +struct appdata_vid +{ + uint vertexID : SV_VertexID; +}; + +v2f_img vert_vid(appdata_vid v) +{ + v2f_img o; + UNITY_INITIALIZE_OUTPUT(v2f_img, o); + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // Generate a triangle in homogeneous clip space, s.t. + // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). + float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); + o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); + +#if UNITY_UV_STARTS_AT_TOP + o.uv = half2(uv.x, 1 - uv.y); +#else + o.uv = uv; +#endif + + return o; +} + +#endif + +#endif // OUTLINE_COMMON_INCLUDED diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta new file mode 100644 index 0000000..2515841 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: cc973aab804133b48b3f3cabc7971d26 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader index 8b5fab6..8c88af2 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader @@ -10,6 +10,35 @@ Shader "UnityFx/Outline/HPass" _Width("Outline thickness (in pixels)", Range(1, 32)) = 5 } + HLSLINCLUDE + + #include "OutlineCommon.hlsl" + + CBUFFER_START(UnityPerMaterial) + int _Width; + CBUFFER_END + + UNITY_DECLARE_TEX2D(_MainTex); + float2 _MainTex_TexelSize; + float _GaussSamples[32]; + + float frag(v2f_img i) : SV_Target + { + float TX_x = _MainTex_TexelSize.x; + float intensity; + int n = _Width; + + for (int k = -n; k <= n; k += 1) + { + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; + } + + return intensity; + } + + ENDHLSL + + // SM3.5+ SubShader { Cull Off @@ -21,47 +50,28 @@ Shader "UnityFx/Outline/HPass" { HLSLPROGRAM - #pragma vertex Vert - #pragma fragment Frag - #include "UnityCG.cginc" - - CBUFFER_START(UnityPerMaterial) - int _Width; - CBUFFER_END - - UNITY_DECLARE_TEX2D(_MainTex); - float2 _MainTex_TexelSize; - float _GaussSamples[32]; - - struct v2f - { - float4 pos : POSITION; - float2 uvs : TEXCOORD0; - }; - - v2f Vert(appdata_base v) - { - v2f o; - - o.pos = float4(v.vertex.xy, 0.0, 1.0); - o.uvs = ComputeScreenPos(o.pos); + #pragma target 3.5 + #pragma vertex vert_vid + #pragma fragment frag - return o; - } + ENDHLSL + } + } - float Frag(v2f i) : COLOR - { - float TX_x = _MainTex_TexelSize.x; - float intensity; - int n = _Width; + // SM2.0 + SubShader + { + Cull Off + ZWrite Off + ZTest Always + Lighting Off - for (int k = -n; k <= n; k += 1) - { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uvs.xy + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; - } + Pass + { + HLSLPROGRAM - return intensity; - } + #pragma vertex vert + #pragma fragment frag ENDHLSL } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader index 7ce520c..fcfef3b 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader @@ -12,6 +12,44 @@ Shader "UnityFx/Outline/VPassBlend" _Color("Outline color", Color) = (1, 0, 0, 1) } + HLSLINCLUDE + + #include "OutlineCommon.hlsl" + + CBUFFER_START(UnityPerMaterial) + float _Intensity; + int _Width; + float4 _Color; + CBUFFER_END + + UNITY_DECLARE_TEX2D(_MainTex); + float2 _MainTex_TexelSize; + UNITY_DECLARE_TEX2D(_MaskTex); + float _GaussSamples[32]; + + float4 frag(v2f_img i) : SV_Target + { + if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) + { + discard; + } + + float TX_y = _MainTex_TexelSize.y; + float intensity; + int n = _Width; + + for (int k = -n; k <= _Width; k += 1) + { + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; + } + + intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; + return float4(_Color.rgb, saturate(_Color.a * intensity)); + } + + ENDHLSL + + // SM3.5+ SubShader { Cull Off @@ -25,56 +63,30 @@ Shader "UnityFx/Outline/VPassBlend" { HLSLPROGRAM - #pragma vertex Vert - #pragma fragment Frag - #include "UnityCG.cginc" - - CBUFFER_START(UnityPerMaterial) - float _Intensity; - int _Width; - float4 _Color; - CBUFFER_END + #pragma target 3.5 + #pragma vertex vert_vid + #pragma fragment frag - UNITY_DECLARE_TEX2D(_MainTex); - float2 _MainTex_TexelSize; - UNITY_DECLARE_TEX2D(_MaskTex); - float _GaussSamples[32]; - - struct v2f - { - float4 pos : POSITION; - float2 uvs : TEXCOORD0; - }; + ENDHLSL + } + } - v2f Vert(appdata_base v) - { - v2f o; + // SM2.0 + SubShader + { + Cull Off + ZWrite Off + ZTest Always + Lighting Off - o.pos = float4(v.vertex.xy, 0.0, 1.0); - o.uvs = ComputeScreenPos(o.pos); + Blend SrcAlpha OneMinusSrcAlpha - return o; - } + Pass + { + HLSLPROGRAM - float4 Frag(v2f i) : COLOR - { - if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uvs.xy).r > 0) - { - discard; - } - - float TX_y = _MainTex_TexelSize.y; - float intensity; - int n = _Width; - - for (int k = -n; k <= _Width; k += 1) - { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uvs.xy + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; - } - - intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; - return float4(_Color.rgb, saturate(_Color.a * intensity)); - } + #pragma vertex vert + #pragma fragment frag ENDHLSL } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader index bf53276..23d7379 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader @@ -16,23 +16,11 @@ Shader "UnityFx/Outline/RenderColor" { HLSLPROGRAM - #pragma vertex Vert - #pragma fragment Frag + #pragma vertex vert_img + #pragma fragment frag #include "UnityCG.cginc" - struct v2f - { - float4 pos: POSITION; - }; - - v2f Vert(v2f i) - { - v2f o; - o.pos = UnityObjectToClipPos(i.pos); - return o; - } - - half4 Frag(): COLOR0 + half4 frag(): SV_Target { return half4(1, 1, 1, 1); } diff --git a/Outline.Core/ProjectSettings/EditorBuildSettings.asset b/Outline.Core/ProjectSettings/EditorBuildSettings.asset index 0147887..d5c9d72 100644 --- a/Outline.Core/ProjectSettings/EditorBuildSettings.asset +++ b/Outline.Core/ProjectSettings/EditorBuildSettings.asset @@ -4,5 +4,8 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 - m_Scenes: [] + m_Scenes: + - enabled: 1 + path: Assets/Examples/SimplePerCamera/Outline.unity + guid: e1f1f5e7ceb61b746b9f2016f0e53a93 m_configObjects: {} From f512a3232c8df420274c44ea3cf1ae0c4a3ceb98 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 6 May 2020 18:29:16 +0300 Subject: [PATCH 03/61] Do not discard render texture when source and destination textures are the same (fixes #7) --- .../Runtime/Scripts/OutlineRenderer.cs | 6 +----- .../Runtime/Scripts/OutlineResources.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index cd1a3e6..cfe01eb 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -465,8 +465,6 @@ private void RenderHPass(OutlineResources resources, IOutlineSettings settings) { _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, -1, props); } - - //_commandBuffer.Blit(_maskRtId, _hPassRtId, resources.HPassMaterial); } private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings) @@ -491,7 +489,7 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti // Set destination texture as render target. #if UNITY_2018_2_OR_NEWER - _commandBuffer.SetRenderTarget(_destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + _commandBuffer.SetRenderTarget(_destination, _source.Equals(_destination) ? RenderBufferLoadAction.Load : RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); #else _commandBuffer.SetRenderTarget(_destination); #endif @@ -505,8 +503,6 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti { _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, -1, props); } - - //_commandBuffer.Blit(_hPassRtId, _destination, resources.VPassBlendMaterial); } #endregion diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 38c77a0..74502c3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Rendering; namespace UnityFx.Outline { @@ -161,8 +162,14 @@ public MaterialPropertyBlock VPassBlendProperties } /// - /// Gets or sets a fullscreen triangle mesh. + /// Gets or sets a fullscreen triangle mesh. The mesh is lazy-initialized on the first access. /// + /// + /// This is used by to avoid Blit() calls and use DrawMesh() passing + /// this mesh as the first argument. When running on a device with Shader Model 3.5 support this + /// should not be used at all, as the vertices are generated in vertex shader with DrawProcedural() call. + /// + /// public Mesh FullscreenTriangleMesh { get @@ -174,7 +181,7 @@ public Mesh FullscreenTriangleMesh name = "Outline - FullscreenTriangle", hideFlags = HideFlags.HideAndDontSave, vertices = new Vector3[] { new Vector3(-1, -1, 0), new Vector3(3, -1, 0), new Vector3(-1, 3, 0) }, - triangles = new int[] {0, 1, 2 } + triangles = new int[] { 0, 1, 2 } }; _fullscreenTriangleMesh.UploadMeshData(true); From 80a48234b41ff05cd7cecc4556b58357e94475ed Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 6 May 2020 19:22:33 +0300 Subject: [PATCH 04/61] Fixed shader error on low-end devices --- .../UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader index 8c88af2..fd33084 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader @@ -22,7 +22,7 @@ Shader "UnityFx/Outline/HPass" float2 _MainTex_TexelSize; float _GaussSamples[32]; - float frag(v2f_img i) : SV_Target + float4 frag(v2f_img i) : SV_Target { float TX_x = _MainTex_TexelSize.x; float intensity; From e0b021a72924ed9f2c7544d641b144c11e0178d1 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 6 May 2020 19:23:03 +0300 Subject: [PATCH 05/61] Added render texture format fallbacks for old devices --- .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index cfe01eb..737c394 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -169,14 +169,15 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, var cx = rtSize.x > 0 ? rtSize.x : -1; var cy = rtSize.y > 0 ? rtSize.y : -1; + var rtFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) ? RenderTextureFormat.R8 : RenderTextureFormat.Default; _source = src; _destination = dst; _commandBuffer = commandBuffer; _commandBuffer.BeginSample(EffectName); - _commandBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); - _commandBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + _commandBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, rtFormat); + _commandBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, rtFormat); // Need to copy src content into dst if they are not the same. For instance this is the case when rendering // the outline effect as part of Unity Post Processing stack. From b5558c1453f3445b68cd03a8a41d5d13de4990e8 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Wed, 6 May 2020 23:41:41 +0300 Subject: [PATCH 06/61] Added FpsCounter --- Outline.Core/Assets/Common.meta | 8 +++ Outline.Core/Assets/Common/FpsCounter.cs | 70 +++++++++++++++++++ Outline.Core/Assets/Common/FpsCounter.cs.meta | 11 +++ .../Examples/SimplePerCamera/Outline.unity | 15 +++- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 Outline.Core/Assets/Common.meta create mode 100644 Outline.Core/Assets/Common/FpsCounter.cs create mode 100644 Outline.Core/Assets/Common/FpsCounter.cs.meta diff --git a/Outline.Core/Assets/Common.meta b/Outline.Core/Assets/Common.meta new file mode 100644 index 0000000..5b070c8 --- /dev/null +++ b/Outline.Core/Assets/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f19b0b14f634f941adfaa12f23064d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/Common/FpsCounter.cs b/Outline.Core/Assets/Common/FpsCounter.cs new file mode 100644 index 0000000..3e6e7b3 --- /dev/null +++ b/Outline.Core/Assets/Common/FpsCounter.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2018-2020 Digimation. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +/// +/// An FPS counter. +/// +/// +public class FpsCounter : MonoBehaviour +{ + private const float _updateInterval = 0.5F; + + private float _accum; + private int _frames; + private float _timeleft; + private float _fps; + + public float Fps => _fps; + + public static void RenderFps(float fps, string s, Rect rc) + { + var text = string.Format("{0}: {1:F2}", s, fps); + + if (fps < 10) + { + GUI.color = Color.red; + } + else if (fps < 30) + { + GUI.color = Color.yellow; + } + else + { + GUI.color = Color.green; + } + + GUI.Label(rc, text); + } + + private void OnEnable() + { + _accum = 0; + _frames = 0; + _timeleft = 0; + _fps = 0; + } + + private void Update() + { + _timeleft -= Time.deltaTime; + _accum += Time.timeScale / Time.deltaTime; + + ++_frames; + + if (_timeleft <= 0.0) + { + _fps = _accum / _frames; + _timeleft = _updateInterval; + _accum = 0.0F; + _frames = 0; + } + } + + private void OnGUI() + { + RenderFps(_fps, "FPS", new Rect(Screen.width - 80, 0, 80, 20)); + } +} diff --git a/Outline.Core/Assets/Common/FpsCounter.cs.meta b/Outline.Core/Assets/Common/FpsCounter.cs.meta new file mode 100644 index 0000000..5ec5174 --- /dev/null +++ b/Outline.Core/Assets/Common/FpsCounter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9e1f138162751048bdb3432e85d7a73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity index c172ec7..add9f47 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity +++ b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity @@ -191,6 +191,7 @@ GameObject: m_Component: - component: {fileID: 692811816} - component: {fileID: 692811815} + - component: {fileID: 692811813} - component: {fileID: 692811818} - component: {fileID: 692811817} m_Layer: 0 @@ -200,6 +201,18 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 +--- !u!114 &692811813 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 692811812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c9e1f138162751048bdb3432e85d7a73, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 @@ -524,7 +537,7 @@ MonoBehaviour: _outlineWidth: 15 _outlineIntensity: 2 _outlineMode: 1 - _depthTestEnabled: 0 + _updateRenderers: 0 --- !u!23 &1789341923 MeshRenderer: m_ObjectHideFlags: 0 From 863f6eeb7b335cd3d249ca63be34f9df60f51f7f Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Wed, 6 May 2020 23:42:17 +0300 Subject: [PATCH 07/61] Changed OutlineSettings inspector to display enum mask instead of checkboxes --- .../Scripts/Helpers/IOutlineSettingsTests.cs | 4 +- .../Editor/Scripts/OutlineEditorUtility.cs | 47 ++++--------------- .../Runtime/Scripts/OutlineRenderFlags.cs | 2 +- 3 files changed, 12 insertions(+), 41 deletions(-) diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs index 55a2687..f1ec8b8 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs @@ -111,8 +111,8 @@ public void OutlineMode_SetsValue() _settings.OutlineRenderMode = OutlineRenderFlags.Blurred; Assert.AreEqual(OutlineRenderFlags.Blurred, _settings.OutlineRenderMode); - _settings.OutlineRenderMode = OutlineRenderFlags.Solid; - Assert.AreEqual(OutlineRenderFlags.Solid, _settings.OutlineRenderMode); + _settings.OutlineRenderMode = OutlineRenderFlags.None; + Assert.AreEqual(OutlineRenderFlags.None, _settings.OutlineRenderMode); } [Test] diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs index 3f82a55..77e02f7 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs @@ -71,13 +71,17 @@ public static void Render(IOutlineSettings settings, UnityEngine.Object undoCont settings.OutlineWidth = width; } - var prevBlurred = (settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0; - var blurred = EditorGUILayout.Toggle("Blurred", prevBlurred); + var prevRenderMode = settings.OutlineRenderMode; + var renderMode = (OutlineRenderFlags)EditorGUILayout.EnumFlagsField("Render Flags", prevRenderMode); - if (blurred) + if (renderMode != prevRenderMode) { - EditorGUI.indentLevel += 1; + Undo.RecordObject(undoContext, "Render Flags"); + settings.OutlineRenderMode = renderMode; + } + if ((renderMode & OutlineRenderFlags.Blurred) != 0) + { var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); if (!Mathf.Approximately(settings.OutlineIntensity, i)) @@ -85,39 +89,6 @@ public static void Render(IOutlineSettings settings, UnityEngine.Object undoCont Undo.RecordObject(undoContext, "Blur Intensity"); settings.OutlineIntensity = i; } - - EditorGUI.indentLevel -= 1; - } - - if (blurred != prevBlurred) - { - Undo.RecordObject(undoContext, "Blur"); - - if (blurred) - { - settings.OutlineRenderMode |= OutlineRenderFlags.Blurred; - } - else - { - settings.OutlineRenderMode &= ~OutlineRenderFlags.Blurred; - } - } - - var prevDepthTestEnabled = (settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0; - var depthTestEnabled = EditorGUILayout.Toggle("Depth Test", prevDepthTestEnabled); - - if (depthTestEnabled != prevDepthTestEnabled) - { - Undo.RecordObject(undoContext, "Depth Test"); - - if (depthTestEnabled) - { - settings.OutlineRenderMode |= OutlineRenderFlags.EnableDepthTesting; - } - else - { - settings.OutlineRenderMode &= ~OutlineRenderFlags.EnableDepthTesting; - } } } @@ -134,7 +105,7 @@ public static void RenderPreview(OutlineLayer layer, int layerIndex, bool showOb if (layer.Enabled) { - EditorGUILayout.LabelField(layer.OutlineRenderMode == OutlineRenderFlags.Solid ? layer.OutlineRenderMode.ToString() : string.Format("Blurred ({0})", layer.OutlineIntensity), GUILayout.MaxWidth(70)); + EditorGUILayout.LabelField(layer.OutlineRenderMode == OutlineRenderFlags.None ? layer.OutlineRenderMode.ToString() : string.Format("Blurred ({0})", layer.OutlineIntensity), GUILayout.MaxWidth(70)); EditorGUILayout.IntField(layer.OutlineWidth, GUILayout.MaxWidth(100)); EditorGUILayout.ColorField(layer.OutlineColor, GUILayout.MinWidth(100)); } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs index c911c0d..264ca47 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs @@ -14,7 +14,7 @@ public enum OutlineRenderFlags /// /// Outline frame is a solid line. /// - Solid = 0, + None = 0, /// /// Outline frame is blurred. From dc7d2600ac8bd56d758b72aa372aacd68c7b13b1 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Thu, 7 May 2020 00:19:07 +0300 Subject: [PATCH 08/61] Outline shader refactoring, merged h/v passes into a single shader --- .../Runtime/Scripts/OutlineRenderer.cs | 48 ++--- .../Runtime/Scripts/OutlineResources.cs | 79 ++------- .../Runtime/Shaders/Outline.shader | 166 ++++++++++++++++++ ...ePass1.shader.meta => Outline.shader.meta} | 0 ...RenderColor.shader => OutlineColor.shader} | 2 +- ...r.shader.meta => OutlineColor.shader.meta} | 0 .../Runtime/Shaders/OutlineCommon.hlsl | 51 ------ .../Runtime/Shaders/OutlineCommon.hlsl.meta | 9 - .../Runtime/Shaders/OutlinePass1.shader | 79 --------- .../Runtime/Shaders/OutlinePass2.shader | 94 ---------- .../Runtime/Shaders/OutlinePass2.shader.meta | 8 - 11 files changed, 209 insertions(+), 327 deletions(-) create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader rename Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/{OutlinePass1.shader.meta => Outline.shader.meta} (100%) rename Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/{OutlineRenderColor.shader => OutlineColor.shader} (94%) rename Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/{OutlineRenderColor.shader.meta => OutlineColor.shader.meta} (100%) delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 737c394..4628c0c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -63,6 +63,11 @@ public struct OutlineRenderer : IDisposable { #region data + private const int _hPassId_35 = 0; + private const int _hPassId = 1; + private const int _vPassId_35 = 2; + private const int _vPassId = 3; + private static readonly int _mainRtId = Shader.PropertyToID("_MainTex"); private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex"); @@ -355,6 +360,22 @@ public void Dispose() private void Init(OutlineResources resources, IOutlineSettings settings) { + // Shader parameter overrides (shared between all passes). + var props = resources.Properties; + + props.SetFloat(resources.WidthId, settings.OutlineWidth); + props.SetColor(resources.ColorId, settings.OutlineColor); + + if ((settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0) + { + props.SetFloat(resources.IntensityId, settings.OutlineIntensity); + } + else + { + props.SetFloat(resources.IntensityId, SolidIntensity); + } + + // Gauss samples. _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); } @@ -443,10 +464,6 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, private void RenderHPass(OutlineResources resources, IOutlineSettings settings) { - // Setup shader parameter overrides. - var props = resources.HPassProperties; - props.SetFloat(resources.WidthId, settings.OutlineWidth); - // Set source texture as _MainTex to match Blit behavior. _commandBuffer.SetGlobalTexture(_mainRtId, _maskRtId); @@ -460,31 +477,16 @@ private void RenderHPass(OutlineResources resources, IOutlineSettings settings) // Blit fullscreen triangle. if (SystemInfo.graphicsShaderLevel >= 35) { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.HPassMaterial, -1, MeshTopology.Triangles, 3, 1, props); + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _hPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); } else { - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, -1, props); + _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.OutlineMaterial, 0, _hPassId, resources.Properties); } } private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings) { - // Setup shader parameter overrides. - var props = resources.VPassBlendProperties; - - props.SetFloat(resources.WidthId, settings.OutlineWidth); - props.SetColor(resources.ColorId, settings.OutlineColor); - - if ((settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0) - { - props.SetFloat(resources.IntensityId, settings.OutlineIntensity); - } - else - { - props.SetFloat(resources.IntensityId, SolidIntensity); - } - // Set source texture as _MainTex to match Blit behavior. _commandBuffer.SetGlobalTexture(_mainRtId, _hPassRtId); @@ -498,11 +500,11 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti // Blit fullscreen triangle. if (SystemInfo.graphicsShaderLevel >= 35) { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.VPassBlendMaterial, -1, MeshTopology.Triangles, 3, 1, props); + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _vPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); } else { - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, -1, props); + _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.OutlineMaterial, 0, _vPassId, resources.Properties); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 74502c3..6e7fe4e 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using UnityEngine; -using UnityEngine.Rendering; namespace UnityFx.Outline { @@ -18,10 +17,8 @@ public sealed class OutlineResources : ScriptableObject #region data private Material _renderMaterial; - private Material _hPassMaterial; - private Material _vPassMaterial; - private MaterialPropertyBlock _hPassProperties; - private MaterialPropertyBlock _vPassProperties; + private Material _outlineMaterial; + private MaterialPropertyBlock _props; private Mesh _fullscreenTriangleMesh; private float[][] _gaussSamples; @@ -60,14 +57,9 @@ public sealed class OutlineResources : ScriptableObject public Shader RenderShader; /// - /// Gets or sets a that renders outline around the mask, that was generated with (pass 1). + /// Gets or sets a that renders outline around the mask, that was generated with . /// - public Shader HPassShader; - - /// - /// Gets or sets a that renders outline around the mask, that was generated with and (pass 2). - /// - public Shader VPassBlendShader; + public Shader OutlineShader; /// /// Gets a -based material. @@ -90,74 +82,38 @@ public Material RenderMaterial } /// - /// Gets a -based material. - /// - public Material HPassMaterial - { - get - { - if (_hPassMaterial == null) - { - _hPassMaterial = new Material(HPassShader) - { - name = "Outline - HPassRender", - hideFlags = HideFlags.HideAndDontSave - }; - } - - return _hPassMaterial; - } - } - - /// - /// Gets a -based material. + /// Gets a -based material. /// - public Material VPassBlendMaterial + public Material OutlineMaterial { get { - if (_vPassMaterial == null) + if (_outlineMaterial == null) { - _vPassMaterial = new Material(VPassBlendShader) + _outlineMaterial = new Material(OutlineShader) { - name = "Outline - VPassBlendRender", + name = "Outline - Main", hideFlags = HideFlags.HideAndDontSave }; } - return _vPassMaterial; - } - } - - /// - /// Gets a for . - /// - public MaterialPropertyBlock HPassProperties - { - get - { - if (_hPassProperties == null) - { - _hPassProperties = new MaterialPropertyBlock(); - } - - return _hPassProperties; + return _outlineMaterial; } } /// /// Gets a for . /// - public MaterialPropertyBlock VPassBlendProperties + public MaterialPropertyBlock Properties { get { - if (_vPassProperties == null) + if (_props == null) { - _vPassProperties = new MaterialPropertyBlock(); + _props = new MaterialPropertyBlock(); } - return _vPassProperties; + return _props; } } @@ -202,7 +158,7 @@ public bool IsValid { get { - return RenderShader && HPassShader && VPassBlendShader; + return RenderShader && OutlineShader; } } @@ -231,9 +187,8 @@ public float[] GetGaussSamples(int width) /// public void ResetToDefaults() { - RenderShader = Shader.Find("UnityFx/Outline/RenderColor"); - HPassShader = Shader.Find("UnityFx/Outline/HPass"); - VPassBlendShader = Shader.Find("UnityFx/Outline/VPassBlend"); + RenderShader = Shader.Find("Hidden/UnityFx/OutlineColor"); + OutlineShader = Shader.Find("Hidden/UnityFx/Outline"); } #endregion diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader new file mode 100644 index 0000000..86ade8e --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -0,0 +1,166 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +// Renders outline based on a texture produces by 'UnityF/Outline/RenderColor' output. +// Modified version of 'Custom/Post Outline' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. +Shader "Hidden/UnityFx/Outline" +{ + Properties + { + _Width("Outline thickness (in pixels)", Range(1, 32)) = 5 + _Intensity("Outline intensity", Range(0.1, 100)) = 2 + _Color("Outline color", Color) = (1, 0, 0, 1) + } + + HLSLINCLUDE + + #include "UnityCG.cginc" + + CBUFFER_START(UnityPerMaterial) + float _Intensity; + int _Width; + float4 _Color; + CBUFFER_END + + UNITY_DECLARE_TEX2D(_MainTex); + float2 _MainTex_TexelSize; + UNITY_DECLARE_TEX2D(_MaskTex); + float _GaussSamples[32]; + +#if SHADER_TARGET >= 35 + + struct appdata_vid + { + uint vertexID : SV_VertexID; + }; + + v2f_img vert_35(appdata_vid v) + { + v2f_img o; + UNITY_INITIALIZE_OUTPUT(v2f_img, o); + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + // Generate a triangle in homogeneous clip space, s.t. + // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). + float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); + o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); + +#if UNITY_UV_STARTS_AT_TOP + o.uv = half2(uv.x, 1 - uv.y); +#else + o.uv = uv; +#endif + + return o; + } + +#endif + + v2f_img vert(appdata_img v) + { + v2f_img o; + UNITY_INITIALIZE_OUTPUT(v2f_img, o); + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); + o.uv = ComputeScreenPos(o.pos); + + return o; + } + + float4 frag_h(v2f_img i) : SV_Target + { + float TX_x = _MainTex_TexelSize.x; + float intensity; + int n = _Width; + + for (int k = -n; k <= n; k += 1) + { + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; + } + + return intensity; + } + + float4 frag_v(v2f_img i) : SV_Target + { + if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) + { + discard; + } + + float TX_y = _MainTex_TexelSize.y; + float intensity; + int n = _Width; + + for (int k = -n; k <= _Width; k += 1) + { + intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; + } + + intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; + return float4(_Color.rgb, saturate(_Color.a * intensity)); + } + + ENDHLSL + + SubShader + { + Cull Off + ZWrite Off + ZTest Always + Lighting Off + + // 0) HPass SM3.5+ + Pass + { + HLSLPROGRAM + + #pragma target 3.5 + #pragma vertex vert_35 + #pragma fragment frag_h + + ENDHLSL + } + + // 1) HPass SM2.0 + Pass + { + HLSLPROGRAM + + #pragma vertex vert + #pragma fragment frag_h + + ENDHLSL + } + + // 2) VPass SM3.5+ + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + + HLSLPROGRAM + + #pragma target 3.5 + #pragma vertex vert_35 + #pragma fragment frag_v + + ENDHLSL + } + + // 3) VPass SM2.0 + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + + HLSLPROGRAM + + #pragma vertex vert + #pragma fragment frag_v + + ENDHLSL + } + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader.meta similarity index 100% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader.meta rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader similarity index 94% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader index 23d7379..8f100a8 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader @@ -3,7 +3,7 @@ // Renders everything with while color. // Modified version of 'Custom/DrawSimple' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. -Shader "UnityFx/Outline/RenderColor" +Shader "Hidden/UnityFx/OutlineColor" { SubShader { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader.meta similarity index 100% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader.meta rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl deleted file mode 100644 index b49445a..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef OUTLINE_COMMON_INCLUDED -#define OUTLINE_COMMON_INCLUDED - -#include "UnityCG.cginc" - -#if SHADER_TARGET < 35 - -v2f_img vert(appdata_img v) -{ - v2f_img o; - UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_SETUP_INSTANCE_ID(v); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); - o.uv = ComputeScreenPos(o.pos); - - return o; -} - -#else - -struct appdata_vid -{ - uint vertexID : SV_VertexID; -}; - -v2f_img vert_vid(appdata_vid v) -{ - v2f_img o; - UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_SETUP_INSTANCE_ID(v); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - // Generate a triangle in homogeneous clip space, s.t. - // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). - float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); - o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); - -#if UNITY_UV_STARTS_AT_TOP - o.uv = half2(uv.x, 1 - uv.y); -#else - o.uv = uv; -#endif - - return o; -} - -#endif - -#endif // OUTLINE_COMMON_INCLUDED diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta deleted file mode 100644 index 2515841..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineCommon.hlsl.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: cc973aab804133b48b3f3cabc7971d26 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader deleted file mode 100644 index fd33084..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -// Renders outline based on a texture produces by 'UnityF/Outline/RenderColor' output. -// Modified version of 'Custom/Post Outline' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. -Shader "UnityFx/Outline/HPass" -{ - Properties - { - _Width("Outline thickness (in pixels)", Range(1, 32)) = 5 - } - - HLSLINCLUDE - - #include "OutlineCommon.hlsl" - - CBUFFER_START(UnityPerMaterial) - int _Width; - CBUFFER_END - - UNITY_DECLARE_TEX2D(_MainTex); - float2 _MainTex_TexelSize; - float _GaussSamples[32]; - - float4 frag(v2f_img i) : SV_Target - { - float TX_x = _MainTex_TexelSize.x; - float intensity; - int n = _Width; - - for (int k = -n; k <= n; k += 1) - { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; - } - - return intensity; - } - - ENDHLSL - - // SM3.5+ - SubShader - { - Cull Off - ZWrite Off - ZTest Always - Lighting Off - - Pass - { - HLSLPROGRAM - - #pragma target 3.5 - #pragma vertex vert_vid - #pragma fragment frag - - ENDHLSL - } - } - - // SM2.0 - SubShader - { - Cull Off - ZWrite Off - ZTest Always - Lighting Off - - Pass - { - HLSLPROGRAM - - #pragma vertex vert - #pragma fragment frag - - ENDHLSL - } - } -} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader deleted file mode 100644 index fcfef3b..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -// Renders outline based on a texture produces by 'UnityF/Outline/RenderColor' output. -// Modified version of 'Custom/Post Outline' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. -Shader "UnityFx/Outline/VPassBlend" -{ - Properties - { - _Width("Outline thickness (in pixels)", Range(1, 32)) = 5 - _Intensity("Outline intensity", Range(0.1, 100)) = 2 - _Color("Outline color", Color) = (1, 0, 0, 1) - } - - HLSLINCLUDE - - #include "OutlineCommon.hlsl" - - CBUFFER_START(UnityPerMaterial) - float _Intensity; - int _Width; - float4 _Color; - CBUFFER_END - - UNITY_DECLARE_TEX2D(_MainTex); - float2 _MainTex_TexelSize; - UNITY_DECLARE_TEX2D(_MaskTex); - float _GaussSamples[32]; - - float4 frag(v2f_img i) : SV_Target - { - if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) - { - discard; - } - - float TX_y = _MainTex_TexelSize.y; - float intensity; - int n = _Width; - - for (int k = -n; k <= _Width; k += 1) - { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; - } - - intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; - return float4(_Color.rgb, saturate(_Color.a * intensity)); - } - - ENDHLSL - - // SM3.5+ - SubShader - { - Cull Off - ZWrite Off - ZTest Always - Lighting Off - - Blend SrcAlpha OneMinusSrcAlpha - - Pass - { - HLSLPROGRAM - - #pragma target 3.5 - #pragma vertex vert_vid - #pragma fragment frag - - ENDHLSL - } - } - - // SM2.0 - SubShader - { - Cull Off - ZWrite Off - ZTest Always - Lighting Off - - Blend SrcAlpha OneMinusSrcAlpha - - Pass - { - HLSLPROGRAM - - #pragma vertex vert - #pragma fragment frag - - ENDHLSL - } - } -} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader.meta deleted file mode 100644 index 5852e4b..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1df0cb1700e142f4ca3b28297d3957da -ShaderImporter: - externalObjects: {} - defaultTextures: [] - userData: - assetBundleName: - assetBundleVariant: From e69d78af7ec35d93ba5ff262b4ab8b0462ac0385 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Thu, 7 May 2020 00:33:22 +0300 Subject: [PATCH 09/61] Added possibility to force DrawMesh instead of DrawProcedural for outline rendering --- .../UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs | 7 ++++++- .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs index 264ca47..a762f0e 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs @@ -24,6 +24,11 @@ public enum OutlineRenderFlags /// /// Enabled depth testing when rendering object outlines. Only visible parts of objects are outlined. /// - EnableDepthTesting = 0x100 + EnableDepthTesting = 2, + + /// + /// If set, DrawMesh() is used instead of DrawProcedural() even for SM3.5+ capable hardware. + /// + UseLegacyRenderer = 0x100 } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 4628c0c..707a7e2 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -475,7 +475,7 @@ private void RenderHPass(OutlineResources resources, IOutlineSettings settings) #endif // Blit fullscreen triangle. - if (SystemInfo.graphicsShaderLevel >= 35) + if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) { _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _hPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); } @@ -498,7 +498,7 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti #endif // Blit fullscreen triangle. - if (SystemInfo.graphicsShaderLevel >= 35) + if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) { _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _vPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); } From 6035afa392147174af2da24cc3ed046f45439524 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Thu, 7 May 2020 01:04:17 +0300 Subject: [PATCH 10/61] tt --- .../Runtime/Prefabs/OutlineResources.asset | 8 ++--- .../Runtime/Shaders/Outline.shader | 33 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset b/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset index 5b0a0c7..26305ad 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset @@ -3,8 +3,9 @@ --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 @@ -12,5 +13,4 @@ MonoBehaviour: m_Name: OutlineResources m_EditorClassIdentifier: RenderShader: {fileID: 4800000, guid: ac20fbf75bafe454aba5ef3c098349df, type: 3} - HPassShader: {fileID: 4800000, guid: 41c9acbf41c8245498ac9beab378de12, type: 3} - VPassBlendShader: {fileID: 4800000, guid: 1df0cb1700e142f4ca3b28297d3957da, type: 3} + OutlineShader: {fileID: 4800000, guid: ac20fbf75bafe454aba5ef3c098349df, type: 3} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 86ade8e..b8ca8d3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -1,7 +1,7 @@ // Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. // See the LICENSE.md file in the project root for more information. -// Renders outline based on a texture produces by 'UnityF/Outline/RenderColor' output. +// Renders outline based on a texture produced with 'UnityF/OutlineColor'. // Modified version of 'Custom/Post Outline' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. Shader "Hidden/UnityFx/Outline" { @@ -22,9 +22,9 @@ Shader "Hidden/UnityFx/Outline" float4 _Color; CBUFFER_END + UNITY_DECLARE_TEX2D(_MaskTex); UNITY_DECLARE_TEX2D(_MainTex); float2 _MainTex_TexelSize; - UNITY_DECLARE_TEX2D(_MaskTex); float _GaussSamples[32]; #if SHADER_TARGET >= 35 @@ -42,7 +42,7 @@ Shader "Hidden/UnityFx/Outline" UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); // Generate a triangle in homogeneous clip space, s.t. - // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). + // v0 = (-1, -1), v1 = (3, -1), v2 = (-1, 3). float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); @@ -70,36 +70,35 @@ Shader "Hidden/UnityFx/Outline" return o; } - float4 frag_h(v2f_img i) : SV_Target + float CalcIntensity(float2 uv, float2 offset) { - float TX_x = _MainTex_TexelSize.x; float intensity; int n = _Width; - for (int k = -n; k <= n; k += 1) + // Accumulates horizontal or vertical blur intensity for the specified texture position. + // Set offset = (tx, 0) for horizontal sampling and offset = (0, ty) for vertical. + for (int k = -n; k <= _Width; k += 1) { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)]; + intensity += UNITY_SAMPLE_TEX2D(_MainTex, uv + k * offset).r * _GaussSamples[abs(k)]; } return intensity; } + float4 frag_h(v2f_img i) : SV_Target + { + return CalcIntensity(i.uv, float2(_MainTex_TexelSize.x, 0)); + } + float4 frag_v(v2f_img i) : SV_Target { - if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) + if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r == 0) { + // TODO: Avoid discard/clip to improve performance on mobiles. discard; } - float TX_y = _MainTex_TexelSize.y; - float intensity; - int n = _Width; - - for (int k = -n; k <= _Width; k += 1) - { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, i.uv + float2(0, k * TX_y)).r * _GaussSamples[abs(k)]; - } - + float intensity = CalcIntensity(i.uv, float2(0, _MainTex_TexelSize.y)); intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; return float4(_Color.rgb, saturate(_Color.a * intensity)); } From eacca5e4746f78ff74f6c60c02af6391e2c9a038 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Thu, 7 May 2020 13:31:32 +0300 Subject: [PATCH 11/61] Misc outline fixes --- .../Runtime/Prefabs/OutlineResources.asset | 2 +- .../Runtime/Scripts/OutlineRenderer.cs | 10 ++- .../Runtime/Shaders/Outline.shader | 68 ++++++++++++------- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset b/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset index 26305ad..285880e 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Prefabs/OutlineResources.asset @@ -13,4 +13,4 @@ MonoBehaviour: m_Name: OutlineResources m_EditorClassIdentifier: RenderShader: {fileID: 4800000, guid: ac20fbf75bafe454aba5ef3c098349df, type: 3} - OutlineShader: {fileID: 4800000, guid: ac20fbf75bafe454aba5ef3c098349df, type: 3} + OutlineShader: {fileID: 4800000, guid: 41c9acbf41c8245498ac9beab378de12, type: 3} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 707a7e2..f38f1af 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -63,10 +63,8 @@ public struct OutlineRenderer : IDisposable { #region data - private const int _hPassId_35 = 0; - private const int _hPassId = 1; - private const int _vPassId_35 = 2; - private const int _vPassId = 3; + private const int _hPassId = 0; + private const int _vPassId = 1; private static readonly int _mainRtId = Shader.PropertyToID("_MainTex"); private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); @@ -477,7 +475,7 @@ private void RenderHPass(OutlineResources resources, IOutlineSettings settings) // Blit fullscreen triangle. if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _hPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _hPassId, MeshTopology.Triangles, 3, 1, resources.Properties); } else { @@ -500,7 +498,7 @@ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings setti // Blit fullscreen triangle. if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _vPassId_35, MeshTopology.Triangles, 3, 1, resources.Properties); + _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _vPassId, MeshTopology.Triangles, 3, 1, resources.Properties); } else { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index b8ca8d3..7ce9ba0 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -27,7 +27,22 @@ Shader "Hidden/UnityFx/Outline" float2 _MainTex_TexelSize; float _GaussSamples[32]; -#if SHADER_TARGET >= 35 +#if SHADER_TARGET < 35 + + v2f_img vert(appdata_img v) + { + v2f_img o; + UNITY_INITIALIZE_OUTPUT(v2f_img, o); + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); + o.uv = ComputeScreenPos(o.pos); + + return o; + } + +#else struct appdata_vid { @@ -57,19 +72,6 @@ Shader "Hidden/UnityFx/Outline" #endif - v2f_img vert(appdata_img v) - { - v2f_img o; - UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_SETUP_INSTANCE_ID(v); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - - o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); - o.uv = ComputeScreenPos(o.pos); - - return o; - } - float CalcIntensity(float2 uv, float2 offset) { float intensity; @@ -92,7 +94,7 @@ Shader "Hidden/UnityFx/Outline" float4 frag_v(v2f_img i) : SV_Target { - if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r == 0) + if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) { // TODO: Avoid discard/clip to improve performance on mobiles. discard; @@ -105,6 +107,7 @@ Shader "Hidden/UnityFx/Outline" ENDHLSL + // SM3.5+ SubShader { Cull Off @@ -112,9 +115,11 @@ Shader "Hidden/UnityFx/Outline" ZTest Always Lighting Off - // 0) HPass SM3.5+ + // 0) HPass Pass { + Name "HPass" + HLSLPROGRAM #pragma target 3.5 @@ -124,34 +129,47 @@ Shader "Hidden/UnityFx/Outline" ENDHLSL } - // 1) HPass SM2.0 + // 1) VPass Pass { + Name "VPassBlend" + Blend SrcAlpha OneMinusSrcAlpha + HLSLPROGRAM - #pragma vertex vert - #pragma fragment frag_h + #pragma target 3.5 + #pragma vertex vert_35 + #pragma fragment frag_v ENDHLSL } + } - // 2) VPass SM3.5+ + // SM2.0 + SubShader + { + Cull Off + ZWrite Off + ZTest Always + Lighting Off + + // 0) HPass Pass { - Blend SrcAlpha OneMinusSrcAlpha + Name "HPass" HLSLPROGRAM - #pragma target 3.5 - #pragma vertex vert_35 - #pragma fragment frag_v + #pragma vertex vert + #pragma fragment frag_h ENDHLSL } - // 3) VPass SM2.0 + // 1) VPass Pass { + Name "VPassBlend" Blend SrcAlpha OneMinusSrcAlpha HLSLPROGRAM From 94de865ca0d64f95b278a3a56a960658f557620c Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Thu, 7 May 2020 15:22:07 +0300 Subject: [PATCH 12/61] Fixed outline flipped Y coordinate on some devices --- .../UnityFx.Outline/Runtime/Shaders/Outline.shader | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 7ce9ba0..f115c04 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -60,12 +60,7 @@ Shader "Hidden/UnityFx/Outline" // v0 = (-1, -1), v1 = (3, -1), v2 = (-1, 3). float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); - -#if UNITY_UV_STARTS_AT_TOP - o.uv = half2(uv.x, 1 - uv.y); -#else - o.uv = uv; -#endif + o.uv = ComputeScreenPos(o.pos); return o; } From 5c29a0339ca15010fc65777ea5f3b543472ca58f Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Thu, 7 May 2020 17:10:20 +0300 Subject: [PATCH 13/61] Minor outline shader changes --- .../Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index f115c04..5913862 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -49,7 +49,7 @@ Shader "Hidden/UnityFx/Outline" uint vertexID : SV_VertexID; }; - v2f_img vert_35(appdata_vid v) + v2f_img vert(appdata_vid v) { v2f_img o; UNITY_INITIALIZE_OUTPUT(v2f_img, o); @@ -118,7 +118,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 - #pragma vertex vert_35 + #pragma vertex vert #pragma fragment frag_h ENDHLSL @@ -133,7 +133,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 - #pragma vertex vert_35 + #pragma vertex vert #pragma fragment frag_v ENDHLSL From ce413ead085424c9d2d56066895e1ae5f8bd6331 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Thu, 7 May 2020 18:55:18 +0300 Subject: [PATCH 14/61] Added depth testing support for both forward and deferred renderers --- .../Runtime/Scripts/OutlineBehaviour.cs | 96 +++++++------------ .../Runtime/Scripts/OutlineEffect.cs | 19 ++-- .../Runtime/Scripts/OutlineLayer.cs | 4 +- .../Runtime/Scripts/OutlineLayerCollection.cs | 4 +- .../Runtime/Scripts/OutlineRenderFlags.cs | 2 +- .../Runtime/Scripts/OutlineRenderer.cs | 39 ++++---- .../Runtime/Shaders/OutlineColor.shader | 17 ++-- 7 files changed, 83 insertions(+), 98 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 325b329..52bd895 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -30,11 +30,9 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettingsEx #pragma warning restore 0649 - private OutlineRendererCollection _renderers; - private CommandBuffer _commandBuffer; - private Dictionary _cameraMap = new Dictionary(); - private float _cameraMapUpdateTimer; + private List _camerasToRemove = new List(); + private OutlineRendererCollection _renderers; #endregion @@ -112,7 +110,6 @@ private void OnDestroy() private void OnEnable() { - CreateCommandBufferIfNeeded(); Camera.onPreRender += OnCameraPreRender; } @@ -126,39 +123,51 @@ private void OnDisable() { kvp.Key.RemoveCommandBuffer(OutlineRenderer.RenderEvent, kvp.Value); } + + kvp.Value.Dispose(); } _cameraMap.Clear(); - - if (_commandBuffer != null) - { - _commandBuffer.Dispose(); - _commandBuffer = null; - } } private void Update() { - _cameraMapUpdateTimer += Time.deltaTime; - - if (_cameraMapUpdateTimer > 16) - { - RemoveDestroyedCameras(); - _cameraMapUpdateTimer = 0; - } - if (_outlineResources != null && _renderers != null) { + _camerasToRemove.Clear(); + if (_updateRenderers) { _renderers.Reset(false); } - _commandBuffer.Clear(); + foreach (var kvp in _cameraMap) + { + var camera = kvp.Key; + var cmdBuffer = kvp.Value; - using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) + if (camera) + { + cmdBuffer.Clear(); + + if (_renderers.Count > 0) + { + using (var renderer = new OutlineRenderer(cmdBuffer, BuiltinRenderTextureType.CameraTarget)) + { + renderer.Render(_renderers.GetList(), _outlineSettings.OutlineResources, _outlineSettings, camera.actualRenderingPath); + } + } + } + else + { + cmdBuffer.Dispose(); + _camerasToRemove.Add(camera); + } + } + + foreach (var camera in _camerasToRemove) { - renderer.Render(_renderers.GetList(), _outlineSettings.OutlineResources, _outlineSettings); + _cameraMap.Remove(camera); } } } @@ -168,7 +177,6 @@ private void Update() private void OnValidate() { CreateRenderersIfNeeded(); - CreateCommandBufferIfNeeded(); CreateSettingsIfNeeded(); _outlineSettings.OutlineResources = _outlineResources; @@ -307,49 +315,15 @@ private void OnCameraPreRender(Camera camera) if (!_cameraMap.ContainsKey(camera)) { - camera.AddCommandBuffer(OutlineRenderer.RenderEvent, _commandBuffer); - _cameraMap.Add(camera, _commandBuffer); - } - } - } - - private void RemoveDestroyedCameras() - { - List camerasToRemove = null; - - foreach (var camera in _cameraMap.Keys) - { - if (camera == null) - { - if (camerasToRemove != null) - { - camerasToRemove.Add(camera); - } - else - { - camerasToRemove = new List() { camera }; - } - } - } + var cmdBuf = new CommandBuffer(); + cmdBuf.name = string.Format("{0} - {1}", GetType().Name, name); + camera.AddCommandBuffer(OutlineRenderer.RenderEvent, cmdBuf); - if (camerasToRemove != null) - { - foreach (var camera in camerasToRemove) - { - _cameraMap.Remove(camera); + _cameraMap.Add(camera, cmdBuf); } } } - private void CreateCommandBufferIfNeeded() - { - if (_commandBuffer == null) - { - _commandBuffer = new CommandBuffer(); - _commandBuffer.name = string.Format("{0} - {1}", GetType().Name, name); - } - } - private void CreateSettingsIfNeeded() { if (_outlineSettings == null) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index a4bacb8..3414ef4 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -28,6 +28,7 @@ public sealed partial class OutlineEffect : MonoBehaviour [SerializeField, HideInInspector] private CameraEvent _cameraEvent = OutlineRenderer.RenderEvent; + private Camera _camera; private CommandBuffer _commandBuffer; #endregion @@ -153,27 +154,25 @@ private void Awake() private void OnEnable() { - var camera = GetComponent(); + _camera = GetComponent(); - if (camera) + if (_camera) { _commandBuffer = new CommandBuffer { name = string.Format("{0} - {1}", GetType().Name, name) }; - camera.depthTextureMode |= DepthTextureMode.Depth; - camera.AddCommandBuffer(_cameraEvent, _commandBuffer); + _camera.depthTextureMode |= DepthTextureMode.Depth; + _camera.AddCommandBuffer(_cameraEvent, _commandBuffer); } } private void OnDisable() { - var camera = GetComponent(); - - if (camera) + if (_camera) { - camera.RemoveCommandBuffer(_cameraEvent, _commandBuffer); + _camera.RemoveCommandBuffer(_cameraEvent, _commandBuffer); } if (_commandBuffer != null) @@ -185,7 +184,7 @@ private void OnDisable() private void Update() { - if (_outlineLayers) + if (_camera && _outlineLayers) { FillCommandBuffer(); } @@ -221,7 +220,7 @@ private void FillCommandBuffer() { using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) { - _outlineLayers.Render(renderer, _outlineResources); + _outlineLayers.Render(renderer, _outlineResources, _camera.actualRenderingPath); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index eac4774..5cc8e09 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -207,7 +207,7 @@ public bool TryGetRenderers(GameObject go, out ICollection renderers) /// /// Renders the layers. /// - public void Render(OutlineRenderer renderer, OutlineResources resources) + public void Render(OutlineRenderer renderer, OutlineResources resources, RenderingPath renderingPath) { if (_enabled) { @@ -217,7 +217,7 @@ public void Render(OutlineRenderer renderer, OutlineResources resources) { if (kvp.Key && kvp.Key.activeInHierarchy) { - renderer.Render(kvp.Value.GetList(), resources, _settings); + renderer.Render(kvp.Value.GetList(), resources, _settings, renderingPath); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index d28f982..3a3ace2 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -53,13 +53,13 @@ public OutlineLayer[] SortedLayers /// /// Renders all layers. /// - public void Render(OutlineRenderer renderer, OutlineResources resources) + public void Render(OutlineRenderer renderer, OutlineResources resources, RenderingPath renderingPath) { UpdateSortedLayersIfNeeded(); foreach (var layer in _sortedLayers) { - layer.Render(renderer, resources); + layer.Render(renderer, resources, renderingPath); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs index a762f0e..a070049 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs @@ -27,7 +27,7 @@ public enum OutlineRenderFlags EnableDepthTesting = 2, /// - /// If set, DrawMesh() is used instead of DrawProcedural() even for SM3.5+ capable hardware. + /// If set, DrawMesh() is used instead of DrawProcedural() even for SM3.5+ capable hardware. Do not use unless you exaclty know what you're doing. /// UseLegacyRenderer = 0x100 } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index f38f1af..44dda59 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -208,10 +208,11 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, /// One or more renderers representing a single object to be outlined. /// Outline resources. /// Outline settings. + /// Rendering path used by the target camera (used is is set). /// Thrown if any of the arguments is . /// /// - public void Render(IList renderers, OutlineResources resources, IOutlineSettings settings) + public void Render(IList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) { if (renderers == null) { @@ -231,7 +232,7 @@ public void Render(IList renderers, OutlineResources resources, IOutli if (renderers.Count > 0) { Init(resources, settings); - RenderObject(resources, settings, renderers); + RenderObject(resources, settings, renderers, renderingPath); RenderHPass(resources, settings); RenderVPassBlend(resources, settings); } @@ -243,10 +244,11 @@ public void Render(IList renderers, OutlineResources resources, IOutli /// One or more renderers representing a single object to be outlined. /// Outline resources. /// Outline settings. + /// Rendering path used by the target camera (used is is set). /// Thrown if any of the arguments is . /// /// - public void Render(IEnumerable renderers, OutlineResources resources, IOutlineSettings settings) + public void Render(IEnumerable renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) { if (renderers == null) { @@ -264,7 +266,7 @@ public void Render(IEnumerable renderers, OutlineResources resources, } Init(resources, settings); - RenderObject(resources, settings, renderers); + RenderObject(resources, settings, renderers, renderingPath); RenderHPass(resources, settings); RenderVPassBlend(resources, settings); } @@ -275,10 +277,11 @@ public void Render(IEnumerable renderers, OutlineResources resources, /// A representing an object to be outlined. /// Outline resources. /// Outline settings. + /// Rendering path used by the target camera (used is is set). /// Thrown if any of the arguments is . /// /// - public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings) + public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) { if (renderer == null) { @@ -296,7 +299,7 @@ public void Render(Renderer renderer, OutlineResources resources, IOutlineSettin } Init(resources, settings); - RenderObject(resources, settings, renderer); + RenderObject(resources, settings, renderer, renderingPath); RenderHPass(resources, settings); RenderVPassBlend(resources, settings); } @@ -377,15 +380,19 @@ private void Init(OutlineResources resources, IOutlineSettings settings) _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); } - private void RenderObjectClear(bool depthTestEnabled) + private void RenderObjectClear(OutlineRenderFlags flags, RenderingPath renderingPath) { - if (depthTestEnabled) + if ((flags & OutlineRenderFlags.EnableDepthTesting) != 0) { + // Have to use BuiltinRenderTextureType.ResolvedDepth for deferred, BuiltinRenderTextureType.Depth for forward. + var depthTextureId = (renderingPath == RenderingPath.DeferredShading || renderingPath == RenderingPath.DeferredLighting) ? + BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth; + // NOTE: Use the camera depth buffer when rendering the mask. Shader only reads from the depth buffer (ZWrite Off). #if UNITY_2018_2_OR_NEWER - _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, BuiltinRenderTextureType.Depth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); + _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, depthTextureId, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); #else - _commandBuffer.SetRenderTarget(_maskRtId, BuiltinRenderTextureType.Depth); + _commandBuffer.SetRenderTarget(_maskRtId, depthTextureId); #endif } else @@ -400,9 +407,9 @@ private void RenderObjectClear(bool depthTestEnabled) _commandBuffer.ClearRenderTarget(false, true, Color.clear); } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IList renderers) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, IList renderers, RenderingPath renderingPath) { - RenderObjectClear((settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0); + RenderObjectClear(settings.OutlineRenderMode, renderingPath); for (var i = 0; i < renderers.Count; ++i) { @@ -422,9 +429,9 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, } } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IEnumerable renderers) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, IEnumerable renderers, RenderingPath renderingPath) { - RenderObjectClear((settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0); + RenderObjectClear(settings.OutlineRenderMode, renderingPath); // NOTE: Calling IEnumerable.GetEnumerator() triggers GC.Alloc. foreach (var r in renderers) @@ -443,9 +450,9 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, } } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer, RenderingPath renderingPath) { - RenderObjectClear((settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0); + RenderObjectClear(settings.OutlineRenderMode, renderingPath); if (renderer && renderer.gameObject.activeInHierarchy && renderer.enabled) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader index 8f100a8..bca1a57 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader @@ -5,6 +5,17 @@ // Modified version of 'Custom/DrawSimple' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. Shader "Hidden/UnityFx/OutlineColor" { + HLSLINCLUDE + + #include "UnityCG.cginc" + + half4 frag() : SV_Target + { + return 1; + } + + ENDHLSL + SubShader { Cull Off @@ -18,12 +29,6 @@ Shader "Hidden/UnityFx/OutlineColor" #pragma vertex vert_img #pragma fragment frag - #include "UnityCG.cginc" - - half4 frag(): SV_Target - { - return half4(1, 1, 1, 1); - } ENDHLSL } From 63fd010e5b75dc6f7a376552184a9cf7aea0e1a8 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Thu, 7 May 2020 19:13:07 +0300 Subject: [PATCH 15/61] README update --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bd34d56..4fbc74e 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,14 @@ Supported outline parameters are: - Color; - Width (in pixels); - Type (solid or blurred); -- Intensity (for blurred outlines). +- Intensity (for blurred outlines); +- Depth testing. Supported platforms: - Windows/Mac standalone; - Android; -- iOS. +- iOS; +- Other platforms (untested). Please see [CHANGELOG](CHANGELOG.md) for information on recent changes. @@ -164,7 +166,7 @@ var resources = GetMyResources(); using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget)) { - renderer.Render(renderers, resources, settings); + renderer.Render(renderers, resources, settings, myCamera.actualRenderingPath); } myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer); From a483259f24e398fd015124b387ca01d50689f1e6 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Fri, 8 May 2020 00:12:18 +0300 Subject: [PATCH 16/61] Added URP skeleton --- Outline.URP/Assets/Example.meta | 8 + .../Assets/Example/OutlineFeature.asset | 14 + .../Assets/Example/OutlineFeature.asset.meta | 8 + .../Example/OutlineLayerCollection.asset | 33 + .../Example/OutlineLayerCollection.asset.meta | 8 + Outline.URP/Assets/Example/OutlineTest.cs | 31 + .../Assets/Example/OutlineTest.cs.meta | 11 + Outline.URP/Assets/Example/Test.unity | 633 ++++++++++++++++++ Outline.URP/Assets/Example/Test.unity.meta | 7 + Outline.URP/Assets/URP.meta | 8 + .../URP/UniversalRenderPipelineAsset.asset | 54 ++ .../UniversalRenderPipelineAsset.asset.meta | 8 + ...niversalRenderPipelineAsset_Renderer.asset | 35 + ...salRenderPipelineAsset_Renderer.asset.meta | 8 + .../Packages/UnityFx.Outline.URP/CHANGELOG.md | 9 + .../UnityFx.Outline.URP/CHANGELOG.md.meta | 7 + .../Packages/UnityFx.Outline.URP/README.md | 11 + .../UnityFx.Outline.URP/README.md.meta | 7 + .../Packages/UnityFx.Outline.URP/Runtime.meta | 8 + .../UnityFx.Outline.URP/Runtime/Scripts.meta | 8 + .../Runtime/Scripts/OutlineFeature.cs | 39 ++ .../Runtime/Scripts/OutlineFeature.cs.meta | 11 + .../Runtime/Scripts/OutlinePass.cs | 31 + .../Runtime/Scripts/OutlinePass.cs.meta | 11 + .../Runtime/Scripts/OutlineRenderColorPass.cs | 51 ++ .../Scripts/OutlineRenderColorPass.cs.meta | 11 + .../Runtime/UnityFx.Outline.URP.asmdef | 17 + .../Runtime/UnityFx.Outline.URP.asmdef.meta | 7 + .../Packages/UnityFx.Outline.URP/package.json | 32 + .../UnityFx.Outline.URP/package.json.meta | 7 + Outline.URP/Packages/manifest.json | 37 + .../ProjectSettings/AudioManager.asset | 19 + .../ProjectSettings/ClusterInputManager.asset | 6 + .../ProjectSettings/DynamicsManager.asset | 36 + .../ProjectSettings/EditorBuildSettings.asset | 8 + .../ProjectSettings/EditorSettings.asset | 35 + .../ProjectSettings/GraphicsSettings.asset | 64 ++ .../ProjectSettings/HDRPProjectSettings.asset | 21 + .../ProjectSettings/InputManager.asset | 487 ++++++++++++++ .../ProjectSettings/NavMeshAreas.asset | 91 +++ .../ProjectSettings/Physics2DSettings.asset | 56 ++ .../ProjectSettings/PresetManager.asset | 7 + .../ProjectSettings/ProjectSettings.asset | 610 +++++++++++++++++ .../ProjectSettings/ProjectVersion.txt | 2 + .../ProjectSettings/QualitySettings.asset | 236 +++++++ Outline.URP/ProjectSettings/TagManager.asset | 43 ++ Outline.URP/ProjectSettings/TimeManager.asset | 9 + .../UnityConnectSettings.asset | 34 + Outline.URP/ProjectSettings/VFXManager.asset | 12 + Outline.URP/ProjectSettings/XRSettings.asset | 10 + 50 files changed, 2956 insertions(+) create mode 100644 Outline.URP/Assets/Example.meta create mode 100644 Outline.URP/Assets/Example/OutlineFeature.asset create mode 100644 Outline.URP/Assets/Example/OutlineFeature.asset.meta create mode 100644 Outline.URP/Assets/Example/OutlineLayerCollection.asset create mode 100644 Outline.URP/Assets/Example/OutlineLayerCollection.asset.meta create mode 100644 Outline.URP/Assets/Example/OutlineTest.cs create mode 100644 Outline.URP/Assets/Example/OutlineTest.cs.meta create mode 100644 Outline.URP/Assets/Example/Test.unity create mode 100644 Outline.URP/Assets/Example/Test.unity.meta create mode 100644 Outline.URP/Assets/URP.meta create mode 100644 Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset create mode 100644 Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset.meta create mode 100644 Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset create mode 100644 Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/README.md create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/README.md.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef.meta create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/package.json create mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/package.json.meta create mode 100644 Outline.URP/Packages/manifest.json create mode 100644 Outline.URP/ProjectSettings/AudioManager.asset create mode 100644 Outline.URP/ProjectSettings/ClusterInputManager.asset create mode 100644 Outline.URP/ProjectSettings/DynamicsManager.asset create mode 100644 Outline.URP/ProjectSettings/EditorBuildSettings.asset create mode 100644 Outline.URP/ProjectSettings/EditorSettings.asset create mode 100644 Outline.URP/ProjectSettings/GraphicsSettings.asset create mode 100644 Outline.URP/ProjectSettings/HDRPProjectSettings.asset create mode 100644 Outline.URP/ProjectSettings/InputManager.asset create mode 100644 Outline.URP/ProjectSettings/NavMeshAreas.asset create mode 100644 Outline.URP/ProjectSettings/Physics2DSettings.asset create mode 100644 Outline.URP/ProjectSettings/PresetManager.asset create mode 100644 Outline.URP/ProjectSettings/ProjectSettings.asset create mode 100644 Outline.URP/ProjectSettings/ProjectVersion.txt create mode 100644 Outline.URP/ProjectSettings/QualitySettings.asset create mode 100644 Outline.URP/ProjectSettings/TagManager.asset create mode 100644 Outline.URP/ProjectSettings/TimeManager.asset create mode 100644 Outline.URP/ProjectSettings/UnityConnectSettings.asset create mode 100644 Outline.URP/ProjectSettings/VFXManager.asset create mode 100644 Outline.URP/ProjectSettings/XRSettings.asset diff --git a/Outline.URP/Assets/Example.meta b/Outline.URP/Assets/Example.meta new file mode 100644 index 0000000..7246202 --- /dev/null +++ b/Outline.URP/Assets/Example.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea27ed3498ff43e40aab89c627664573 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/Example/OutlineFeature.asset b/Outline.URP/Assets/Example/OutlineFeature.asset new file mode 100644 index 0000000..2eb6c9d --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineFeature.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dd37d03d18ee9584d881763c34816b35, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: diff --git a/Outline.URP/Assets/Example/OutlineFeature.asset.meta b/Outline.URP/Assets/Example/OutlineFeature.asset.meta new file mode 100644 index 0000000..2a2da2a --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineFeature.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 259b6fe12142a4642a8e5670d95637dc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/Example/OutlineLayerCollection.asset b/Outline.URP/Assets/Example/OutlineLayerCollection.asset new file mode 100644 index 0000000..c96e20d --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineLayerCollection.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 57d0c11168277cf4eb3b4b89706e6aa5, type: 3} + m_Name: OutlineLayerCollection + m_EditorClassIdentifier: + _layers: + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 0, a: 1} + _outlineWidth: 4 + _outlineIntensity: 2 + _outlineMode: 0 + _name: + _zOrder: 0 + _enabled: 1 + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 0, g: 1, b: 0.060156345, a: 1} + _outlineWidth: 7 + _outlineIntensity: 2 + _outlineMode: 1 + _name: + _zOrder: 0 + _enabled: 1 diff --git a/Outline.URP/Assets/Example/OutlineLayerCollection.asset.meta b/Outline.URP/Assets/Example/OutlineLayerCollection.asset.meta new file mode 100644 index 0000000..0548bf7 --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineLayerCollection.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 059d229f23209a74687769672d1084b8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/Example/OutlineTest.cs b/Outline.URP/Assets/Example/OutlineTest.cs new file mode 100644 index 0000000..0253a66 --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineTest.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityFx.Outline; + +public class OutlineTest : MonoBehaviour +{ +#pragma warning disable 0649 + + [SerializeField] + private GameObject[] _layer0; + [SerializeField] + private GameObject[] _layer1; + [SerializeField] + private OutlineLayerCollection _layers; + +#pragma warning restore 0649 + + void Start() + { + foreach (var go in _layer0) + { + _layers[0].Add(go); + } + + foreach (var go in _layer1) + { + _layers[1].Add(go); + } + } +} diff --git a/Outline.URP/Assets/Example/OutlineTest.cs.meta b/Outline.URP/Assets/Example/OutlineTest.cs.meta new file mode 100644 index 0000000..a753946 --- /dev/null +++ b/Outline.URP/Assets/Example/OutlineTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21871d619b9e3f04b89bbca6cd338745 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/Example/Test.unity b/Outline.URP/Assets/Example/Test.unity new file mode 100644 index 0000000..4d65fc6 --- /dev/null +++ b/Outline.URP/Assets/Example/Test.unity @@ -0,0 +1,633 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &646807773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 646807774} + - component: {fileID: 646807777} + - component: {fileID: 646807776} + - component: {fileID: 646807775} + m_Layer: 0 + m_Name: Cylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &646807774 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 646807773} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.52, y: -0.31, z: 4.31} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1130691891} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &646807775 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 646807773} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &646807776 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 646807773} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &646807777 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 646807773} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &750107942 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 750107943} + - component: {fileID: 750107946} + - component: {fileID: 750107945} + - component: {fileID: 750107944} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &750107943 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 750107942} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 1.5699999, y: -0.30999994, z: 6.1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1130691891} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &750107944 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 750107942} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &750107945 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 750107942} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &750107946 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 750107942} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &1130691890 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalPosition.x + value: -2.4961035 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalPosition.y + value: 3.0931349 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalPosition.z + value: -3.8995318 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4819242101474771701, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_AllowDynamicResolution + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4893056312182120781, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_Name + value: DefaultSceneRoot + objectReference: {fileID: 0} + - target: {fileID: 4949957087466332343, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_Version + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 4949957087466332343, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_RenderingPathCustomFrameSettings.bitDatas.data1 + value: 734440390720 + objectReference: {fileID: 0} + - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_Version + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_MinFilterSize + value: 0.01 + objectReference: {fileID: 0} + - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: m_ShadowResolution.m_Level + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8708978604625570628, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + propertyPath: sharedProfile + value: + objectReference: {fileID: 11400000, guid: aab0876a9ec74194fb766183257d02c9, + type: 2} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: de1884a706667b84cbf9c4195ee402ca, type: 3} +--- !u!4 &1130691891 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 4958332782299279292, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + m_PrefabInstance: {fileID: 1130691890} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1130691892 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 4613009710449648096, guid: de1884a706667b84cbf9c4195ee402ca, + type: 3} + m_PrefabInstance: {fileID: 1130691890} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1130691893 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1130691892} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 22d06c15672ad2440afbe792e641c411, type: 3} + m_Name: + m_EditorClassIdentifier: + _layer0: + - {fileID: 1202059779} + - {fileID: 1822928728} + _layer1: + - {fileID: 646807773} + - {fileID: 750107942} + _layers: {fileID: 11400000, guid: 65159dc68f867cd4f90261bae63e29a7, type: 2} +--- !u!1 &1202059779 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1202059780} + - component: {fileID: 1202059783} + - component: {fileID: 1202059782} + - component: {fileID: 1202059781} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1202059780 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202059779} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -2.28, y: -0.30999994, z: 5.32} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1130691891} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &1202059781 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202059779} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1202059782 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202059779} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1202059783 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202059779} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1822928728 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1822928729} + - component: {fileID: 1822928732} + - component: {fileID: 1822928731} + - component: {fileID: 1822928730} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1822928729 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1822928728} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -1.7100003, y: -0.30999994, z: 4.7999997} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1130691891} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1822928730 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1822928728} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1822928731 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1822928728} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1822928732 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1822928728} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Outline.URP/Assets/Example/Test.unity.meta b/Outline.URP/Assets/Example/Test.unity.meta new file mode 100644 index 0000000..d176f60 --- /dev/null +++ b/Outline.URP/Assets/Example/Test.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: de30e76e0b738334f8e043d91d10419d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/URP.meta b/Outline.URP/Assets/URP.meta new file mode 100644 index 0000000..90625cd --- /dev/null +++ b/Outline.URP/Assets/URP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10050ed397807bc4289f21067a025607 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset new file mode 100644 index 0000000..2c548dc --- /dev/null +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset @@ -0,0 +1,54 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRenderPipelineAsset + m_EditorClassIdentifier: + k_AssetVersion: 5 + k_AssetPreviousVersion: 5 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: f1ccc14d55573e14f80806280c11d740, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 1 + m_SupportsHDR: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 2048 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightsShadowmapResolution: 512 + m_ShadowDistance: 50 + m_ShadowCascades: 0 + m_Cascade2Split: 0.25 + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467} + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_SoftShadowsSupported: 0 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_DebugLevel: 0 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_ShaderVariantLogLevel: 0 diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset.meta b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset.meta new file mode 100644 index 0000000..360640c --- /dev/null +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d47f01a90fe56d43b0cfac27039c94c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset new file mode 100644 index 0000000..e53abaf --- /dev/null +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: UniversalRenderPipelineAsset_Renderer + m_EditorClassIdentifier: + m_RendererFeatures: [] + postProcessData: {fileID: 0} + shaders: + blitPS: {fileID: 0} + copyDepthPS: {fileID: 0} + screenSpaceShadowPS: {fileID: 0} + samplingPS: {fileID: 0} + fallbackErrorPS: {fileID: 0} + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 0 + failOperation: 0 + zFailOperation: 0 diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset.meta b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset.meta new file mode 100644 index 0000000..477bcf6 --- /dev/null +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1ccc14d55573e14f80806280c11d740 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md new file mode 100644 index 0000000..1cf7420 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md @@ -0,0 +1,9 @@ +# UnityFx.Outline.HDRP changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). + +## [0.1.0] - unreleased + +### Added +- Initial release. diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md.meta b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md.meta new file mode 100644 index 0000000..f3ea157 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d2731cfdae865ee439fd0fef782fa994 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/README.md b/Outline.URP/Packages/UnityFx.Outline.URP/README.md new file mode 100644 index 0000000..7149507 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/README.md @@ -0,0 +1,11 @@ +# UnityFx.Outline.HDRP + +## SUMMARY +Screen-space outline effects for HDRP. + +## USEFUL LINKS +* [Github project](https://github.com/Arvtesh/UnityFx.Outline) +* [npm package](https://www.npmjs.com/package/com.unityfx.outline.hdrp) +* [Documentation](https://github.com/Arvtesh/UnityFx.Outline/blob/master/README.md) +* [License](https://github.com/Arvtesh/UnityFx.Outline/blob/master/LICENSE.md) +* [Support](mailto:arvtesh@gmail.com) diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/README.md.meta b/Outline.URP/Packages/UnityFx.Outline.URP/README.md.meta new file mode 100644 index 0000000..39c522c --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3db1fff9dd9ae804888eebc4382e1fb8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime.meta new file mode 100644 index 0000000..5ef6e3e --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58d8c6c8330ffc042ade41ba15f8da23 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts.meta new file mode 100644 index 0000000..100ae09 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 85518f862b075044bbd76d57354f8f3e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs new file mode 100644 index 0000000..5b2ca48 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +namespace UnityFx.Outline.URP +{ + /// + /// Outline feature (URP). + /// + [CreateAssetMenu(fileName = "OutlineFeature", menuName = "UnityFx/Outline/Outline (URP)")] + public class OutlineFeature : ScriptableRendererFeature + { + private OutlineRenderColorPass _renderColorPass; + private OutlinePass _outlinePass; + + public override void Create() + { + _renderColorPass = new OutlineRenderColorPass(); + _outlinePass = new OutlinePass(); + + // Configures where the render pass should be injected. + _renderColorPass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; + } + + // Here you can inject one or multiple render passes in the renderer. + // This method is called when setting up the renderer once per-camera. + public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) + { + _renderColorPass.SetDepth(renderer.cameraDepth); + + renderer.EnqueuePass(_renderColorPass); + renderer.EnqueuePass(_outlinePass); + } + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta new file mode 100644 index 0000000..56e2317 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd37d03d18ee9584d881763c34816b35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs new file mode 100644 index 0000000..02cb148 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +namespace UnityFx.Outline.URP +{ + /// + /// + /// + internal class OutlinePass : ScriptableRenderPass + { + public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) + { + // TODO + } + + public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) + { + throw new NotImplementedException(); + } + + public override void FrameCleanup(CommandBuffer cmd) + { + // TODO + } + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta new file mode 100644 index 0000000..869a028 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3a7683689e159546992ec0f529efcca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs new file mode 100644 index 0000000..fd6b3cb --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs @@ -0,0 +1,51 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +namespace UnityFx.Outline.URP +{ + /// + /// + /// + internal class OutlineRenderColorPass : ScriptableRenderPass + { + private RenderTargetHandle _rt; + private RenderTargetIdentifier _depth; + + public OutlineRenderColorPass() + { + _rt.Init("_MaskTex"); + } + + public void SetDepth(RenderTargetIdentifier depth) + { + _depth = depth; + } + + public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) + { + var rtFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) ? RenderTextureFormat.R8 : RenderTextureFormat.Default; + cmd.GetTemporaryRT(_rt.id, cameraTextureDescriptor.width, cameraTextureDescriptor.height, 0, FilterMode.Bilinear, rtFormat); + ConfigureClear(ClearFlag.Color, Color.clear); + ConfigureTarget(_rt.Identifier(), _depth); + } + + public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) + { + // Here you can implement the rendering logic. + // Use ScriptableRenderContext to issue drawing commands or execute command buffers + // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html + // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline. + + } + + public override void FrameCleanup(CommandBuffer cmd) + { + cmd.ReleaseTemporaryRT(_rt.id); + } + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta new file mode 100644 index 0000000..8fc50f9 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4c2f531479cf7343abc806e7e72c2a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef new file mode 100644 index 0000000..3f9ff3f --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef @@ -0,0 +1,17 @@ +{ + "name": "UnityFx.Outline.URP", + "references": [ + "Unity.RenderPipelines.Core.Runtime", + "Unity.RenderPipelines.Universal.Runtime", + "UnityFx.Outline" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef.meta new file mode 100644 index 0000000..418ae3e --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/UnityFx.Outline.URP.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8130e23c3199afb43ae1c34b3e328d00 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/package.json b/Outline.URP/Packages/UnityFx.Outline.URP/package.json new file mode 100644 index 0000000..6cc1220 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/package.json @@ -0,0 +1,32 @@ +{ + "name": "com.unityfx.outline.urp", + "version": "0.1.0", + "displayName": "Screen-space outline (URP)", + "description": "Configurable outline for URP.", + "unity": "2019.3", + "dependencies": { + "com.unityfx.outline": "0.8.0", + "com.unity.render-pipelines.universal": "7.0.0" + }, + "keywords": [ + "UnityFx", + "UnityFx.Outline", + "UnityFx.Outline.URP", + "Outline", + "URP" + ], + "category": "UnityFx", + "author": { + "name": "Arvtesh", + "email": "arvtesh@gmail.com" + }, + "license": "MIT", + "homepage": "https://github.com/Arvtesh/UnityFx.Outline", + "repository": { + "type": "git", + "url": "https://github.com/Arvtesh/UnityFx.Outline.git" + }, + "bugs": { + "url": "https://github.com/Arvtesh/UnityFx.Outline/issues" + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/package.json.meta b/Outline.URP/Packages/UnityFx.Outline.URP/package.json.meta new file mode 100644 index 0000000..3132f4f --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 761dcd9f6f741bd4b9a86aa1fc1f11b7 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/manifest.json b/Outline.URP/Packages/manifest.json new file mode 100644 index 0000000..7c56d24 --- /dev/null +++ b/Outline.URP/Packages/manifest.json @@ -0,0 +1,37 @@ +{ + "dependencies": { + "com.unity.render-pipelines.universal": "7.1.8", + "com.unityfx.outline": "file:../../Outline.Core/Packages/UnityFx.Outline", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/Outline.URP/ProjectSettings/AudioManager.asset b/Outline.URP/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..27287fe --- /dev/null +++ b/Outline.URP/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 diff --git a/Outline.URP/ProjectSettings/ClusterInputManager.asset b/Outline.URP/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/Outline.URP/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/Outline.URP/ProjectSettings/DynamicsManager.asset b/Outline.URP/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..1596c42 --- /dev/null +++ b/Outline.URP/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 0 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 diff --git a/Outline.URP/ProjectSettings/EditorBuildSettings.asset b/Outline.URP/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..0147887 --- /dev/null +++ b/Outline.URP/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] + m_configObjects: {} diff --git a/Outline.URP/ProjectSettings/EditorSettings.asset b/Outline.URP/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..c8da44e --- /dev/null +++ b/Outline.URP/ProjectSettings/EditorSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 2 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 0 + m_AssetPipelineMode: 1 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 diff --git a/Outline.URP/ProjectSettings/GraphicsSettings.asset b/Outline.URP/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..35a0fa7 --- /dev/null +++ b/Outline.URP/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,64 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/Outline.URP/ProjectSettings/HDRPProjectSettings.asset b/Outline.URP/ProjectSettings/HDRPProjectSettings.asset new file mode 100644 index 0000000..dddb307 --- /dev/null +++ b/Outline.URP/ProjectSettings/HDRPProjectSettings.asset @@ -0,0 +1,21 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 63a2978a97e4fc04cb9d905947216f3d, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 1 + m_DefaultScenePrefabSaved: {fileID: 0} + m_DefaultDXRScenePrefabSaved: {fileID: 0} + m_ProjectSettingFolderPath: HDRPDefaultResources + m_WizardPopupAtStart: 0 + m_WizardActiveTab: 0 + m_PackageVersionForMaterials: 7.1.8 diff --git a/Outline.URP/ProjectSettings/InputManager.asset b/Outline.URP/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..b16147e --- /dev/null +++ b/Outline.URP/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/Outline.URP/ProjectSettings/NavMeshAreas.asset b/Outline.URP/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/Outline.URP/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/Outline.URP/ProjectSettings/Physics2DSettings.asset b/Outline.URP/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..6c5cf8a --- /dev/null +++ b/Outline.URP/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 0 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/Outline.URP/ProjectSettings/PresetManager.asset b/Outline.URP/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/Outline.URP/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/Outline.URP/ProjectSettings/ProjectSettings.asset b/Outline.URP/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..dd0b4e2 --- /dev/null +++ b/Outline.URP/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,610 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 20 + productGUID: 0070264e70e54274fa5f11274f89afab + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: Outline.URP + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 + androidBlitType: 0 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + cardboard: + depthFormat: 0 + enableTransitionView: 0 + daydream: + depthFormat: 0 + useSustainedPerformanceMode: 0 + enableVideoLayer: 0 + useProtectedVideoMemory: 0 + minimumSupportedHeadTracking: 0 + maximumSupportedHeadTracking: 1 + hololens: + depthFormat: 1 + depthBufferSharingEnabled: 1 + lumin: + depthFormat: 0 + frameTiming: 2 + enableGLCache: 0 + glCacheMaxBlobSize: 524288 + glCacheMaxFileSize: 8388608 + oculus: + sharedDepthBuffer: 1 + dashSupport: 1 + lowOverheadMode: 0 + protectedContext: 0 + v2Signing: 1 + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 0 + resolutionScalingMode: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: {} + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 19 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + iPhoneSplashScreen: {fileID: 0} + iPhoneHighResSplashScreen: {fileID: 0} + iPhoneTallHighResSplashScreen: {fileID: 0} + iPhone47inSplashScreen: {fileID: 0} + iPhone55inPortraitSplashScreen: {fileID: 0} + iPhone55inLandscapeSplashScreen: {fileID: 0} + iPhone58inPortraitSplashScreen: {fileID: 0} + iPhone58inLandscapeSplashScreen: {fileID: 0} + iPadPortraitSplashScreen: {fileID: 0} + iPadHighResPortraitSplashScreen: {fileID: 0} + iPadLandscapeSplashScreen: {fileID: 0} + iPadHighResLandscapeSplashScreen: {fileID: 0} + iPhone65inPortraitSplashScreen: {fileID: 0} + iPhone65inLandscapeSplashScreen: {fileID: 0} + iPhone61inPortraitSplashScreen: {fileID: 0} + iPhone61inLandscapeSplashScreen: {fileID: 0} + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSUseLaunchScreenStoryboard: 0 + iOSLaunchScreenCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + clonedFromGUID: 00000000000000000000000000000000 + templatePackageId: + templateDefaultScene: + AndroidTargetArchitectures: 1 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: [] + m_BuildTargetBatching: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: [] + m_BuildTargetVRSettings: [] + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLWasmStreaming: 0 + scriptingDefineSymbols: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + allowUnsafeCode: 0 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 0 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Outline.URP + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Outline.URP + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, + a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + vrEditorSettings: + daydream: + daydreamIconForeground: {fileID: 0} + daydreamIconBackground: {fileID: 0} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + projectName: + organizationId: + cloudEnabled: 0 + enableNativePlatformBackendsForNewInputSystem: 0 + disableOldInputManagerSupport: 0 + legacyClampBlendShapeWeights: 0 diff --git a/Outline.URP/ProjectSettings/ProjectVersion.txt b/Outline.URP/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..798259b --- /dev/null +++ b/Outline.URP/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2019.3.0f6 +m_EditorVersionWithRevision: 2019.3.0f6 (27ab2135bccf) diff --git a/Outline.URP/ProjectSettings/QualitySettings.asset b/Outline.URP/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..d24eb10 --- /dev/null +++ b/Outline.URP/ProjectSettings/QualitySettings.asset @@ -0,0 +1,236 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 255 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + Nintendo Switch: 5 + PS4: 5 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/Outline.URP/ProjectSettings/TagManager.asset b/Outline.URP/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..1c92a78 --- /dev/null +++ b/Outline.URP/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/Outline.URP/ProjectSettings/TimeManager.asset b/Outline.URP/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/Outline.URP/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/Outline.URP/ProjectSettings/UnityConnectSettings.asset b/Outline.URP/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..fa0b146 --- /dev/null +++ b/Outline.URP/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/Outline.URP/ProjectSettings/VFXManager.asset b/Outline.URP/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/Outline.URP/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/Outline.URP/ProjectSettings/XRSettings.asset b/Outline.URP/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/Outline.URP/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file From d05ae81608c790a0b5be47be6c993fe760d6f4d2 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 12:33:30 +0300 Subject: [PATCH 17/61] Removed obsolete data --- .../Runtime/Scripts/OutlineBehaviour.cs | 25 +++---------------- .../Runtime/Scripts/OutlineLayer.cs | 3 --- .../Runtime/Scripts/OutlineLayerCollection.cs | 2 +- .../Scripts/OutlineSettingsInstance.cs | 19 -------------- 4 files changed, 4 insertions(+), 45 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 52bd895..5876d91 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -55,13 +55,7 @@ public OutlineResources OutlineResources throw new ArgumentNullException("OutlineResources"); } - if (_outlineResources != value) - { - CreateSettingsIfNeeded(); - - _outlineResources = value; - _outlineSettings.OutlineResources = _outlineResources; - } + _outlineResources = value; } } @@ -96,16 +90,10 @@ private void Awake() { CreateRenderersIfNeeded(); CreateSettingsIfNeeded(); - - _outlineSettings.OutlineResources = _outlineResources; } private void OnDestroy() { - if (_outlineSettings != null) - { - _outlineSettings.OutlineResources = null; - } } private void OnEnable() @@ -154,7 +142,7 @@ private void Update() { using (var renderer = new OutlineRenderer(cmdBuffer, BuiltinRenderTextureType.CameraTarget)) { - renderer.Render(_renderers.GetList(), _outlineSettings.OutlineResources, _outlineSettings, camera.actualRenderingPath); + renderer.Render(_renderers.GetList(), _outlineResources, _outlineSettings, camera.actualRenderingPath); } } } @@ -178,17 +166,10 @@ private void OnValidate() { CreateRenderersIfNeeded(); CreateSettingsIfNeeded(); - - _outlineSettings.OutlineResources = _outlineResources; } private void Reset() { - if (_outlineSettings != null) - { - _outlineSettings.OutlineResources = _outlineResources; - } - if (_renderers != null) { _renderers.Reset(true); @@ -328,7 +309,7 @@ private void CreateSettingsIfNeeded() { if (_outlineSettings == null) { - _outlineSettings = new OutlineSettingsInstance(_outlineResources); + _outlineSettings = new OutlineSettingsInstance(); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 5cc8e09..d8af004 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -211,8 +211,6 @@ public void Render(OutlineRenderer renderer, OutlineResources resources, Renderi { if (_enabled) { - _settings.OutlineResources = resources; - foreach (var kvp in _outlineObjects) { if (kvp.Key && kvp.Key.activeInHierarchy) @@ -249,7 +247,6 @@ internal OutlineLayerCollection ParentCollection internal void Reset() { - _settings.OutlineResources = null; _outlineObjects.Clear(); } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 3a3ace2..7a2cd1a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -15,7 +15,7 @@ namespace UnityFx.Outline /// /// [CreateAssetMenu(fileName = "OutlineLayerCollection", menuName = "UnityFx/Outline/Outline Layer Collection")] - public sealed class OutlineLayerCollection : ScriptableObject, IList + public sealed class OutlineLayerCollection : ScriptableObject, IList, IReadOnlyList { #region data diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs index a39ef7e..fb282d6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs @@ -27,24 +27,10 @@ internal class OutlineSettingsInstance : IOutlineSettingsEx #pragma warning restore 0649 - private OutlineResources _resources; - #endregion #region interface - public OutlineResources OutlineResources - { - get - { - return _resources; - } - set - { - _resources = value; - } - } - public bool RequiresCameraDepth { get @@ -64,11 +50,6 @@ internal OutlineSettingsInstance() { } - internal OutlineSettingsInstance(OutlineResources resources) - { - _resources = resources; - } - #endregion #region IOutlineSettingsEx From e98bbab6aa4481ec06666e64afb880083a734dc4 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 13:42:23 +0300 Subject: [PATCH 18/61] Dropped .NET 3.5 support, set minimal Unity version to 2018 LTS --- .../Scripts/Helpers/IOutlineSettingsTests.cs | 20 +- .../Editor/Scripts/OutlineRendererTests.cs | 2 +- .../Editor/Scripts/OutlineEditorUtility.cs | 4 +- .../Runtime/Scripts/IOutlineRenderer.cs | 17 ++ .../Runtime/Scripts/IOutlineRenderer.cs.meta | 11 + .../Runtime/Scripts/OutlineBehaviour.cs | 4 +- .../Runtime/Scripts/OutlineEffect.cs | 4 +- .../Runtime/Scripts/OutlineLayer.cs | 44 ++- .../Runtime/Scripts/OutlineLayerCollection.cs | 30 +-- .../Runtime/Scripts/OutlineRenderer.cs | 251 +++--------------- .../Scripts/OutlineRendererCollection.cs | 22 +- .../Runtime/Scripts/OutlineResources.cs | 137 +++++++++- .../Runtime/Scripts/OutlineSettings.cs | 4 +- .../Scripts/OutlineSettingsInstance.cs | 41 +-- .../Runtime/Scripts/Properties/Startup.cs | 10 + .../Scripts/Properties/Startup.cs.meta | 11 + .../Packages/UnityFx.Outline/package.json | 6 +- 17 files changed, 274 insertions(+), 344 deletions(-) create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs.meta diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs index f1ec8b8..805662e 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs @@ -56,14 +56,14 @@ public void OutlineColor_DoesNotSetsChangedOnSameValue() [Test] public void OutlineWidth_DefaultValueIsValid() { - Assert.LessOrEqual(OutlineRenderer.MinWidth, _settings.OutlineWidth); - Assert.GreaterOrEqual(OutlineRenderer.MaxWidth, _settings.OutlineWidth); + Assert.LessOrEqual(OutlineResources.MinWidth, _settings.OutlineWidth); + Assert.GreaterOrEqual(OutlineResources.MaxWidth, _settings.OutlineWidth); } [Test] public void OutlineWidth_SetsValue() { - var width = UnityEngine.Random.Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + var width = UnityEngine.Random.Range(OutlineResources.MinWidth, OutlineResources.MaxWidth); _settings.OutlineWidth = width; Assert.AreEqual(width, _settings.OutlineWidth); @@ -74,11 +74,11 @@ public void OutlineWidth_ClampsValue() { _settings.OutlineWidth = 1000; - Assert.AreEqual(OutlineRenderer.MaxWidth, _settings.OutlineWidth); + Assert.AreEqual(OutlineResources.MaxWidth, _settings.OutlineWidth); _settings.OutlineWidth = -1000; - Assert.AreEqual(OutlineRenderer.MinWidth, _settings.OutlineWidth); + Assert.AreEqual(OutlineResources.MinWidth, _settings.OutlineWidth); } [Test] @@ -142,14 +142,14 @@ public void OutlineMode_DoesNotSetsChangedOnSameValue() [Test] public void OutlineIntensity_DefaultValueIsValid() { - Assert.LessOrEqual(OutlineRenderer.MinIntensity, _settings.OutlineIntensity); - Assert.GreaterOrEqual(OutlineRenderer.MaxIntensity, _settings.OutlineIntensity); + Assert.LessOrEqual(OutlineResources.MinIntensity, _settings.OutlineIntensity); + Assert.GreaterOrEqual(OutlineResources.MaxIntensity, _settings.OutlineIntensity); } [Test] public void OutlineIntensity_SetsValue() { - var intensity = UnityEngine.Random.Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + var intensity = UnityEngine.Random.Range(OutlineResources.MinIntensity, OutlineResources.MaxIntensity); _settings.OutlineIntensity = intensity; @@ -161,11 +161,11 @@ public void OutlineIntensity_ClampsValue() { _settings.OutlineIntensity = 1000; - Assert.AreEqual(OutlineRenderer.MaxIntensity, _settings.OutlineIntensity); + Assert.AreEqual(OutlineResources.MaxIntensity, _settings.OutlineIntensity); _settings.OutlineIntensity = -1000; - Assert.AreEqual(OutlineRenderer.MinIntensity, _settings.OutlineIntensity); + Assert.AreEqual(OutlineResources.MinIntensity, _settings.OutlineIntensity); } [Test] diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs index e4c83b0..89e4b7d 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs @@ -40,7 +40,7 @@ public void Dispose_CanBeCalledMultipleTimes() [Test] public void RenderSingleObject_ThrowsIfNullArguments() { - Assert.Throws(() => _renderer.Render(default(IList), null, null)); + Assert.Throws(() => _renderer.Render(default(IReadOnlyList), null, null)); Assert.Throws(() => _renderer.Render(default(Renderer), null, null)); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs index 77e02f7..3bd9d1c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs @@ -63,7 +63,7 @@ public static void Render(IOutlineSettings settings, UnityEngine.Object undoCont settings.OutlineColor = color; } - var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); if (settings.OutlineWidth != width) { @@ -82,7 +82,7 @@ public static void Render(IOutlineSettings settings, UnityEngine.Object undoCont if ((renderMode & OutlineRenderFlags.Blurred) != 0) { - var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); if (!Mathf.Approximately(settings.OutlineIntensity, i)) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs new file mode 100644 index 0000000..6838be5 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs @@ -0,0 +1,17 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityFx.Outline +{ + public interface IOutlineRenderer + { + /// + /// Renders outline around a single object represented with a collection of renderers. + /// + void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath); + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta new file mode 100644 index 0000000..3bd4622 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e9a2bb1f9645b145962450e502c99d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 5876d91..838ae67 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -50,9 +50,9 @@ public OutlineResources OutlineResources } set { - if (value == null) + if (value is null) { - throw new ArgumentNullException("OutlineResources"); + throw new ArgumentNullException(nameof(OutlineResources)); } _outlineResources = value; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index 3414ef4..7bf9353 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -47,9 +47,9 @@ public OutlineResources OutlineResources } set { - if (ReferenceEquals(value, null)) + if (value is null) { - throw new ArgumentNullException("OutlineResources"); + throw new ArgumentNullException(nameof(OutlineResources)); } _outlineResources = value; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index d8af004..fcebbfc 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -130,9 +130,9 @@ public OutlineLayer(string name) /// Thrown if is . public OutlineLayer(OutlineSettings settings) { - if (ReferenceEquals(settings, null)) + if (settings is null) { - throw new ArgumentNullException("settings"); + throw new ArgumentNullException(nameof(settings)); } _settings.OutlineSettings = settings; @@ -144,9 +144,9 @@ public OutlineLayer(OutlineSettings settings) /// Thrown if is . public OutlineLayer(string name, OutlineSettings settings) { - if (ReferenceEquals(settings, null)) + if (settings is null) { - throw new ArgumentNullException("settings"); + throw new ArgumentNullException(nameof(settings)); } _name = name; @@ -159,9 +159,9 @@ public OutlineLayer(string name, OutlineSettings settings) /// Thrown if is . public void Add(GameObject go, int ignoreLayerMask) { - if (ReferenceEquals(go, null)) + if (go is null) { - throw new ArgumentNullException("go"); + throw new ArgumentNullException(nameof(go)); } if (!_outlineObjects.ContainsKey(go)) @@ -187,14 +187,12 @@ public void Add(GameObject go, string ignoreLayer) /// Thrown if is . public bool TryGetRenderers(GameObject go, out ICollection renderers) { - if (ReferenceEquals(go, null)) + if (go is null) { - throw new ArgumentNullException("go"); + throw new ArgumentNullException(nameof(go)); } - OutlineRendererCollection result; - - if (_outlineObjects.TryGetValue(go, out result)) + if (_outlineObjects.TryGetValue(go, out var result)) { renderers = result; return true; @@ -342,22 +340,10 @@ public OutlineRenderFlags OutlineRenderMode #region ICollection /// - public int Count - { - get - { - return _outlineObjects.Count; - } - } + public int Count => _outlineObjects.Count; /// - public bool IsReadOnly - { - get - { - return false; - } - } + public bool IsReadOnly => false; /// public void Add(GameObject go) @@ -368,18 +354,18 @@ public void Add(GameObject go) /// public bool Remove(GameObject go) { - if (!ReferenceEquals(go, null)) + if (go is null) { - return _outlineObjects.Remove(go); + return false; } - return false; + return _outlineObjects.Remove(go); } /// public bool Contains(GameObject go) { - if (ReferenceEquals(go, null)) + if (go is null) { return false; } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 7a2cd1a..47982eb 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -107,14 +107,14 @@ public OutlineLayer this[int layerIndex] } set { - if (value == null) + if (value is null) { throw new ArgumentNullException("layer"); } if (layerIndex < 0 || layerIndex >= _layers.Count) { - throw new ArgumentOutOfRangeException("layerIndex"); + throw new ArgumentOutOfRangeException(nameof(layerIndex)); } if (_layers[layerIndex] != value) @@ -143,9 +143,9 @@ public int IndexOf(OutlineLayer layer) /// public void Insert(int index, OutlineLayer layer) { - if (layer == null) + if (layer is null) { - throw new ArgumentNullException("layer"); + throw new ArgumentNullException(nameof(layer)); } if (layer.ParentCollection != this) @@ -175,29 +175,17 @@ public void RemoveAt(int index) #region ICollection /// - public int Count - { - get - { - return _layers.Count; - } - } + public int Count => _layers.Count; /// - public bool IsReadOnly - { - get - { - return false; - } - } + public bool IsReadOnly => false; /// public void Add(OutlineLayer layer) { - if (layer == null) + if (layer is null) { - throw new ArgumentNullException("layer"); + throw new ArgumentNullException(nameof(layer)); } if (layer.ParentCollection != this) @@ -242,7 +230,7 @@ public void Clear() /// public bool Contains(OutlineLayer layer) { - if (layer == null) + if (layer is null) { return false; } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 44dda59..fc376a3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.Rendering; @@ -59,7 +60,7 @@ namespace UnityFx.Outline /// } /// /// - public struct OutlineRenderer : IDisposable + public struct OutlineRenderer : IOutlineRenderer, IDisposable { #region data @@ -88,39 +89,6 @@ public struct OutlineRenderer : IDisposable /// public const string EffectName = "Outline"; - /// - /// Minimum value of outline width parameter. - /// - /// - public const int MinWidth = 1; - - /// - /// Maximum value of outline width parameter. - /// - /// - public const int MaxWidth = 32; - - /// - /// Minimum value of outline intensity parameter. - /// - /// - /// - public const int MinIntensity = 1; - - /// - /// Maximum value of outline intensity parameter. - /// - /// - /// - public const int MaxIntensity = 64; - - /// - /// Value of outline intensity parameter that is treated as solid fill. - /// - /// - /// - public const int SolidIntensity = 100; - /// /// Initializes a new instance of the struct. /// @@ -165,9 +133,9 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, /// Thrown if is . public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst, Vector2Int rtSize) { - if (commandBuffer == null) + if (commandBuffer is null) { - throw new ArgumentNullException("commandBuffer"); + throw new ArgumentNullException(nameof(commandBuffer)); } var cx = rtSize.x > 0 ? rtSize.x : -1; @@ -192,16 +160,16 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, } else { -#if UNITY_2018_2_OR_NEWER _commandBuffer.SetRenderTarget(dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); -#else - _commandBuffer.SetRenderTarget(dst); -#endif _commandBuffer.Blit(src, BuiltinRenderTextureType.CurrentActive); } } } + #endregion + + #region IOutlineRenderer + /// /// Renders outline around a single object. This version allows enumeration of with no GC allocations. /// @@ -212,63 +180,28 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, /// Thrown if any of the arguments is . /// /// - public void Render(IList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) + public void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) { - if (renderers == null) + if (renderers is null) { - throw new ArgumentNullException("renderers"); + throw new ArgumentNullException(nameof(renderers)); } - if (resources == null) + if (resources is null) { - throw new ArgumentNullException("resources"); + throw new ArgumentNullException(nameof(resources)); } - if (settings == null) + if (settings is null) { - throw new ArgumentNullException("settings"); + throw new ArgumentNullException(nameof(settings)); } if (renderers.Count > 0) { - Init(resources, settings); RenderObject(resources, settings, renderers, renderingPath); - RenderHPass(resources, settings); - RenderVPassBlend(resources, settings); - } - } - - /// - /// Renders outline around a single object. - /// - /// One or more renderers representing a single object to be outlined. - /// Outline resources. - /// Outline settings. - /// Rendering path used by the target camera (used is is set). - /// Thrown if any of the arguments is . - /// - /// - public void Render(IEnumerable renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) - { - if (renderers == null) - { - throw new ArgumentNullException("renderers"); - } - - if (resources == null) - { - throw new ArgumentNullException("resources"); + RenderOutline(resources, settings); } - - if (settings == null) - { - throw new ArgumentNullException("settings"); - } - - Init(resources, settings); - RenderObject(resources, settings, renderers, renderingPath); - RenderHPass(resources, settings); - RenderVPassBlend(resources, settings); } /// @@ -283,62 +216,23 @@ public void Render(IEnumerable renderers, OutlineResources resources, /// public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) { - if (renderer == null) + if (renderer is null) { - throw new ArgumentNullException("renderers"); + throw new ArgumentNullException(nameof(renderer)); } - if (resources == null) + if (resources is null) { - throw new ArgumentNullException("resources"); + throw new ArgumentNullException(nameof(resources)); } - if (settings == null) + if (settings is null) { - throw new ArgumentNullException("settings"); + throw new ArgumentNullException(nameof(settings)); } - Init(resources, settings); RenderObject(resources, settings, renderer, renderingPath); - RenderHPass(resources, settings); - RenderVPassBlend(resources, settings); - } - - /// - /// Calculates value of Gauss function for the specified and values. - /// - /// - /// - public static float Gauss(float x, float stdDev) - { - var stdDev2 = stdDev * stdDev * 2; - var a = 1 / Mathf.Sqrt((float)Math.PI * stdDev2); - var gauss = a * Mathf.Pow((float)Math.E, -x * x / stdDev2); - - return gauss; - } - - /// - /// Samples Gauss function for the specified . - /// - /// - public static float[] GetGaussSamples(int width, float[] samples) - { - // NOTE: According to '3 sigma' rule there is no reason to have StdDev less then width / 3. - // In practice blur looks best when StdDev is within range [width / 3, width / 2]. - var stdDev = width * 0.5f; - - if (samples == null) - { - samples = new float[MaxWidth]; - } - - for (var i = 0; i < width; i++) - { - samples[i] = Gauss(i, stdDev); - } - - return samples; + RenderOutline(resources, settings); } #endregion @@ -359,27 +253,6 @@ public void Dispose() #region implementation - private void Init(OutlineResources resources, IOutlineSettings settings) - { - // Shader parameter overrides (shared between all passes). - var props = resources.Properties; - - props.SetFloat(resources.WidthId, settings.OutlineWidth); - props.SetColor(resources.ColorId, settings.OutlineColor); - - if ((settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0) - { - props.SetFloat(resources.IntensityId, settings.OutlineIntensity); - } - else - { - props.SetFloat(resources.IntensityId, SolidIntensity); - } - - // Gauss samples. - _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); - } - private void RenderObjectClear(OutlineRenderFlags flags, RenderingPath renderingPath) { if ((flags & OutlineRenderFlags.EnableDepthTesting) != 0) @@ -389,25 +262,17 @@ private void RenderObjectClear(OutlineRenderFlags flags, RenderingPath rendering BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth; // NOTE: Use the camera depth buffer when rendering the mask. Shader only reads from the depth buffer (ZWrite Off). -#if UNITY_2018_2_OR_NEWER _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, depthTextureId, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); -#else - _commandBuffer.SetRenderTarget(_maskRtId, depthTextureId); -#endif } else { -#if UNITY_2018_2_OR_NEWER _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); -#else - _commandBuffer.SetRenderTarget(_maskRtId); -#endif } _commandBuffer.ClearRenderTarget(false, true, Color.clear); } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IList renderers, RenderingPath renderingPath) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, IReadOnlyList renderers, RenderingPath renderingPath) { RenderObjectClear(settings.OutlineRenderMode, renderingPath); @@ -429,27 +294,6 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, } } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IEnumerable renderers, RenderingPath renderingPath) - { - RenderObjectClear(settings.OutlineRenderMode, renderingPath); - - // NOTE: Calling IEnumerable.GetEnumerator() triggers GC.Alloc. - foreach (var r in renderers) - { - if (r && r.enabled && r.gameObject.activeInHierarchy) - { - // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary - // list of materials, cached with the outline resources. - r.GetSharedMaterials(resources.TmpMaterials); - - for (var j = 0; j < resources.TmpMaterials.Count; ++j) - { - _commandBuffer.DrawRenderer(r, resources.RenderMaterial, j); - } - } - } - } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer, RenderingPath renderingPath) { RenderObjectClear(settings.OutlineRenderMode, renderingPath); @@ -467,49 +311,36 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, } } - private void RenderHPass(OutlineResources resources, IOutlineSettings settings) + private void RenderOutline(OutlineResources resources, IOutlineSettings settings) { - // Set source texture as _MainTex to match Blit behavior. - _commandBuffer.SetGlobalTexture(_mainRtId, _maskRtId); + var forceDrawMesh = (settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) != 0; + var mat = resources.OutlineMaterial; + var props = resources.GetProperties(settings); + + _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); - // Set destination texture as render target. -#if UNITY_2018_2_OR_NEWER + // HPass _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); -#else - _commandBuffer.SetRenderTarget(_hPassRtId); -#endif + Blit(_commandBuffer, _maskRtId, resources, _hPassId, mat, props, forceDrawMesh); - // Blit fullscreen triangle. - if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) - { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _hPassId, MeshTopology.Triangles, 3, 1, resources.Properties); - } - else - { - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.OutlineMaterial, 0, _hPassId, resources.Properties); - } + // VPassBlend + _commandBuffer.SetRenderTarget(_destination, _source.Equals(_destination) ? RenderBufferLoadAction.Load : RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props, forceDrawMesh); } - private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, OutlineResources resources, int shaderPass, Material mat, MaterialPropertyBlock props, bool forceDrawMesh = false) { // Set source texture as _MainTex to match Blit behavior. - _commandBuffer.SetGlobalTexture(_mainRtId, _hPassRtId); - - // Set destination texture as render target. -#if UNITY_2018_2_OR_NEWER - _commandBuffer.SetRenderTarget(_destination, _source.Equals(_destination) ? RenderBufferLoadAction.Load : RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); -#else - _commandBuffer.SetRenderTarget(_destination); -#endif + cmdBuffer.SetGlobalTexture(_mainRtId, src); - // Blit fullscreen triangle. - if ((settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) == 0 && SystemInfo.graphicsShaderLevel >= 35) + if (forceDrawMesh || SystemInfo.graphicsShaderLevel < 35) { - _commandBuffer.DrawProcedural(Matrix4x4.identity, resources.OutlineMaterial, _vPassId, MeshTopology.Triangles, 3, 1, resources.Properties); + cmdBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, mat, 0, shaderPass, props); } else { - _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.OutlineMaterial, 0, _vPassId, resources.Properties); + cmdBuffer.DrawProcedural(Matrix4x4.identity, mat, shaderPass, MeshTopology.Triangles, 3, 1, props); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs index 730e6dd..6d0ddac 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs @@ -67,21 +67,9 @@ internal void Reset(bool includeInactive, int ignoreLayerMask) #region ICollection - public int Count - { - get - { - return _renderers.Count; - } - } + public int Count => _renderers.Count; - public bool IsReadOnly - { - get - { - return false; - } - } + public bool IsReadOnly => false; public void Add(Renderer renderer) { @@ -130,14 +118,14 @@ IEnumerator IEnumerable.GetEnumerator() private void Validate(Renderer renderer) { - if (renderer == null) + if (renderer is null) { - throw new ArgumentNullException("renderer"); + throw new ArgumentNullException(nameof(renderer)); } if (!renderer.transform.IsChildOf(_go.transform)) { - throw new ArgumentException(string.Format("Only children of the {0} are allowed.", _go.name), "renderer"); + throw new ArgumentException(string.Format("Only children of the {0} are allowed.", _go.name), nameof(renderer)); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 6e7fe4e..86b8dd7 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -26,25 +26,78 @@ public sealed class OutlineResources : ScriptableObject #region interface + /// + /// Minimum value of outline width parameter. + /// + /// + public const int MinWidth = 1; + + /// + /// Maximum value of outline width parameter. + /// + /// + public const int MaxWidth = 32; + + /// + /// Minimum value of outline intensity parameter. + /// + /// + /// + public const int MinIntensity = 1; + + /// + /// Maximum value of outline intensity parameter. + /// + /// + /// + public const int MaxIntensity = 64; + + /// + /// Value of outline intensity parameter that is treated as solid fill. + /// + /// + /// + public const int SolidIntensity = 100; + + /// + /// Name of _Color shader parameter. + /// + public const string ColorName = "_Color"; + + /// + /// Name of _Width shader parameter. + /// + public const string WidthName = "_Width"; + + /// + /// Name of _Intensity shader parameter. + /// + public const string IntensityName = "_Intensity"; + + /// + /// Name of _GaussSamples shader parameter. + /// + public const string GaussSamplesName = "_GaussSamples"; + /// /// Hashed name of _Color shader parameter. /// - public readonly int ColorId = Shader.PropertyToID("_Color"); + public readonly int ColorId = Shader.PropertyToID(ColorName); /// /// Hashed name of _Width shader parameter. /// - public readonly int WidthId = Shader.PropertyToID("_Width"); + public readonly int WidthId = Shader.PropertyToID(WidthName); /// /// Hashed name of _Intensity shader parameter. /// - public readonly int IntensityId = Shader.PropertyToID("_Intensity"); + public readonly int IntensityId = Shader.PropertyToID(IntensityName); /// /// Hashed name of _GaussSamples shader parameter. /// - public readonly int GaussSamplesId = Shader.PropertyToID("_GaussSamples"); + public readonly int GaussSamplesId = Shader.PropertyToID(GaussSamplesName); /// /// Temp materials list. Used by to avoid GC allocations. @@ -72,7 +125,7 @@ public Material RenderMaterial { _renderMaterial = new Material(RenderShader) { - name = "Outline - SimpleRender", + name = "Outline - RenderColor", hideFlags = HideFlags.HideAndDontSave }; } @@ -108,7 +161,7 @@ public MaterialPropertyBlock Properties { get { - if (_props == null) + if (_props is null) { _props = new MaterialPropertyBlock(); } @@ -162,21 +215,46 @@ public bool IsValid } } + /// + /// Returns a instance initialized with values from . + /// + public MaterialPropertyBlock GetProperties(IOutlineSettings settings) + { + if (_props is null) + { + _props = new MaterialPropertyBlock(); + } + + _props.SetFloat(WidthId, settings.OutlineWidth); + _props.SetColor(ColorId, settings.OutlineColor); + + if ((settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0) + { + _props.SetFloat(IntensityId, settings.OutlineIntensity); + } + else + { + _props.SetFloat(IntensityId, SolidIntensity); + } + + return _props; + } + /// /// Gets cached gauss samples for the specified outline . /// public float[] GetGaussSamples(int width) { - var index = Mathf.Clamp(width, 1, OutlineRenderer.MaxWidth) - 1; + var index = Mathf.Clamp(width, 1, MaxWidth) - 1; - if (_gaussSamples == null) + if (_gaussSamples is null) { - _gaussSamples = new float[OutlineRenderer.MaxWidth][]; + _gaussSamples = new float[MaxWidth][]; } - if (_gaussSamples[index] == null) + if (_gaussSamples[index] is null) { - _gaussSamples[index] = OutlineRenderer.GetGaussSamples(width, null); + _gaussSamples[index] = GetGaussSamples(width, null); } return _gaussSamples[index]; @@ -191,6 +269,43 @@ public void ResetToDefaults() OutlineShader = Shader.Find("Hidden/UnityFx/Outline"); } + /// + /// Calculates value of Gauss function for the specified and values. + /// + /// + /// + public static float Gauss(float x, float stdDev) + { + var stdDev2 = stdDev * stdDev * 2; + var a = 1 / Mathf.Sqrt(Mathf.PI * stdDev2); + var gauss = a * Mathf.Pow((float)Math.E, -x * x / stdDev2); + + return gauss; + } + + /// + /// Samples Gauss function for the specified . + /// + /// + public static float[] GetGaussSamples(int width, float[] samples) + { + // NOTE: According to '3 sigma' rule there is no reason to have StdDev less then width / 3. + // In practice blur looks best when StdDev is within range [width / 3, width / 2]. + var stdDev = width * 0.5f; + + if (samples is null) + { + samples = new float[MaxWidth]; + } + + for (var i = 0; i < width; i++) + { + samples[i] = Gauss(i, stdDev); + } + + return samples; + } + #endregion } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs index 2535031..1b6fe4b 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs @@ -67,7 +67,7 @@ public int OutlineWidth } set { - _outlineWidth = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + _outlineWidth = Mathf.Clamp(value, OutlineResources.MinWidth, OutlineResources.MaxWidth); } } @@ -80,7 +80,7 @@ public float OutlineIntensity } set { - _outlineIntensity = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + _outlineIntensity = Mathf.Clamp(value, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs index fb282d6..b587fbd 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs @@ -35,14 +35,7 @@ public bool RequiresCameraDepth { get { - var renderMode = _outlineMode; - - if (!ReferenceEquals(_outlineSettings, null)) - { - renderMode = _outlineSettings.OutlineRenderMode; - } - - return (renderMode & OutlineRenderFlags.EnableDepthTesting) != 0; + return (OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0; } } @@ -75,12 +68,7 @@ public Color OutlineColor { get { - if (!ReferenceEquals(_outlineSettings, null)) - { - return _outlineSettings.OutlineColor; - } - - return _outlineColor; + return _outlineSettings is null ? _outlineColor : _outlineSettings.OutlineColor; } set { @@ -93,16 +81,11 @@ public int OutlineWidth { get { - if (!ReferenceEquals(_outlineSettings, null)) - { - return _outlineSettings.OutlineWidth; - } - - return _outlineWidth; + return _outlineSettings is null ? _outlineWidth : _outlineSettings.OutlineWidth; } set { - _outlineWidth = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + _outlineWidth = Mathf.Clamp(value, OutlineResources.MinWidth, OutlineResources.MaxWidth); } } @@ -111,16 +94,11 @@ public float OutlineIntensity { get { - if (!ReferenceEquals(_outlineSettings, null)) - { - return _outlineSettings.OutlineIntensity; - } - - return _outlineIntensity; + return _outlineSettings is null ? _outlineIntensity : _outlineSettings.OutlineIntensity; } set { - _outlineIntensity = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + _outlineIntensity = Mathf.Clamp(value, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); } } @@ -129,12 +107,7 @@ public OutlineRenderFlags OutlineRenderMode { get { - if (!ReferenceEquals(_outlineSettings, null)) - { - return _outlineSettings.OutlineRenderMode; - } - - return _outlineMode; + return _outlineSettings is null ? _outlineMode : _outlineSettings.OutlineRenderMode; } set { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs new file mode 100644 index 0000000..7925a95 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs @@ -0,0 +1,10 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +#if !UNITY_2018_4_OR_NEWER +#error UnityFx.Outline requires Unity 2018.4 or newer. +#endif + +#if NET_LEGACY || NET_2_0 || NET_2_0_SUBSET +#error UnityFx.Outline does not support .NET 3.5. Please set Scripting Runtime Version to .NET 4.x Equivalent in Unity Player Settings. +#endif diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs.meta new file mode 100644 index 0000000..b4865cd --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/Properties/Startup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 955bb53eefa37054cb49969575341469 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/package.json b/Outline.Core/Packages/UnityFx.Outline/package.json index b41e8a4..208d2fd 100644 --- a/Outline.Core/Packages/UnityFx.Outline/package.json +++ b/Outline.Core/Packages/UnityFx.Outline/package.json @@ -1,9 +1,9 @@ { "name": "com.unityfx.outline", - "version": "0.7.2", - "displayName": "Screen-space outline", + "version": "0.8.0", + "displayName": "Screen-space outlines", "description": "Configurable per-object and per-camera outline effect implementation for built-in render pipeline. Both solid and blurred outline modes are supported (Gauss blur). Scriptable render pipeline is not supported.", - "unity": "2017.2", + "unity": "2018.4", "keywords": [ "UnityFx", "UnityFx.Outline", From 918b036a8e91ef73e928328e2615c6c9a636b88d Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 15:54:43 +0300 Subject: [PATCH 19/61] Removed dependencies from OutlineRenderer from OutlineLayer and OutlineLayerCollection --- .../Runtime/Scripts/IOutlineRenderer.cs | 17 ----- .../Runtime/Scripts/OutlineEffect.cs | 11 ++- .../Runtime/Scripts/OutlineLayer.cs | 10 +-- .../Runtime/Scripts/OutlineLayerCollection.cs | 6 +- .../Runtime/Scripts/OutlineObject.cs | 72 +++++++++++++++++++ ...Renderer.cs.meta => OutlineObject.cs.meta} | 2 +- .../Runtime/Scripts/OutlineRenderer.cs | 11 +-- .../Scripts/OutlineRendererCollection.cs | 2 +- 8 files changed, 95 insertions(+), 36 deletions(-) delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs rename Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/{IOutlineRenderer.cs.meta => OutlineObject.cs.meta} (83%) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs deleted file mode 100644 index 6838be5..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace UnityFx.Outline -{ - public interface IOutlineRenderer - { - /// - /// Renders outline around a single object represented with a collection of renderers. - /// - void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath); - } -} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index 7bf9353..4f5e687 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -30,6 +30,7 @@ public sealed partial class OutlineEffect : MonoBehaviour private Camera _camera; private CommandBuffer _commandBuffer; + private List _renderObjects = new List(16); #endregion @@ -220,14 +221,20 @@ private void FillCommandBuffer() { using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) { - _outlineLayers.Render(renderer, _outlineResources, _camera.actualRenderingPath); + _renderObjects.Clear(); + _outlineLayers.GetRenderObjects(_renderObjects); + + foreach (var renderObject in _renderObjects) + { + renderer.Render(renderObject.Renderers, _outlineResources, renderObject.OutlineSettings, _camera.actualRenderingPath); + } } } } private void CreateLayersIfNeeded() { - if (ReferenceEquals(_outlineLayers, null)) + if (_outlineLayers is null) { _outlineLayers = ScriptableObject.CreateInstance(); _outlineLayers.name = "OutlineLayers"; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index fcebbfc..b4de106 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -203,17 +203,19 @@ public bool TryGetRenderers(GameObject go, out ICollection renderers) } /// - /// Renders the layers. + /// Gets the objects for rendering. /// - public void Render(OutlineRenderer renderer, OutlineResources resources, RenderingPath renderingPath) + public void GetRenderObjects(IList renderObjects) { if (_enabled) { foreach (var kvp in _outlineObjects) { - if (kvp.Key && kvp.Key.activeInHierarchy) + var go = kvp.Key; + + if (go && go.activeInHierarchy) { - renderer.Render(kvp.Value.GetList(), resources, _settings, renderingPath); + renderObjects.Add(new OutlineObject(go, kvp.Value.GetList(), _settings)); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 47982eb..08810fa 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -51,15 +51,15 @@ public OutlineLayer[] SortedLayers } /// - /// Renders all layers. + /// Gets the objects for rendering. /// - public void Render(OutlineRenderer renderer, OutlineResources resources, RenderingPath renderingPath) + public void GetRenderObjects(IList renderObjects) { UpdateSortedLayersIfNeeded(); foreach (var layer in _sortedLayers) { - layer.Render(renderer, resources, renderingPath); + layer.GetRenderObjects(renderObjects); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs new file mode 100644 index 0000000..6ed07ce --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace UnityFx.Outline +{ + /// + /// A single outline object + its outline settings. + /// + public readonly struct OutlineObject : IEquatable + { + #region data + + private readonly GameObject _go; + private readonly IReadOnlyList _renderers; + private readonly IOutlineSettings _outlineSettings; + + #endregion + + #region interface + + /// + /// Gets the . + /// + public GameObject Go => _go; + + /// + /// Gets renderers for the object. + /// + public IReadOnlyList Renderers => _renderers; + + /// + /// Gets outline settings for this object. + /// + public IOutlineSettings OutlineSettings => _outlineSettings; + + /// + /// Initializes a new instance of the struct. + /// + public OutlineObject(GameObject go, IReadOnlyList renderers, IOutlineSettings outlineSettings) + { + _go = go; + _renderers = renderers; + _outlineSettings = outlineSettings; + } + + /// + /// Implicit convertino to . + /// + public static implicit operator GameObject(OutlineObject o) + { + return o._go; + } + + #endregion + + #region IEquatable + + /// + public bool Equals(OutlineObject other) + { + return _go == other._go && _renderers == other._renderers && _outlineSettings == other._outlineSettings; + } + + #endregion + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs.meta similarity index 83% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs.meta index 3bd4622..024cad2 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineRenderer.cs.meta +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2e9a2bb1f9645b145962450e502c99d9 +guid: b9fa0d37014ee9049afd5e65be9f288b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index fc376a3..32db86d 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -60,7 +60,7 @@ namespace UnityFx.Outline /// } /// /// - public struct OutlineRenderer : IOutlineRenderer, IDisposable + public struct OutlineRenderer : IDisposable { #region data @@ -140,15 +140,14 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, var cx = rtSize.x > 0 ? rtSize.x : -1; var cy = rtSize.y > 0 ? rtSize.y : -1; - var rtFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) ? RenderTextureFormat.R8 : RenderTextureFormat.Default; _source = src; _destination = dst; _commandBuffer = commandBuffer; _commandBuffer.BeginSample(EffectName); - _commandBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, rtFormat); - _commandBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, rtFormat); + _commandBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + _commandBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); // Need to copy src content into dst if they are not the same. For instance this is the case when rendering // the outline effect as part of Unity Post Processing stack. @@ -166,10 +165,6 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, } } - #endregion - - #region IOutlineRenderer - /// /// Renders outline around a single object. This version allows enumeration of with no GC allocations. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs index 6d0ddac..1ec074f 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs @@ -25,7 +25,7 @@ internal OutlineRendererCollection(GameObject go) _go = go; } - internal List GetList() + internal IReadOnlyList GetList() { return _renderers; } From 454d8040c63cc006594c280f55fb473735d2ecf8 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 16:12:15 +0300 Subject: [PATCH 20/61] Misc renderer improvements --- .../Runtime/Scripts/OutlineRenderer.cs | 74 +++++++++++-------- .../Runtime/Scripts/OutlineResources.cs | 10 +++ 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 32db86d..581699b 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -60,14 +60,13 @@ namespace UnityFx.Outline /// } /// /// - public struct OutlineRenderer : IDisposable + public readonly struct OutlineRenderer : IDisposable { #region data private const int _hPassId = 0; private const int _vPassId = 1; - private static readonly int _mainRtId = Shader.PropertyToID("_MainTex"); private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex"); @@ -95,8 +94,8 @@ public struct OutlineRenderer : IDisposable /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Render target. /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, BuiltinRenderTextureType rt) - : this(commandBuffer, rt, rt, Vector2Int.zero) + public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt) + : this(commandBuffer, rt, Vector2Int.zero) { } @@ -106,9 +105,18 @@ public OutlineRenderer(CommandBuffer commandBuffer, BuiltinRenderTextureType rt) /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Render target. /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt) - : this(commandBuffer, rt, rt, Vector2Int.zero) + public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt, Vector2Int rtSize) { + if (commandBuffer is null) + { + throw new ArgumentNullException(nameof(commandBuffer)); + } + + _source = rt; + _destination = rt; + _commandBuffer = commandBuffer; + + Init(_commandBuffer, rtSize); } /// @@ -138,31 +146,14 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, throw new ArgumentNullException(nameof(commandBuffer)); } - var cx = rtSize.x > 0 ? rtSize.x : -1; - var cy = rtSize.y > 0 ? rtSize.y : -1; + Debug.Assert(!src.Equals(dst)); _source = src; _destination = dst; - _commandBuffer = commandBuffer; - _commandBuffer.BeginSample(EffectName); - _commandBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); - _commandBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); - // Need to copy src content into dst if they are not the same. For instance this is the case when rendering - // the outline effect as part of Unity Post Processing stack. - if (!src.Equals(dst)) - { - if (SystemInfo.copyTextureSupport > CopyTextureSupport.None) - { - _commandBuffer.CopyTexture(src, dst); - } - else - { - _commandBuffer.SetRenderTarget(dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - _commandBuffer.Blit(src, BuiltinRenderTextureType.CurrentActive); - } - } + Init(_commandBuffer, rtSize); + Blit(_commandBuffer, src, dst); } /// @@ -275,7 +266,7 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, { var r = renderers[i]; - if (r && r.enabled && r.gameObject.activeInHierarchy) + if (r && r.enabled && r.isVisible && r.gameObject.activeInHierarchy) { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. @@ -293,7 +284,7 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, { RenderObjectClear(settings.OutlineRenderMode, renderingPath); - if (renderer && renderer.gameObject.activeInHierarchy && renderer.enabled) + if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. @@ -323,11 +314,36 @@ private void RenderOutline(OutlineResources resources, IOutlineSettings settings Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props, forceDrawMesh); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Init(CommandBuffer cmdBuffer, Vector2Int rtSize) + { + var cx = rtSize.x > 0 ? rtSize.x : -1; + var cy = rtSize.y > 0 ? rtSize.y : -1; + + cmdBuffer.BeginSample(EffectName); + cmdBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + cmdBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst) + { + if (SystemInfo.copyTextureSupport > CopyTextureSupport.None) + { + cmdBuffer.CopyTexture(src, dst); + } + else + { + cmdBuffer.SetRenderTarget(dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + cmdBuffer.Blit(src, BuiltinRenderTextureType.CurrentActive); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, OutlineResources resources, int shaderPass, Material mat, MaterialPropertyBlock props, bool forceDrawMesh = false) { // Set source texture as _MainTex to match Blit behavior. - cmdBuffer.SetGlobalTexture(_mainRtId, src); + cmdBuffer.SetGlobalTexture(resources.MainTexId, src); if (forceDrawMesh || SystemInfo.graphicsShaderLevel < 35) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 86b8dd7..415fe50 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -59,6 +59,11 @@ public sealed class OutlineResources : ScriptableObject /// public const int SolidIntensity = 100; + /// + /// Name of _MainTex shader parameter. + /// + public const string MainTexName = "_MainTex"; + /// /// Name of _Color shader parameter. /// @@ -79,6 +84,11 @@ public sealed class OutlineResources : ScriptableObject /// public const string GaussSamplesName = "_GaussSamples"; + /// + /// Hashed name of _MainTex shader parameter. + /// + public readonly int MainTexId = Shader.PropertyToID(MainTexName); + /// /// Hashed name of _Color shader parameter. /// From a045c622387697d03d9698d01952490615e6a1b8 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 16:56:53 +0300 Subject: [PATCH 21/61] Added fallback to legacy blit for outline shader --- .../UnityFx.Outline/Runtime/Scripts/OutlineResources.cs | 5 +++++ .../Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 415fe50..e47a7e0 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -84,6 +84,11 @@ public sealed class OutlineResources : ScriptableObject /// public const string GaussSamplesName = "_GaussSamples"; + /// + /// Name of the _USE_DRAWMESH shader feature. + /// + public const string UseDrawMeshFeatureName = "_USE_DRAWMESH"; + /// /// Hashed name of _MainTex shader parameter. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 5913862..02780d0 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -27,7 +27,7 @@ Shader "Hidden/UnityFx/Outline" float2 _MainTex_TexelSize; float _GaussSamples[32]; -#if SHADER_TARGET < 35 +#if SHADER_TARGET < 35 || _USE_DRAWMESH v2f_img vert(appdata_img v) { @@ -118,6 +118,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 + #pragma shader_feature _USE_DRAWMESH #pragma vertex vert #pragma fragment frag_h @@ -133,6 +134,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 + #pragma shader_feature _USE_DRAWMESH #pragma vertex vert #pragma fragment frag_v From 9c992ab21391b9fe8d4704647815ad809fc8ad4f Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 8 May 2020 16:59:21 +0300 Subject: [PATCH 22/61] Removed UseLegacyRenderer flag --- .../Runtime/Scripts/OutlineRenderFlags.cs | 7 +------ .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 9 ++++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs index a070049..d180f46 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderFlags.cs @@ -24,11 +24,6 @@ public enum OutlineRenderFlags /// /// Enabled depth testing when rendering object outlines. Only visible parts of objects are outlined. /// - EnableDepthTesting = 2, - - /// - /// If set, DrawMesh() is used instead of DrawProcedural() even for SM3.5+ capable hardware. Do not use unless you exaclty know what you're doing. - /// - UseLegacyRenderer = 0x100 + EnableDepthTesting = 2 } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 581699b..2e37663 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -299,7 +299,6 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, private void RenderOutline(OutlineResources resources, IOutlineSettings settings) { - var forceDrawMesh = (settings.OutlineRenderMode & OutlineRenderFlags.UseLegacyRenderer) != 0; var mat = resources.OutlineMaterial; var props = resources.GetProperties(settings); @@ -307,11 +306,11 @@ private void RenderOutline(OutlineResources resources, IOutlineSettings settings // HPass _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _maskRtId, resources, _hPassId, mat, props, forceDrawMesh); + Blit(_commandBuffer, _maskRtId, resources, _hPassId, mat, props); // VPassBlend _commandBuffer.SetRenderTarget(_destination, _source.Equals(_destination) ? RenderBufferLoadAction.Load : RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props, forceDrawMesh); + Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -340,12 +339,12 @@ private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, Re } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, OutlineResources resources, int shaderPass, Material mat, MaterialPropertyBlock props, bool forceDrawMesh = false) + private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, OutlineResources resources, int shaderPass, Material mat, MaterialPropertyBlock props) { // Set source texture as _MainTex to match Blit behavior. cmdBuffer.SetGlobalTexture(resources.MainTexId, src); - if (forceDrawMesh || SystemInfo.graphicsShaderLevel < 35) + if (SystemInfo.graphicsShaderLevel < 35) { cmdBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, mat, 0, shaderPass, props); } From b1639b00e09cd3bf72109cbf4822504aa2c0b7d6 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 9 May 2020 15:37:23 +0300 Subject: [PATCH 23/61] Misc outline shader chages --- .../Runtime/Shaders/Outline.shader | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 02780d0..7041a77 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -22,8 +22,8 @@ Shader "Hidden/UnityFx/Outline" float4 _Color; CBUFFER_END - UNITY_DECLARE_TEX2D(_MaskTex); - UNITY_DECLARE_TEX2D(_MainTex); + UNITY_DECLARE_SCREENSPACE_TEXTURE(_MaskTex); + UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); float2 _MainTex_TexelSize; float _GaussSamples[32]; @@ -47,8 +47,17 @@ Shader "Hidden/UnityFx/Outline" struct appdata_vid { uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID }; + float4 GetFullScreenTriangleVertexPosition(uint vertexID, float z) + { + // Generates a triangle in homogeneous clip space, s.t. + // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). + float2 uv = float2((vertexID << 1) & 2, vertexID & 2); + return float4(uv * 2 - 1, z, 1); + } + v2f_img vert(appdata_vid v) { v2f_img o; @@ -56,10 +65,7 @@ Shader "Hidden/UnityFx/Outline" UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - // Generate a triangle in homogeneous clip space, s.t. - // v0 = (-1, -1), v1 = (3, -1), v2 = (-1, 3). - float2 uv = float2((v.vertexID << 1) & 2, v.vertexID & 2); - o.pos = float4(uv * 2 - 1, UNITY_NEAR_CLIP_VALUE, 1); + o.pos = GetFullScreenTriangleVertexPosition(v.vertexID, UNITY_NEAR_CLIP_VALUE); o.uv = ComputeScreenPos(o.pos); return o; @@ -69,14 +75,13 @@ Shader "Hidden/UnityFx/Outline" float CalcIntensity(float2 uv, float2 offset) { - float intensity; - int n = _Width; + float intensity = 0; // Accumulates horizontal or vertical blur intensity for the specified texture position. // Set offset = (tx, 0) for horizontal sampling and offset = (0, ty) for vertical. - for (int k = -n; k <= _Width; k += 1) + for (int k = -_Width; k <= _Width; ++k) { - intensity += UNITY_SAMPLE_TEX2D(_MainTex, uv + k * offset).r * _GaussSamples[abs(k)]; + intensity += UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, uv + k * offset).r * _GaussSamples[abs(k)]; } return intensity; @@ -84,12 +89,13 @@ Shader "Hidden/UnityFx/Outline" float4 frag_h(v2f_img i) : SV_Target { - return CalcIntensity(i.uv, float2(_MainTex_TexelSize.x, 0)); + float intensity = CalcIntensity(i.uv, float2(_MainTex_TexelSize.x, 0)); + return float4(intensity, intensity, intensity, 1); } float4 frag_v(v2f_img i) : SV_Target { - if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uv).r > 0) + if (UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MaskTex, i.uv).r > 0) { // TODO: Avoid discard/clip to improve performance on mobiles. discard; From 2011dd6cc6af02c8e530f2e7a57bbab4f6d2a445 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 9 May 2020 19:54:41 +0300 Subject: [PATCH 24/61] OutlineRenderer refactoring --- .../Runtime/Scripts/OutlineBehaviour.cs | 4 +- .../Runtime/Scripts/OutlineEffect.cs | 4 +- .../Runtime/Scripts/OutlineRenderer.cs | 163 +++++++++++------- .../Runtime/Scripts/OutlineRenderer.cs.meta | 2 - 4 files changed, 100 insertions(+), 73 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 838ae67..e856706 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -140,9 +140,9 @@ private void Update() if (_renderers.Count > 0) { - using (var renderer = new OutlineRenderer(cmdBuffer, BuiltinRenderTextureType.CameraTarget)) + using (var renderer = new OutlineRenderer(cmdBuffer, camera.actualRenderingPath)) { - renderer.Render(_renderers.GetList(), _outlineResources, _outlineSettings, camera.actualRenderingPath); + renderer.Render(_renderers.GetList(), _outlineResources, _outlineSettings); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index 4f5e687..c36e1d5 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -219,14 +219,14 @@ private void FillCommandBuffer() if (_outlineResources && _outlineResources.IsValid) { - using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) + using (var renderer = new OutlineRenderer(_commandBuffer, _camera.actualRenderingPath)) { _renderObjects.Clear(); _outlineLayers.GetRenderObjects(_renderObjects); foreach (var renderObject in _renderObjects) { - renderer.Render(renderObject.Renderers, _outlineResources, renderObject.OutlineSettings, _camera.actualRenderingPath); + renderer.Render(renderObject, _outlineResources); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 2e37663..2bc2e30 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -70,8 +70,8 @@ namespace UnityFx.Outline private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex"); - private readonly RenderTargetIdentifier _source; - private readonly RenderTargetIdentifier _destination; + private readonly RenderTargetIdentifier _rt; + private readonly RenderTargetIdentifier _depth; private readonly CommandBuffer _commandBuffer; #endregion @@ -91,69 +91,108 @@ namespace UnityFx.Outline /// /// Initializes a new instance of the struct. /// - /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. - /// Render target. - /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt) - : this(commandBuffer, rt, Vector2Int.zero) + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd) + : this(cmd, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, default) { } /// /// Initializes a new instance of the struct. /// - /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. - /// Render target. - /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt, Vector2Int rtSize) + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// The rendering path of target camera (). + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd, RenderingPath renderingPath) + : this(cmd, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), default) { - if (commandBuffer is null) - { - throw new ArgumentNullException(nameof(commandBuffer)); - } - - _source = rt; - _destination = rt; - _commandBuffer = commandBuffer; + } - Init(_commandBuffer, rtSize); + /// + /// Initializes a new instance of the struct. + /// + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Render target. + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst) + : this(cmd, dst, BuiltinRenderTextureType.Depth, default) + { } /// /// Initializes a new instance of the struct. /// - /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. - /// Source image. Can be the same as . + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Render target. - /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst) - : this(commandBuffer, src, dst, Vector2Int.zero) + /// Depth dexture to use. + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTargetIdentifier depth) + : this(cmd, dst, depth, default) { } /// /// Initializes a new instance of the struct. /// - /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. - /// Source image. Can be the same as . + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Render target. - /// Size of the temporaty render textures. - /// Thrown if is . - public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst, Vector2Int rtSize) + /// Depth dexture to use. + /// TODO + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTargetIdentifier depth, RenderTextureDescriptor rtDesc) { - if (commandBuffer is null) + if (cmd is null) + { + throw new ArgumentNullException(nameof(cmd)); + } + + if (rtDesc.width <= 0) { - throw new ArgumentNullException(nameof(commandBuffer)); + rtDesc.width = -1; } - Debug.Assert(!src.Equals(dst)); + if (rtDesc.height <= 0) + { + rtDesc.height = -1; + } + + if (rtDesc.dimension == TextureDimension.None || rtDesc.dimension == TextureDimension.Unknown) + { + // TODO: Remove this. + cmd.BeginSample(EffectName); + cmd.GetTemporaryRT(_maskRtId, rtDesc.width, rtDesc.height, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + cmd.GetTemporaryRT(_hPassRtId, rtDesc.width, rtDesc.height, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + } + else + { + rtDesc.shadowSamplingMode = ShadowSamplingMode.None; + rtDesc.depthBufferBits = 0; + rtDesc.colorFormat = RenderTextureFormat.R8; - _source = src; - _destination = dst; - _commandBuffer = commandBuffer; + cmd.BeginSample(EffectName); + cmd.GetTemporaryRT(_maskRtId, rtDesc, FilterMode.Bilinear); + cmd.GetTemporaryRT(_hPassRtId, rtDesc, FilterMode.Bilinear); + } - Init(_commandBuffer, rtSize); - Blit(_commandBuffer, src, dst); + _rt = dst; + _depth = depth; + _commandBuffer = cmd; + } + + /// + /// Renders outline around a single object. This version allows enumeration of with no GC allocations. + /// + /// An object to be outlines. + /// Outline resources. + /// Outline settings. + /// Rendering path used by the target camera (used is is set). + /// Thrown if any of the arguments is . + /// + /// + public void Render(OutlineObject obj, OutlineResources resources) + { + Render(obj.Renderers, resources, obj.OutlineSettings); } /// @@ -166,7 +205,7 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, /// Thrown if any of the arguments is . /// /// - public void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) + public void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings) { if (renderers is null) { @@ -185,7 +224,7 @@ public void Render(IReadOnlyList renderers, OutlineResources resources if (renderers.Count > 0) { - RenderObject(resources, settings, renderers, renderingPath); + RenderObject(resources, settings, renderers); RenderOutline(resources, settings); } } @@ -200,7 +239,7 @@ public void Render(IReadOnlyList renderers, OutlineResources resources /// Thrown if any of the arguments is . /// /// - public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings, RenderingPath renderingPath = RenderingPath.UsePlayerSettings) + public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings) { if (renderer is null) { @@ -217,10 +256,18 @@ public void Render(Renderer renderer, OutlineResources resources, IOutlineSettin throw new ArgumentNullException(nameof(settings)); } - RenderObject(resources, settings, renderer, renderingPath); + RenderObject(resources, settings, renderer); RenderOutline(resources, settings); } + /// + /// TODO + /// + public static RenderTargetIdentifier GetBuiltinDepth(RenderingPath renderingPath) + { + return (renderingPath == RenderingPath.DeferredShading || renderingPath == RenderingPath.DeferredLighting) ? BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth; + } + #endregion #region IDisposable @@ -239,16 +286,12 @@ public void Dispose() #region implementation - private void RenderObjectClear(OutlineRenderFlags flags, RenderingPath renderingPath) + private void RenderObjectClear(OutlineRenderFlags flags) { if ((flags & OutlineRenderFlags.EnableDepthTesting) != 0) { - // Have to use BuiltinRenderTextureType.ResolvedDepth for deferred, BuiltinRenderTextureType.Depth for forward. - var depthTextureId = (renderingPath == RenderingPath.DeferredShading || renderingPath == RenderingPath.DeferredLighting) ? - BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth; - // NOTE: Use the camera depth buffer when rendering the mask. Shader only reads from the depth buffer (ZWrite Off). - _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, depthTextureId, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); + _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, _depth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); } else { @@ -258,9 +301,9 @@ private void RenderObjectClear(OutlineRenderFlags flags, RenderingPath rendering _commandBuffer.ClearRenderTarget(false, true, Color.clear); } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IReadOnlyList renderers, RenderingPath renderingPath) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, IReadOnlyList renderers) { - RenderObjectClear(settings.OutlineRenderMode, renderingPath); + RenderObjectClear(settings.OutlineRenderMode); for (var i = 0; i < renderers.Count; ++i) { @@ -280,9 +323,9 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, } } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer, RenderingPath renderingPath) + private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer) { - RenderObjectClear(settings.OutlineRenderMode, renderingPath); + RenderObjectClear(settings.OutlineRenderMode); if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) { @@ -309,7 +352,7 @@ private void RenderOutline(OutlineResources resources, IOutlineSettings settings Blit(_commandBuffer, _maskRtId, resources, _hPassId, mat, props); // VPassBlend - _commandBuffer.SetRenderTarget(_destination, _source.Equals(_destination) ? RenderBufferLoadAction.Load : RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + _commandBuffer.SetRenderTarget(_rt, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store); Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props); } @@ -324,20 +367,6 @@ private static void Init(CommandBuffer cmdBuffer, Vector2Int rtSize) cmdBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst) - { - if (SystemInfo.copyTextureSupport > CopyTextureSupport.None) - { - cmdBuffer.CopyTexture(src, dst); - } - else - { - cmdBuffer.SetRenderTarget(dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - cmdBuffer.Blit(src, BuiltinRenderTextureType.CurrentActive); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, OutlineResources resources, int shaderPass, Material mat, MaterialPropertyBlock props) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs.meta index 90c49ef..6bfadc4 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs.meta +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs.meta @@ -1,7 +1,5 @@ fileFormatVersion: 2 guid: 4271470bd9f5d5041a4a8881d8457a55 -timeCreated: 1566150038 -licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 From e24bc896984cddcfe211a74f1a250c8661b3fca2 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 9 May 2020 22:19:48 +0300 Subject: [PATCH 25/61] Misc renderer changes --- .../Editor/Scripts/OutlineRendererTests.cs | 47 ------ .../Scripts/OutlineRendererTests.cs.meta | 11 -- .../Runtime/Scripts/OutlineBehaviour.cs | 4 +- .../Runtime/Scripts/OutlineEffect.cs | 4 +- .../Runtime/Scripts/OutlineRenderer.cs | 147 ++++++++---------- 5 files changed, 69 insertions(+), 144 deletions(-) delete mode 100644 Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs delete mode 100644 Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs.meta diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs deleted file mode 100644 index 89e4b7d..0000000 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.TestTools; -using NUnit.Framework; - -namespace UnityFx.Outline -{ - [Category("OutlineRenderer"), TestOf(typeof(OutlineRenderer))] - public class OutlineRendererTests : IDisposable - { - private CommandBuffer _commandBuffer; - private OutlineRenderer _renderer; - - [SetUp] - public void Init() - { - _commandBuffer = new CommandBuffer(); - _renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget); - } - - [TearDown] - public void Dispose() - { - _commandBuffer.Dispose(); - } - - [Test] - public void Dispose_CanBeCalledMultipleTimes() - { - _renderer.Dispose(); - _renderer.Dispose(); - } - - [Test] - public void RenderSingleObject_ThrowsIfNullArguments() - { - Assert.Throws(() => _renderer.Render(default(IReadOnlyList), null, null)); - Assert.Throws(() => _renderer.Render(default(Renderer), null, null)); - } - } -} diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs.meta b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs.meta deleted file mode 100644 index dce56a7..0000000 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineRendererTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0c4dcc61e824b6f4f8805dbe543d2997 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index e856706..01d63cd 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -140,9 +140,9 @@ private void Update() if (_renderers.Count > 0) { - using (var renderer = new OutlineRenderer(cmdBuffer, camera.actualRenderingPath)) + using (var renderer = new OutlineRenderer(cmdBuffer, _outlineResources, camera.actualRenderingPath)) { - renderer.Render(_renderers.GetList(), _outlineResources, _outlineSettings); + renderer.Render(_renderers.GetList(), _outlineSettings); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index c36e1d5..3eae2b3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -219,14 +219,14 @@ private void FillCommandBuffer() if (_outlineResources && _outlineResources.IsValid) { - using (var renderer = new OutlineRenderer(_commandBuffer, _camera.actualRenderingPath)) + using (var renderer = new OutlineRenderer(_commandBuffer, _outlineResources, _camera.actualRenderingPath)) { _renderObjects.Clear(); _outlineLayers.GetRenderObjects(_renderObjects); foreach (var renderObject in _renderObjects) { - renderer.Render(renderObject, _outlineResources); + renderer.Render(renderObject); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 2bc2e30..744aea9 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -73,6 +73,7 @@ namespace UnityFx.Outline private readonly RenderTargetIdentifier _rt; private readonly RenderTargetIdentifier _depth; private readonly CommandBuffer _commandBuffer; + private readonly OutlineResources _resources; #endregion @@ -93,8 +94,8 @@ namespace UnityFx.Outline /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd) - : this(cmd, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, default) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources) + : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, GetDefaultRtDesc()) { } @@ -104,8 +105,8 @@ public OutlineRenderer(CommandBuffer cmd) /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// The rendering path of target camera (). /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, RenderingPath renderingPath) - : this(cmd, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), default) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderingPath renderingPath) + : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), GetDefaultRtDesc()) { } @@ -115,8 +116,8 @@ public OutlineRenderer(CommandBuffer cmd, RenderingPath renderingPath) /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. /// Render target. /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst) - : this(cmd, dst, BuiltinRenderTextureType.Depth, default) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst) + : this(cmd, resources, dst, BuiltinRenderTextureType.Depth, GetDefaultRtDesc()) { } @@ -127,8 +128,8 @@ public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst) /// Render target. /// Depth dexture to use. /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTargetIdentifier depth) - : this(cmd, dst, depth, default) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderTargetIdentifier depth) + : this(cmd, resources, dst, depth, GetDefaultRtDesc()) { } @@ -136,17 +137,23 @@ public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTarg /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// Render target. /// Depth dexture to use. - /// TODO + /// Render texture decsriptor. /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTargetIdentifier depth, RenderTextureDescriptor rtDesc) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderTargetIdentifier depth, RenderTextureDescriptor rtDesc) { if (cmd is null) { throw new ArgumentNullException(nameof(cmd)); } + if (resources is null) + { + throw new ArgumentNullException(nameof(resources)); + } + if (rtDesc.width <= 0) { rtDesc.width = -1; @@ -159,64 +166,50 @@ public OutlineRenderer(CommandBuffer cmd, RenderTargetIdentifier dst, RenderTarg if (rtDesc.dimension == TextureDimension.None || rtDesc.dimension == TextureDimension.Unknown) { - // TODO: Remove this. - cmd.BeginSample(EffectName); - cmd.GetTemporaryRT(_maskRtId, rtDesc.width, rtDesc.height, 0, FilterMode.Bilinear, RenderTextureFormat.R8); - cmd.GetTemporaryRT(_hPassRtId, rtDesc.width, rtDesc.height, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + rtDesc.dimension = TextureDimension.Tex2D; } - else - { - rtDesc.shadowSamplingMode = ShadowSamplingMode.None; - rtDesc.depthBufferBits = 0; - rtDesc.colorFormat = RenderTextureFormat.R8; - cmd.BeginSample(EffectName); - cmd.GetTemporaryRT(_maskRtId, rtDesc, FilterMode.Bilinear); - cmd.GetTemporaryRT(_hPassRtId, rtDesc, FilterMode.Bilinear); - } + rtDesc.shadowSamplingMode = ShadowSamplingMode.None; + rtDesc.depthBufferBits = 0; + rtDesc.colorFormat = RenderTextureFormat.R8; + rtDesc.volumeDepth = 1; + + cmd.BeginSample(EffectName); + cmd.GetTemporaryRT(_maskRtId, rtDesc, FilterMode.Bilinear); + cmd.GetTemporaryRT(_hPassRtId, rtDesc, FilterMode.Bilinear); _rt = dst; _depth = depth; _commandBuffer = cmd; + _resources = resources; } /// /// Renders outline around a single object. This version allows enumeration of with no GC allocations. /// - /// An object to be outlines. - /// Outline resources. - /// Outline settings. - /// Rendering path used by the target camera (used is is set). - /// Thrown if any of the arguments is . - /// - /// - public void Render(OutlineObject obj, OutlineResources resources) + /// An object to be outlined. + /// + /// + public void Render(OutlineObject obj) { - Render(obj.Renderers, resources, obj.OutlineSettings); + Render(obj.Renderers, obj.OutlineSettings); } /// /// Renders outline around a single object. This version allows enumeration of with no GC allocations. /// /// One or more renderers representing a single object to be outlined. - /// Outline resources. /// Outline settings. - /// Rendering path used by the target camera (used is is set). /// Thrown if any of the arguments is . - /// - /// - public void Render(IReadOnlyList renderers, OutlineResources resources, IOutlineSettings settings) + /// + /// + public void Render(IReadOnlyList renderers, IOutlineSettings settings) { if (renderers is null) { throw new ArgumentNullException(nameof(renderers)); } - if (resources is null) - { - throw new ArgumentNullException(nameof(resources)); - } - if (settings is null) { throw new ArgumentNullException(nameof(settings)); @@ -224,8 +217,8 @@ public void Render(IReadOnlyList renderers, OutlineResources resources if (renderers.Count > 0) { - RenderObject(resources, settings, renderers); - RenderOutline(resources, settings); + RenderObject(settings, renderers); + RenderOutline(settings); } } @@ -233,41 +226,42 @@ public void Render(IReadOnlyList renderers, OutlineResources resources /// Renders outline around a single object. /// /// A representing an object to be outlined. - /// Outline resources. /// Outline settings. - /// Rendering path used by the target camera (used is is set). /// Thrown if any of the arguments is . - /// - /// - public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings) + /// + /// + public void Render(Renderer renderer, IOutlineSettings settings) { if (renderer is null) { throw new ArgumentNullException(nameof(renderer)); } - if (resources is null) - { - throw new ArgumentNullException(nameof(resources)); - } - if (settings is null) { throw new ArgumentNullException(nameof(settings)); } - RenderObject(resources, settings, renderer); - RenderOutline(resources, settings); + RenderObject(settings, renderer); + RenderOutline(settings); } /// - /// TODO + /// Gets depth texture identifier for built-in render pipeline. /// public static RenderTargetIdentifier GetBuiltinDepth(RenderingPath renderingPath) { return (renderingPath == RenderingPath.DeferredShading || renderingPath == RenderingPath.DeferredLighting) ? BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth; } + /// + /// Creates a default instance or . + /// + public static RenderTextureDescriptor GetDefaultRtDesc() + { + return new RenderTextureDescriptor(-1, -1, RenderTextureFormat.R8, 0); + } + #endregion #region IDisposable @@ -301,7 +295,7 @@ private void RenderObjectClear(OutlineRenderFlags flags) _commandBuffer.ClearRenderTarget(false, true, Color.clear); } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, IReadOnlyList renderers) + private void RenderObject(IOutlineSettings settings, IReadOnlyList renderers) { RenderObjectClear(settings.OutlineRenderMode); @@ -313,17 +307,17 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. - r.GetSharedMaterials(resources.TmpMaterials); + r.GetSharedMaterials(_resources.TmpMaterials); - for (var j = 0; j < resources.TmpMaterials.Count; ++j) + for (var j = 0; j < _resources.TmpMaterials.Count; ++j) { - _commandBuffer.DrawRenderer(r, resources.RenderMaterial, j); + _commandBuffer.DrawRenderer(r, _resources.RenderMaterial, j); } } } } - private void RenderObject(OutlineResources resources, IOutlineSettings settings, Renderer renderer) + private void RenderObject(IOutlineSettings settings, Renderer renderer) { RenderObjectClear(settings.OutlineRenderMode); @@ -331,40 +325,29 @@ private void RenderObject(OutlineResources resources, IOutlineSettings settings, { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. - renderer.GetSharedMaterials(resources.TmpMaterials); + renderer.GetSharedMaterials(_resources.TmpMaterials); - for (var i = 0; i < resources.TmpMaterials.Count; ++i) + for (var i = 0; i < _resources.TmpMaterials.Count; ++i) { - _commandBuffer.DrawRenderer(renderer, resources.RenderMaterial, i); + _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i); } } } - private void RenderOutline(OutlineResources resources, IOutlineSettings settings) + private void RenderOutline(IOutlineSettings settings) { - var mat = resources.OutlineMaterial; - var props = resources.GetProperties(settings); + var mat = _resources.OutlineMaterial; + var props = _resources.GetProperties(settings); - _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); + _commandBuffer.SetGlobalFloatArray(_resources.GaussSamplesId, _resources.GetGaussSamples(settings.OutlineWidth)); // HPass _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _maskRtId, resources, _hPassId, mat, props); + Blit(_commandBuffer, _maskRtId, _resources, _hPassId, mat, props); // VPassBlend _commandBuffer.SetRenderTarget(_rt, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _hPassRtId, resources, _vPassId, mat, props); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Init(CommandBuffer cmdBuffer, Vector2Int rtSize) - { - var cx = rtSize.x > 0 ? rtSize.x : -1; - var cy = rtSize.y > 0 ? rtSize.y : -1; - - cmdBuffer.BeginSample(EffectName); - cmdBuffer.GetTemporaryRT(_maskRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); - cmdBuffer.GetTemporaryRT(_hPassRtId, cx, cy, 0, FilterMode.Bilinear, RenderTextureFormat.R8); + Blit(_commandBuffer, _hPassRtId, _resources, _vPassId, mat, props); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From f2044d780b0a77fdd38aff6daf2ba0683dd1c6bb Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 9 May 2020 23:11:52 +0300 Subject: [PATCH 26/61] Post-processing related fixes --- .../Runtime/Scripts/OutlineRenderer.cs | 48 +++++++------------ .../Runtime/Scripts/OutlineEffectRenderer.cs | 16 +++++-- Outline.PostProcessing/Packages/manifest.json | 11 +---- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 744aea9..cbb6433 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -24,41 +24,13 @@ namespace UnityFx.Outline /// /// var commandBuffer = new CommandBuffer(); /// - /// using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget)) + /// using (var renderer = new OutlineRenderer(commandBuffer, resources)) /// { - /// renderer.Render(renderers, resources, settings); + /// renderer.Render(renderers, settings); /// } /// /// camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer); /// - /// - /// [Preserve] - /// public class OutlineEffectRenderer : PostProcessEffectRenderer - /// { - /// public override void Init() - /// { - /// base.Init(); - /// - /// // Reuse fullscreen triangle mesh from PostProcessing (do not create own). - /// settings.OutlineResources.FullscreenTriangleMesh = RuntimeUtilities.fullscreenTriangle; - /// } - /// - /// public override void Render(PostProcessRenderContext context) - /// { - /// var resources = settings.OutlineResources; - /// var layers = settings.OutlineLayers; - /// - /// if (resources && resources.IsValid && layers) - /// { - /// // No need to setup property sheet parameters, all the rendering staff is handled by the OutlineRenderer. - /// using (var renderer = new OutlineRenderer(context.command, context.source, context.destination)) - /// { - /// layers.Render(renderer, resources); - /// } - /// } - /// } - /// } - /// /// public readonly struct OutlineRenderer : IDisposable { @@ -93,6 +65,7 @@ namespace UnityFx.Outline /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources) : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, GetDefaultRtDesc()) @@ -103,6 +76,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources) /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// The rendering path of target camera (). /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderingPath renderingPath) @@ -114,6 +88,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderingP /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// Render target. /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst) @@ -125,6 +100,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// Render target. /// Depth dexture to use. /// Thrown if is . @@ -133,6 +109,18 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg { } + /// + /// Initializes a new instance of the struct. + /// + /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Render target. + /// The rendering path of target camera (). + /// Thrown if is . + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderingPath renderingPath) + : this(cmd, resources, dst, GetBuiltinDepth(renderingPath), GetDefaultRtDesc()) + { + } + /// /// Initializes a new instance of the struct. /// diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs index 3b8cf2f..ff3a481 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs @@ -2,6 +2,7 @@ // See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.PostProcessing; using UnityEngine.Scripting; @@ -12,12 +13,13 @@ namespace UnityFx.Outline.PostProcessing public sealed class OutlineEffectRenderer : PostProcessEffectRenderer { private OutlineResources _defaultResources; + private List _objects = new List(); public override void Render(PostProcessRenderContext context) { OutlineResources resources; - if (settings.Resources.value != null) + if (settings.Resources.value) { resources = settings.Resources; } @@ -35,9 +37,17 @@ public override void Render(PostProcessRenderContext context) if (resources && resources.IsValid) { - using (var renderer = new OutlineRenderer(context.command, context.source, context.destination)) + RuntimeUtilities.CopyTexture(context.command, context.source, context.destination); + + using (var renderer = new OutlineRenderer(context.command, resources, context.destination, context.camera.actualRenderingPath)) { - settings.Layers.value.Render(renderer, resources); + _objects.Clear(); + settings.Layers.value.GetRenderObjects(_objects); + + foreach (var obj in _objects) + { + renderer.Render(obj); + } } } } diff --git a/Outline.PostProcessing/Packages/manifest.json b/Outline.PostProcessing/Packages/manifest.json index 215c50c..1a706d4 100644 --- a/Outline.PostProcessing/Packages/manifest.json +++ b/Outline.PostProcessing/Packages/manifest.json @@ -1,16 +1,7 @@ { - "scopedRegistries": [ - { - "name": "Arvtesh", - "url": "https://registry.npmjs.org/", - "scopes": [ - "com.unityfx" - ] - } - ], "dependencies": { "com.unity.package-manager-ui": "2.0.8", - "com.unityfx.outline": "0.7.1", + "com.unityfx.outline": "file:../../Outline.Core/Packages/UnityFx.Outline", "com.unity.modules.ai": "1.0.0", "com.unity.modules.animation": "1.0.0", "com.unity.modules.assetbundle": "1.0.0", From 30f756f7bc06586fc9b0d6e52eaa82c19756ba60 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Mon, 11 May 2020 19:00:43 +0300 Subject: [PATCH 27/61] Removed layer Priority field --- .../Scripts/OutlineLayerCollectionTests.cs | 20 ------- .../Runtime/Scripts/OutlineBehaviour.cs | 4 -- .../Runtime/Scripts/OutlineLayer.cs | 33 ---------- .../Runtime/Scripts/OutlineLayerCollection.cs | 60 +------------------ 4 files changed, 1 insertion(+), 116 deletions(-) diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs index fc19adb..1629d5c 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs @@ -140,25 +140,5 @@ public void Contains_SearchesArgument() Assert.IsTrue(_layerCollection.Contains(layer)); } - - [Test] - public void SortedLayers_IsSortedByPriority() - { - var layer1 = new OutlineLayer() - { - Priority = 2 - }; - - var layer2 = new OutlineLayer(); - var layer3 = new OutlineLayer(); - - _layerCollection.Add(layer1); - _layerCollection.Add(layer2); - _layerCollection.Add(layer3); - - Assert.AreEqual(layer2, _layerCollection.SortedLayers[0]); - Assert.AreEqual(layer3, _layerCollection.SortedLayers[1]); - Assert.AreEqual(layer1, _layerCollection.SortedLayers[2]); - } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 01d63cd..9e0b9f5 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -92,10 +92,6 @@ private void Awake() CreateSettingsIfNeeded(); } - private void OnDestroy() - { - } - private void OnEnable() { Camera.onPreRender += OnCameraPreRender; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index b4de106..160f448 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -25,8 +25,6 @@ public sealed partial class OutlineLayer : ICollection, IOutlineSett [SerializeField, HideInInspector] private string _name; [SerializeField, HideInInspector] - private int _zOrder; - [SerializeField, HideInInspector] private bool _enabled = true; private OutlineLayerCollection _parentCollection; @@ -68,31 +66,6 @@ public bool Enabled } } - /// - /// Gets or sets the layer priority. Layers with greater values are rendered on top of layers with lower priority. - /// Layers with equal priorities are rendered according to index in parent collection. - /// - /// - public int Priority - { - get - { - return _zOrder; - } - set - { - if (_zOrder != value) - { - if (_parentCollection != null) - { - _parentCollection.SetOrderChanged(); - } - - _zOrder = value; - } - } - } - /// /// Gets index of the layer in parent collection. /// @@ -436,12 +409,6 @@ public override string ToString() text.Append(_parentCollection.IndexOf(this)); } - if (_zOrder > 0) - { - text.Append(" z"); - text.Append(_zOrder); - } - if (_outlineObjects.Count > 0) { text.Append(" ("); diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 08810fa..a3681af 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -19,45 +19,19 @@ public sealed class OutlineLayerCollection : ScriptableObject, IList - { - public int Compare(OutlineLayer x, OutlineLayer y) - { - return x.Priority - y.Priority; - } - } - [SerializeField, HideInInspector] private List _layers = new List(); - private List _sortedLayers = new List(); - private OutlineLayerComparer _sortComparer = new OutlineLayerComparer(); - private bool _orderChanged = true; - #endregion #region interface - /// - /// Gets layers ordered by . - /// - public OutlineLayer[] SortedLayers - { - get - { - UpdateSortedLayersIfNeeded(); - return _sortedLayers.ToArray(); - } - } - /// /// Gets the objects for rendering. /// public void GetRenderObjects(IList renderObjects) { - UpdateSortedLayersIfNeeded(); - - foreach (var layer in _sortedLayers) + foreach (var layer in _layers) { layer.GetRenderObjects(renderObjects); } @@ -67,11 +41,6 @@ public void GetRenderObjects(IList renderObjects) #region internals - internal void SetOrderChanged() - { - _orderChanged = true; - } - internal void Reset() { foreach (var layer in _layers) @@ -90,8 +59,6 @@ private void OnEnable() { layer.SetCollection(this); } - - _orderChanged = true; } #endregion @@ -123,8 +90,6 @@ public OutlineLayer this[int layerIndex] _layers[layerIndex].SetCollection(null); _layers[layerIndex] = value; - - _orderChanged = true; } } } @@ -151,10 +116,7 @@ public void Insert(int index, OutlineLayer layer) if (layer.ParentCollection != this) { layer.SetCollection(this); - _layers.Insert(index, layer); - - _orderChanged = true; } } @@ -165,8 +127,6 @@ public void RemoveAt(int index) { _layers[index].SetCollection(null); _layers.RemoveAt(index); - - _orderChanged = true; } } @@ -191,9 +151,7 @@ public void Add(OutlineLayer layer) if (layer.ParentCollection != this) { layer.SetCollection(this); - _layers.Add(layer); - _orderChanged = true; } } @@ -203,9 +161,6 @@ public bool Remove(OutlineLayer layer) if (_layers.Remove(layer)) { layer.SetCollection(null); - - _sortedLayers.Remove(layer); - return true; } @@ -223,7 +178,6 @@ public void Clear() } _layers.Clear(); - _sortedLayers.Clear(); } } @@ -262,18 +216,6 @@ IEnumerator IEnumerable.GetEnumerator() #endregion #region implementation - - private void UpdateSortedLayersIfNeeded() - { - if (_orderChanged) - { - _sortedLayers.Clear(); - _sortedLayers.AddRange(_layers); - _sortedLayers.Sort(_sortComparer); - _orderChanged = false; - } - } - #endregion } } From b31ecd220cc813d975cc8c7fa91c2bea10d06990 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Mon, 11 May 2020 19:46:59 +0300 Subject: [PATCH 28/61] OutlineLayerCollection editor fixes --- .../SimplePerCamera/TestOutlineLayers.asset | 6 +- .../Scripts/OutlineLayerCollectionEditor.cs | 178 ++++++++++++++++-- .../Runtime/Scripts/OutlineLayer.cs | 10 +- 3 files changed, 172 insertions(+), 22 deletions(-) diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset index 3de703c..584cbc3 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset +++ b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset @@ -20,7 +20,7 @@ MonoBehaviour: _outlineWidth: 5 _outlineIntensity: 2 _outlineMode: 0 - _name: + _name: My pretty layer _zOrder: 0 _enabled: 1 - _settings: @@ -29,7 +29,7 @@ MonoBehaviour: _outlineWidth: 15 _outlineIntensity: 2 _outlineMode: 1 - _name: + _name: The second layer _zOrder: 0 _enabled: 1 - _settings: @@ -38,6 +38,6 @@ MonoBehaviour: _outlineWidth: 4 _outlineIntensity: 2 _outlineMode: 0 - _name: + _name: The best layer _zOrder: 0 _enabled: 1 diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index f0c57e0..30ebf2f 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using UnityEditor; +using UnityEditorInternal; using UnityEngine; namespace UnityFx.Outline @@ -15,13 +16,31 @@ public class OutlineLayerCollectionEditor : Editor private readonly GUILayoutOption _layerButtonStyle = GUILayout.ExpandWidth(false); private OutlineLayerCollection _layers; + //private SerializedProperty _layersProp; + //private ReorderableList _layersList; + + private void OnEnable() + { + _layers = (OutlineLayerCollection)target; + + //_layersProp = serializedObject.FindProperty("_layers"); + //_layersList = new ReorderableList(serializedObject, _layersProp, true, true, true, true); + //_layersList.drawElementCallback += OnDrawLayer; + //_layersList.drawHeaderCallback += OnDrawHeader; + //_layersList.elementHeightCallback += OnGetElementHeight; + } + public override void OnInspectorGUI() { base.OnInspectorGUI(); + //_layersList.DoLayoutList(); + EditorGUI.BeginChangeCheck(); var removeLayer = -1; + var moveUpLayer = -1; + var moveDownLayer = -1; // 1) Layers list. if (_layers.Count > 0) @@ -49,6 +68,22 @@ public override void OnInspectorGUI() } GUILayout.FlexibleSpace(); + EditorGUI.BeginDisabledGroup(i == 0); + + if (GUILayout.Button("Move Up", _layerButtonStyle)) + { + moveUpLayer = i; + } + + EditorGUI.EndDisabledGroup(); + EditorGUI.BeginDisabledGroup(i == _layers.Count - 1); + + if (GUILayout.Button("Move Down", _layerButtonStyle)) + { + moveDownLayer = i; + } + + EditorGUI.EndDisabledGroup(); if (GUILayout.Button("Remove", _layerButtonStyle)) { @@ -56,7 +91,6 @@ public override void OnInspectorGUI() } EditorGUILayout.EndHorizontal(); - EditorGUILayout.Space(); var name = EditorGUILayout.TextField("Layer Name", _layers[i].NameTag); @@ -66,14 +100,6 @@ public override void OnInspectorGUI() _layers[i].NameTag = name; } - var priority = EditorGUILayout.IntField("Layer Priority", _layers[i].Priority); - - if (priority != _layers[i].Priority) - { - Undo.RecordObject(_layers, "Set Layer Priority"); - _layers[i].Priority = priority; - } - OutlineEditorUtility.Render(_layers[i], _layers); } } @@ -99,6 +125,22 @@ public override void OnInspectorGUI() _layers.Clear(); } + if (moveUpLayer > 0) + { + Undo.RecordObject(_layers, "Move Layer"); + var tmp = _layers[moveUpLayer - 1]; + _layers[moveUpLayer - 1] = _layers[moveUpLayer]; + _layers[moveUpLayer] = tmp; + } + + if (moveDownLayer >= 0) + { + Undo.RecordObject(_layers, "Move Layer"); + var tmp = _layers[moveDownLayer + 1]; + _layers[moveDownLayer + 1] = _layers[moveDownLayer]; + _layers[moveDownLayer] = tmp; + } + if (removeLayer >= 0) { Undo.RecordObject(_layers, "Remove Layer"); @@ -111,11 +153,125 @@ public override void OnInspectorGUI() { EditorUtility.SetDirty(_layers); } + + serializedObject.ApplyModifiedProperties(); } - private void OnEnable() + private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) { - _layers = (OutlineLayerCollection)target; + var lineHeight = EditorGUIUtility.singleLineHeight; + var lineSpacing = EditorGUIUtility.standardVerticalSpacing; + var lineOffset = lineHeight + lineSpacing; + var y = rect.y; + var layer = _layers[index]; + + EditorGUI.BeginChangeCheck(); + + var obj = (OutlineSettings)EditorGUI.ObjectField(new Rect(rect.x, y, rect.width, lineHeight), " ", layer.OutlineSettings, typeof(OutlineSettings), true); + + if (layer.OutlineSettings != obj) + { + Undo.RecordObject(_layers, "Settings"); + layer.OutlineSettings = obj; + } + + var enabled = EditorGUI.ToggleLeft(new Rect(rect.x, y, rect.width, lineHeight), "Layer #" + index.ToString(), layer.Enabled, EditorStyles.boldLabel); + + if (layer.Enabled != enabled) + { + if (enabled) + { + Undo.RecordObject(_layers, "Enable Layer"); + } + else + { + Undo.RecordObject(_layers, "Disable Layer"); + } + + layer.Enabled = enabled; + } + + y += lineOffset; + EditorGUI.DrawRect(new Rect(rect.x, y, rect.width, 1), Color.gray); + EditorGUI.DrawRect(new Rect(rect.x, y + 1, rect.width, 1), Color.white); + + y += lineSpacing + 2; + var name = EditorGUI.TextField(new Rect(rect.x, y, rect.width, lineHeight), "Tag", layer.NameTag); + + if (name != layer.NameTag) + { + Undo.RecordObject(_layers, "Layer Name"); + layer.NameTag = name; + } + + EditorGUI.BeginDisabledGroup(obj != null); + + y += lineOffset; + var color = EditorGUI.ColorField(new Rect(rect.x, y, rect.width, lineHeight), "Color", layer.OutlineColor); + + if (layer.OutlineColor != color) + { + Undo.RecordObject(_layers, "Color"); + layer.OutlineColor = color; + } + + y += lineOffset; + var width = EditorGUI.IntSlider(new Rect(rect.x, y, rect.width, lineHeight), "Width", layer.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); + + if (layer.OutlineWidth != width) + { + Undo.RecordObject(_layers, "Width"); + layer.OutlineWidth = width; + } + + y += lineOffset; + var renderMode = (OutlineRenderFlags)EditorGUI.EnumFlagsField(new Rect(rect.x, y, rect.width, lineHeight), "Render Flags", layer.OutlineRenderMode); + + if (layer.OutlineRenderMode != renderMode) + { + Undo.RecordObject(_layers, "Render Flags"); + layer.OutlineRenderMode = renderMode; + } + + if ((renderMode & OutlineRenderFlags.Blurred) != 0) + { + y += lineOffset; + var i = EditorGUI.Slider(new Rect(rect.x, y, rect.width, lineHeight), "Blur Intensity", layer.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); + + if (!Mathf.Approximately(layer.OutlineIntensity, i)) + { + Undo.RecordObject(_layers, "Blur Intensity"); + layer.OutlineIntensity = i; + } + } + + EditorGUI.EndDisabledGroup(); + + y += lineOffset; + EditorGUI.DrawRect(new Rect(rect.x, y, rect.width, 1), Color.gray); + EditorGUI.DrawRect(new Rect(rect.x, y + 1, rect.width, 1), Color.white); + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(_layers); + } + } + + private void OnDrawHeader(Rect rect) + { + EditorGUI.LabelField(rect, "Layers"); + } + + private float OnGetElementHeight(int index) + { + var numberOfLines = 5; + + if ((_layers[index].OutlineRenderMode & OutlineRenderFlags.Blurred) != 0) + { + ++numberOfLines; + } + + return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * numberOfLines + EditorGUIUtility.standardVerticalSpacing + 5; } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 160f448..c533c2d 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -16,7 +16,7 @@ namespace UnityFx.Outline /// /// [Serializable] - public sealed partial class OutlineLayer : ICollection, IOutlineSettingsEx + public sealed class OutlineLayer : ICollection, IReadOnlyCollection, IOutlineSettingsEx { #region data @@ -210,13 +210,7 @@ internal string NameTag } } - internal OutlineLayerCollection ParentCollection - { - get - { - return _parentCollection; - } - } + internal OutlineLayerCollection ParentCollection => _parentCollection; internal void Reset() { From ae95d2b58369849cee532cbc6f5b6842eabbd95e Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 13 May 2020 13:44:43 +0300 Subject: [PATCH 29/61] Added objects preview to OutlineLayerCollection editor --- .../Scripts/OutlineLayerCollectionEditor.cs | 324 ++++++++---------- .../Runtime/Scripts/OutlineLayer.cs | 132 +++++++ 2 files changed, 275 insertions(+), 181 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index 30ebf2f..3ee0dcf 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -13,146 +13,46 @@ namespace UnityFx.Outline [CustomEditor(typeof(OutlineLayerCollection))] public class OutlineLayerCollectionEditor : Editor { - private readonly GUILayoutOption _layerButtonStyle = GUILayout.ExpandWidth(false); private OutlineLayerCollection _layers; - //private SerializedProperty _layersProp; - //private ReorderableList _layersList; + private SerializedProperty _layersProp; + private ReorderableList _layersList; + + private Dictionary _layerLists = new Dictionary(); private void OnEnable() { _layers = (OutlineLayerCollection)target; - //_layersProp = serializedObject.FindProperty("_layers"); - //_layersList = new ReorderableList(serializedObject, _layersProp, true, true, true, true); - //_layersList.drawElementCallback += OnDrawLayer; - //_layersList.drawHeaderCallback += OnDrawHeader; - //_layersList.elementHeightCallback += OnGetElementHeight; + _layersProp = serializedObject.FindProperty("_layers"); + _layersList = new ReorderableList(serializedObject, _layersProp, true, true, true, true); + _layersList.drawElementCallback += OnDrawLayer; + _layersList.drawHeaderCallback += OnDrawHeader; + _layersList.elementHeightCallback += OnGetElementHeight; + _layersList.onAddCallback += OnAddLayer; + _layersList.onRemoveCallback += OnRemoveLayer; + + foreach (var layer in _layers) + { + AddLayerList(layer); + } } public override void OnInspectorGUI() { base.OnInspectorGUI(); - //_layersList.DoLayoutList(); + _layersList.DoLayoutList(); - EditorGUI.BeginChangeCheck(); - - var removeLayer = -1; - var moveUpLayer = -1; - var moveDownLayer = -1; + EditorGUILayout.Space(); - // 1) Layers list. - if (_layers.Count > 0) + foreach (var list in _layerLists.Values) { - for (var i = 0; i < _layers.Count; i++) + if (list.count > 0) { - EditorGUILayout.Space(); - OutlineEditorUtility.RenderDivider(Color.gray); - - EditorGUILayout.BeginHorizontal(); - var enabled = EditorGUILayout.ToggleLeft("Layer #" + i.ToString(), _layers[i].Enabled, EditorStyles.boldLabel); - - if (enabled != _layers[i].Enabled) - { - if (enabled) - { - Undo.RecordObject(_layers, "Enable Layer"); - } - else - { - Undo.RecordObject(_layers, "Disable Layer"); - } - - _layers[i].Enabled = enabled; - } - - GUILayout.FlexibleSpace(); - EditorGUI.BeginDisabledGroup(i == 0); - - if (GUILayout.Button("Move Up", _layerButtonStyle)) - { - moveUpLayer = i; - } - - EditorGUI.EndDisabledGroup(); - EditorGUI.BeginDisabledGroup(i == _layers.Count - 1); - - if (GUILayout.Button("Move Down", _layerButtonStyle)) - { - moveDownLayer = i; - } - - EditorGUI.EndDisabledGroup(); - - if (GUILayout.Button("Remove", _layerButtonStyle)) - { - removeLayer = i; - } - - EditorGUILayout.EndHorizontal(); - - var name = EditorGUILayout.TextField("Layer Name", _layers[i].NameTag); - - if (name != _layers[i].NameTag) - { - Undo.RecordObject(_layers, "Set Layer Name"); - _layers[i].NameTag = name; - } - - OutlineEditorUtility.Render(_layers[i], _layers); + list.DoLayoutList(); } } - else - { - EditorGUILayout.HelpBox("The layer collection is empty.", MessageType.Info, true); - } - - // Add/remove processing. - OutlineEditorUtility.RenderDivider(Color.gray); - EditorGUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - - if (GUILayout.Button("Add New", _layerButtonStyle)) - { - Undo.RecordObject(_layers, "Add Layer"); - _layers.Add(new OutlineLayer()); - } - - if (GUILayout.Button("Remove All", _layerButtonStyle)) - { - Undo.RecordObject(_layers, "Remove All Layers"); - _layers.Clear(); - } - - if (moveUpLayer > 0) - { - Undo.RecordObject(_layers, "Move Layer"); - var tmp = _layers[moveUpLayer - 1]; - _layers[moveUpLayer - 1] = _layers[moveUpLayer]; - _layers[moveUpLayer] = tmp; - } - - if (moveDownLayer >= 0) - { - Undo.RecordObject(_layers, "Move Layer"); - var tmp = _layers[moveDownLayer + 1]; - _layers[moveDownLayer + 1] = _layers[moveDownLayer]; - _layers[moveDownLayer] = tmp; - } - - if (removeLayer >= 0) - { - Undo.RecordObject(_layers, "Remove Layer"); - _layers.RemoveAt(removeLayer); - } - - EditorGUILayout.EndHorizontal(); - - if (EditorGUI.EndChangeCheck()) - { - EditorUtility.SetDirty(_layers); - } serializedObject.ApplyModifiedProperties(); } @@ -162,94 +62,109 @@ private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) var lineHeight = EditorGUIUtility.singleLineHeight; var lineSpacing = EditorGUIUtility.standardVerticalSpacing; var lineOffset = lineHeight + lineSpacing; - var y = rect.y; + var y = rect.y + lineSpacing; var layer = _layers[index]; + var settingsDisabled = false; EditorGUI.BeginChangeCheck(); - var obj = (OutlineSettings)EditorGUI.ObjectField(new Rect(rect.x, y, rect.width, lineHeight), " ", layer.OutlineSettings, typeof(OutlineSettings), true); - - if (layer.OutlineSettings != obj) + // Header { - Undo.RecordObject(_layers, "Settings"); - layer.OutlineSettings = obj; - } + var rc = new Rect(rect.x, y, rect.width, lineHeight); + var bgRect = new Rect(rect.x - 2, y - 2, rect.width + 3, lineHeight + 3); - var enabled = EditorGUI.ToggleLeft(new Rect(rect.x, y, rect.width, lineHeight), "Layer #" + index.ToString(), layer.Enabled, EditorStyles.boldLabel); + // Header background + EditorGUI.DrawRect(rc, Color.gray); + EditorGUI.DrawRect(new Rect(bgRect.x, bgRect.y, bgRect.width, 1), Color.gray); + EditorGUI.DrawRect(new Rect(bgRect.x, bgRect.yMax, bgRect.width, 1), Color.gray); + EditorGUI.DrawRect(new Rect(bgRect.x, bgRect.y, 1, bgRect.height), Color.gray); + EditorGUI.DrawRect(new Rect(bgRect.xMax, bgRect.y, 1, bgRect.height), Color.gray); - if (layer.Enabled != enabled) - { - if (enabled) + var obj = (OutlineSettings)EditorGUI.ObjectField(rc, " ", layer.OutlineSettings, typeof(OutlineSettings), true); + + if (layer.OutlineSettings != obj) { - Undo.RecordObject(_layers, "Enable Layer"); + Undo.RecordObject(_layers, "Settings"); + layer.OutlineSettings = obj; } - else + + var enabled = EditorGUI.ToggleLeft(rc, "Layer #" + index.ToString(), layer.Enabled, EditorStyles.boldLabel); + + if (layer.Enabled != enabled) { - Undo.RecordObject(_layers, "Disable Layer"); + if (enabled) + { + Undo.RecordObject(_layers, "Enable Layer"); + } + else + { + Undo.RecordObject(_layers, "Disable Layer"); + } + + layer.Enabled = enabled; } - layer.Enabled = enabled; + settingsDisabled = obj != null; + y += lineOffset; } - y += lineOffset; - EditorGUI.DrawRect(new Rect(rect.x, y, rect.width, 1), Color.gray); - EditorGUI.DrawRect(new Rect(rect.x, y + 1, rect.width, 1), Color.white); - - y += lineSpacing + 2; - var name = EditorGUI.TextField(new Rect(rect.x, y, rect.width, lineHeight), "Tag", layer.NameTag); - - if (name != layer.NameTag) + // Layer properties { - Undo.RecordObject(_layers, "Layer Name"); - layer.NameTag = name; - } + var name = EditorGUI.TextField(new Rect(rect.x, y, rect.width, lineHeight), "Name", layer.NameTag); - EditorGUI.BeginDisabledGroup(obj != null); + if (name != layer.NameTag) + { + Undo.RecordObject(_layers, "Layer Name"); + layer.NameTag = name; + } - y += lineOffset; - var color = EditorGUI.ColorField(new Rect(rect.x, y, rect.width, lineHeight), "Color", layer.OutlineColor); + y += lineOffset; + } - if (layer.OutlineColor != color) + // Outline settings { - Undo.RecordObject(_layers, "Color"); - layer.OutlineColor = color; - } + EditorGUI.BeginDisabledGroup(settingsDisabled); - y += lineOffset; - var width = EditorGUI.IntSlider(new Rect(rect.x, y, rect.width, lineHeight), "Width", layer.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); + var color = EditorGUI.ColorField(new Rect(rect.x, y, rect.width, lineHeight), "Color", layer.OutlineColor); - if (layer.OutlineWidth != width) - { - Undo.RecordObject(_layers, "Width"); - layer.OutlineWidth = width; - } + if (layer.OutlineColor != color) + { + Undo.RecordObject(_layers, "Color"); + layer.OutlineColor = color; + } - y += lineOffset; - var renderMode = (OutlineRenderFlags)EditorGUI.EnumFlagsField(new Rect(rect.x, y, rect.width, lineHeight), "Render Flags", layer.OutlineRenderMode); + y += lineOffset; + var width = EditorGUI.IntSlider(new Rect(rect.x, y, rect.width, lineHeight), "Width", layer.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); - if (layer.OutlineRenderMode != renderMode) - { - Undo.RecordObject(_layers, "Render Flags"); - layer.OutlineRenderMode = renderMode; - } + if (layer.OutlineWidth != width) + { + Undo.RecordObject(_layers, "Width"); + layer.OutlineWidth = width; + } - if ((renderMode & OutlineRenderFlags.Blurred) != 0) - { y += lineOffset; - var i = EditorGUI.Slider(new Rect(rect.x, y, rect.width, lineHeight), "Blur Intensity", layer.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); + var renderMode = (OutlineRenderFlags)EditorGUI.EnumFlagsField(new Rect(rect.x, y, rect.width, lineHeight), "Render Flags", layer.OutlineRenderMode); - if (!Mathf.Approximately(layer.OutlineIntensity, i)) + if (layer.OutlineRenderMode != renderMode) { - Undo.RecordObject(_layers, "Blur Intensity"); - layer.OutlineIntensity = i; + Undo.RecordObject(_layers, "Render Flags"); + layer.OutlineRenderMode = renderMode; } - } - EditorGUI.EndDisabledGroup(); + if ((renderMode & OutlineRenderFlags.Blurred) != 0) + { + y += lineOffset; + var i = EditorGUI.Slider(new Rect(rect.x, y, rect.width, lineHeight), "Blur Intensity", layer.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); - y += lineOffset; - EditorGUI.DrawRect(new Rect(rect.x, y, rect.width, 1), Color.gray); - EditorGUI.DrawRect(new Rect(rect.x, y + 1, rect.width, 1), Color.white); + if (!Mathf.Approximately(layer.OutlineIntensity, i)) + { + Undo.RecordObject(_layers, "Blur Intensity"); + layer.OutlineIntensity = i; + } + } + + EditorGUI.EndDisabledGroup(); + } if (EditorGUI.EndChangeCheck()) { @@ -259,7 +174,7 @@ private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) private void OnDrawHeader(Rect rect) { - EditorGUI.LabelField(rect, "Layers"); + EditorGUI.LabelField(rect, "Layer settings"); } private float OnGetElementHeight(int index) @@ -271,7 +186,54 @@ private float OnGetElementHeight(int index) ++numberOfLines; } - return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * numberOfLines + EditorGUIUtility.standardVerticalSpacing + 5; + return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * numberOfLines + EditorGUIUtility.standardVerticalSpacing; + } + + private void OnAddLayer(ReorderableList list) + { + var layer = new OutlineLayer(); + + Undo.RecordObject(_layers, "Add Layer"); + EditorUtility.SetDirty(_layers); + + _layers.Add(layer); + AddLayerList(layer); + } + + private void OnRemoveLayer(ReorderableList list) + { + var index = list.index; + var layer = _layers[index]; + + Undo.RecordObject(_layers, "Remove Layer"); + EditorUtility.SetDirty(_layers); + + _layers.RemoveAt(index); + _layerLists.Remove(layer); + } + + private void AddLayerList(OutlineLayer layer) + { + var list = new ReorderableList(layer.GetList(), typeof(GameObject), false, true, false, false); + + list.drawElementCallback += (rect, index, isActive, isFocused) => + { + EditorGUI.BeginDisabledGroup(true); + EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), "#" + index, list.list[index] as GameObject, typeof(GameObject), true); + EditorGUI.EndDisabledGroup(); + }; + + list.drawHeaderCallback += (rect) => + { + EditorGUI.LabelField(rect, layer.Name); + }; + + list.elementHeightCallback += (index) => + { + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + }; + + _layerLists.Add(layer, list); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index c533c2d..c5b24e9 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -30,6 +30,124 @@ public sealed class OutlineLayer : ICollection, IReadOnlyCollection< private OutlineLayerCollection _parentCollection; private Dictionary _outlineObjects = new Dictionary(); +#if UNITY_EDITOR + + private class EditorList : IList + { + private readonly Dictionary _objects; + + public EditorList(OutlineLayer layer) + { + _objects = layer._outlineObjects; + } + + public object this[int index] + { + get + { + var myIndex = 0; + + foreach (var go in _objects.Keys) + { + if (myIndex == index) + { + return go; + } + + myIndex++; + } + + return null; + } + set + { + throw new NotImplementedException(); + } + } + + public bool IsFixedSize => false; + + public bool IsReadOnly => true; + + public int Count => _objects.Count; + + public bool IsSynchronized => false; + + public object SyncRoot => null; + + public bool Contains(object value) + { + if (value is GameObject go) + { + return _objects.ContainsKey(go); + } + + return false; + } + + public void CopyTo(Array array, int index) + { + foreach (var go in _objects.Keys) + { + array.SetValue(go, index++); + } + } + + public IEnumerator GetEnumerator() + { + return _objects.Keys.GetEnumerator(); + } + + public int IndexOf(object value) + { + if (value is GameObject valueGo) + { + var index = 0; + + foreach (var go in _objects.Keys) + { + if (go == valueGo) + { + return index; + } + + index++; + } + } + + return -1; + } + + public int Add(object value) + { + throw new NotImplementedException(); + } + + public void Insert(int index, object value) + { + throw new NotImplementedException(); + } + + public void Remove(object value) + { + throw new NotImplementedException(); + } + + public void RemoveAt(int index) + { + throw new NotImplementedException(); + } + + public void Clear() + { + throw new NotImplementedException(); + } + } + + private EditorList _editorObjects; + +#endif + #endregion #region interface @@ -212,6 +330,20 @@ internal string NameTag internal OutlineLayerCollection ParentCollection => _parentCollection; +#if UNITY_EDITOR + + internal IList GetList() + { + if (_editorObjects is null) + { + _editorObjects = new EditorList(this); + } + + return _editorObjects; + } + +#endif + internal void Reset() { _outlineObjects.Clear(); From 6c0391879818c2f21632917acf0307c482cfbb3a Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Wed, 13 May 2020 14:56:17 +0300 Subject: [PATCH 30/61] tt --- .../Scripts/OutlineLayerCollectionEditor.cs | 52 ++++++------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index 3ee0dcf..86c799a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -18,8 +18,6 @@ public class OutlineLayerCollectionEditor : Editor private SerializedProperty _layersProp; private ReorderableList _layersList; - private Dictionary _layerLists = new Dictionary(); - private void OnEnable() { _layers = (OutlineLayerCollection)target; @@ -31,11 +29,6 @@ private void OnEnable() _layersList.elementHeightCallback += OnGetElementHeight; _layersList.onAddCallback += OnAddLayer; _layersList.onRemoveCallback += OnRemoveLayer; - - foreach (var layer in _layers) - { - AddLayerList(layer); - } } public override void OnInspectorGUI() @@ -46,11 +39,24 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); - foreach (var list in _layerLists.Values) + foreach (var layer in _layers) { - if (list.count > 0) + if (layer.Count > 0) { - list.DoLayoutList(); + EditorGUILayout.LabelField(layer.Name, EditorStyles.boldLabel); + EditorGUI.BeginDisabledGroup(true); + EditorGUI.indentLevel += 1; + + var index = 0; + + foreach (var go in layer) + { + EditorGUILayout.ObjectField("#" + index, go, typeof(GameObject), true); + index++; + } + + EditorGUI.indentLevel -= 1; + EditorGUI.EndDisabledGroup(); } } @@ -197,7 +203,6 @@ private void OnAddLayer(ReorderableList list) EditorUtility.SetDirty(_layers); _layers.Add(layer); - AddLayerList(layer); } private void OnRemoveLayer(ReorderableList list) @@ -209,31 +214,6 @@ private void OnRemoveLayer(ReorderableList list) EditorUtility.SetDirty(_layers); _layers.RemoveAt(index); - _layerLists.Remove(layer); - } - - private void AddLayerList(OutlineLayer layer) - { - var list = new ReorderableList(layer.GetList(), typeof(GameObject), false, true, false, false); - - list.drawElementCallback += (rect, index, isActive, isFocused) => - { - EditorGUI.BeginDisabledGroup(true); - EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), "#" + index, list.list[index] as GameObject, typeof(GameObject), true); - EditorGUI.EndDisabledGroup(); - }; - - list.drawHeaderCallback += (rect) => - { - EditorGUI.LabelField(rect, layer.Name); - }; - - list.elementHeightCallback += (index) => - { - return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - }; - - _layerLists.Add(layer, list); } } } From 7d2c4c83f91381e578c8d0285ac140c3309974d7 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Wed, 13 May 2020 22:08:03 +0300 Subject: [PATCH 31/61] Removed IOutlineSettingsEx --- .../SimplePerCamera/TestOutlineLayers.asset | 3 - .../Helpers/IOutlineSettingsExTests.cs | 98 ------------------- .../Helpers/IOutlineSettingsExTests.cs.meta | 11 --- .../Editor/Scripts/OutlineBehaviourTests.cs | 2 +- .../Tests/Editor/Scripts/OutlineLayerTests.cs | 6 +- .../Editor/Scripts/OutlineBehaviourEditor.cs | 28 +++++- .../Editor/Scripts/OutlineEditorUtility.cs | 31 ------ .../Runtime/Scripts/IOutlineSettingsEx.cs | 19 ---- .../Scripts/IOutlineSettingsEx.cs.meta | 11 --- .../Runtime/Scripts/OutlineBehaviour.cs | 58 ++++++----- .../Runtime/Scripts/OutlineLayer.cs | 36 +++---- .../Scripts/OutlineSettingsInstance.cs | 10 +- 12 files changed, 75 insertions(+), 238 deletions(-) delete mode 100644 Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs delete mode 100644 Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs delete mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset index 584cbc3..814475a 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset +++ b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset @@ -21,7 +21,6 @@ MonoBehaviour: _outlineIntensity: 2 _outlineMode: 0 _name: My pretty layer - _zOrder: 0 _enabled: 1 - _settings: _outlineSettings: {fileID: 0} @@ -30,7 +29,6 @@ MonoBehaviour: _outlineIntensity: 2 _outlineMode: 1 _name: The second layer - _zOrder: 0 _enabled: 1 - _settings: _outlineSettings: {fileID: 0} @@ -39,5 +37,4 @@ MonoBehaviour: _outlineIntensity: 2 _outlineMode: 0 _name: The best layer - _zOrder: 0 _enabled: 1 diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs deleted file mode 100644 index af05396..0000000 --- a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using System.ComponentModel; -using UnityEngine; -using UnityEngine.TestTools; -using NUnit.Framework; - -namespace UnityFx.Outline -{ - public abstract class IOutlineSettingsExTests : IOutlineSettingsTests - { - private IOutlineSettingsEx _settings; - private IChangeTracking _changeTracking; - - protected void Init(IOutlineSettingsEx settings) - { - _settings = settings; - _changeTracking = settings as IChangeTracking; - base.Init(settings); - } - - [Test] - public void OutlineSettings_SetsValue() - { - var settings = ScriptableObject.CreateInstance(); - - try - { - _settings.OutlineSettings = settings; - - Assert.AreEqual(settings, _settings.OutlineSettings); - - _settings.OutlineSettings = null; - - Assert.IsNull(_settings.OutlineSettings); - } - finally - { - UnityEngine.Object.DestroyImmediate(settings); - } - } - - [Test] - public void OutlineSettings_SetsChanged() - { - if (_changeTracking != null) - { - var settings = ScriptableObject.CreateInstance(); - - try - { - _changeTracking.AcceptChanges(); - _settings.OutlineSettings = settings; - - Assert.IsTrue(_changeTracking.IsChanged); - } - finally - { - UnityEngine.Object.DestroyImmediate(settings); - } - } - } - - [Test] - public void OutlineSettings_DoesNotSetsChangedOnSameValue() - { - if (_changeTracking != null) - { - _changeTracking.AcceptChanges(); - _settings.OutlineSettings = _settings.OutlineSettings; - - Assert.IsFalse(_changeTracking.IsChanged); - } - } - - [Test] - public void OutlineSettings_MakesOtherSettersThrow() - { - var settings = ScriptableObject.CreateInstance(); - - try - { - _settings.OutlineSettings = settings; - - Assert.Throws(() => _settings.OutlineColor = Color.blue); - Assert.Throws(() => _settings.OutlineWidth = 12); - Assert.Throws(() => _settings.OutlineRenderMode = OutlineRenderFlags.Blurred); - Assert.Throws(() => _settings.OutlineIntensity = 17); - } - finally - { - UnityEngine.Object.DestroyImmediate(settings); - } - } - } -} diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta b/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta deleted file mode 100644 index eacde42..0000000 --- a/Outline.Core/Assets/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7d2cd56d59228e40917059e616e5ee9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineBehaviourTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineBehaviourTests.cs index 02c4202..1fe501f 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineBehaviourTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineBehaviourTests.cs @@ -11,7 +11,7 @@ namespace UnityFx.Outline { [Category("OutlineBehaviour"), TestOf(typeof(OutlineBehaviour))] - public class OutlineBehaviourTests : IOutlineSettingsExTests, IDisposable + public class OutlineBehaviourTests : IOutlineSettingsTests, IDisposable { private GameObject _go; private OutlineBehaviour _outlineEffect; diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs index df639c6..cdd9c6e 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs @@ -11,7 +11,7 @@ namespace UnityFx.Outline { [Category("OutlineLayer"), TestOf(typeof(OutlineLayer))] - public class OutlineLayerTests : IOutlineSettingsExTests, IDisposable + public class OutlineLayerTests : IOutlineSettingsTests, IDisposable { private OutlineLayer _layer; @@ -60,10 +60,8 @@ public void Add_FiltersRenderesByLayer() go2.layer = LayerMask.NameToLayer("TransparentFX"); go2.transform.SetParent(go.transform, false); - ICollection r; - _layer.Add(go, "TransparentFX"); - _layer.TryGetRenderers(go, out r); + _layer.TryGetRenderers(go, out var r); Assert.AreEqual(1, r.Count); Assert.IsTrue(r.Contains(go.GetComponent())); diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs index 492498a..d5ecb97 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs @@ -28,7 +28,33 @@ public override void OnInspectorGUI() // 1) Outline settings. EditorGUI.BeginChangeCheck(); - OutlineEditorUtility.Render(_effect, _effect); + var obj = (OutlineSettings)EditorGUILayout.ObjectField("Outline Settings", _effect.OutlineSettings, typeof(OutlineSettings), true); + + if (_effect.OutlineSettings != obj) + { + Undo.RecordObject(_effect, "Settings"); + _effect.OutlineSettings = obj; + } + + if (obj) + { + EditorGUI.BeginDisabledGroup(true); + EditorGUI.indentLevel += 1; + + OutlineEditorUtility.Render(_effect, _effect); + + EditorGUILayout.HelpBox(string.Format("Outline settings are overriden with values from {0}.", obj.name), MessageType.Info, true); + EditorGUI.indentLevel -= 1; + EditorGUI.EndDisabledGroup(); + } + else + { + EditorGUI.indentLevel += 1; + + OutlineEditorUtility.Render(_effect, _effect); + + EditorGUI.indentLevel -= 1; + } if (EditorGUI.EndChangeCheck()) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs index 3bd9d1c..2b8bf4c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs @@ -22,37 +22,6 @@ public static void RenderDivider(Color color, int thickness = 1, int padding = 5 EditorGUI.DrawRect(r, color); } - public static void Render(IOutlineSettingsEx settings, UnityEngine.Object undoContext) - { - var obj = (OutlineSettings)EditorGUILayout.ObjectField("Outline Settings", settings.OutlineSettings, typeof(OutlineSettings), true); - - if (settings.OutlineSettings != obj) - { - Undo.RecordObject(undoContext, "Settings"); - settings.OutlineSettings = obj; - } - - if (obj) - { - EditorGUI.BeginDisabledGroup(true); - EditorGUI.indentLevel += 1; - - Render((IOutlineSettings)settings, undoContext); - - EditorGUILayout.HelpBox(string.Format("Outline settings are overriden with values from {0}.", obj.name), MessageType.Info, true); - EditorGUI.indentLevel -= 1; - EditorGUI.EndDisabledGroup(); - } - else - { - EditorGUI.indentLevel += 1; - - Render((IOutlineSettings)settings, undoContext); - - EditorGUI.indentLevel -= 1; - } - } - public static void Render(IOutlineSettings settings, UnityEngine.Object undoContext) { var color = EditorGUILayout.ColorField("Color", settings.OutlineColor); diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs deleted file mode 100644 index 0939a90..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using UnityEngine; - -namespace UnityFx.Outline -{ - /// - /// Extended outline settings. - /// - public interface IOutlineSettingsEx : IOutlineSettings - { - /// - /// Gets or sets serializable outline settings. Set this to non- value to share settings with other components. - /// - OutlineSettings OutlineSettings { get; set; } - } -} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta deleted file mode 100644 index 73a20da..0000000 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9d3517d0fef6af540b0b046d3b2421dd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 9e0b9f5..b477946 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -15,7 +15,7 @@ namespace UnityFx.Outline /// [ExecuteInEditMode] [DisallowMultipleComponent] - public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettingsEx + public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings { #region data @@ -42,6 +42,7 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettingsEx /// Gets or sets resources used by the effect implementation. /// /// Thrown if setter argument is . + /// public OutlineResources OutlineResources { get @@ -59,6 +60,32 @@ public OutlineResources OutlineResources } } + /// + /// Gets or sets outline settings. Set this to non- value to share settings with other components. + /// + /// + public OutlineSettings OutlineSettings + { + get + { + if (_outlineSettings == null) + { + _outlineSettings = new OutlineSettingsInstance(); + } + + return _outlineSettings.OutlineSettings; + } + set + { + if (_outlineSettings == null) + { + _outlineSettings = new OutlineSettingsInstance(); + } + + _outlineSettings.OutlineSettings = value; + } + } + /// /// Gets outline renderers. By default all child components are used for outlining. /// @@ -176,35 +203,6 @@ private void Reset() #endregion - #region IOutlineSettingsEx - - /// - /// Gets or sets outline settings. Set this to non- value to share settings with other components. - /// - public OutlineSettings OutlineSettings - { - get - { - if (_outlineSettings == null) - { - _outlineSettings = new OutlineSettingsInstance(); - } - - return _outlineSettings.OutlineSettings; - } - set - { - if (_outlineSettings == null) - { - _outlineSettings = new OutlineSettingsInstance(); - } - - _outlineSettings.OutlineSettings = value; - } - } - - #endregion - #region IOutlineSettings /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index c5b24e9..c29efed 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -16,7 +16,7 @@ namespace UnityFx.Outline /// /// [Serializable] - public sealed class OutlineLayer : ICollection, IReadOnlyCollection, IOutlineSettingsEx + public sealed class OutlineLayer : ICollection, IReadOnlyCollection, IOutlineSettings { #region data @@ -200,6 +200,21 @@ public int Index } } + /// + /// Gets or sets outline settings. Set this to non- value to share settings with other components. + /// + public OutlineSettings OutlineSettings + { + get + { + return _settings.OutlineSettings; + } + set + { + _settings.OutlineSettings = value; + } + } + /// /// Initializes a new instance of the class. /// @@ -363,25 +378,6 @@ internal void SetCollection(OutlineLayerCollection collection) #endregion - #region IOutlineSettingsEx - - /// - /// Gets or sets outline settings. Set this to non- value to share settings with other components. - /// - public OutlineSettings OutlineSettings - { - get - { - return _settings.OutlineSettings; - } - set - { - _settings.OutlineSettings = value; - } - } - - #endregion - #region IOutlineSettings /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs index b587fbd..b887cdd 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs @@ -7,7 +7,7 @@ namespace UnityFx.Outline { [Serializable] - internal class OutlineSettingsInstance : IOutlineSettingsEx + internal class OutlineSettingsInstance : IOutlineSettings { #region data @@ -39,14 +39,6 @@ public bool RequiresCameraDepth } } - internal OutlineSettingsInstance() - { - } - - #endregion - - #region IOutlineSettingsEx - public OutlineSettings OutlineSettings { get From 51cff7abd6f9d5754bd9dbc7919d6a871e23a22a Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Wed, 13 May 2020 22:21:11 +0300 Subject: [PATCH 32/61] Minor editor improvements --- .../Editor/Scripts/OutlineLayerCollectionEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index 86c799a..53fd772 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -38,6 +38,7 @@ public override void OnInspectorGUI() _layersList.DoLayoutList(); EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Read-only lists below represent game objects assigned to specific outline layers. Only non-empty layers are displayed.", MessageType.Info); foreach (var layer in _layers) { @@ -51,8 +52,7 @@ public override void OnInspectorGUI() foreach (var go in layer) { - EditorGUILayout.ObjectField("#" + index, go, typeof(GameObject), true); - index++; + EditorGUILayout.ObjectField($"#{index++}", go, typeof(GameObject), true); } EditorGUI.indentLevel -= 1; From c5c21bfdf58a5e833f213eb671949e8de5b4fb12 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Wed, 13 May 2020 22:56:42 +0300 Subject: [PATCH 33/61] Added ignore layer mask to OutlineLayerCollection (shared between all layers) and Outlinebehaviour --- .../SimplePerCamera/TestOutlineLayers.asset | 1 + .../Tests/Editor/Scripts/OutlineLayerTests.cs | 5 +- .../Editor/Scripts/OutlineBehaviourEditor.cs | 11 +- .../Scripts/OutlineLayerCollectionEditor.cs | 102 +++++++----------- .../Runtime/Scripts/OutlineBehaviour.cs | 41 +++++-- .../Runtime/Scripts/OutlineLayer.cs | 48 ++++----- .../Runtime/Scripts/OutlineLayerCollection.cs | 25 +++++ .../Scripts/OutlineRendererCollection.cs | 24 ++--- 8 files changed, 139 insertions(+), 118 deletions(-) diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset index 814475a..0c2023b 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset +++ b/Outline.Core/Assets/Examples/SimplePerCamera/TestOutlineLayers.asset @@ -38,3 +38,4 @@ MonoBehaviour: _outlineMode: 0 _name: The best layer _enabled: 1 + _layerMask: 2 diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs index cdd9c6e..e6d4eb2 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerTests.cs @@ -56,11 +56,14 @@ public void Add_FiltersRenderesByLayer() { var go = new GameObject("r1", typeof(MeshRenderer)); var go2 = new GameObject("r2", typeof(MeshRenderer)); + var layers = new OutlineLayerCollection(); + layers.IgnoreLayerMask = 1 << LayerMask.NameToLayer("TransparentFX"); + layers.Add(_layer); go2.layer = LayerMask.NameToLayer("TransparentFX"); go2.transform.SetParent(go.transform, false); - _layer.Add(go, "TransparentFX"); + _layer.Add(go); _layer.TryGetRenderers(go, out var r); Assert.AreEqual(1, r.Count); diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs index d5ecb97..17b32c6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs @@ -3,6 +3,7 @@ using System; using UnityEditor; +using UnityEditorInternal; using UnityEditor.SceneManagement; using UnityEngine; @@ -28,11 +29,19 @@ public override void OnInspectorGUI() // 1) Outline settings. EditorGUI.BeginChangeCheck(); + var mask = EditorGUILayout.MaskField("Ignore layers", _effect.IgnoreLayerMask, InternalEditorUtility.layers); + + if (_effect.IgnoreLayerMask != mask) + { + Undo.RecordObject(_effect, "Set Ignore Layers"); + _effect.IgnoreLayerMask = mask; + } + var obj = (OutlineSettings)EditorGUILayout.ObjectField("Outline Settings", _effect.OutlineSettings, typeof(OutlineSettings), true); if (_effect.OutlineSettings != obj) { - Undo.RecordObject(_effect, "Settings"); + Undo.RecordObject(_effect, "Set Settings"); _effect.OutlineSettings = obj; } diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index 53fd772..073ea39 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -35,6 +35,18 @@ public override void OnInspectorGUI() { base.OnInspectorGUI(); + EditorGUI.BeginChangeCheck(); + + var mask = EditorGUILayout.MaskField("Ignore layers", _layers.IgnoreLayerMask, InternalEditorUtility.layers); + + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(_layers, "Set Layers"); + _layers.IgnoreLayerMask = mask; + } + + EditorGUILayout.Space(); + _layersList.DoLayoutList(); EditorGUILayout.Space(); @@ -70,7 +82,14 @@ private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) var lineOffset = lineHeight + lineSpacing; var y = rect.y + lineSpacing; var layer = _layers[index]; - var settingsDisabled = false; + + var obj = layer.OutlineSettings; + var enabled = layer.Enabled; + var name = layer.NameTag; + var color = layer.OutlineColor; + var width = layer.OutlineWidth; + var renderMode = layer.OutlineRenderMode; + var blurIntensity = layer.OutlineIntensity; EditorGUI.BeginChangeCheck(); @@ -86,87 +105,33 @@ private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) EditorGUI.DrawRect(new Rect(bgRect.x, bgRect.y, 1, bgRect.height), Color.gray); EditorGUI.DrawRect(new Rect(bgRect.xMax, bgRect.y, 1, bgRect.height), Color.gray); - var obj = (OutlineSettings)EditorGUI.ObjectField(rc, " ", layer.OutlineSettings, typeof(OutlineSettings), true); - - if (layer.OutlineSettings != obj) - { - Undo.RecordObject(_layers, "Settings"); - layer.OutlineSettings = obj; - } - - var enabled = EditorGUI.ToggleLeft(rc, "Layer #" + index.ToString(), layer.Enabled, EditorStyles.boldLabel); - - if (layer.Enabled != enabled) - { - if (enabled) - { - Undo.RecordObject(_layers, "Enable Layer"); - } - else - { - Undo.RecordObject(_layers, "Disable Layer"); - } - - layer.Enabled = enabled; - } - - settingsDisabled = obj != null; + obj = (OutlineSettings)EditorGUI.ObjectField(rc, " ", obj, typeof(OutlineSettings), true); + enabled = EditorGUI.ToggleLeft(rc, "Layer #" + index.ToString(), enabled, EditorStyles.boldLabel); y += lineOffset; } // Layer properties { - var name = EditorGUI.TextField(new Rect(rect.x, y, rect.width, lineHeight), "Name", layer.NameTag); - - if (name != layer.NameTag) - { - Undo.RecordObject(_layers, "Layer Name"); - layer.NameTag = name; - } - + name = EditorGUI.TextField(new Rect(rect.x, y, rect.width, lineHeight), "Name", name); y += lineOffset; } // Outline settings { - EditorGUI.BeginDisabledGroup(settingsDisabled); - - var color = EditorGUI.ColorField(new Rect(rect.x, y, rect.width, lineHeight), "Color", layer.OutlineColor); - - if (layer.OutlineColor != color) - { - Undo.RecordObject(_layers, "Color"); - layer.OutlineColor = color; - } + EditorGUI.BeginDisabledGroup(obj != null); + color = EditorGUI.ColorField(new Rect(rect.x, y, rect.width, lineHeight), "Color", color); y += lineOffset; - var width = EditorGUI.IntSlider(new Rect(rect.x, y, rect.width, lineHeight), "Width", layer.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); - - if (layer.OutlineWidth != width) - { - Undo.RecordObject(_layers, "Width"); - layer.OutlineWidth = width; - } + width = EditorGUI.IntSlider(new Rect(rect.x, y, rect.width, lineHeight), "Width", width, OutlineResources.MinWidth, OutlineResources.MaxWidth); y += lineOffset; - var renderMode = (OutlineRenderFlags)EditorGUI.EnumFlagsField(new Rect(rect.x, y, rect.width, lineHeight), "Render Flags", layer.OutlineRenderMode); - if (layer.OutlineRenderMode != renderMode) - { - Undo.RecordObject(_layers, "Render Flags"); - layer.OutlineRenderMode = renderMode; - } + renderMode = (OutlineRenderFlags)EditorGUI.EnumFlagsField(new Rect(rect.x, y, rect.width, lineHeight), "Render Flags", renderMode); + y += lineOffset; if ((renderMode & OutlineRenderFlags.Blurred) != 0) { - y += lineOffset; - var i = EditorGUI.Slider(new Rect(rect.x, y, rect.width, lineHeight), "Blur Intensity", layer.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); - - if (!Mathf.Approximately(layer.OutlineIntensity, i)) - { - Undo.RecordObject(_layers, "Blur Intensity"); - layer.OutlineIntensity = i; - } + blurIntensity = EditorGUI.Slider(new Rect(rect.x, y, rect.width, lineHeight), "Blur Intensity", blurIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); } EditorGUI.EndDisabledGroup(); @@ -174,7 +139,16 @@ private void OnDrawLayer(Rect rect, int index, bool isActive, bool isFocused) if (EditorGUI.EndChangeCheck()) { + Undo.RecordObject(_layers, "Layers changed"); EditorUtility.SetDirty(_layers); + + layer.OutlineSettings = obj; + layer.Enabled = enabled; + layer.NameTag = name; + layer.OutlineWidth = width; + layer.OutlineColor = color; + layer.OutlineRenderMode = renderMode; + layer.OutlineIntensity = blurIntensity; } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index b477946..f9034a6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -25,6 +25,8 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings private OutlineResources _outlineResources; [SerializeField, HideInInspector] private OutlineSettingsInstance _outlineSettings; + [SerializeField, HideInInspector] + private int _layerMask; [SerializeField, Tooltip("If set, list of object renderers is updated on each frame. Enable if the object has child renderers which are enabled/disabled frequently.")] private bool _updateRenderers; @@ -86,9 +88,29 @@ public OutlineSettings OutlineSettings } } + /// + /// Gets or sets layer mask to use for ignored components in this game object. + /// + public int IgnoreLayerMask + { + get + { + return _layerMask; + } + set + { + if (_layerMask != value) + { + _layerMask = value; + _renderers?.Reset(false, value); + } + } + } + /// /// Gets outline renderers. By default all child components are used for outlining. /// + /// public ICollection OutlineRenderers { get @@ -101,12 +123,15 @@ public ICollection OutlineRenderers /// /// Gets all cameras outline data is rendered to. /// - public ICollection Cameras + public ICollection Cameras => _cameraMap.Keys; + + /// + /// Updates renderer list. + /// + /// + public void UpdateRenderers() { - get - { - return _cameraMap.Keys; - } + _renderers?.Reset(false, _layerMask); } #endregion @@ -149,7 +174,7 @@ private void Update() if (_updateRenderers) { - _renderers.Reset(false); + _renderers.Reset(false, _layerMask); } foreach (var kvp in _cameraMap) @@ -195,7 +220,7 @@ private void Reset() { if (_renderers != null) { - _renderers.Reset(true); + _renderers.Reset(false, _layerMask); } } @@ -312,7 +337,7 @@ private void CreateRenderersIfNeeded() if (_renderers == null) { _renderers = new OutlineRendererCollection(gameObject); - _renderers.Reset(true); + _renderers.Reset(false, _layerMask); } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index c29efed..4053df7 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -259,34 +259,6 @@ public OutlineLayer(string name, OutlineSettings settings) _settings.OutlineSettings = settings; } - /// - /// Adds a new object to the layer. - /// - /// Thrown if is . - public void Add(GameObject go, int ignoreLayerMask) - { - if (go is null) - { - throw new ArgumentNullException(nameof(go)); - } - - if (!_outlineObjects.ContainsKey(go)) - { - var renderers = new OutlineRendererCollection(go); - renderers.Reset(false, ignoreLayerMask); - _outlineObjects.Add(go, renderers); - } - } - - /// - /// Adds a new object to the layer. - /// - /// Thrown if is . - public void Add(GameObject go, string ignoreLayer) - { - Add(go, 1 << LayerMask.NameToLayer(ignoreLayer)); - } - /// /// Attempts to get renderers assosiated with the specified . /// @@ -359,6 +331,14 @@ internal IList GetList() #endif + internal void UpdateRenderers(int ignoreLayers) + { + foreach (var renderers in _outlineObjects.Values) + { + renderers.Reset(false, ignoreLayers); + } + } + internal void Reset() { _outlineObjects.Clear(); @@ -445,7 +425,17 @@ public OutlineRenderFlags OutlineRenderMode /// public void Add(GameObject go) { - Add(go, 0); + if (go is null) + { + throw new ArgumentNullException(nameof(go)); + } + + if (!_outlineObjects.ContainsKey(go)) + { + var renderers = new OutlineRendererCollection(go); + renderers.Reset(false, _parentCollection.IgnoreLayerMask); + _outlineObjects.Add(go, renderers); + } } /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index a3681af..8783fb6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -21,11 +21,36 @@ public sealed class OutlineLayerCollection : ScriptableObject, IList _layers = new List(); + [SerializeField, HideInInspector] + private int _layerMask; #endregion #region interface + /// + /// Gets or sets layer mask to use for ignored components in layer game objects. + /// + public int IgnoreLayerMask + { + get + { + return _layerMask; + } + set + { + if (_layerMask != value) + { + _layerMask = value; + + foreach (var layer in _layers) + { + layer.UpdateRenderers(value); + } + } + } + } + /// /// Gets the objects for rendering. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs index 1ec074f..e157672 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRendererCollection.cs @@ -39,28 +39,22 @@ internal void Reset(bool includeInactive, int ignoreLayerMask) { _renderers.Clear(); - var renderers = _go.GetComponentsInChildren(includeInactive); - - if (renderers != null) + if (ignoreLayerMask != 0) { - if (ignoreLayerMask != 0) - { - foreach (var renderer in renderers) - { - if (((1 << renderer.gameObject.layer) & ignoreLayerMask) == 0) - { - _renderers.Add(renderer); - } - } - } - else + var renderers = _go.GetComponentsInChildren(includeInactive); + + foreach (var renderer in renderers) { - foreach (var renderer in renderers) + if (((1 << renderer.gameObject.layer) & ignoreLayerMask) == 0) { _renderers.Add(renderer); } } } + else + { + _go.GetComponentsInChildren(includeInactive, _renderers); + } } #endregion From bbf9fa8b84c12fe96d1b7aed6848e1738fe4a274 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 11:49:16 +0300 Subject: [PATCH 34/61] Misc renderer fixes --- .../Runtime/Scripts/OutlineLayer.cs | 132 ------------------ .../Runtime/Scripts/OutlineRenderer.cs | 50 +++++-- .../Runtime/Scripts/OutlineEffectRenderer.cs | 7 +- 3 files changed, 45 insertions(+), 144 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 4053df7..691b08a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -30,124 +30,6 @@ public sealed class OutlineLayer : ICollection, IReadOnlyCollection< private OutlineLayerCollection _parentCollection; private Dictionary _outlineObjects = new Dictionary(); -#if UNITY_EDITOR - - private class EditorList : IList - { - private readonly Dictionary _objects; - - public EditorList(OutlineLayer layer) - { - _objects = layer._outlineObjects; - } - - public object this[int index] - { - get - { - var myIndex = 0; - - foreach (var go in _objects.Keys) - { - if (myIndex == index) - { - return go; - } - - myIndex++; - } - - return null; - } - set - { - throw new NotImplementedException(); - } - } - - public bool IsFixedSize => false; - - public bool IsReadOnly => true; - - public int Count => _objects.Count; - - public bool IsSynchronized => false; - - public object SyncRoot => null; - - public bool Contains(object value) - { - if (value is GameObject go) - { - return _objects.ContainsKey(go); - } - - return false; - } - - public void CopyTo(Array array, int index) - { - foreach (var go in _objects.Keys) - { - array.SetValue(go, index++); - } - } - - public IEnumerator GetEnumerator() - { - return _objects.Keys.GetEnumerator(); - } - - public int IndexOf(object value) - { - if (value is GameObject valueGo) - { - var index = 0; - - foreach (var go in _objects.Keys) - { - if (go == valueGo) - { - return index; - } - - index++; - } - } - - return -1; - } - - public int Add(object value) - { - throw new NotImplementedException(); - } - - public void Insert(int index, object value) - { - throw new NotImplementedException(); - } - - public void Remove(object value) - { - throw new NotImplementedException(); - } - - public void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - } - - private EditorList _editorObjects; - -#endif - #endregion #region interface @@ -317,20 +199,6 @@ internal string NameTag internal OutlineLayerCollection ParentCollection => _parentCollection; -#if UNITY_EDITOR - - internal IList GetList() - { - if (_editorObjects is null) - { - _editorObjects = new EditorList(this); - } - - return _editorObjects; - } - -#endif - internal void UpdateRenderers(int ignoreLayers) { foreach (var renderers in _outlineObjects.Values) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index cbb6433..ce94e4c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -38,6 +38,7 @@ namespace UnityFx.Outline private const int _hPassId = 0; private const int _vPassId = 1; + private const RenderTextureFormat _rtFormat = RenderTextureFormat.R8; private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex"); @@ -68,7 +69,7 @@ namespace UnityFx.Outline /// Outline resources. /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources) - : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, GetDefaultRtDesc()) + : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.Depth, Vector2Int.zero) { } @@ -80,7 +81,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources) /// The rendering path of target camera (). /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderingPath renderingPath) - : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), GetDefaultRtDesc()) + : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), Vector2Int.zero) { } @@ -92,7 +93,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderingP /// Render target. /// Thrown if is . public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst) - : this(cmd, resources, dst, BuiltinRenderTextureType.Depth, GetDefaultRtDesc()) + : this(cmd, resources, dst, BuiltinRenderTextureType.Depth, Vector2Int.zero) { } @@ -100,12 +101,11 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. - /// Outline resources. /// Render target. - /// Depth dexture to use. + /// The rendering path of target camera (). /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderTargetIdentifier depth) - : this(cmd, resources, dst, depth, GetDefaultRtDesc()) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderingPath renderingPath, Vector2Int rtSize) + : this(cmd, resources, dst, GetBuiltinDepth(renderingPath), rtSize) { } @@ -113,12 +113,40 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg /// Initializes a new instance of the struct. /// /// A to render the effect to. It should be cleared manually (if needed) before passing to this method. + /// Outline resources. /// Render target. - /// The rendering path of target camera (). + /// Depth dexture to use. /// Thrown if is . - public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderingPath renderingPath) - : this(cmd, resources, dst, GetBuiltinDepth(renderingPath), GetDefaultRtDesc()) + public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTargetIdentifier dst, RenderTargetIdentifier depth, Vector2Int rtSize) { + if (cmd is null) + { + throw new ArgumentNullException(nameof(cmd)); + } + + if (resources is null) + { + throw new ArgumentNullException(nameof(resources)); + } + + if (rtSize.x <= 0) + { + rtSize.x = -1; + } + + if (rtSize.y <= 0) + { + rtSize.y = -1; + } + + cmd.BeginSample(EffectName); + cmd.GetTemporaryRT(_maskRtId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, _rtFormat); + cmd.GetTemporaryRT(_hPassRtId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, _rtFormat); + + _rt = dst; + _depth = depth; + _commandBuffer = cmd; + _resources = resources; } /// @@ -159,7 +187,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg rtDesc.shadowSamplingMode = ShadowSamplingMode.None; rtDesc.depthBufferBits = 0; - rtDesc.colorFormat = RenderTextureFormat.R8; + rtDesc.colorFormat = _rtFormat; rtDesc.volumeDepth = 1; cmd.BeginSample(EffectName); diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs index ff3a481..79fdd06 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs @@ -15,6 +15,11 @@ public sealed class OutlineEffectRenderer : PostProcessEffectRenderer private OutlineResources _defaultResources; private List _objects = new List(); + public override DepthTextureMode GetCameraFlags() + { + return DepthTextureMode.Depth; + } + public override void Render(PostProcessRenderContext context) { OutlineResources resources; @@ -39,7 +44,7 @@ public override void Render(PostProcessRenderContext context) { RuntimeUtilities.CopyTexture(context.command, context.source, context.destination); - using (var renderer = new OutlineRenderer(context.command, resources, context.destination, context.camera.actualRenderingPath)) + using (var renderer = new OutlineRenderer(context.command, resources, context.destination, context.camera.actualRenderingPath, new Vector2Int(context.width, context.height))) { _objects.Clear(); settings.Layers.value.GetRenderObjects(_objects); From 699b9f63d79e78cfbac5579e67bae88019c2d2d3 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 14:31:05 +0300 Subject: [PATCH 35/61] Added OutlineBuilder helper --- .../Editor/Scripts/OutlineBuilderEditor.cs | 98 +++++++++++++++++++ .../Scripts/OutlineBuilderEditor.cs.meta | 11 +++ .../Runtime/Scripts/OutlineBuilder.cs | 63 ++++++++++++ .../Runtime/Scripts/OutlineBuilder.cs.meta | 11 +++ .../Runtime/Scripts/OutlineEffect.cs | 5 + .../Runtime/Scripts/OutlineLayerCollection.cs | 11 +++ 6 files changed, 199 insertions(+) create mode 100644 Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs create mode 100644 Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs.meta create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs create mode 100644 Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs new file mode 100644 index 0000000..bdbaf05 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs @@ -0,0 +1,98 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace UnityFx.Outline +{ + [CustomEditor(typeof(OutlineBuilder))] + public class OutlineBuilderEditor : Editor + { + private OutlineBuilder _builder; + private List _lists = new List(); + + private void OnEnable() + { + _builder = (OutlineBuilder)target; + + foreach (var layer in _builder.OutlineLayers) + { + var list0 = new ArrayList(layer.Count); + + foreach (var go in layer) + { + list0.Add(go); + } + + var editorList = new ReorderableList(list0, typeof(GameObject), false, true, true, true); + + editorList.onAddCallback += (list) => + { + list.list.Add(null); + }; + + editorList.onRemoveCallback += (list) => + { + var go = list.list[list.index]; + list.list.RemoveAt(list.index); + layer.Remove(go as GameObject); + }; + + editorList.drawElementCallback += (rect, index, isActive, isFocused) => + { + var prevGo = list0[index] as GameObject; + var go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), $"#{index}", prevGo, typeof(GameObject), true); + + if (prevGo != go) + { + list0[index] = go; + layer.Remove(prevGo); + layer.Add(go); + } + }; + + editorList.drawHeaderCallback += (rect) => + { + EditorGUI.LabelField(rect, layer.Name); + }; + + editorList.elementHeightCallback += (index) => + { + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + }; + + _lists.Add(editorList); + } + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + EditorGUILayout.Space(); + + for (var i = 0; i < _lists.Count; ++i) + { + _lists[i].DoLayoutList(); + EditorGUILayout.Space(); + } + + if (GUILayout.Button("Clear")) + { + foreach (var list in _lists) + { + list.list.Clear(); + } + + _builder.Clear(); + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs.meta new file mode 100644 index 0000000..20872eb --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2ba41e0b025a6e46abc7b69d31d1907 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs new file mode 100644 index 0000000..2d4efe7 --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs @@ -0,0 +1,63 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityFx.Outline +{ + /// + /// A helper behaviour for managing content of via Unity Editor. + /// + public sealed class OutlineBuilder : MonoBehaviour + { + #region data + +#pragma warning disable 0649 + + [SerializeField, Tooltip("Collection of outline layers to manage.")] + private OutlineLayerCollection _outlineLayers; + +#pragma warning restore 0649 + + #endregion + + #region interface + + /// + /// Gets or sets a collection of layers to manage. + /// + public OutlineLayerCollection OutlineLayers { get => _outlineLayers; set => _outlineLayers = value; } + + /// + /// Clears content of all layers. + /// + /// + public void Clear() + { + _outlineLayers?.ClearLayerContent(); + } + + #endregion + + #region MonoBehaviour + +#if UNITY_EDITOR + + private void Reset() + { + var effect = GetComponent(); + + if (effect) + { + _outlineLayers = effect.OutlineLayersInternal; + } + } + +#endif + + #endregion + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs.meta new file mode 100644 index 0000000..fc6b25c --- /dev/null +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e746e776b0ae00d4a9d458b9430b95d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index 3eae2b3..b405392 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -70,6 +70,11 @@ public IList OutlineLayers } } + /// + /// Gets outline layers (for internal use only). + /// + internal OutlineLayerCollection OutlineLayersInternal => _outlineLayers; + /// /// Gets or sets used to render the outlines. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 8783fb6..44965be 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -62,6 +62,17 @@ public void GetRenderObjects(IList renderObjects) } } + /// + /// Removes all game objects registered in layers. + /// + public void ClearLayerContent() + { + foreach (var layer in _layers) + { + layer.Clear(); + } + } + #endregion #region internals From 916e117207835565322c22ffa261a9de02c00630 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 14:58:52 +0300 Subject: [PATCH 36/61] Post-processing package fixes --- .../Examples/SimplePerCamera/Outline.unity | 31 +++-- .../Editor/Scripts/OutlineBuilderEditor.cs | 108 ++++++++++-------- .../OutlineLayerCollection.asset | 24 ++++ .../OutlineLayerCollection.asset.meta | 8 ++ .../PostProcessingProfile.asset | 4 +- .../PostProcessing/PostProcessingSample.unity | 14 +++ 6 files changed, 122 insertions(+), 67 deletions(-) create mode 100644 Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset create mode 100644 Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset.meta diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity index add9f47..3edd003 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity +++ b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity @@ -193,7 +193,7 @@ GameObject: - component: {fileID: 692811815} - component: {fileID: 692811813} - component: {fileID: 692811818} - - component: {fileID: 692811817} + - component: {fileID: 692811814} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -213,6 +213,19 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c9e1f138162751048bdb3432e85d7a73, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!114 &692811814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 692811812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e746e776b0ae00d4a9d458b9430b95d7, type: 3} + m_Name: + m_EditorClassIdentifier: + _outlineLayers: {fileID: 11400000, guid: 3a6c3b3c5f6e3ad4ab8e09fc219865bd, type: 2} --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 @@ -272,21 +285,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &692811817 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 692811812} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5a318c96b1bc1614683eccf7abd717a1, type: 3} - m_Name: - m_EditorClassIdentifier: - _outlineGos: - - {fileID: 1579373802} - - {fileID: 748173439} --- !u!114 &692811818 MonoBehaviour: m_ObjectHideFlags: 0 @@ -537,6 +535,7 @@ MonoBehaviour: _outlineWidth: 15 _outlineIntensity: 2 _outlineMode: 1 + _layerMask: 0 _updateRenderers: 0 --- !u!23 &1789341923 MeshRenderer: diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs index bdbaf05..eb2bd65 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs @@ -20,53 +20,56 @@ private void OnEnable() { _builder = (OutlineBuilder)target; - foreach (var layer in _builder.OutlineLayers) + if (_builder.OutlineLayers) { - var list0 = new ArrayList(layer.Count); - - foreach (var go in layer) + foreach (var layer in _builder.OutlineLayers) { - list0.Add(go); - } + var list0 = new ArrayList(layer.Count); - var editorList = new ReorderableList(list0, typeof(GameObject), false, true, true, true); - - editorList.onAddCallback += (list) => - { - list.list.Add(null); - }; + foreach (var go in layer) + { + list0.Add(go); + } - editorList.onRemoveCallback += (list) => - { - var go = list.list[list.index]; - list.list.RemoveAt(list.index); - layer.Remove(go as GameObject); - }; + var editorList = new ReorderableList(list0, typeof(GameObject), false, true, true, true); - editorList.drawElementCallback += (rect, index, isActive, isFocused) => - { - var prevGo = list0[index] as GameObject; - var go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), $"#{index}", prevGo, typeof(GameObject), true); + editorList.onAddCallback += (list) => + { + list.list.Add(null); + }; - if (prevGo != go) + editorList.onRemoveCallback += (list) => { - list0[index] = go; - layer.Remove(prevGo); - layer.Add(go); - } - }; + var go = list.list[list.index]; + list.list.RemoveAt(list.index); + layer.Remove(go as GameObject); + }; - editorList.drawHeaderCallback += (rect) => - { - EditorGUI.LabelField(rect, layer.Name); - }; + editorList.drawElementCallback += (rect, index, isActive, isFocused) => + { + var prevGo = list0[index] as GameObject; + var go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), $"#{index}", prevGo, typeof(GameObject), true); + + if (prevGo != go) + { + list0[index] = go; + layer.Remove(prevGo); + layer.Add(go); + } + }; + + editorList.drawHeaderCallback += (rect) => + { + EditorGUI.LabelField(rect, layer.Name); + }; - editorList.elementHeightCallback += (index) => - { - return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - }; + editorList.elementHeightCallback += (index) => + { + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + }; - _lists.Add(editorList); + _lists.Add(editorList); + } } } @@ -74,25 +77,32 @@ public override void OnInspectorGUI() { base.OnInspectorGUI(); - EditorGUILayout.Space(); - - for (var i = 0; i < _lists.Count; ++i) + if (_lists.Count > 0) { - _lists[i].DoLayoutList(); EditorGUILayout.Space(); - } - if (GUILayout.Button("Clear")) - { - foreach (var list in _lists) + for (var i = 0; i < _lists.Count; ++i) { - list.list.Clear(); + _lists[i].DoLayoutList(); + EditorGUILayout.Space(); } - _builder.Clear(); - } + if (GUILayout.Button("Clear")) + { + foreach (var list in _lists) + { + list.list.Clear(); + } + + _builder.Clear(); + } - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); + } + else + { + // TODO + } } } } diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset new file mode 100644 index 0000000..e347a15 --- /dev/null +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset @@ -0,0 +1,24 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 57d0c11168277cf4eb3b4b89706e6aa5, type: 3} + m_Name: OutlineLayerCollection + m_EditorClassIdentifier: + _layers: + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 0.970881, a: 1} + _outlineWidth: 4 + _outlineIntensity: 2 + _outlineMode: 0 + _name: + _enabled: 1 + _layerMask: 0 diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset.meta b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset.meta new file mode 100644 index 0000000..528902b --- /dev/null +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 747aa7f9a78f24945a8d07c0ba1511c6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingProfile.asset b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingProfile.asset index 725ebe2..17e2ac4 100644 --- a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingProfile.asset +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingProfile.asset @@ -35,5 +35,5 @@ MonoBehaviour: overrideState: 0 value: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, type: 2} Layers: - overrideState: 0 - value: {fileID: 0} + overrideState: 1 + value: {fileID: 11400000, guid: 747aa7f9a78f24945a8d07c0ba1511c6, type: 2} diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity index 289e850..d7dbb7e 100644 --- a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity @@ -192,6 +192,7 @@ GameObject: - component: {fileID: 692811816} - component: {fileID: 692811815} - component: {fileID: 692811813} + - component: {fileID: 692811814} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -261,6 +262,19 @@ MonoBehaviour: - assemblyQualifiedName: UnityFx.Outline.PostProcessing.Outline, UnityFx.Outline.PostProcessing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null m_AfterStackBundles: [] +--- !u!114 &692811814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 692811812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e746e776b0ae00d4a9d458b9430b95d7, type: 3} + m_Name: + m_EditorClassIdentifier: + _outlineLayers: {fileID: 11400000, guid: 747aa7f9a78f24945a8d07c0ba1511c6, type: 2} --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 From 20f19ee3eb606f2207a5fc19782642c18b07bdcb Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 17:37:53 +0300 Subject: [PATCH 37/61] Changed outline shader to use local keywords (instead of global) --- .../Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 7041a77..ec2be87 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -124,7 +124,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 - #pragma shader_feature _USE_DRAWMESH + #pragma shader_feature_local _USE_DRAWMESH #pragma vertex vert #pragma fragment frag_h @@ -140,7 +140,7 @@ Shader "Hidden/UnityFx/Outline" HLSLPROGRAM #pragma target 3.5 - #pragma shader_feature _USE_DRAWMESH + #pragma shader_feature_local _USE_DRAWMESH #pragma vertex vert #pragma fragment frag_v From f8c750dd425f694abc6c3e5a927166717ee90cc0 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 17:50:13 +0300 Subject: [PATCH 38/61] Added UseDrawMesh flag to OutlineResources --- .../Runtime/Scripts/OutlineResources.cs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index e47a7e0..5b2712e 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -21,6 +21,7 @@ public sealed class OutlineResources : ScriptableObject private MaterialPropertyBlock _props; private Mesh _fullscreenTriangleMesh; private float[][] _gaussSamples; + private bool _useDrawMesh; #endregion @@ -163,6 +164,11 @@ public Material OutlineMaterial name = "Outline - Main", hideFlags = HideFlags.HideAndDontSave }; + + if (_useDrawMesh) + { + _outlineMaterial.EnableKeyword(UseDrawMeshFeatureName); + } } return _outlineMaterial; @@ -220,16 +226,40 @@ public Mesh FullscreenTriangleMesh } /// - /// Gets a value indicating whether the instance is in valid state. + /// Gets or sets a value indicating whether DrawMesh calls should be used instead of DrawProcedural /// - public bool IsValid + public bool UseDrawMesh { get { - return RenderShader && OutlineShader; + return _useDrawMesh; + } + set + { + if (_useDrawMesh != value) + { + _useDrawMesh = value; + + if (_outlineMaterial) + { + if (_useDrawMesh) + { + _outlineMaterial.EnableKeyword(UseDrawMeshFeatureName); + } + else + { + _outlineMaterial.DisableKeyword(UseDrawMeshFeatureName); + } + } + } } } + /// + /// Gets a value indicating whether the instance is in valid state. + /// + public bool IsValid => RenderShader && OutlineShader; + /// /// Returns a instance initialized with values from . /// From bfbd629330fb3a011d339d95b3a6047fa4bc727c Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 17:56:28 +0300 Subject: [PATCH 39/61] OutlineRenderer now uses UseDrawMesh flag --- .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 2 +- .../UnityFx.Outline/Runtime/Scripts/OutlineResources.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index ce94e4c..c1da43c 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -372,7 +372,7 @@ private static void Blit(CommandBuffer cmdBuffer, RenderTargetIdentifier src, Ou // Set source texture as _MainTex to match Blit behavior. cmdBuffer.SetGlobalTexture(resources.MainTexId, src); - if (SystemInfo.graphicsShaderLevel < 35) + if (SystemInfo.graphicsShaderLevel < 35 || resources.UseFullscreenTriangleMesh) { cmdBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, mat, 0, shaderPass, props); } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index 5b2712e..fc3efa2 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -226,9 +226,9 @@ public Mesh FullscreenTriangleMesh } /// - /// Gets or sets a value indicating whether DrawMesh calls should be used instead of DrawProcedural + /// Gets or sets a value indicating whether is used for image effects rendering even when procedural rendering is available. /// - public bool UseDrawMesh + public bool UseFullscreenTriangleMesh { get { From 4d899ef3113a0d9d8133ac98c1c663d6ae29dae7 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 17:59:55 +0300 Subject: [PATCH 40/61] Renamed OutlineObject to OutlineRenderObject --- .../UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs | 2 +- .../UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs | 4 ++-- .../Runtime/Scripts/OutlineLayerCollection.cs | 2 +- .../{OutlineObject.cs => OutlineRenderObject.cs} | 10 +++++----- ...tlineObject.cs.meta => OutlineRenderObject.cs.meta} | 0 .../UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) rename Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/{OutlineObject.cs => OutlineRenderObject.cs} (77%) rename Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/{OutlineObject.cs.meta => OutlineRenderObject.cs.meta} (100%) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index b405392..13a428a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -30,7 +30,7 @@ public sealed partial class OutlineEffect : MonoBehaviour private Camera _camera; private CommandBuffer _commandBuffer; - private List _renderObjects = new List(16); + private List _renderObjects = new List(16); #endregion diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 691b08a..29e1458 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -165,7 +165,7 @@ public bool TryGetRenderers(GameObject go, out ICollection renderers) /// /// Gets the objects for rendering. /// - public void GetRenderObjects(IList renderObjects) + public void GetRenderObjects(IList renderObjects) { if (_enabled) { @@ -175,7 +175,7 @@ public void GetRenderObjects(IList renderObjects) if (go && go.activeInHierarchy) { - renderObjects.Add(new OutlineObject(go, kvp.Value.GetList(), _settings)); + renderObjects.Add(new OutlineRenderObject(go, kvp.Value.GetList(), _settings)); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 44965be..1ff20f3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -54,7 +54,7 @@ public int IgnoreLayerMask /// /// Gets the objects for rendering. /// - public void GetRenderObjects(IList renderObjects) + public void GetRenderObjects(IList renderObjects) { foreach (var layer in _layers) { diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderObject.cs similarity index 77% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderObject.cs index 6ed07ce..fe7469a 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderObject.cs @@ -12,7 +12,7 @@ namespace UnityFx.Outline /// /// A single outline object + its outline settings. /// - public readonly struct OutlineObject : IEquatable + public readonly struct OutlineRenderObject : IEquatable { #region data @@ -40,9 +40,9 @@ namespace UnityFx.Outline public IOutlineSettings OutlineSettings => _outlineSettings; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// - public OutlineObject(GameObject go, IReadOnlyList renderers, IOutlineSettings outlineSettings) + public OutlineRenderObject(GameObject go, IReadOnlyList renderers, IOutlineSettings outlineSettings) { _go = go; _renderers = renderers; @@ -52,7 +52,7 @@ public OutlineObject(GameObject go, IReadOnlyList renderers, IOutlineS /// /// Implicit convertino to . /// - public static implicit operator GameObject(OutlineObject o) + public static implicit operator GameObject(OutlineRenderObject o) { return o._go; } @@ -62,7 +62,7 @@ public static implicit operator GameObject(OutlineObject o) #region IEquatable /// - public bool Equals(OutlineObject other) + public bool Equals(OutlineRenderObject other) { return _go == other._go && _renderers == other._renderers && _outlineSettings == other._outlineSettings; } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs.meta b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderObject.cs.meta similarity index 100% rename from Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineObject.cs.meta rename to Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderObject.cs.meta diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index c1da43c..41cf978 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -206,7 +206,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg /// An object to be outlined. /// /// - public void Render(OutlineObject obj) + public void Render(OutlineRenderObject obj) { Render(obj.Renderers, obj.OutlineSettings); } @@ -217,7 +217,7 @@ public void Render(OutlineObject obj) /// One or more renderers representing a single object to be outlined. /// Outline settings. /// Thrown if any of the arguments is . - /// + /// /// public void Render(IReadOnlyList renderers, IOutlineSettings settings) { @@ -244,7 +244,7 @@ public void Render(IReadOnlyList renderers, IOutlineSettings settings) /// A representing an object to be outlined. /// Outline settings. /// Thrown if any of the arguments is . - /// + /// /// public void Render(Renderer renderer, IOutlineSettings settings) { From 103ced7c1530c7f953e642e88644b19b596044ec Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Fri, 15 May 2020 18:41:29 +0300 Subject: [PATCH 41/61] URP-related changes --- .../Assets/Example/OutlineFeature.asset.meta | 8 - Outline.URP/Assets/Example/Test.unity | 556 ++++++------------ ...niversalRenderPipelineAsset_Renderer.asset | 33 +- .../Runtime/Scripts/OutlineFeature.cs | 22 +- .../Runtime/Scripts/OutlineFeature.cs.meta | 5 +- .../Runtime/Scripts/OutlinePass.cs | 33 +- .../ProjectSettings/GraphicsSettings.asset | 3 +- .../ProjectSettings/QualitySettings.asset | 2 +- .../URPProjectSettings.asset} | 9 +- 9 files changed, 261 insertions(+), 410 deletions(-) delete mode 100644 Outline.URP/Assets/Example/OutlineFeature.asset.meta rename Outline.URP/{Assets/Example/OutlineFeature.asset => ProjectSettings/URPProjectSettings.asset} (61%) diff --git a/Outline.URP/Assets/Example/OutlineFeature.asset.meta b/Outline.URP/Assets/Example/OutlineFeature.asset.meta deleted file mode 100644 index 2a2da2a..0000000 --- a/Outline.URP/Assets/Example/OutlineFeature.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 259b6fe12142a4642a8e5670d95637dc -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.URP/Assets/Example/Test.unity b/Outline.URP/Assets/Example/Test.unity index 4d65fc6..6800d1d 100644 --- a/Outline.URP/Assets/Example/Test.unity +++ b/Outline.URP/Assets/Example/Test.unity @@ -121,7 +121,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &646807773 +--- !u!1 &845078339 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -129,93 +129,91 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 646807774} - - component: {fileID: 646807777} - - component: {fileID: 646807776} - - component: {fileID: 646807775} + - component: {fileID: 845078341} + - component: {fileID: 845078340} m_Layer: 0 - m_Name: Cylinder + m_Name: Directional Light m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &646807774 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 646807773} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.52, y: -0.31, z: 4.31} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1130691891} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!136 &646807775 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 646807773} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - m_Radius: 0.5000001 - m_Height: 2 - m_Direction: 1 - m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} ---- !u!23 &646807776 -MeshRenderer: +--- !u!108 &845078340 +Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 646807773} + m_GameObject: {fileID: 845078339} m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 ---- !u!33 &646807777 -MeshFilter: + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &845078341 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 646807773} - m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &750107942 + m_GameObject: {fileID: 845078339} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 1.56, y: 3.71, z: -2.7} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &925532356 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -223,321 +221,129 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 750107943} - - component: {fileID: 750107946} - - component: {fileID: 750107945} - - component: {fileID: 750107944} + - component: {fileID: 925532360} + - component: {fileID: 925532359} + - component: {fileID: 925532358} + - component: {fileID: 925532357} + - component: {fileID: 925532361} m_Layer: 0 - m_Name: Cube - m_TagString: Untagged + m_Name: Camera + m_TagString: MainCamera m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &750107943 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 750107942} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 1.5699999, y: -0.30999994, z: 6.1} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1130691891} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &750107944 -BoxCollider: +--- !u!114 &925532357 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 750107942} - m_Material: {fileID: 0} - m_IsTrigger: 0 + m_GameObject: {fileID: 925532356} m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &750107945 -MeshRenderer: + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e746e776b0ae00d4a9d458b9430b95d7, type: 3} + m_Name: + m_EditorClassIdentifier: + _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} +--- !u!81 &925532358 +AudioListener: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 750107942} + m_GameObject: {fileID: 925532356} m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 ---- !u!33 &750107946 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 750107942} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1001 &1130691890 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalPosition.x - value: -2.4961035 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalPosition.y - value: 3.0931349 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalPosition.z - value: -3.8995318 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4264326293830219037, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4819242101474771701, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_AllowDynamicResolution - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4893056312182120781, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_Name - value: DefaultSceneRoot - objectReference: {fileID: 0} - - target: {fileID: 4949957087466332343, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_Version - value: 7 - objectReference: {fileID: 0} - - target: {fileID: 4949957087466332343, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_RenderingPathCustomFrameSettings.bitDatas.data1 - value: 734440390720 - objectReference: {fileID: 0} - - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_Version - value: 9 - objectReference: {fileID: 0} - - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_MinFilterSize - value: 0.01 - objectReference: {fileID: 0} - - target: {fileID: 5131575625094108011, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: m_ShadowResolution.m_Level - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8708978604625570628, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - propertyPath: sharedProfile - value: - objectReference: {fileID: 11400000, guid: aab0876a9ec74194fb766183257d02c9, - type: 2} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: de1884a706667b84cbf9c4195ee402ca, type: 3} ---- !u!4 &1130691891 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 4958332782299279292, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - m_PrefabInstance: {fileID: 1130691890} - m_PrefabAsset: {fileID: 0} ---- !u!1 &1130691892 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 4613009710449648096, guid: de1884a706667b84cbf9c4195ee402ca, - type: 3} - m_PrefabInstance: {fileID: 1130691890} - m_PrefabAsset: {fileID: 0} ---- !u!114 &1130691893 -MonoBehaviour: +--- !u!20 &925532359 +Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1130691892} + m_GameObject: {fileID: 925532356} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 22d06c15672ad2440afbe792e641c411, type: 3} - m_Name: - m_EditorClassIdentifier: - _layer0: - - {fileID: 1202059779} - - {fileID: 1822928728} - _layer1: - - {fileID: 646807773} - - {fileID: 750107942} - _layers: {fileID: 11400000, guid: 65159dc68f867cd4f90261bae63e29a7, type: 2} ---- !u!1 &1202059779 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1202059780} - - component: {fileID: 1202059783} - - component: {fileID: 1202059782} - - component: {fileID: 1202059781} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1202059780 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &925532360 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1202059779} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -2.28, y: -0.30999994, z: 5.32} + m_GameObject: {fileID: 925532356} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1130691891} + m_Children: + - {fileID: 958073179} + m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!135 &1202059781 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1202059779} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1202059782 -MeshRenderer: +--- !u!114 &925532361 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1202059779} + m_GameObject: {fileID: 925532356} m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 ---- !u!33 &1202059783 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1202059779} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1822928728 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_Version: 2 +--- !u!1 &958073178 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -545,52 +351,52 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1822928729} - - component: {fileID: 1822928732} - - component: {fileID: 1822928731} - - component: {fileID: 1822928730} + - component: {fileID: 958073179} + - component: {fileID: 958073182} + - component: {fileID: 958073181} + - component: {fileID: 958073180} m_Layer: 0 - m_Name: Capsule + m_Name: Cylinder m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &1822928729 +--- !u!4 &958073179 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1822928728} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -1.7100003, y: -0.30999994, z: 4.7999997} + m_GameObject: {fileID: 958073178} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 3.06} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] - m_Father: {fileID: 1130691891} - m_RootOrder: 1 + m_Father: {fileID: 925532360} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!136 &1822928730 +--- !u!136 &958073180 CapsuleCollider: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1822928728} + m_GameObject: {fileID: 958073178} m_Material: {fileID: 0} m_IsTrigger: 0 m_Enabled: 1 - m_Radius: 0.5 + m_Radius: 0.5000001 m_Height: 2 m_Direction: 1 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1822928731 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &958073181 MeshRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1822928728} + m_GameObject: {fileID: 958073178} m_Enabled: 1 m_CastShadows: 1 m_ReceiveShadows: 1 @@ -602,7 +408,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} + - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -623,11 +429,11 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 ---- !u!33 &1822928732 +--- !u!33 &958073182 MeshFilter: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1822928728} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} + m_GameObject: {fileID: 958073178} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset index e53abaf..8df1e75 100644 --- a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset @@ -1,5 +1,20 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!114 &-3150190567137265444 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dd37d03d18ee9584d881763c34816b35, type: 3} + m_Name: Outline + m_EditorClassIdentifier: + m_Active: 1 + _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, type: 2} + _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 @@ -12,14 +27,17 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} m_Name: UniversalRenderPipelineAsset_Renderer m_EditorClassIdentifier: - m_RendererFeatures: [] - postProcessData: {fileID: 0} + m_RendererFeatures: + - {fileID: -3150190567137265444} + m_RendererFeatureMap: dc38ff9e5e4648d4 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} shaders: - blitPS: {fileID: 0} - copyDepthPS: {fileID: 0} - screenSpaceShadowPS: {fileID: 0} - samplingPS: {fileID: 0} - fallbackErrorPS: {fileID: 0} + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, + type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} m_OpaqueLayerMask: serializedVersion: 2 m_Bits: 4294967295 @@ -33,3 +51,4 @@ MonoBehaviour: passOperation: 0 failOperation: 0 zFailOperation: 0 + m_ShadowTransparentReceive: 0 diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs index 5b2ca48..14c58f2 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -11,28 +11,28 @@ namespace UnityFx.Outline.URP /// /// Outline feature (URP). /// - [CreateAssetMenu(fileName = "OutlineFeature", menuName = "UnityFx/Outline/Outline (URP)")] public class OutlineFeature : ScriptableRendererFeature { - private OutlineRenderColorPass _renderColorPass; +#pragma warning disable 0649 + + [SerializeField] + private OutlineResources _outlineResources; + [SerializeField] + private OutlineLayerCollection _outlineLayers; + +#pragma warning restore 0649 + private OutlinePass _outlinePass; public override void Create() { - _renderColorPass = new OutlineRenderColorPass(); _outlinePass = new OutlinePass(); - - // Configures where the render pass should be injected. - _renderColorPass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; + _outlinePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; } - // Here you can inject one or multiple render passes in the renderer. - // This method is called when setting up the renderer once per-camera. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - _renderColorPass.SetDepth(renderer.cameraDepth); - - renderer.EnqueuePass(_renderColorPass); + _outlinePass.Setup(_outlineResources, renderer.cameraDepth, _outlineLayers); renderer.EnqueuePass(_outlinePass); } } diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta index 56e2317..cb0f643 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs.meta @@ -3,7 +3,10 @@ guid: dd37d03d18ee9584d881763c34816b35 MonoImporter: externalObjects: {} serializedVersion: 2 - defaultReferences: [] + defaultReferences: + - _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, + type: 2} + - _outlineLayers: {instanceID: 0} executionOrder: 0 icon: {instanceID: 0} userData: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs index 02cb148..ba1a65d 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -2,6 +2,7 @@ // See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; @@ -13,14 +14,42 @@ namespace UnityFx.Outline.URP /// internal class OutlinePass : ScriptableRenderPass { + private List _renderObjects = new List(); + + private OutlineResources _outlineResources; + private OutlineLayerCollection _outlineLayers; + private RenderTargetIdentifier _depth; + private RenderTextureDescriptor _rtDesc; + + public void Setup(OutlineResources resources, RenderTargetIdentifier depth, OutlineLayerCollection layers) + { + _outlineResources = resources; + _outlineLayers = layers; + _depth = depth; + } + public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) { - // TODO + _rtDesc = cameraTextureDescriptor; } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { - throw new NotImplementedException(); + var cmd = CommandBufferPool.Get(OutlineRenderer.EffectName); + + using (var renderer = new OutlineRenderer(cmd, _outlineResources, BuiltinRenderTextureType.CameraTarget, _depth, _rtDesc)) + { + _renderObjects.Clear(); + _outlineLayers.GetRenderObjects(_renderObjects); + + foreach (var obj in _renderObjects) + { + renderer.Render(obj); + } + } + + context.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); } public override void FrameCleanup(CommandBuffer cmd) diff --git a/Outline.URP/ProjectSettings/GraphicsSettings.asset b/Outline.URP/ProjectSettings/GraphicsSettings.asset index 35a0fa7..f032055 100644 --- a/Outline.URP/ProjectSettings/GraphicsSettings.asset +++ b/Outline.URP/ProjectSettings/GraphicsSettings.asset @@ -39,7 +39,8 @@ GraphicsSettings: m_PreloadedShaders: [] m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} - m_CustomRenderPipeline: {fileID: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 3d47f01a90fe56d43b0cfac27039c94c, + type: 2} m_TransparencySortMode: 0 m_TransparencySortAxis: {x: 0, y: 0, z: 1} m_DefaultRenderingPath: 1 diff --git a/Outline.URP/ProjectSettings/QualitySettings.asset b/Outline.URP/ProjectSettings/QualitySettings.asset index d24eb10..38a45f3 100644 --- a/Outline.URP/ProjectSettings/QualitySettings.asset +++ b/Outline.URP/ProjectSettings/QualitySettings.asset @@ -201,7 +201,7 @@ QualitySettings: skinWeights: 255 textureQuality: 0 anisotropicTextures: 2 - antiAliasing: 2 + antiAliasing: 0 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 diff --git a/Outline.URP/Assets/Example/OutlineFeature.asset b/Outline.URP/ProjectSettings/URPProjectSettings.asset similarity index 61% rename from Outline.URP/Assets/Example/OutlineFeature.asset rename to Outline.URP/ProjectSettings/URPProjectSettings.asset index 2eb6c9d..fa89832 100644 --- a/Outline.URP/Assets/Example/OutlineFeature.asset +++ b/Outline.URP/ProjectSettings/URPProjectSettings.asset @@ -1,14 +1,15 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 +--- !u!114 &1 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 61 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dd37d03d18ee9584d881763c34816b35, type: 3} - m_Name: OutlineFeature + m_Script: {fileID: 11500000, guid: 247994e1f5a72c2419c26a37e9334c01, type: 3} + m_Name: m_EditorClassIdentifier: + m_LastMaterialVersion: 1 From 81a9919610ca84cf485e802b30f61e4e1fc80a1b Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Fri, 15 May 2020 21:46:50 +0300 Subject: [PATCH 42/61] URP outline implemented --- Outline.URP/Assets/Example/OutlineTest.cs | 31 ----------- .../Assets/Example/OutlineTest.cs.meta | 11 ---- .../Example/{Test.unity => TestScene.unity} | 0 .../{Test.unity.meta => TestScene.unity.meta} | 0 .../Runtime/Scripts/OutlineFeature.cs | 2 +- .../Runtime/Scripts/OutlinePass.cs | 6 ++- .../Runtime/Scripts/OutlineRenderColorPass.cs | 51 ------------------- .../Scripts/OutlineRenderColorPass.cs.meta | 11 ---- 8 files changed, 5 insertions(+), 107 deletions(-) delete mode 100644 Outline.URP/Assets/Example/OutlineTest.cs delete mode 100644 Outline.URP/Assets/Example/OutlineTest.cs.meta rename Outline.URP/Assets/Example/{Test.unity => TestScene.unity} (100%) rename Outline.URP/Assets/Example/{Test.unity.meta => TestScene.unity.meta} (100%) delete mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs delete mode 100644 Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta diff --git a/Outline.URP/Assets/Example/OutlineTest.cs b/Outline.URP/Assets/Example/OutlineTest.cs deleted file mode 100644 index 0253a66..0000000 --- a/Outline.URP/Assets/Example/OutlineTest.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityFx.Outline; - -public class OutlineTest : MonoBehaviour -{ -#pragma warning disable 0649 - - [SerializeField] - private GameObject[] _layer0; - [SerializeField] - private GameObject[] _layer1; - [SerializeField] - private OutlineLayerCollection _layers; - -#pragma warning restore 0649 - - void Start() - { - foreach (var go in _layer0) - { - _layers[0].Add(go); - } - - foreach (var go in _layer1) - { - _layers[1].Add(go); - } - } -} diff --git a/Outline.URP/Assets/Example/OutlineTest.cs.meta b/Outline.URP/Assets/Example/OutlineTest.cs.meta deleted file mode 100644 index a753946..0000000 --- a/Outline.URP/Assets/Example/OutlineTest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 21871d619b9e3f04b89bbca6cd338745 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Outline.URP/Assets/Example/Test.unity b/Outline.URP/Assets/Example/TestScene.unity similarity index 100% rename from Outline.URP/Assets/Example/Test.unity rename to Outline.URP/Assets/Example/TestScene.unity diff --git a/Outline.URP/Assets/Example/Test.unity.meta b/Outline.URP/Assets/Example/TestScene.unity.meta similarity index 100% rename from Outline.URP/Assets/Example/Test.unity.meta rename to Outline.URP/Assets/Example/TestScene.unity.meta diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs index 14c58f2..b99393c 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -32,7 +32,7 @@ public override void Create() public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - _outlinePass.Setup(_outlineResources, renderer.cameraDepth, _outlineLayers); + _outlinePass.Setup(_outlineResources, _outlineLayers, renderer.cameraColorTarget, renderer.cameraDepth); renderer.EnqueuePass(_outlinePass); } } diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs index ba1a65d..083d87c 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -18,13 +18,15 @@ internal class OutlinePass : ScriptableRenderPass private OutlineResources _outlineResources; private OutlineLayerCollection _outlineLayers; + private RenderTargetIdentifier _rt; private RenderTargetIdentifier _depth; private RenderTextureDescriptor _rtDesc; - public void Setup(OutlineResources resources, RenderTargetIdentifier depth, OutlineLayerCollection layers) + public void Setup(OutlineResources resources, OutlineLayerCollection layers, RenderTargetIdentifier rt, RenderTargetIdentifier depth) { _outlineResources = resources; _outlineLayers = layers; + _rt = rt; _depth = depth; } @@ -37,7 +39,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData { var cmd = CommandBufferPool.Get(OutlineRenderer.EffectName); - using (var renderer = new OutlineRenderer(cmd, _outlineResources, BuiltinRenderTextureType.CameraTarget, _depth, _rtDesc)) + using (var renderer = new OutlineRenderer(cmd, _outlineResources, _rt, _depth, _rtDesc)) { _renderObjects.Clear(); _outlineLayers.GetRenderObjects(_renderObjects); diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs deleted file mode 100644 index fd6b3cb..0000000 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.Rendering.Universal; - -namespace UnityFx.Outline.URP -{ - /// - /// - /// - internal class OutlineRenderColorPass : ScriptableRenderPass - { - private RenderTargetHandle _rt; - private RenderTargetIdentifier _depth; - - public OutlineRenderColorPass() - { - _rt.Init("_MaskTex"); - } - - public void SetDepth(RenderTargetIdentifier depth) - { - _depth = depth; - } - - public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) - { - var rtFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) ? RenderTextureFormat.R8 : RenderTextureFormat.Default; - cmd.GetTemporaryRT(_rt.id, cameraTextureDescriptor.width, cameraTextureDescriptor.height, 0, FilterMode.Bilinear, rtFormat); - ConfigureClear(ClearFlag.Color, Color.clear); - ConfigureTarget(_rt.Identifier(), _depth); - } - - public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) - { - // Here you can implement the rendering logic. - // Use ScriptableRenderContext to issue drawing commands or execute command buffers - // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html - // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline. - - } - - public override void FrameCleanup(CommandBuffer cmd) - { - cmd.ReleaseTemporaryRT(_rt.id); - } - } -} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta deleted file mode 100644 index 8fc50f9..0000000 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineRenderColorPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c4c2f531479cf7343abc806e7e72c2a9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From fde8ef84c86992a062ba41821e5e39991aed8167 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 16 May 2020 21:33:45 +0300 Subject: [PATCH 43/61] Changed naming of the outline samples in profiler --- .../Runtime/Scripts/OutlineBehaviour.cs | 2 +- .../Runtime/Scripts/OutlineRenderer.cs | 29 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index f9034a6..342f062 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -190,7 +190,7 @@ private void Update() { using (var renderer = new OutlineRenderer(cmdBuffer, _outlineResources, camera.actualRenderingPath)) { - renderer.Render(_renderers.GetList(), _outlineSettings); + renderer.Render(_renderers.GetList(), _outlineSettings, name); } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 41cf978..770e654 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -139,7 +139,6 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg rtSize.y = -1; } - cmd.BeginSample(EffectName); cmd.GetTemporaryRT(_maskRtId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, _rtFormat); cmd.GetTemporaryRT(_hPassRtId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, _rtFormat); @@ -190,7 +189,6 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg rtDesc.colorFormat = _rtFormat; rtDesc.volumeDepth = 1; - cmd.BeginSample(EffectName); cmd.GetTemporaryRT(_maskRtId, rtDesc, FilterMode.Bilinear); cmd.GetTemporaryRT(_hPassRtId, rtDesc, FilterMode.Bilinear); @@ -208,7 +206,7 @@ public OutlineRenderer(CommandBuffer cmd, OutlineResources resources, RenderTarg /// public void Render(OutlineRenderObject obj) { - Render(obj.Renderers, obj.OutlineSettings); + Render(obj.Renderers, obj.OutlineSettings, obj.Go.name); } /// @@ -216,10 +214,11 @@ public void Render(OutlineRenderObject obj) /// /// One or more renderers representing a single object to be outlined. /// Outline settings. + /// Optional name of the sample (visible in profiler). /// Thrown if any of the arguments is . /// - /// - public void Render(IReadOnlyList renderers, IOutlineSettings settings) + /// + public void Render(IReadOnlyList renderers, IOutlineSettings settings, string sampleName = null) { if (renderers is null) { @@ -233,8 +232,15 @@ public void Render(IReadOnlyList renderers, IOutlineSettings settings) if (renderers.Count > 0) { + if (string.IsNullOrEmpty(sampleName)) + { + sampleName = renderers[0].name; + } + + _commandBuffer.BeginSample(sampleName); RenderObject(settings, renderers); RenderOutline(settings); + _commandBuffer.EndSample(sampleName); } } @@ -243,10 +249,11 @@ public void Render(IReadOnlyList renderers, IOutlineSettings settings) /// /// A representing an object to be outlined. /// Outline settings. + /// Optional name of the sample (visible in profiler). /// Thrown if any of the arguments is . /// - /// - public void Render(Renderer renderer, IOutlineSettings settings) + /// + public void Render(Renderer renderer, IOutlineSettings settings, string sampleName = null) { if (renderer is null) { @@ -258,8 +265,15 @@ public void Render(Renderer renderer, IOutlineSettings settings) throw new ArgumentNullException(nameof(settings)); } + if (string.IsNullOrEmpty(sampleName)) + { + sampleName = renderer.name; + } + + _commandBuffer.BeginSample(sampleName); RenderObject(settings, renderer); RenderOutline(settings); + _commandBuffer.EndSample(sampleName); } /// @@ -289,7 +303,6 @@ public void Dispose() { _commandBuffer.ReleaseTemporaryRT(_hPassRtId); _commandBuffer.ReleaseTemporaryRT(_maskRtId); - _commandBuffer.EndSample(EffectName); } #endregion From 473715f278967f54094bb30f7c95c704a05f538d Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 16 May 2020 22:07:10 +0300 Subject: [PATCH 44/61] Added URP support (fixes #5) --- .../Runtime/Scripts/OutlineBehaviour.cs | 2 +- .../Runtime/Scripts/OutlineEffect.cs | 4 ++-- .../Runtime/Scripts/OutlineRenderer.cs | 5 ----- .../Runtime/Scripts/OutlineResources.cs | 15 +++++++++++++++ .../Assets/Example/OutlineLayerCollection.asset | 7 +++---- .../Packages/UnityFx.Outline.URP/CHANGELOG.md | 2 +- .../Packages/UnityFx.Outline.URP/README.md | 6 +++--- .../Runtime/Scripts/OutlineFeature.cs | 16 ++++++++++++---- .../Runtime/Scripts/OutlinePass.cs | 11 +++-------- 9 files changed, 40 insertions(+), 28 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 342f062..96daed1 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -21,7 +21,7 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings #pragma warning disable 0649 - [SerializeField, Tooltip("Sets outline resources to use. Do not change the defaults unless you know what you're doing.")] + [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] private OutlineResources _outlineResources; [SerializeField, HideInInspector] private OutlineSettingsInstance _outlineSettings; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index 13a428a..0150be3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -21,9 +21,9 @@ public sealed partial class OutlineEffect : MonoBehaviour { #region data - [SerializeField, Tooltip("Sets outline resources to use. Do not change the defaults unless you know what you're doing.")] + [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] private OutlineResources _outlineResources; - [SerializeField, Tooltip("Collection of outline layers to use. This can be used to share outline settings between multiple cameras.")] + [SerializeField, Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] private OutlineLayerCollection _outlineLayers; [SerializeField, HideInInspector] private CameraEvent _cameraEvent = OutlineRenderer.RenderEvent; diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 770e654..6ac7e84 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -57,11 +57,6 @@ namespace UnityFx.Outline /// public const CameraEvent RenderEvent = CameraEvent.BeforeImageEffects; - /// - /// Name of the outline effect. - /// - public const string EffectName = "Outline"; - /// /// Initializes a new instance of the struct. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index fc3efa2..3431e1f 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -90,6 +90,21 @@ public sealed class OutlineResources : ScriptableObject /// public const string UseDrawMeshFeatureName = "_USE_DRAWMESH"; + /// + /// Name of the outline effect. + /// + public const string EffectName = "Outline"; + + /// + /// Tooltip text for field. + /// + public const string OutlineResourcesTooltip = "Outline resources to use (shaders, materials etc). Do not change defaults unless you know what you're doing."; + + /// + /// Tooltip text for field. + /// + public const string OutlineLayerCollectionTooltip = "Collection of outline layers to use. This can be used to share outline settings between multiple cameras."; + /// /// Hashed name of _MainTex shader parameter. /// diff --git a/Outline.URP/Assets/Example/OutlineLayerCollection.asset b/Outline.URP/Assets/Example/OutlineLayerCollection.asset index c96e20d..b09ddfe 100644 --- a/Outline.URP/Assets/Example/OutlineLayerCollection.asset +++ b/Outline.URP/Assets/Example/OutlineLayerCollection.asset @@ -16,11 +16,10 @@ MonoBehaviour: - _settings: _outlineSettings: {fileID: 0} _outlineColor: {r: 1, g: 0, b: 0, a: 1} - _outlineWidth: 4 + _outlineWidth: 25 _outlineIntensity: 2 - _outlineMode: 0 + _outlineMode: 1 _name: - _zOrder: 0 _enabled: 1 - _settings: _outlineSettings: {fileID: 0} @@ -29,5 +28,5 @@ MonoBehaviour: _outlineIntensity: 2 _outlineMode: 1 _name: - _zOrder: 0 _enabled: 1 + _layerMask: 0 diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md index 1cf7420..7f443e9 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md +++ b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md @@ -1,4 +1,4 @@ -# UnityFx.Outline.HDRP changelog +# UnityFx.Outline.URP changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/README.md b/Outline.URP/Packages/UnityFx.Outline.URP/README.md index 7149507..aec8aa2 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/README.md +++ b/Outline.URP/Packages/UnityFx.Outline.URP/README.md @@ -1,11 +1,11 @@ -# UnityFx.Outline.HDRP +# UnityFx.Outline.URP ## SUMMARY -Screen-space outline effects for HDRP. +Screen-space outline effects for URP. ## USEFUL LINKS * [Github project](https://github.com/Arvtesh/UnityFx.Outline) -* [npm package](https://www.npmjs.com/package/com.unityfx.outline.hdrp) +* [npm package](https://www.npmjs.com/package/com.unityfx.outline.urp) * [Documentation](https://github.com/Arvtesh/UnityFx.Outline/blob/master/README.md) * [License](https://github.com/Arvtesh/UnityFx.Outline/blob/master/LICENSE.md) * [Support](mailto:arvtesh@gmail.com) diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs index b99393c..0fae297 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -11,13 +11,18 @@ namespace UnityFx.Outline.URP /// /// Outline feature (URP). /// + /// + /// Add instance of this class to . Configure + /// and assign outline resources and layers collection. Make sure + /// is set if you use . + /// public class OutlineFeature : ScriptableRendererFeature { #pragma warning disable 0649 - [SerializeField] + [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] private OutlineResources _outlineResources; - [SerializeField] + [SerializeField, Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] private OutlineLayerCollection _outlineLayers; #pragma warning restore 0649 @@ -32,8 +37,11 @@ public override void Create() public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - _outlinePass.Setup(_outlineResources, _outlineLayers, renderer.cameraColorTarget, renderer.cameraDepth); - renderer.EnqueuePass(_outlinePass); + if (_outlineResources && _outlineLayers) + { + _outlinePass.Setup(_outlineResources, _outlineLayers, renderer.cameraColorTarget, renderer.cameraDepth); + renderer.EnqueuePass(_outlinePass); + } } } } diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs index 083d87c..278aea4 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -14,10 +14,10 @@ namespace UnityFx.Outline.URP /// internal class OutlinePass : ScriptableRenderPass { - private List _renderObjects = new List(); - private OutlineResources _outlineResources; private OutlineLayerCollection _outlineLayers; + + private List _renderObjects = new List(); private RenderTargetIdentifier _rt; private RenderTargetIdentifier _depth; private RenderTextureDescriptor _rtDesc; @@ -37,7 +37,7 @@ public override void Configure(CommandBuffer cmd, RenderTextureDescriptor camera public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { - var cmd = CommandBufferPool.Get(OutlineRenderer.EffectName); + var cmd = CommandBufferPool.Get(OutlineResources.EffectName); using (var renderer = new OutlineRenderer(cmd, _outlineResources, _rt, _depth, _rtDesc)) { @@ -53,10 +53,5 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } - - public override void FrameCleanup(CommandBuffer cmd) - { - // TODO - } } } From b6ba453b0420d2e170db0266533ea634eaaceadb Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 16 May 2020 22:08:43 +0300 Subject: [PATCH 45/61] Misc changes --- Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset | 4 ++-- .../Assets/URP/UniversalRenderPipelineAsset_Renderer.asset | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset index 2c548dc..9540d39 100644 --- a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset @@ -19,10 +19,10 @@ MonoBehaviour: m_RendererDataList: - {fileID: 11400000, guid: f1ccc14d55573e14f80806280c11d740, type: 2} m_DefaultRendererIndex: 0 - m_RequireDepthTexture: 0 + m_RequireDepthTexture: 1 m_RequireOpaqueTexture: 0 m_OpaqueDownsampling: 1 - m_SupportsTerrainHoles: 1 + m_SupportsTerrainHoles: 0 m_SupportsHDR: 0 m_MSAA: 1 m_RenderScale: 1 diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset index 8df1e75..df60544 100644 --- a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset @@ -1,6 +1,6 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!114 &-3150190567137265444 +--- !u!114 &-2278397774415627597 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -12,7 +12,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: dd37d03d18ee9584d881763c34816b35, type: 3} m_Name: Outline m_EditorClassIdentifier: - m_Active: 1 _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, type: 2} _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} --- !u!114 &11400000 @@ -28,8 +27,7 @@ MonoBehaviour: m_Name: UniversalRenderPipelineAsset_Renderer m_EditorClassIdentifier: m_RendererFeatures: - - {fileID: -3150190567137265444} - m_RendererFeatureMap: dc38ff9e5e4648d4 + - {fileID: -2278397774415627597} postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} shaders: blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} @@ -51,4 +49,3 @@ MonoBehaviour: passOperation: 0 failOperation: 0 zFailOperation: 0 - m_ShadowTransparentReceive: 0 From c79c9192de66bef78b6f646ab3e508126b945532 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 16 May 2020 22:21:42 +0300 Subject: [PATCH 46/61] Added post-processing tooltips and bumped UnityFx.Outline version to 0.8 --- .../Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md | 6 ++++++ .../Runtime/Scripts/Outline.cs | 2 ++ .../Runtime/Scripts/OutlineEffectRenderer.cs | 2 +- .../Packages/UnityFx.Outline.PostProcessing/package.json | 8 ++++---- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md index ae04922..7294762 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.2.0] - unreleased + +### Added +- Added inspector tooltips. +- Added depth support. + ## [0.1.0] - 2020.04.08 ### Added diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/Outline.cs b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/Outline.cs index e7ef71d..b43431e 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/Outline.cs +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/Outline.cs @@ -38,7 +38,9 @@ public class OutlineLayersParameter : ParameterOverride } // NOTE: PostProcessEffectSettings.OnEnable implementation requires the fields to be public to function properly. + [Tooltip(OutlineResources.OutlineResourcesTooltip)] public OutlineResourcesParameter Resources = new OutlineResourcesParameter(); + [Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] public OutlineLayersParameter Layers = new OutlineLayersParameter(); public Outline() diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs index 79fdd06..b60c331 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/Runtime/Scripts/OutlineEffectRenderer.cs @@ -13,7 +13,7 @@ namespace UnityFx.Outline.PostProcessing public sealed class OutlineEffectRenderer : PostProcessEffectRenderer { private OutlineResources _defaultResources; - private List _objects = new List(); + private List _objects = new List(); public override DepthTextureMode GetCameraFlags() { diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json index 6c5b92f..5b54a65 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json @@ -1,12 +1,12 @@ { "name": "com.unityfx.outline.postprocessing", - "version": "0.1.0", + "version": "0.2.0", "displayName": "Screen-space outline (Post-processing v2)", - "description": "Configurable outline implementation for Unity post-processing stack (v2). Both solid and blurred modes supported (Gauss blur). Scriptable render pipeline is not supported.", + "description": "Configurable screen-space outline implementation for Unity post-processing stack (v2).", "unity": "2018.4", "dependencies": { - "com.unityfx.outline": "0.7.2", - "com.unity.postprocessing": "2.2.2" + "com.unityfx.outline": "0.8.0", + "com.unity.postprocessing": "2.3.0" }, "keywords": [ "UnityFx", From 3e4cf650526cba75d32f0aa7d1af4dbc374e47e9 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 16 May 2020 23:03:44 +0300 Subject: [PATCH 47/61] Added HDRP CustomPass for outline --- Outline.HDRP/Assets/Example/Test.unity | 33 +++++ .../Runtime/Scripts/Outline.cs | 131 ------------------ .../Runtime/Scripts/OutlinePass.cs | 63 +++++++++ .../{Outline.cs.meta => OutlinePass.cs.meta} | 0 4 files changed, 96 insertions(+), 131 deletions(-) delete mode 100644 Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs create mode 100644 Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs rename Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/{Outline.cs.meta => OutlinePass.cs.meta} (100%) diff --git a/Outline.HDRP/Assets/Example/Test.unity b/Outline.HDRP/Assets/Example/Test.unity index 4d65fc6..e6e52f5 100644 --- a/Outline.HDRP/Assets/Example/Test.unity +++ b/Outline.HDRP/Assets/Example/Test.unity @@ -444,6 +444,39 @@ MonoBehaviour: - {fileID: 646807773} - {fileID: 750107942} _layers: {fileID: 11400000, guid: 65159dc68f867cd4f90261bae63e29a7, type: 2} +--- !u!114 &1130691894 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1130691892} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26d6499a6bd256e47b859377446493a1, type: 3} + m_Name: + m_EditorClassIdentifier: + isGlobal: 1 + fadeRadius: 0 + customPasses: + - id: 0 + injectionPoint: 2 + references: + version: 1 + 00000000: + type: {class: OutlinePass, ns: UnityFx.Outline.HDRP, asm: UnityFx.Outline.HDRP} + data: + name: Outline + enabled: 1 + targetColorBuffer: 0 + targetDepthBuffer: 0 + clearFlags: 0 + passFoldout: 0 + m_Version: 0 + _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, + type: 2} + _outlineLayers: {fileID: 11400000, guid: 65159dc68f867cd4f90261bae63e29a7, + type: 2} --- !u!1 &1202059779 GameObject: m_ObjectHideFlags: 0 diff --git a/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs b/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs deleted file mode 100644 index 0293025..0000000 --- a/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.Rendering.HighDefinition; - -namespace UnityFx.Outline.HDRP -{ - [Serializable] - [VolumeComponentMenu("Post-processing/UnityFx/Outline")] - public sealed class Outline : CustomPostProcessVolumeComponent, IPostProcessComponent - { - #region data - -#pragma warning disable 0649 - - [Serializable] - private class OutlineResourcesParameter : VolumeParameter - { - } - - [Serializable] - private class OutlineLayersParameter : VolumeParameter - { - } - - [SerializeField, HideInInspector] - private OutlineResources _defaultResources; - [SerializeField] - private OutlineResourcesParameter _resources = new OutlineResourcesParameter(); - [SerializeField] - private OutlineLayersParameter _layers = new OutlineLayersParameter(); - -#pragma warning restore 0649 - - #endregion - - #region interface - - public IList OutlineLayers - { - get - { - return _layers.value; - } - } - - #endregion - - #region CustomPostProcessVolumeComponent - - public override CustomPostProcessInjectionPoint injectionPoint - { - get - { - return CustomPostProcessInjectionPoint.BeforePostProcess; - } - } - - public override void Setup() - { - base.Setup(); - } - - public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination) - { - using (var renderer = new OutlineRenderer(cmd, source, destination, source.referenceSize)) - { - _layers.value.Render(renderer, _resources.value); - } - } - - public override void Cleanup() - { - base.Cleanup(); - } - - #endregion - - #region ScriptableObject - - protected override void OnEnable() - { - // NOTE: This should go before base.OnEnable(). - if (!_resources.value) - { - _resources.value = _defaultResources; - } - - base.OnEnable(); - } - - #endregion - - #region IPostProcessComponent - - public bool IsActive() - { - if (!Application.isPlaying) - { - return false; - } - - if (_resources == null || _layers == null) - { - return false; - } - - var r = _resources.value; - - if (r == null || !r.IsValid) - { - return false; - } - - var l = _layers.value; - - if (l == null || l.Count == 0) - { - return false; - } - - return true; - } - - #endregion - } -} diff --git a/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs b/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs new file mode 100644 index 0000000..425a186 --- /dev/null +++ b/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs @@ -0,0 +1,63 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.HighDefinition; + +namespace UnityFx.Outline.HDRP +{ + /// + /// + /// + public sealed class OutlinePass : CustomPass + { + #region data + +#pragma warning disable 0649 + + [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] + private OutlineResources _outlineResources; + [SerializeField, Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] + private OutlineLayerCollection _outlineLayers; + +#pragma warning restore 0649 + + private List _renderList; + + #endregion + + #region CustomPass + + protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) + { + if (_renderList is null) + { + _renderList = new List(); + } + } + + protected override void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResult) + { + if (_outlineResources && _outlineLayers) + { + GetCameraBuffers(out var colorBuffer, out var depthBuffer); + + using (var renderer = new OutlineRenderer(cmd, _outlineResources, colorBuffer.nameID, depthBuffer.nameID, colorBuffer.rt.descriptor)) + { + _renderList.Clear(); + _outlineLayers.GetRenderObjects(_renderList); + + foreach (var obj in _renderList) + { + renderer.Render(obj); + } + } + } + } + + #endregion + } +} diff --git a/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs.meta b/Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs.meta similarity index 100% rename from Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/Outline.cs.meta rename to Outline.HDRP/Packages/UnityFx.Outline.HDRP/Runtime/Scripts/OutlinePass.cs.meta From 98b7f60b52c60beec44f66553dfb8f24b00ec509 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sun, 17 May 2020 11:53:14 +0300 Subject: [PATCH 48/61] Updated auto-deploy script --- .github/workflows/npmpublish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index 9d54621..f5ac9f4 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -17,5 +17,6 @@ jobs: - run: | npm publish Outline.Core/Packages/UnityFx.Outline npm publish Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing + npm publish Outline.URP/Packages/UnityFx.Outline.URP env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} From 29d43a9df29a938c4a9fbcc28ce9cad030f3a1f0 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sun, 17 May 2020 11:53:39 +0300 Subject: [PATCH 49/61] Minor URP-related fixes --- .../Runtime/Scripts/OutlineFeature.cs | 34 ++++++++++++++++--- .../Runtime/Scripts/OutlinePass.cs | 21 ++++++------ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs index 0fae297..ad6c82e 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -18,6 +18,8 @@ namespace UnityFx.Outline.URP /// public class OutlineFeature : ScriptableRendererFeature { + #region data + #pragma warning disable 0649 [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] @@ -29,19 +31,43 @@ public class OutlineFeature : ScriptableRendererFeature private OutlinePass _outlinePass; + #endregion + + #region interface + + /// + /// Gets the outline resources. + /// + public OutlineResources OutlineResources => _outlineResources; + + /// + /// Gets outline layers collection attached. + /// + public OutlineLayerCollection OutlineLayers => _outlineLayers; + + #endregion + + #region ScriptableRendererFeature + + /// public override void Create() { - _outlinePass = new OutlinePass(); - _outlinePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; + _outlinePass = new OutlinePass(this) + { + renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing + }; } + /// public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - if (_outlineResources && _outlineLayers) + if (_outlineResources && _outlineResources.IsValid && _outlineLayers) { - _outlinePass.Setup(_outlineResources, _outlineLayers, renderer.cameraColorTarget, renderer.cameraDepth); + _outlinePass.Setup(renderer.cameraColorTarget, renderer.cameraDepth); renderer.EnqueuePass(_outlinePass); } } + + #endregion } } diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs index 278aea4..154fde4 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -9,23 +9,22 @@ namespace UnityFx.Outline.URP { - /// - /// - /// internal class OutlinePass : ScriptableRenderPass { - private OutlineResources _outlineResources; - private OutlineLayerCollection _outlineLayers; + private readonly OutlineFeature _feature; + private readonly List _renderObjects = new List(); - private List _renderObjects = new List(); private RenderTargetIdentifier _rt; private RenderTargetIdentifier _depth; private RenderTextureDescriptor _rtDesc; - public void Setup(OutlineResources resources, OutlineLayerCollection layers, RenderTargetIdentifier rt, RenderTargetIdentifier depth) + public OutlinePass(OutlineFeature feature) + { + _feature = feature; + } + + public void Setup(RenderTargetIdentifier rt, RenderTargetIdentifier depth) { - _outlineResources = resources; - _outlineLayers = layers; _rt = rt; _depth = depth; } @@ -39,10 +38,10 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData { var cmd = CommandBufferPool.Get(OutlineResources.EffectName); - using (var renderer = new OutlineRenderer(cmd, _outlineResources, _rt, _depth, _rtDesc)) + using (var renderer = new OutlineRenderer(cmd, _feature.OutlineResources, _rt, _depth, _rtDesc)) { _renderObjects.Clear(); - _outlineLayers.GetRenderObjects(_renderObjects); + _feature.OutlineLayers.GetRenderObjects(_renderObjects); foreach (var obj in _renderObjects) { From b815ce5c035707420a3f9310fbc31ee46a62976d Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sun, 17 May 2020 11:53:49 +0300 Subject: [PATCH 50/61] README update --- README.md | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 4fbc74e..ecc2a11 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,11 @@ Channel | UnityFx.Outline | Github | [![GitHub release](https://img.shields.io/github/release/Arvtesh/UnityFx.Outline.svg?logo=github)](https://github.com/Arvtesh/UnityFx.Outline/releases) Npm (core + built-in RP) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.svg)](https://www.npmjs.com/package/com.unityfx.outline) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline) Npm (Post-processing v2) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.postprocessing.svg)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline.postprocessing) +Npm (URP) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.urp.svg)](https://www.npmjs.com/package/com.unityfx.outline.urp) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline.urp) -**Requires Unity 2017 or higher.**
-**Compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2).** +**Requires Unity 2018.4 or higher.**
+**Compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2).**
+**Compatible with [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html).** **Please ask any questions and leave feedback at the [Unity forums](https://forum.unity.com/threads/screen-space-outline-effect-for-unity-free.836908/).** @@ -17,7 +19,7 @@ Npm (Post-processing v2) | [![Npm release](https://img.shields.io/npm/v/com.unit *UnityFx.Outline* implements configurable per-object and per-camera outlines. Both solid and blurred outline modes are supported (Gauss blur). The outlines can be easily customized either through scripts or with Unity editor (both in edit-time or runtime). -Implementation is based on Unity [command buffers](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html), compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2), extendable and has no external dependencies. +Implementation is based on Unity [command buffers](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html), compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2) and [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html), extendable and has no external dependencies. Supported outline parameters are: - Color; @@ -37,7 +39,7 @@ Please see [CHANGELOG](CHANGELOG.md) for information on recent changes. ## Getting Started ### Prerequisites You may need the following software installed in order to build/use the library: -- [Unity3d 2017+](https://store.unity.com/). +- [Unity3d 2018.4+](https://store.unity.com/). ### Getting the code You can get the code by cloning the github repository using your preffered git client UI or you can do it from command line as follows: @@ -48,6 +50,7 @@ git clone https://github.com/Arvtesh/UnityFx.Outline.git ### Npm packages [![NPM](https://nodei.co/npm/com.unityfx.outline.png)](https://www.npmjs.com/package/com.unityfx.outline)
[![NPM](https://nodei.co/npm/com.unityfx.outline.postprocessing.png)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing)
+[![NPM](https://nodei.co/npm/com.unityfx.outline.urp.png)](https://www.npmjs.com/package/com.unityfx.outline.urp)
Npm core package is available at [npmjs.com](https://www.npmjs.com/package/com.unityfx.outline). There are dedicated packages for [Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2), [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.0/manual/index.html) and [High Definition Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@8.0/manual/index.html). To use the packages, add the following line to dependencies section of your `manifest.json`. Unity should download and link the package automatically: ```json @@ -62,8 +65,8 @@ Npm core package is available at [npmjs.com](https://www.npmjs.com/package/com.u } ], "dependencies": { - "com.unityfx.outline": "0.7.2", - "com.unityfx.outline.postprocessing": "0.1.0" + "com.unityfx.outline": "0.8.0", + "com.unityfx.outline.urp": "0.1.0", } } ``` @@ -77,7 +80,7 @@ using UnityFx.Outline; ### Per-camera outlines (built-in RP) ![Outline demo](Docs/OutlineEffectInspector.png "OutlineEffect Inspector") -Add `OutlineEffect` script to a camera that should render outlines. Then add and configure as many layers as you need: +Add `OutlineEffect` script to a camera that should render outlines. Then add and configure as many layers as you need. An outline layer is a group of game objects that share the same outline settings: ```csharp var outlineEffect = Camera.main.GetComponent(); var layer = new OutlineLayer("MyOutlines"); @@ -164,9 +167,9 @@ settings.OutlineWidth = 12; // Get outline assets instance. In real app this usually comes from MonoBehaviour's serialized fields. var resources = GetMyResources(); -using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget)) +using (var renderer = new OutlineRenderer(commandBuffer, resources)) { - renderer.Render(renderers, resources, settings, myCamera.actualRenderingPath); + renderer.Render(renderers, settings, myCamera.actualRenderingPath); } myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer); @@ -187,16 +190,27 @@ using UnityFx.Outline; public sealed class Outline : PostProcessEffectSettings { public OutlineResources OutlineResources; - public OutlineLayers OutlineLayers; + public OutlineLayerCollection OutlineLayers; } +[Preserve] public sealed class OutlineEffectRenderer : PostProcessEffectRenderer { + private List _objects = new List(); + public override void Render(PostProcessRenderContext context) { - using (var renderer = new OutlineRenderer(context.command, context.source, context.destination)) + RuntimeUtilities.CopyTexture(context.command, context.source, context.destination); + + using (var renderer = new OutlineRenderer(context.command, settings.OutlineResources, context.destination, context.camera.actualRenderingPath, new Vector2Int(context.width, context.height))) { - settings.OutlineLayers.Render(renderer, settings.OutlineResources); + _objects.Clear(); + settings.OutlineLayers.GetRenderObjects(_objects); + + foreach (var obj in _objects) + { + renderer.Render(obj); + } } } } @@ -208,7 +222,7 @@ More info on writing custom post processing effects can be found [here](https:// ### Integration with Universal Render Pipeline (URP). [![NPM](https://nodei.co/npm/com.unityfx.outline.urp.png)](https://www.npmjs.com/package/com.unityfx.outline.urp) -TODO +Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources and layer collection are set). Enable depth texture rendering is enabled in `UniversalRenderPipelineAsset`. And that's it, just add game objects ot the layer collection to make the outlined! ### Integration with High Definition Render Pipeline (HDRP). [![NPM](https://nodei.co/npm/com.unityfx.outline.hdrp.png)](https://www.npmjs.com/package/com.unityfx.outline.hdrp) From e66f6b7d37b85111a56debc384030e4e98b44fef Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sun, 17 May 2020 12:12:01 +0300 Subject: [PATCH 51/61] CHANGELOG update --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1498997..5331f74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,32 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.8.0] - unreleased + +[URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html) support, core refactoring and bugfixes. + +### Added +- Added [URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html) support ([#5](https://github.com/Arvtesh/UnityFx.Outline/issues/5)). +- Use procedural geometry ([DrawProcedural](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawProcedural.html)) on SM3.5+. +- Added support for both forward and deferred renderers (built-in RP). +- Added ignore layer mask settings to `OutlineLayerCollection` (previously the ignore layers were specified when adding game objects to layers). +- Added `OutlineBuilder` helper script for managinf `OutlineLayerCollection` content from editor. + +### Changed +- Changed `OutlineSettings` to display enum mask instead of checkboxes. +- Changed inspector look and feel for `OutlineLayerCollection` assets. +- Merged shaders for the 2 outline passes into one multi-pass shader. +- `OutlineLayerCollection` doe not depend on `OutlineRenderer` now. + +### Fixed +- Fixed outline rendering on mobiles ([#7](https://github.com/Arvtesh/UnityFx.Outline/issues/7)). +- Fixed outline shader error on low-end devices. +- Fixed post-ptocessing implementation to require depth texture. + +### Removed +- Dropped .NET 3.5 support, minimal Unity version is set to 2018.4. +- Removed `IOutlineSettingsEx` interface. + ## [0.7.2] - 2020.04.08 Depth testing support and performance optimizations. From ea44fa8fbce2e84fb99c95376c4abbb78d988b59 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Mon, 18 May 2020 12:16:24 +0300 Subject: [PATCH 52/61] README update --- Docs/OutlineBehaviourInspector.png | Bin 20783 -> 23423 bytes Docs/OutlineLayerCollectionInspector.png | Bin 27150 -> 26773 bytes Docs/PpOutlineSettings.PNG | Bin 0 -> 15803 bytes Docs/UrpOutlineSettings.png | Bin 0 -> 14110 bytes README.md | 49 +++++------------------ 5 files changed, 10 insertions(+), 39 deletions(-) create mode 100644 Docs/PpOutlineSettings.PNG create mode 100644 Docs/UrpOutlineSettings.png diff --git a/Docs/OutlineBehaviourInspector.png b/Docs/OutlineBehaviourInspector.png index 8ec031ff5df178643053caa4be72a17b464262f0..2a2a2b616e237c5a06f4194fe527c7ffeb472e19 100644 GIT binary patch literal 23423 zcmZ6zWmFqo*e;B_JH?$skOIYB3N2QlxO;JTcc*yKw9q0&8a%kW7l+{PT3o)#^S<9% zXPqBetVw2)nLT^OEis#Y#q11_7Zm5&OXe71+jfQqplnK)~yUzYxBR9<^ZR z(0tCke!k2bRl6b}qDMgrM!0vcqwka3 zO3T#_IvpfAIaxk|Ko(;n?|NC!^q$5$qFnnf`rqO7_|Z9`Lqka=-=ou zZ*aHDAd)bv*hmUh_yyjy61?E!MduEV3qG60a~% za-5UHmmuMU9Epk?)y^7voOYnIsg{jJKvU@PP0CA3oXI#atC!UMJ3AHhGreq}5GyB`!rQoAUbs#?;k8GcVr8W5acy;i?lzHYV3FbZfOPWNM&odw7J{>>q_ z_cI07()W5}Z=xV_sBQmu>0#5#V}*g&TDYM7LQVI==){C=++v=qowYS2liy0$!oq@4 z3nMA!@A*4m=9EqgO_?>!A9tb8&5q@mYvqWIT+uZZ9aZi~)}0^{+yA?3)aHtI>BMB~ zF5F0zTHaG;rH80X-kO^Z9P$L-#wyd!^ial+s~KnTIF`I(W?H%%ZKoS-3Lw-?23x&* z!Dk+2;M9TYaNkGkJDd*ES>Kkx;0dQJyc-L+;@4|%`NiqQrk)#*qYZ>z_*(m$LU8pHAk6OU#f|t?QDd>x!Km7wbme z{f#<&emZ&XExbQzTRCE)!C%)mm(HKOj}Os>daUo&ucyU z_@w7Go!hv~)qd%pM)!e)+(T+~+!vdMKauf-+a>RInSk*u)!Q-2K0WdB=u4zK8FlOk zLFHD*NXq$aYkRnxGFnwn)@)+ddu+wi*3xOSPh~#^2@o{TFudB1EDgQ>Juve}$Bg)j z);v){YHWX&NBN;qA{E^^+LQK?;Meo+INbW>?+-QLw@8Q zwca1QGA7=4gi@FqFg;vqU~>qJg28xL4hz{0COmBqE{sAKk1S$zH+$-VHqU2t&n9j6 zOD8#22xr0gk~i&-_IpkdP9F#Ioxzbw9%I4;Eb?K!f#TTcv|itb4%oe@yo{BVH>5`1 zKuxB9e|FfH*+n?%t#5m@_vC8vz4q{KuT{?xo_NG<*j{vK;;OV1+eYw0IyQIg0$)o-GG8frt;?oysHm&RUl`Ie5!VDxYQS4aweqXE2 zM(U;mUti{}?~4#UJw02YCASn;Z2HCzH~thxDN&1pR}}1{XNH8Y%ZU%v9&2HM0-_U|Jhb>KK3GGPHwFAOSYhWjcV{K z&1!e$GNIQrUSM8ozc#YLTJtR=2bY$278ZZ*VCPffjcqkkro+uc1C3y?OL8|4blwU571?vU9?MfVGuY{+ zC4h7g&PROB+V_sNGczcgbvkrZ4ll}@A`czb=q2d&hF*W|H1Lncy_)ACFEoxmB_`X^ z@`uD*j3ipLRP8#qxAfn$4KiD=s;6f(>gQSGsZ2)P7m>P5KGRnPvn;+ph>L0uQ^i!Z zll+k2BZpINGXF<8f@jv+!{?y9e!;8#8(ZSGfPQytj`@D}W-=B?tZ)hUTOnuA-9N11 zn@8V;K&i%sj-R18`Svy>wDhb!9vL9UuLTuP)Qvc|Y<Fk?UYJ09yq#K5l~GwfPa-&2NXNC*?q1L@t%!f}Qy6H9k?<0`g1M^C&ctMs zTZ6A}T-R96O&4`;d?zEY*KAd;U^f?QTg0+Ii}=`2GSDpoN9xKe;_fy#wmO=wemt(| zJsF<_p5p6Kr6QMV1(;IJmV1(JxQ(Z7OpgDMTcn5w-Mg1a-)oj>uVr-j%6Ln8O&XF59hh|dvVL?tN$|BA;ND6_b zwB7TaiA3S!RLLg;*_^!^q=4)MZZr1_p`SrTDY$77J+b8Vbu@3z+N|Coi<-(bf$LZQ z9`P*Qo_cOLN-LnuR+3A!(K>zk+bbQ(L7NU~SG?|Xc7Anny)LAIV4b)cAk*09?G`xD z{zCrL`&H-qn{dR50;Wk?-@`T7e4^Bo*TLDX@0s12=v8ixq4ySPJ@{8leN3HqUFq-CZ$qFU!YRA;;wgsOBf#_DY zpx$U{M_P#&VhbU(3q1?E8*;JW&boG;LqTKLjEx6@@NRUWij&Kk#GV!&q%wNYo|=z~ z1n(fvs_65}RGdnLPu5OEtTk*=SsFHipC5M0NtqesUEU$R{QZZgeqrCBTyQ)*rYcXy z+sML#bUJuK!{l?z9m>U4-CYVx-OAUyb_B21TrEyg4WC!AV)IC`L`y8w19$YL&eaR! zsU)u*|E(rvlHW`f^-%kPuGewdJUImVFxv^gx}*MA3TvU#kN^Gzx@*?bVGDrQs716u z2GOMinG@9PAH6?^{MgH=et|#V z-(barR<>M1E$R0yEL3D#^!WHxpVTw7A*)OECDJ4*m`rTp-wVaaZSb`rCdyhE3}O93 zjVi`XA$AJ7@D1|wcgErUq-zskfQYET$Vm-?Q8Y2g#t^M3I-aCpt_LQnb7zCRkUgCq?q=btZJI*VcPu_=3-^_%nLvkgLl2Ee)Sn zRJlR@Onl^v@QKXc1eyc1+SPk8nDWF~QcCb@SlgZ@0$v;S=n3c$?4L~WDUuA|QH~b0<@8Gdtq`57O4X3Nhvpn)oG@@y795HL$ z%b~p86{fp-aa5dN+EKgPj2S8hB(94ApKrH^Knmn zZc(gaD8iyNV($qgW*+}WP`A+L59xeR`pm4*e8fon%((g0+MuXjZRLc`f%YVAo;_W2 zdl#R5)846l(sHK?x?K4PSZYOQ09qi?JT6b!5wg7$-MWfF6n#xNs|EEJS#nIFA;z#C zV;4SYy>}=D*1PzF>om(kP~U42XVCHvz%d)`^Y7JBCz2>G7VrzXyAvWjVX>t`huUh_ z$5vbrobSU!kz4Pm$Z97czVTVSi|;r3tY~Qc!0ZwM?>B`h+QBQ8x%I~3yBq`|zk-V$ z<`%5!%FAm11&?zZeYWD9tw%}URr7nWST2Rs_FenbAexMvRVWxa@vLg7l+4{>D1JSz zA4qt6ihdPJs!T;v-9_WQxNeV{BA>sH zf|Qrl#=iR9&ZH=?PH6n6o_I^TR9v_3rY|aPi|(>9lX&P0y@H$w`Bm8}zSc8|d{BPR z#yatNm9M8fGz|qR^C(UHE4rENEf;2;JwzR;)a`8jXq`E1?)JO>_vpS1Y=e0C+Uks? zychsO->#7sd@U$~t%Xr}@v#PpQ(kKwH9Y`976b8eC#fAPi3P)swd)5aLk#w%Iualg z$&wKK{)-LhR3g%3W$aia{s5ed(?{+7+8&c1)Pb|R`SS!6PCz?|Dk`$|TmQdz$)lYs zyEb+O1q2(^U50USciRRqx0Q7xGTC`J-NEPPVpBx~j8Z0XwrFweFM=PRuG<`EjRO6f zycw!Gu*;rRtlGb>37QUTb8>RlZ->?01+#vyY#o)E71WY&> zy5YSkW~6^gQJ2i@-_vz#6CHEzquDVf;V06S?64ATAepO5Vp4qKU3?)*C^#yzLoN1n zvtj>mbLN0ir?HV7AtT>~{4NarTYrx$Jh&1s4icv+XArre~(!uk?nneC>&5%iGPPV;m+xpcmILx zG#%-J1P6%Ztmw>1-OF23FlBo3W&~rLV{)hgaz~lO-EP6Lp|4xpIdbp8wj_Zn7g$_Y zoKu`Q)2~oY-_`B-XNsDOTpr({qgUL6aMiKGuuLLA&3ys+;Si9IYT6#Qcq;0M;)_$% zjY*$3*`z9kmc6>vq#iHjE7)1Hva-tey!ej!$f6amIRlFU zQHlmvF_AX6|0QT#WIb=ibH!gx>RXjc07q4wu{t0N`fg`h!B&^1(4w+r#NVP(vw88$ zmus{QlR(&8wqDd3ceR=2U5Fo)RqNZQE`-wQQx9zp^N-bhQkR(48Sl=;Q6$9NxE^aQ zes%tSER&zDQt)3ZWNJ*}T3>9xxIljjpKdCsm;(-(3`Qad-r(3JC=(?cG=T%3Zg-AS zKdDt#k4Y|$Z2bOSxRa=EpWS9*B;5!X!|AWcRs+@0vKr;Y z>cEAfKjk7U{ds6Kf*~78ZewTaLbNNq6dw?tA0n(pQY{Of5jv z@1A2)WkI*0c+s(KNoPoWn3fhpeycFsp$aasEv>qpp1#NQdVahn7UBB2K#t@CjP8GY z{0T~nl4RSum97U{3E5Ivvj8;5x+SMBTn9=aF^5P%6d0k24M7%lHDnYav5^Q3F+JRs zDCa1ix-9-(gZOy2a863Mc=w(D2d}lm9?~=x!?g8B3^@fh?l3))6~jJ(lsYk+2iT`F z9*)#JrUc>6&z2|94LmJ|f=-I?cPL|@FDHKjgC@P*aQAo;xS|_{fC@TpS$RD6JYJYr zEIb6XnXB_5o<%@ZRIVR(f3LLSf4y`y+x9fA&>b?GqeX({%40+OKSMS|n@X+J#WYpr;`&tlI%3hlntWSyo*ZAO0%LdBJ9?8I;x04NT35#n z(YGxxtecs>bf%d^Tbv?^vW-Zfxtg9PfKhwyR9Ot=d|sy%arxOaYjnRbn{$mph#AV_ z0uXZHj*e;))@euY8H|p;>Y+*rc`Bca5uv3Ov_z6umi*yYf*d`x3zYLh_nm{j4`+P_ z0q|+T!1a=fPv)94Pk)8ySRD%EW`tuthO9^R~8*<9{@b}jahaz*V@1Rm%Mj!kJoxm68c$~?vOk$7dEhhDuj6| zX`Xta%R6n=TpuEdZ>h)EZbG8aL+xQ)oxozBkuzx1?v zLGewAo7GTmG}oIHW~G0Nk+eSj-mb-0`Y_~uIW-8n=Ggk*ouA#Gmt2$kibh&H}-+O zX?D{tmuxH8Vfjd)UHlIh_e$qIq5k;Hw-dj(` zT&vvKLXL*OIoN+_#ump$d5IrN`gOD^883_8Y5GjuOE3PMZ=n-9^xmOogQ4pn`ZXH1#%jSUFr6&fqJ-&k~y>!+{M+o z60|@Qzt$>b_S-hmkl4v@w9gZD=cZX8SA?fB*P5-UD(0On2Um4(;hWO((t7s;p*c2i zMa}0@E!45@7gmI?r|r9#zm)e}lqIV(s4B#SWD9aG6o^Cb8~(sJ>x$lA)4VOVo9G>V z%>R0wt4}{K9+u%vcB(;7ecAtWJ)9h~bJ3Yr+eVzY^{eVXy}Xy_B{(0yT!HCM<0eWH zY`5nN*|@pol-$cFY!OC7@w^`*HpZvA?q@SEVme!X4WNHG-3{29eU!Zsks9pq`@sa> zbK=sVX0Og<^(E`FW@h_9B9ETMUS3?q70*&JGCj+adjVok4SCjI)0oz<+UjUtPJBQg z8zpZ&MZE`np}Fl(G)Z))%O*)>3|Tm`+9j_R!;I!tl33V^{D6&DjPk~*F?OeeciuDDGc2=G;LO`1&jRj*9|*) z2l=|Zt0KYk3VKk-?&8gWSL*p+y44G!3BghC!^W`~<+angmF~3~G?VEn&3V1G&6a^zZ<5hy|N#-17DXJIG{;K0_zNaE7LJ_Io0R{nyK z&)zTYiKMV*Uhq9^=Wuc5sSfvrK=DW;Tb@@ZtI9Xym4|I1`>Em&(J(S?&kj^_XoA{= z`WM>32WPS8hl?Y?VDcEM`NRl<+oaX2e2)Q1qjGQkkSi&5;0cs$CCP$)krdCD1BavM>U;q#1 z`#pvjG(e^<`1HG5a81n|@arjE96GR)@K0Mf*P|`oSv6^l<0&gjh*s>0X#069ZJM93g8inM3e~kyGKKb10KJFvog-xHUC3^_-J%R-7Bm7hV;9 z%dUf6R*z*t6XO>d%nC6q!1VIQNTwUbb|lWAU=wZ5ITVt2h#AuQ_>m(nEQkm%^$W~r zFkN`?O#=08m)i7&obo4Qn^kM&>>Y!OTQBde)FvZ>GH{Np*p8@>QHEzDq-=9li zqU)srPZwZM#BR(N5c2^dawF0knhDb=kSk!$G)maCAad4Cd{mGqS*7RD(DQHDR0Icg{&2qf zD1yqtX^1VyDTKKEzjZF@N6=uZo@2}O(ay5(NiE>fOD5UY8Fz%tIJuH|T{%paJb z%G&@bI7uA)_w#LvZXo{JE!3W18UWQl{`sHXzI*p>Df`rp0n#pTxOX01#gdSN0b&d8 ziTU>yS7H#>;A(Jf*(hjM>*KNF@9DdhrUg4O^x0#v>WTQFNkji$K1AX?T1BY-cNK%@QSM8pr@HRV!by z%l#J{DM>t*RD zd1m2!eYbV$C@Pu=Imb-;<8p7Hj~Ce& z%rL)mH)gnzm8p9%o>ts!0hacRH=`2D?)5DI1!`;^+cuMxVJ==$G`W3da*L8+q7Rjq z|1%`kuD^65uajR6P1q;vKy*A^&cQojVub#HmsY`>?~1R<@%loh%C!q8@O!66aT#I_Z}#YHd7~q zSqa|43KXfG!ydPV+TLz%OJOk4;Yk6aP&D<2-PPW;JfGkZ#n!WUM`+><*n2xu(EeFA z>Nrx8xHVCp!mR?HBuS2DpkcK_@}2&y)j*t|uAcZ7)*FrxST@AnGz^5E5U(i{=0v28 zZ)ZraC69CbNOc(G*MbaYcrf<<~fIv2LGxnG2RE3_6~zMtvLCWA2j=n zWQ<1brdt;6$rit@41vOj!I9<;(kj%hF#((q>r)z{%VunbMl5+UllU0U|AmY6!K4Z@ zjgG&=33{*#Ft(B4OFqSyaKwhaDEcr0>4x?ox&Py&n6?u)PWkFCm@nn%p*`OwIBF5f z9yXs^AciV!zB6{^(=ZhbL#~h9!48%cTQNmhW5%W69cQI>iJ}R(Ar!Q~`yi9$5J~6# zlg4Wtg;UvYXuE!--c8AAIgXXAzJiko*|2+rTy}8lmamh#z^Z6h-+$XR_1 z(B8|LE9eQWl?zi7ow{Kam|SH&k#?RDNwlBKRaWqtY5{r6KE3SCE~5Z4AJO++MJLsanhHk^Ncnq#h>QWTa3_ZVvW@uspp2+xURY6I37?8_F!Lc zFRQJcjSKilKwwJGz(16DdM|i4FJNW|^nSK`W|3hyCy^XRL!XDjcxvW`Od~*{l`V~e z^Y)z+Qi#Ro?~ONg#+ZEX7J$f*ecR)aXaVutUd4j9mbb4^ZK{@CaP=T-E3d}9`IMw; z-E8nlJc2A-fO081M1q}_k%4%>A^i{?5|XCcG1w5%=dW7#XSX4_bLh#3Pr~S21Z~0( zQWy=!_Cg*7ggUJ*I#IV`>{IS4Hk%GST0Z6*y~O(8v=Si;wk6X-0&{g)qNVe7)B6YC z9I9^}n~&@M8P7`qwd{D=i&N0<=#>C_2hC~RA>h~7nfAoYuv2O4+KpZGY0ruWE_a%{ zz04P)@xPo(IX3>iqK&%3hAn8A|hAtx&ce0Qti^Z}l& zs80755ub`8%!k)rz_NaI?ZO;7h#)gVC~SCXP0?U}ACqV6CX!&jGbG-bfU1hH0-++h z?vl8Mnbj}*lr{x3DjIhP)@wtwtAJ841Jib7>4@oNm3?2^Z5!X|-}PBZfqgJ3cx$K; zu8eUH63K9P8Y4P8Rtl83dCw(a?E~axO_u8899t-o)c)NTWx|`Jd{bfL_Mq;ME&*q; zMm1`WejGq7t{4YiUymie6Rn!9`XnC#BQmiioSggT&!wr%Se``Fh?o*;wC6LxWc+P| z_tzZNtCQKe$N8T@US_ddZlW2Uxj7$YMpDVq$aQXh!EFDuz_5LRYTeMjUBaE^{{Rm< zy?%csGlHT#J(=YHi)s4SwDNED>pP^4$)fo9EZ^T*N&N|h?Nwje6>^-2Gt$#_Rs#HU zwf`N=uJ~wZvDMk(Uz1+HcQZaQ@LZZko$Isd@#Qz|j_S@LgZMZfaqHC$>on1Jvbc=3 zUDf^(Nqql%t|P8sm_H3u+tEN(OCOn*N#9QUrl#+2#lXe!UVrP~q3C(=3 zXSEv1O4BCBuV7p-#8mVIYQIS7#N>p(h3uu@o<`3%s51|4)@;u5t%cTC1{5ti4*91+{Vs*>M~BUp^*L( z$fPma2K%ptlk4M>d{7YfV%K5)Rud^mRwn2p{WpRnA~LO$p30gjQ{21C_vZd`Z{uNo z;09Q)4o6XygD!r2{mFXtwibB0J+5HROzST;7C9G;yH@L-RzvaiJ5p3f41N|iM0Y$B z&h~y~SxiC?Kh=$~_hB)HK$FTkn(OvoGBE)kEV|`xfUg{tH`QBI%%vw-n zi5UjmTFjd4z=M>;%%X(hk&!<;hkWulMSa781a5+_BYMwNs@Oue*>DayR&HNZ--)<6GBi|I??Yt2WQ) z<)s2Yq_M&OTO*qgfwp0QTH@&7fo=zJaWTK`z7@$#UmX&%W;w5L0gZJvv>DDBar?O% z8H;^2l3XSZNX4uZ{ZBU!7lWAc?nm1%vG#lPVKv*??MSBWwX2jwx#$OJg^UZ3J&T;d zeKa45jmj=0axrv32Wv#&fk2;KCYm%cK4`!9F6@J%Xhwl#j0?ci7z`*!C;v%h`9b}S z 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 literal 20783 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 diff --git a/Docs/OutlineLayerCollectionInspector.png b/Docs/OutlineLayerCollectionInspector.png index 3dead01632ce3d057364cc0dda3cd9f87b12db20..ce77d67541fcabf2fa6295c83fc723c28b93d6b0 100644 GIT binary patch literal 26773 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 literal 27150 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 Yt>7aXm-$ur4W~mF&gp9vYFLK;7YUb{WB>pF diff --git a/Docs/PpOutlineSettings.PNG b/Docs/PpOutlineSettings.PNG new file mode 100644 index 0000000000000000000000000000000000000000..3b3d686e8d9d5b0ad996470a48484b4efb1b1e68 GIT binary patch literal 15803 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 B{>T6T literal 0 HcmV?d00001 diff --git a/Docs/UrpOutlineSettings.png b/Docs/UrpOutlineSettings.png new file mode 100644 index 0000000000000000000000000000000000000000..88d669de0d7c6543d38e9d914a8856317de12f8e GIT binary patch literal 14110 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 YrkeB4$a*rcr|pHjjEZ!bq_N-s0>>4a5C8xG literal 0 HcmV?d00001 diff --git a/README.md b/README.md index ecc2a11..3caa8a5 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ git clone https://github.com/Arvtesh/UnityFx.Outline.git [![NPM](https://nodei.co/npm/com.unityfx.outline.postprocessing.png)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing)
[![NPM](https://nodei.co/npm/com.unityfx.outline.urp.png)](https://www.npmjs.com/package/com.unityfx.outline.urp)
-Npm core package is available at [npmjs.com](https://www.npmjs.com/package/com.unityfx.outline). There are dedicated packages for [Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2), [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.0/manual/index.html) and [High Definition Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@8.0/manual/index.html). To use the packages, add the following line to dependencies section of your `manifest.json`. Unity should download and link the package automatically: +Npm core package is available at [npmjs.com](https://www.npmjs.com/package/com.unityfx.outline). There are dedicated packages for [Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2) and [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.0/manual/index.html). To use the packages, add the following line to dependencies section of your `manifest.json`. Unity should download and link the package automatically: ```json { "scopedRegistries": [ @@ -178,51 +178,22 @@ myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer); ### Integration with Unity post-processing. [![NPM](https://nodei.co/npm/com.unityfx.outline.postprocessing.png)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing) -The outline effect can easily be added to [Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2). A minimal integration example is shown below: -```csharp -using System; -using UnityEngine; -using UnityEngine.Rendering.PostProcessing; -using UnityFx.Outline; - -[Serializable] -[PostProcess(typeof(OutlineEffectRenderer), PostProcessEvent.BeforeStack, "MyOutline", false)] -public sealed class Outline : PostProcessEffectSettings -{ - public OutlineResources OutlineResources; - public OutlineLayerCollection OutlineLayers; -} +Install the package, add `Outline` effect to `PostProcessProfile`'s overrides list. Configure the effect parameters, make sure outline resources and layer collection are set: -[Preserve] -public sealed class OutlineEffectRenderer : PostProcessEffectRenderer -{ - private List _objects = new List(); +![Post processing outlinesettings](Docs/PpOutlineSettings.png "Post processing outlinesettings") - public override void Render(PostProcessRenderContext context) - { - RuntimeUtilities.CopyTexture(context.command, context.source, context.destination); +Assign the configured `PostProcessProfile` to `PostProcessVolume` and that's it! - using (var renderer = new OutlineRenderer(context.command, settings.OutlineResources, context.destination, context.camera.actualRenderingPath, new Vector2Int(context.width, context.height))) - { - _objects.Clear(); - settings.OutlineLayers.GetRenderObjects(_objects); - - foreach (var obj in _objects) - { - renderer.Render(obj); - } - } - } -} -``` -For the sake of simplicity the sample does not include any kind of error checking and no editor integration provided. In real world app the `Outline` class should expose its data to Unity editor either via custom inspector or using parameter overrides. Also, there are quite a few optimizations missing (for example, resusing `RuntimeUtilities.fullscreenTriangle` value as `OutlineResources.FullscreenTriangleMesh`). - -More info on writing custom post processing effects can be found [here](https://docs.unity3d.com/Packages/com.unity.postprocessing@2.2/manual/Writing-Custom-Effects.html). +More info on writing custom post processing effects can be found [here](https://docs.unity3d.com/Packages/com.unity.postprocessing@2.3/manual/Writing-Custom-Effects.html). ### Integration with Universal Render Pipeline (URP). [![NPM](https://nodei.co/npm/com.unityfx.outline.urp.png)](https://www.npmjs.com/package/com.unityfx.outline.urp) -Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources and layer collection are set). Enable depth texture rendering is enabled in `UniversalRenderPipelineAsset`. And that's it, just add game objects ot the layer collection to make the outlined! +Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources and layer collection are set): + +![URP outline settings](Docs/UrpOutlineSettings.png "URP outline settings") + +Enable depth texture rendering in `UniversalRenderPipelineAsset` and that's it! ### Integration with High Definition Render Pipeline (HDRP). [![NPM](https://nodei.co/npm/com.unityfx.outline.hdrp.png)](https://www.npmjs.com/package/com.unityfx.outline.hdrp) From c3dfdade0067d83b91eb1a921e2622a83288b82b Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Mon, 18 May 2020 12:19:11 +0300 Subject: [PATCH 53/61] tt --- ...{PpOutlineSettings.PNG => PpOutlineSettings.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename Docs/{PpOutlineSettings.PNG => PpOutlineSettings.png} (100%) diff --git a/Docs/PpOutlineSettings.PNG b/Docs/PpOutlineSettings.png similarity index 100% rename from Docs/PpOutlineSettings.PNG rename to Docs/PpOutlineSettings.png From e192d775fed603dd249b41af62b588f24d6aaa03 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Mon, 18 May 2020 12:29:25 +0300 Subject: [PATCH 54/61] Minor OutlineLyaerCollection inspector fixes --- .../Scripts/OutlineLayerCollectionEditor.cs | 33 ++++++++++--------- .../Runtime/Scripts/OutlineLayerCollection.cs | 18 ++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs index 073ea39..faa90bf 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -49,26 +49,29 @@ public override void OnInspectorGUI() _layersList.DoLayoutList(); - EditorGUILayout.Space(); - EditorGUILayout.HelpBox("Read-only lists below represent game objects assigned to specific outline layers. Only non-empty layers are displayed.", MessageType.Info); - - foreach (var layer in _layers) + if (_layers.NumberOfObjects > 0) { - if (layer.Count > 0) + EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Read-only lists below represent game objects assigned to specific outline layers. Only non-empty layers are displayed.", MessageType.Info); + + foreach (var layer in _layers) { - EditorGUILayout.LabelField(layer.Name, EditorStyles.boldLabel); - EditorGUI.BeginDisabledGroup(true); - EditorGUI.indentLevel += 1; + if (layer.Count > 0) + { + EditorGUILayout.LabelField(layer.Name, EditorStyles.boldLabel); + EditorGUI.BeginDisabledGroup(true); + EditorGUI.indentLevel += 1; - var index = 0; + var index = 0; - foreach (var go in layer) - { - EditorGUILayout.ObjectField($"#{index++}", go, typeof(GameObject), true); - } + foreach (var go in layer) + { + EditorGUILayout.ObjectField($"#{index++}", go, typeof(GameObject), true); + } - EditorGUI.indentLevel -= 1; - EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUI.EndDisabledGroup(); + } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 1ff20f3..f14a7c4 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -51,6 +51,24 @@ public int IgnoreLayerMask } } + ///

+ /// Gets number of game objects in the layers. + /// + public int NumberOfObjects + { + get + { + var result = 0; + + foreach (var layer in _layers) + { + result += layer.Count; + } + + return result; + } + } + /// /// Gets the objects for rendering. /// From d9849c6744223cb257fecb2965942d822bb7e263 Mon Sep 17 00:00:00 2001 From: abogarsukov Date: Mon, 18 May 2020 14:38:38 +0300 Subject: [PATCH 55/61] Removed obsolete components --- .../SimplePerCamera/OutlineEffectBuilder.cs | 88 ------------------- .../OutlineEffectBuilder.cs.meta | 13 --- 2 files changed, 101 deletions(-) delete mode 100644 Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs delete mode 100644 Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs.meta diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs b/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs deleted file mode 100644 index 444b39c..0000000 --- a/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using UnityEngine; - -namespace UnityFx.Outline.Examples -{ - /// - /// Helperr class for managing outlines from editor. - /// - [RequireComponent(typeof(OutlineEffect))] - public class OutlineEffectBuilder : MonoBehaviour - { - #region data - -#pragma warning disable 0649 - - [SerializeField] - private GameObject[] _outlineGos; - -#pragma warning restore 0649 - - private OutlineEffect _outlineEffect; - private OutlineLayer _outlineLayer; - - #endregion - - #region MonoBehaviour - - private void Awake() - { - if (_outlineEffect == null) - { - _outlineEffect = GetComponent(); - } - - if (_outlineLayer == null) - { - if (_outlineEffect.OutlineLayers.Count > 0) - { - _outlineLayer = _outlineEffect.OutlineLayers[0]; - } - else - { - _outlineLayer = new OutlineLayer(); - _outlineEffect.OutlineLayers.Add(_outlineLayer); - } - } - - foreach (var go in _outlineGos) - { - if (go) - { - _outlineLayer.Add(go); - } - } - } - - private void OnValidate() - { - if (_outlineEffect == null) - { - _outlineEffect = GetComponent(); - } - - if (_outlineEffect.OutlineLayers.Count > 0) - { - _outlineLayer = _outlineEffect.OutlineLayers[0]; - } - else - { - _outlineLayer = new OutlineLayer(); - _outlineEffect.OutlineLayers.Add(_outlineLayer); - } - - foreach (var go in _outlineGos) - { - if (go) - { - _outlineLayer.Add(go); - } - } - } - - #endregion - } -} diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs.meta b/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs.meta deleted file mode 100644 index 7150935..0000000 --- a/Outline.Core/Assets/Examples/SimplePerCamera/OutlineEffectBuilder.cs.meta +++ /dev/null @@ -1,13 +0,0 @@ -fileFormatVersion: 2 -guid: 5a318c96b1bc1614683eccf7abd717a1 -timeCreated: 1566138009 -licenseType: Free -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 317be4b897712beeab17d55167616d2673f473d6 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 12:55:48 +0300 Subject: [PATCH 56/61] Added pilot version of the OutlineBuilder (#8) --- .../Examples/SimplePerCamera/Outline.unity | 5 + .../Editor/Scripts/OutlineBuilderEditor.cs | 132 ++++++++++++------ .../Runtime/Scripts/OutlineBuilder.cs | 27 +++- .../Runtime/Scripts/OutlineLayer.cs | 8 ++ .../Runtime/Scripts/OutlineLayerCollection.cs | 28 ++++ .../OutlineLayerCollection.asset | 16 +++ .../PostProcessing/PostProcessingSample.unity | 7 + Outline.URP/Assets/Example/TestScene.unity | 5 +- 8 files changed, 187 insertions(+), 41 deletions(-) diff --git a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity index 3edd003..5a17553 100644 --- a/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity +++ b/Outline.Core/Assets/Examples/SimplePerCamera/Outline.unity @@ -226,6 +226,11 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _outlineLayers: {fileID: 11400000, guid: 3a6c3b3c5f6e3ad4ab8e09fc219865bd, type: 2} + _content: + - Go: {fileID: 1579373802} + LayerIndex: 0 + - Go: {fileID: 748173439} + LayerIndex: 1 --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs index eb2bd65..45e5c2b 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; +using UnityEditor.SceneManagement; using UnityEngine; namespace UnityFx.Outline @@ -14,70 +15,112 @@ namespace UnityFx.Outline public class OutlineBuilderEditor : Editor { private OutlineBuilder _builder; - private List _lists = new List(); + private ReorderableList _content; + private List _lists; private void OnEnable() { _builder = (OutlineBuilder)target; - if (_builder.OutlineLayers) + if (EditorApplication.isPlaying) { - foreach (var layer in _builder.OutlineLayers) + if (_builder.OutlineLayers) { - var list0 = new ArrayList(layer.Count); + _lists = new List(_builder.OutlineLayers.Count); - foreach (var go in layer) + foreach (var layer in _builder.OutlineLayers) { - list0.Add(go); - } - - var editorList = new ReorderableList(list0, typeof(GameObject), false, true, true, true); + var list0 = new ArrayList(layer.Count); - editorList.onAddCallback += (list) => - { - list.list.Add(null); - }; + foreach (var go in layer) + { + list0.Add(go); + } - editorList.onRemoveCallback += (list) => - { - var go = list.list[list.index]; - list.list.RemoveAt(list.index); - layer.Remove(go as GameObject); - }; + var editorList = new ReorderableList(list0, typeof(GameObject), false, true, true, true); - editorList.drawElementCallback += (rect, index, isActive, isFocused) => - { - var prevGo = list0[index] as GameObject; - var go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), $"#{index}", prevGo, typeof(GameObject), true); + editorList.onAddCallback += (list) => + { + list.list.Add(null); + }; - if (prevGo != go) + editorList.onRemoveCallback += (list) => { - list0[index] = go; - layer.Remove(prevGo); - layer.Add(go); - } - }; + var go = list.list[list.index]; + list.list.RemoveAt(list.index); + layer.Remove(go as GameObject); + }; - editorList.drawHeaderCallback += (rect) => - { - EditorGUI.LabelField(rect, layer.Name); - }; + editorList.drawElementCallback += (rect, index, isActive, isFocused) => + { + var prevGo = list0[index] as GameObject; + var go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), $"#{index}", prevGo, typeof(GameObject), true); + + if (prevGo != go) + { + list0[index] = go; + layer.Remove(prevGo); + layer.Add(go); + } + }; + + editorList.drawHeaderCallback += (rect) => + { + EditorGUI.LabelField(rect, layer.Name); + }; - editorList.elementHeightCallback += (index) => - { - return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - }; + editorList.elementHeightCallback += (index) => + { + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + }; - _lists.Add(editorList); + _lists.Add(editorList); + } } } + else + { + _content = new ReorderableList(_builder.Content, typeof(OutlineBuilder.ContentItem), true, true, true, true); + + _content.drawElementCallback += (rect, index, isActive, isFocused) => + { + var item = _builder.Content[index]; + item.Go = (GameObject)EditorGUI.ObjectField(new Rect(rect.x + rect.width * 0.3f + 1, rect.y, rect.width * 0.7f, EditorGUIUtility.singleLineHeight), item.Go, typeof(GameObject), true); + item.LayerIndex = EditorGUI.IntField(new Rect(rect.x, rect.y, rect.width * 0.3f - 1, EditorGUIUtility.singleLineHeight), item.LayerIndex); + }; + + _content.drawHeaderCallback += (rect) => + { + EditorGUI.LabelField(rect, "Content"); + }; + + _content.elementHeightCallback += (index) => + { + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + }; + } } public override void OnInspectorGUI() { base.OnInspectorGUI(); - if (_lists.Count > 0) + EditorGUI.BeginChangeCheck(); + + if (_content != null) + { + EditorGUILayout.Space(); + _content.DoLayoutList(); + EditorGUILayout.Space(); + + if (GUILayout.Button("Clear")) + { + _builder.Content.Clear(); + } + + serializedObject.ApplyModifiedProperties(); + } + else if (_lists != null && _lists.Count > 0) { EditorGUILayout.Space(); @@ -103,6 +146,17 @@ public override void OnInspectorGUI() { // TODO } + + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(_builder, "Builder"); + + if (!EditorApplication.isPlayingOrWillChangePlaymode) + { + EditorUtility.SetDirty(_builder.gameObject); + EditorSceneManager.MarkSceneDirty(_builder.gameObject.scene); + } + } } } } diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs index 2d4efe7..da6fc3e 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs @@ -15,10 +15,19 @@ public sealed class OutlineBuilder : MonoBehaviour { #region data + [Serializable] + internal class ContentItem + { + public GameObject Go; + public int LayerIndex; + } + #pragma warning disable 0649 - [SerializeField, Tooltip("Collection of outline layers to manage.")] + [SerializeField, Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] private OutlineLayerCollection _outlineLayers; + [SerializeField, HideInInspector] + private List _content; #pragma warning restore 0649 @@ -26,6 +35,8 @@ public sealed class OutlineBuilder : MonoBehaviour #region interface + internal List Content { get => _content; set => _content = value; } + /// /// Gets or sets a collection of layers to manage. /// @@ -44,6 +55,20 @@ public void Clear() #region MonoBehaviour + private void OnEnable() + { + if (_outlineLayers && _content != null) + { + foreach (var item in _content) + { + if (item.LayerIndex >= 0 && item.LayerIndex < _outlineLayers.Count && item.Go) + { + _outlineLayers.GetOrAddLayer(item.LayerIndex).Add(item.Go); + } + } + } + } + #if UNITY_EDITOR private void Reset() diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 29e1458..d3d71da 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -104,6 +104,14 @@ public OutlineLayer() { } + /// + /// Initializes a new instance of the class. + /// + internal OutlineLayer(OutlineLayerCollection parentCollection) + { + _parentCollection = parentCollection; + } + /// /// Initializes a new instance of the class. /// diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index f14a7c4..2c18174 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -69,6 +69,34 @@ public int NumberOfObjects } } + /// + /// Gets a layer with the specified index. If layer at the does not exist, creates one. + /// + public OutlineLayer GetOrAddLayer(int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + while (index >= _layers.Count) + { + _layers.Add(new OutlineLayer(this)); + } + + return _layers[index]; + } + + /// + /// Adds a new layer. + /// + public OutlineLayer AddLayer() + { + var layer = new OutlineLayer(this); + _layers.Add(layer); + return layer; + } + /// /// Gets the objects for rendering. /// diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset index e347a15..42472cb 100644 --- a/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/OutlineLayerCollection.asset @@ -21,4 +21,20 @@ MonoBehaviour: _outlineMode: 0 _name: _enabled: 1 + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 0, a: 1} + _outlineWidth: 6 + _outlineIntensity: 2 + _outlineMode: 2 + _name: + _enabled: 1 + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 0, g: 0.23238373, b: 1, a: 1} + _outlineWidth: 10 + _outlineIntensity: 2 + _outlineMode: 1 + _name: + _enabled: 1 _layerMask: 0 diff --git a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity index d7dbb7e..bc614c5 100644 --- a/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity +++ b/Outline.PostProcessing/Assets/Examples/PostProcessing/PostProcessingSample.unity @@ -275,6 +275,13 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _outlineLayers: {fileID: 11400000, guid: 747aa7f9a78f24945a8d07c0ba1511c6, type: 2} + _content: + - Go: {fileID: 1579373802} + LayerIndex: 0 + - Go: {fileID: 748173439} + LayerIndex: 1 + - Go: {fileID: 1789341920} + LayerIndex: 2 --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 diff --git a/Outline.URP/Assets/Example/TestScene.unity b/Outline.URP/Assets/Example/TestScene.unity index 6800d1d..20e3d19 100644 --- a/Outline.URP/Assets/Example/TestScene.unity +++ b/Outline.URP/Assets/Example/TestScene.unity @@ -246,6 +246,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} + _content: + - Go: {fileID: 958073178} + LayerIndex: 0 --- !u!81 &925532358 AudioListener: m_ObjectHideFlags: 0 @@ -328,6 +331,7 @@ MonoBehaviour: m_RequiresDepthTextureOption: 2 m_RequiresOpaqueTextureOption: 2 m_CameraType: 0 + m_CameraOutput: 0 m_Cameras: [] m_RendererIndex: -1 m_VolumeLayerMask: @@ -339,7 +343,6 @@ MonoBehaviour: m_AntialiasingQuality: 2 m_StopNaN: 0 m_Dithering: 0 - m_ClearDepth: 1 m_RequiresDepthTexture: 0 m_RequiresColorTexture: 0 m_Version: 2 From 8b30a3de6983e99ab2b57841ef3cb8e93db9ea6e Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 13:12:18 +0300 Subject: [PATCH 57/61] Clear layer game objects on app start/stop --- .../UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs | 5 +++++ .../Runtime/Scripts/OutlineLayerCollection.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs index da6fc3e..5192987 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineBuilder.cs @@ -81,6 +81,11 @@ private void Reset() } } + private void OnDestroy() + { + _outlineLayers?.ClearLayerContent(); + } + #endif #endregion diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 2c18174..a701654 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -139,6 +139,7 @@ private void OnEnable() { foreach (var layer in _layers) { + layer.Clear(); layer.SetCollection(this); } } From 1c56b5428c9e8ae4efe62c966651e432496e0825 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 13:20:09 +0300 Subject: [PATCH 58/61] Added help instructions for OutlineBuilder (fixes #8) --- .../UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs index 45e5c2b..75d54b8 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs @@ -109,7 +109,7 @@ public override void OnInspectorGUI() if (_content != null) { - EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Game objectes listed below will be added to corresponding outline layers when application is started. Only scene references are allowed.", MessageType.Info); _content.DoLayoutList(); EditorGUILayout.Space(); @@ -122,7 +122,7 @@ public override void OnInspectorGUI() } else if (_lists != null && _lists.Count > 0) { - EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Settings below are not serialized, they only exist in runtime.", MessageType.Info); for (var i = 0; i < _lists.Count; ++i) { From e5db7fc0172b7b5aa1506e2704ad05ff89f1d0be Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 21:35:09 +0300 Subject: [PATCH 59/61] README update --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3caa8a5..9fff0c8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # UnityFx.Outline Channel | UnityFx.Outline | ----------|---------------| +--------|-----------------| Github | [![GitHub release](https://img.shields.io/github/release/Arvtesh/UnityFx.Outline.svg?logo=github)](https://github.com/Arvtesh/UnityFx.Outline/releases) Npm (core + built-in RP) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.svg)](https://www.npmjs.com/package/com.unityfx.outline) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline) Npm (Post-processing v2) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.postprocessing.svg)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline.postprocessing) Npm (URP) | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.urp.svg)](https://www.npmjs.com/package/com.unityfx.outline.urp) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline.urp) +Npm (HDRP) | TODO **Requires Unity 2018.4 or higher.**
**Compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2).**
@@ -137,7 +138,7 @@ outlineBehaviour.OutlineIntensity = 10; ``` ### Depth testing -By default depth testing is disabled when rendering outlines. This behaviour can be overriden by setting `OutlineRenderFlags.EnableDepthTesting` flag of `OutlineRenderMode` or settings the corresponding checkbox in editor. +By default depth testing is disabled when rendering outlines. This behaviour can be overriden by setting `EnableDepthTesting` flag of `Rander Flags` (either via scripting API or with editor). ```csharp var outlineSettings = GetComponent(); @@ -146,6 +147,13 @@ outlineSettings.OutlineWidth = 2; outlineSettings.OutlineRenderMode = OutlineRenderFlags.Blurred | OutlineRenderFlags.EnableDepthTesting; ``` +### Ignore layers +When adding a `GameObject` to outline collection it is often desirable to ignore child renderers in specific layers (for instance, `TransparentFX`). This can be achieved by settings the `IgnoreLayers` mask in outline settings (or through corresponding API). +```csharp +var outlineSettings = GetComponent(); +outlineSettings.IgnoreLayerMask = LayerMask.GetMask("TransparentFX", "UI"); +``` + ### Extensibility There are a number of helper classes that can be used for writing highly customized outline implementations (if neither `OutlineBehaviour` nor `OutlineEffect` does not suit your needs). All outline implementations use following helpers: @@ -175,7 +183,7 @@ using (var renderer = new OutlineRenderer(commandBuffer, resources)) myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer); ``` -### Integration with Unity post-processing. +## Integration with Unity post-processing v2. [![NPM](https://nodei.co/npm/com.unityfx.outline.postprocessing.png)](https://www.npmjs.com/package/com.unityfx.outline.postprocessing) Install the package, add `Outline` effect to `PostProcessProfile`'s overrides list. Configure the effect parameters, make sure outline resources and layer collection are set: @@ -186,7 +194,7 @@ Assign the configured `PostProcessProfile` to `PostProcessVolume` and that's it! More info on writing custom post processing effects can be found [here](https://docs.unity3d.com/Packages/com.unity.postprocessing@2.3/manual/Writing-Custom-Effects.html). -### Integration with Universal Render Pipeline (URP). +## Integration with Universal Render Pipeline (URP). [![NPM](https://nodei.co/npm/com.unityfx.outline.urp.png)](https://www.npmjs.com/package/com.unityfx.outline.urp) Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources and layer collection are set): From b87e237c9000461f2593f5e024f710446245bcf0 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 21:46:43 +0300 Subject: [PATCH 60/61] CHANGELOG update --- CHANGELOG.md | 4 ++-- .../Packages/UnityFx.Outline/CHANGELOG.md | 24 +++++++++++++++++++ .../CHANGELOG.md | 12 ++++++---- .../Packages/UnityFx.Outline.URP/CHANGELOG.md | 2 +- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5331f74..b1728fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). -## [0.8.0] - unreleased +## [0.8.0] - 2020.05.30 [URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html) support, core refactoring and bugfixes. @@ -12,7 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/); this proj - Use procedural geometry ([DrawProcedural](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawProcedural.html)) on SM3.5+. - Added support for both forward and deferred renderers (built-in RP). - Added ignore layer mask settings to `OutlineLayerCollection` (previously the ignore layers were specified when adding game objects to layers). -- Added `OutlineBuilder` helper script for managinf `OutlineLayerCollection` content from editor. +- Added `OutlineBuilder` helper script for managinf `OutlineLayerCollection` content from editor ([#8](https://github.com/Arvtesh/UnityFx.Outline/issues/8)). ### Changed - Changed `OutlineSettings` to display enum mask instead of checkboxes. diff --git a/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md b/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md index d148afd..0460817 100644 --- a/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md +++ b/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.8.0] - 2020.05.30 + +Major refactoring and bugfixes. + +### Added +- Use procedural geometry ([DrawProcedural](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawProcedural.html)) on SM3.5+. +- Added support for both forward and deferred renderers. +- Added ignore layer mask settings to `OutlineLayerCollection` (previously the ignore layers were specified when adding game objects to layers). +- Added `OutlineBuilder` helper script for managinf `OutlineLayerCollection` content from editor ([#8](https://github.com/Arvtesh/UnityFx.Outline/issues/8)). + +### Changed +- Changed `OutlineSettings` to display enum mask instead of checkboxes. +- Changed inspector look and feel for `OutlineLayerCollection` assets. +- Merged shaders for the 2 outline passes into one multi-pass shader. +- `OutlineLayerCollection` doe not depend on `OutlineRenderer` now. + +### Fixed +- Fixed outline rendering on mobiles ([#7](https://github.com/Arvtesh/UnityFx.Outline/issues/7)). +- Fixed outline shader error on low-end devices. + +### Removed +- Dropped .NET 3.5 support, minimal Unity version is set to 2018.4. +- Removed `IOutlineSettingsEx` interface. + ## [0.7.2] - 2020.04.08 Depth testing support and performance optimizations. diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md index 7294762..d3a13d5 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/CHANGELOG.md @@ -3,11 +3,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). -## [0.2.0] - unreleased +## [0.2.0] - 2020.05.30 -### Added -- Added inspector tooltips. -- Added depth support. +Minor improvements and bugfixes. + +### Fixed +- Fixed post-ptocessing implementation to require depth texture. + +### Removed +- Dropped .NET 3.5 support, minimal Unity version is set to 2018.4. ## [0.1.0] - 2020.04.08 diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md index 7f443e9..1935a50 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md +++ b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). -## [0.1.0] - unreleased +## [0.1.0] - 2020.05.30 ### Added - Initial release. From 40cb408805db772a6727af55834e2485ec881ee8 Mon Sep 17 00:00:00 2001 From: Arvtesh <22732458+Arvtesh@users.noreply.github.com> Date: Sat, 30 May 2020 21:46:58 +0300 Subject: [PATCH 61/61] Fixed package naming --- Outline.Core/Packages/UnityFx.Outline/package.json | 4 ++-- .../Packages/UnityFx.Outline.PostProcessing/package.json | 4 ++-- Outline.URP/Packages/UnityFx.Outline.URP/package.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Outline.Core/Packages/UnityFx.Outline/package.json b/Outline.Core/Packages/UnityFx.Outline/package.json index 208d2fd..6dc340f 100644 --- a/Outline.Core/Packages/UnityFx.Outline/package.json +++ b/Outline.Core/Packages/UnityFx.Outline/package.json @@ -1,8 +1,8 @@ { "name": "com.unityfx.outline", "version": "0.8.0", - "displayName": "Screen-space outlines", - "description": "Configurable per-object and per-camera outline effect implementation for built-in render pipeline. Both solid and blurred outline modes are supported (Gauss blur). Scriptable render pipeline is not supported.", + "displayName": "Outline toolkit", + "description": "This package contains configurable per-object and per-camera outline effect implementation for built-in render pipeline. Both solid and blurred outline modes are supported (Gauss blur), as well as depth testing. Reusable and extensible API.", "unity": "2018.4", "keywords": [ "UnityFx", diff --git a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json index 5b54a65..a6bc730 100644 --- a/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json +++ b/Outline.PostProcessing/Packages/UnityFx.Outline.PostProcessing/package.json @@ -1,8 +1,8 @@ { "name": "com.unityfx.outline.postprocessing", "version": "0.2.0", - "displayName": "Screen-space outline (Post-processing v2)", - "description": "Configurable screen-space outline implementation for Unity post-processing stack (v2).", + "displayName": "Outline toolkit (Post-processing v2)", + "description": "This package contains configurable outline implementation for Unity post-processing stack (v2).", "unity": "2018.4", "dependencies": { "com.unityfx.outline": "0.8.0", diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/package.json b/Outline.URP/Packages/UnityFx.Outline.URP/package.json index 6cc1220..9c6ce85 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/package.json +++ b/Outline.URP/Packages/UnityFx.Outline.URP/package.json @@ -1,8 +1,8 @@ { "name": "com.unityfx.outline.urp", "version": "0.1.0", - "displayName": "Screen-space outline (URP)", - "description": "Configurable outline for URP.", + "displayName": "Outline toolkit (URP)", + "description": "This package contains configurable outline implementation for Universal Render Pipeline.", "unity": "2019.3", "dependencies": { "com.unityfx.outline": "0.8.0",