diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index f5ac9f4..9c6ba14 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -16,7 +16,6 @@ jobs: registry-url: https://registry.npmjs.org/ - 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}} diff --git a/CHANGELOG.md b/CHANGELOG.md index ccf5497..1cea2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ 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.2] - 2020.11.10 + +[URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html) per-layer outlines and misc improvements. + +### Added +- Added URP-specific shader versions. +- Added URP layer-based outline rendering ([#9](https://github.com/Arvtesh/UnityFx.Outline/issues/9)). +- Added support for Single Pass Instanced XR rendering for built-in and URP ([#13](https://github.com/Arvtesh/UnityFx.Outline/issues/13)). + +### Fixed +- Fixed URP outlines rendering issue in Unity 2020.2 ([#21](https://github.com/Arvtesh/UnityFx.Outline/issues/21)). + ## [0.8.1] - 2020.09.21 Alpha test support, bugfixes and misc improvements. diff --git a/NpmPublish.bat b/NpmPublish.bat index 0fd89a5..b869126 100644 --- a/NpmPublish.bat +++ b/NpmPublish.bat @@ -1,3 +1,2 @@ npm publish Outline.Core\Packages\UnityFx.Outline -npm publish Outline.PostProcessing\Packages\UnityFx.Outline.PostProcessing npm publish Outline.HDRP\Packages\UnityFx.Outline.HDRP diff --git a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs index 1629d5c..f79e73c 100644 --- a/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs +++ b/Outline.Core/Assets/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs @@ -97,12 +97,6 @@ public void Insert_SetsCount() Assert.AreEqual(1, _layerCollection.Count); } - [Test] - public void Remove_DoesNotThrowOnNullArgument() - { - Assert.DoesNotThrow(() => _layerCollection.Remove(null)); - } - [Test] public void Remove_SetsCount() { diff --git a/Outline.Core/Assets/XR.meta b/Outline.Core/Assets/XR.meta new file mode 100644 index 0000000..7e2346f --- /dev/null +++ b/Outline.Core/Assets/XR.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a499a58476be534f9e78f45b2af3b77 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/XR/Loaders.meta b/Outline.Core/Assets/XR/Loaders.meta new file mode 100644 index 0000000..305ea14 --- /dev/null +++ b/Outline.Core/Assets/XR/Loaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 393716061aba98748a018e54cfc48714 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.asset b/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.asset new file mode 100644 index 0000000..f7b4662 --- /dev/null +++ b/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.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: 0660e8fc444734757ae6f6c40c2d33a0, type: 3} + m_Name: Mock HMD Loader + m_EditorClassIdentifier: diff --git a/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.asset.meta b/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.asset.meta new file mode 100644 index 0000000..eec3927 --- /dev/null +++ b/Outline.Core/Assets/XR/Loaders/Mock HMD Loader.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fcabf9da944033d4d9ca7914d91c03e7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/XR/Settings.meta b/Outline.Core/Assets/XR/Settings.meta new file mode 100644 index 0000000..3bf484b --- /dev/null +++ b/Outline.Core/Assets/XR/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 78c5f368e4f5dbb4a8473c07076933e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset b/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset new file mode 100644 index 0000000..0acbf62 --- /dev/null +++ b/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset @@ -0,0 +1,15 @@ +%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: c8bf066bf8a4947a1be502d267edb82f, type: 3} + m_Name: Mock HMD Build Settings + m_EditorClassIdentifier: + renderMode: 1 diff --git a/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset.meta b/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset.meta new file mode 100644 index 0000000..811660e --- /dev/null +++ b/Outline.Core/Assets/XR/Settings/Mock HMD Build Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3521b75f8cf98d4d90d8baa975f2345 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Assets/XR/XRGeneralSettings.asset b/Outline.Core/Assets/XR/XRGeneralSettings.asset new file mode 100644 index 0000000..1dc656d --- /dev/null +++ b/Outline.Core/Assets/XR/XRGeneralSettings.asset @@ -0,0 +1,48 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-6957712260415362079 +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: d236b7d11115f2143951f1e14045df39, type: 3} + m_Name: Standalone Settings + m_EditorClassIdentifier: + m_LoaderManagerInstance: {fileID: 3934069634805112854} + m_InitManagerOnStart: 1 +--- !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: d2dc886499c26824283350fa532d087d, type: 3} + m_Name: XRGeneralSettings + m_EditorClassIdentifier: + Keys: 01000000 + Values: + - {fileID: -6957712260415362079} +--- !u!114 &3934069634805112854 +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: f4c3631f5e58749a59194e0cf6baf6d5, type: 3} + m_Name: Standalone Providers + m_EditorClassIdentifier: + m_RequiresSettingsUpdate: 0 + m_AutomaticLoading: 0 + m_AutomaticRunning: 0 + m_Loaders: + - {fileID: 11400000, guid: fcabf9da944033d4d9ca7914d91c03e7, type: 2} diff --git a/Outline.Core/Assets/XR/XRGeneralSettings.asset.meta b/Outline.Core/Assets/XR/XRGeneralSettings.asset.meta new file mode 100644 index 0000000..212e5a5 --- /dev/null +++ b/Outline.Core/Assets/XR/XRGeneralSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 82aec1eceb005f64292d3e5f6108b4d6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md b/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md index 7254ca7..ecfee66 100644 --- a/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md +++ b/Outline.Core/Packages/UnityFx.Outline/CHANGELOG.md @@ -3,6 +3,16 @@ 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.2] - 2020.11.10 + +Misc improvements. + +### Added +- Added support for Single Pass Instanced XR rendering for built-in render pipeline ([#13](https://github.com/Arvtesh/UnityFx.Outline/issues/13)). + +### Changed +- Misc inspector improvements. + ## [0.8.1] - 2020.09.21 Alpha test support, bugfixes and misc improvements. diff --git a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs index 75d54b8..30df2b9 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Editor/Scripts/OutlineBuilderEditor.cs @@ -84,9 +84,16 @@ private void OnEnable() _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); + if (_builder && _builder.Content != null && index < _builder.Content.Count) + { + var item = _builder.Content[index]; + + if (item != null) + { + 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) => diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 32d2510..3ca4413 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -1,420 +1,467 @@ -// 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 System.Runtime.CompilerServices; -using UnityEngine; -using UnityEngine.Rendering; - -namespace UnityFx.Outline -{ - /// - /// Helper class for outline rendering with . - /// - /// - /// The class can be used on its own or as part of a higher level systems. It is used - /// by higher level outline implementations ( and - /// ). It is fully compatible with Unity post processing stack as well. - /// The class implements to be used inside - /// block as shown in the code samples. Disposing does not dispose - /// the corresponding . - /// Command buffer is not cleared before rendering. It is user responsibility to do so if needed. - /// - /// - /// var commandBuffer = new CommandBuffer(); - /// - /// using (var renderer = new OutlineRenderer(commandBuffer, resources)) - /// { - /// renderer.Render(renderers, settings); - /// } - /// - /// camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer); - /// - /// - public readonly struct OutlineRenderer : IDisposable - { - #region data - - private const int _defaultRenderPassId = 0; - private const int _alphaTestRenderPassId = 1; - private const int _outlineHPassId = 0; - private const int _outlineVPassId = 1; - private const RenderTextureFormat _rtFormat = RenderTextureFormat.R8; - - private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex"); - private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex"); - - private readonly RenderTargetIdentifier _rt; - private readonly RenderTargetIdentifier _depth; - private readonly CommandBuffer _commandBuffer; - private readonly OutlineResources _resources; - - #endregion - - #region interface - - /// - /// A default outline rendering should be assosiated with. - /// - public const CameraEvent RenderEvent = CameraEvent.AfterSkybox; - - /// - /// 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, Vector2Int.zero) - { - } - - /// - /// 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) - : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), Vector2Int.zero) - { - } - - /// - /// 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) - : this(cmd, resources, dst, BuiltinRenderTextureType.Depth, Vector2Int.zero) - { - } - - /// - /// 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, Vector2Int rtSize) - : this(cmd, resources, dst, GetBuiltinDepth(renderingPath), 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. - /// Outline resources. - /// Render target. - /// Depth dexture to use. - /// Thrown if is . - 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.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; - } - - /// - /// 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. - /// Render texture decsriptor. - /// Thrown if is . - 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; - } - - if (rtDesc.height <= 0) - { - rtDesc.height = -1; - } - - if (rtDesc.dimension == TextureDimension.None || rtDesc.dimension == TextureDimension.Unknown) - { - rtDesc.dimension = TextureDimension.Tex2D; - } - - rtDesc.shadowSamplingMode = ShadowSamplingMode.None; - rtDesc.depthBufferBits = 0; - rtDesc.colorFormat = _rtFormat; - rtDesc.volumeDepth = 1; - - 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 outlined. - /// - /// - public void Render(OutlineRenderObject obj) - { - Render(obj.Renderers, obj.OutlineSettings, obj.Tag); - } - - /// - /// 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 settings. - /// Optional name of the sample (visible in profiler). - /// Thrown if any of the arguments is . - /// - /// - public void Render(IReadOnlyList renderers, IOutlineSettings settings, string sampleName = null) - { - if (renderers is null) - { - throw new ArgumentNullException(nameof(renderers)); - } - - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - if (renderers.Count > 0) - { - if (string.IsNullOrEmpty(sampleName)) - { - sampleName = renderers[0].name; - } - - _commandBuffer.BeginSample(sampleName); - { - RenderObject(settings, renderers); - RenderOutline(settings); - } - _commandBuffer.EndSample(sampleName); - } - } - - /// - /// Renders outline around a single object. - /// - /// 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, string sampleName = null) - { - if (renderer is null) - { - throw new ArgumentNullException(nameof(renderer)); - } - - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - if (string.IsNullOrEmpty(sampleName)) - { - sampleName = renderer.name; - } - - _commandBuffer.BeginSample(sampleName); - { - RenderObject(settings, renderer); - RenderOutline(settings); - } - _commandBuffer.EndSample(sampleName); - } - - /// - /// 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 - - /// - /// Finalizes the effect rendering and releases temporary textures used. Should only be called once. - /// - public void Dispose() - { - _commandBuffer.ReleaseTemporaryRT(_hPassRtId); - _commandBuffer.ReleaseTemporaryRT(_maskRtId); - } - - #endregion - - #region implementation - - private void RenderObjectClear(OutlineRenderFlags flags) - { - if ((flags & OutlineRenderFlags.EnableDepthTesting) != 0) - { - // 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, _depth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); - } - else - { - _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - } - - _commandBuffer.ClearRenderTarget(false, true, Color.clear); - } - - private void DrawRenderer(Renderer renderer, IOutlineSettings settings) - { - if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) - { - var alphaTest = (settings.OutlineRenderMode & OutlineRenderFlags.EnableAlphaTesting) != 0; - - // 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); - - if (alphaTest) - { - for (var i = 0; i < _resources.TmpMaterials.Count; ++i) - { - var mat = _resources.TmpMaterials[i]; - - // Use material cutoff value if available. - if (mat.HasProperty(_resources.AlphaCutoffId)) - { - _commandBuffer.SetGlobalFloat(_resources.AlphaCutoffId, mat.GetFloat(_resources.AlphaCutoffId)); - } - else - { - _commandBuffer.SetGlobalFloat(_resources.AlphaCutoffId, settings.OutlineAlphaCutoff); - } - - _commandBuffer.SetGlobalTexture(_resources.MainTexId, _resources.TmpMaterials[i].mainTexture); - _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i, _alphaTestRenderPassId); - } - } - else - { - for (var i = 0; i < _resources.TmpMaterials.Count; ++i) - { - _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i, _defaultRenderPassId); - } - } - } - } - - private void RenderObject(IOutlineSettings settings, IReadOnlyList renderers) - { - RenderObjectClear(settings.OutlineRenderMode); - - for (var i = 0; i < renderers.Count; ++i) - { - DrawRenderer(renderers[i], settings); - } - } - - private void RenderObject(IOutlineSettings settings, Renderer renderer) - { - RenderObjectClear(settings.OutlineRenderMode); - DrawRenderer(renderer, settings); - } - - private void RenderOutline(IOutlineSettings settings) - { - var mat = _resources.OutlineMaterial; - var props = _resources.GetProperties(settings); - - _commandBuffer.SetGlobalFloatArray(_resources.GaussSamplesId, _resources.GetGaussSamples(settings.OutlineWidth)); - - // HPass - _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _maskRtId, _resources, _outlineHPassId, mat, props); - - // VPassBlend - _commandBuffer.SetRenderTarget(_rt, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store); - Blit(_commandBuffer, _hPassRtId, _resources, _outlineVPassId, mat, props); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - 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); - - // NOTE: SystemInfo.graphicsShaderLevel check is not enough sometimes (esp. on mobiles), so there is SystemInfo.supportsInstancing - // check and a flag for forcing DrawMesh. - if (SystemInfo.graphicsShaderLevel >= 35 && SystemInfo.supportsInstancing && !resources.UseFullscreenTriangleMesh) - { - cmdBuffer.DrawProcedural(Matrix4x4.identity, mat, shaderPass, MeshTopology.Triangles, 3, 1, props); - } - else - { - cmdBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, mat, 0, shaderPass, props); - } - } - - #endregion - } -} +// 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 System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.XR; + +namespace UnityFx.Outline +{ + /// + /// Helper class for outline rendering with . + /// + /// + /// The class can be used on its own or as part of a higher level systems. It is used + /// by higher level outline implementations ( and + /// ). It is fully compatible with Unity post processing stack as well. + /// The class implements to be used inside + /// block as shown in the code samples. Disposing does not dispose + /// the corresponding . + /// Command buffer is not cleared before rendering. It is user responsibility to do so if needed. + /// + /// + /// var commandBuffer = new CommandBuffer(); + /// + /// using (var renderer = new OutlineRenderer(commandBuffer, resources)) + /// { + /// renderer.Render(renderers, settings); + /// } + /// + /// camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer); + /// + /// + public readonly struct OutlineRenderer : IDisposable + { + #region data + + private const int _defaultRenderPassId = 0; + private const int _alphaTestRenderPassId = 1; + + private readonly TextureDimension _rtDimention; + private readonly RenderTargetIdentifier _rt; + private readonly RenderTargetIdentifier _depth; + private readonly CommandBuffer _commandBuffer; + private readonly OutlineResources _resources; + + #endregion + + #region interface + + /// + /// A default outline rendering should be assosiated with. + /// + public const CameraEvent RenderEvent = CameraEvent.AfterSkybox; + + /// + /// A default render texture format for the outline effect. + /// + public const RenderTextureFormat RtFormat = RenderTextureFormat.R8; + + /// + /// 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, Vector2Int.zero) + { + } + + /// + /// 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) + : this(cmd, resources, BuiltinRenderTextureType.CameraTarget, GetBuiltinDepth(renderingPath), Vector2Int.zero) + { + } + + /// + /// 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) + : this(cmd, resources, dst, BuiltinRenderTextureType.Depth, Vector2Int.zero) + { + } + + /// + /// 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, Vector2Int rtSize) + : this(cmd, resources, dst, GetBuiltinDepth(renderingPath), 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. + /// Outline resources. + /// Render target. + /// Depth dexture to use. + /// Thrown if is . + 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; + } + + if (XRSettings.enabled) + { + var rtDesc = XRSettings.eyeTextureDesc; + + rtDesc.shadowSamplingMode = ShadowSamplingMode.None; + rtDesc.depthBufferBits = 0; + rtDesc.colorFormat = RtFormat; + + cmd.GetTemporaryRT(resources.MaskTexId, rtDesc, FilterMode.Bilinear); + cmd.GetTemporaryRT(resources.TempTexId, rtDesc, FilterMode.Bilinear); + + _rtDimention = rtDesc.dimension; + } + else + { + cmd.GetTemporaryRT(resources.MaskTexId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, RtFormat); + cmd.GetTemporaryRT(resources.TempTexId, rtSize.x, rtSize.y, 0, FilterMode.Bilinear, RtFormat); + + _rtDimention = TextureDimension.Tex2D; + } + + _rt = dst; + _depth = depth; + _commandBuffer = cmd; + _resources = 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. + /// Render target. + /// Depth dexture to use. + /// Render texture decsriptor. + /// Thrown if is . + 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; + } + + if (rtDesc.height <= 0) + { + rtDesc.height = -1; + } + + if (rtDesc.dimension == TextureDimension.None || rtDesc.dimension == TextureDimension.Unknown) + { + rtDesc.dimension = TextureDimension.Tex2D; + } + + rtDesc.shadowSamplingMode = ShadowSamplingMode.None; + rtDesc.depthBufferBits = 0; + rtDesc.colorFormat = RtFormat; + + cmd.GetTemporaryRT(resources.MaskTexId, rtDesc, FilterMode.Bilinear); + cmd.GetTemporaryRT(resources.TempTexId, rtDesc, FilterMode.Bilinear); + + _rtDimention = rtDesc.dimension; + _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 outlined. + /// + /// + public void Render(OutlineRenderObject obj) + { + Render(obj.Renderers, obj.OutlineSettings, obj.Tag); + } + + /// + /// 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 settings. + /// Optional name of the sample (visible in profiler). + /// Thrown if any of the arguments is . + /// + /// + public void Render(IReadOnlyList renderers, IOutlineSettings settings, string sampleName = null) + { + if (renderers is null) + { + throw new ArgumentNullException(nameof(renderers)); + } + + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } + + if (renderers.Count > 0) + { + if (string.IsNullOrEmpty(sampleName)) + { + sampleName = renderers[0].name; + } + + _commandBuffer.BeginSample(sampleName); + { + RenderObjectClear(settings.OutlineRenderMode); + + for (var i = 0; i < renderers.Count; ++i) + { + DrawRenderer(renderers[i], settings); + } + + RenderOutline(settings); + } + _commandBuffer.EndSample(sampleName); + } + } + + /// + /// Renders outline around a single object. + /// + /// 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, string sampleName = null) + { + if (renderer is null) + { + throw new ArgumentNullException(nameof(renderer)); + } + + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } + + if (string.IsNullOrEmpty(sampleName)) + { + sampleName = renderer.name; + } + + _commandBuffer.BeginSample(sampleName); + { + RenderObjectClear(settings.OutlineRenderMode); + DrawRenderer(renderer, settings); + RenderOutline(settings); + } + _commandBuffer.EndSample(sampleName); + } + + /// + /// 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); + } + + /// + /// Specialized render target setup. Do not use if not sure. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RenderObjectClear(OutlineRenderFlags flags) + { + // NOTE: Use the camera depth buffer when rendering the mask. Shader only reads from the depth buffer (ZWrite Off). + if ((flags & OutlineRenderFlags.EnableDepthTesting) != 0) + { + if (_rtDimention == TextureDimension.Tex2DArray) + { + // NOTE: Need to use this SetRenderTarget overload for XR, otherwise single pass instanced rendering does not function properly. + _commandBuffer.SetRenderTarget(_resources.MaskTex, _depth, 0, CubemapFace.Unknown, -1); + } + else + { + _commandBuffer.SetRenderTarget(_resources.MaskTex, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, _depth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare); + } + } + else + { + if (_rtDimention == TextureDimension.Tex2DArray) + { + _commandBuffer.SetRenderTarget(_resources.MaskTex, 0, CubemapFace.Unknown, -1); + } + else + { + _commandBuffer.SetRenderTarget(_resources.MaskTex, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + } + } + + //_commandBuffer.SetSinglePassStereo(SinglePassStereoMode.Instancing); + _commandBuffer.ClearRenderTarget(false, true, Color.clear); + } + + /// + /// Renders outline. Do not use if not sure. + /// + public void RenderOutline(IOutlineSettings settings) + { + var mat = _resources.OutlineMaterial; + var props = _resources.GetProperties(settings); + + //_commandBuffer.SetSinglePassStereo(SinglePassStereoMode.Instancing); + _commandBuffer.SetGlobalFloatArray(_resources.GaussSamplesId, _resources.GetGaussSamples(settings.OutlineWidth)); + + if (_rtDimention == TextureDimension.Tex2DArray) + { + // HPass + _commandBuffer.SetRenderTarget(_resources.TempTex, 0, CubemapFace.Unknown, -1); + Blit(_resources.MaskTex, OutlineResources.OutlineShaderHPassId, mat, props); + + // VPassBlend + _commandBuffer.SetRenderTarget(_rt, 0, CubemapFace.Unknown, -1); + Blit(_resources.TempTex, OutlineResources.OutlineShaderVPassId, mat, props); + } + else + { + // HPass + _commandBuffer.SetRenderTarget(_resources.TempTex, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); + Blit(_resources.MaskTex, OutlineResources.OutlineShaderHPassId, mat, props); + + // VPassBlend + _commandBuffer.SetRenderTarget(_rt, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store); + Blit(_resources.TempTex, OutlineResources.OutlineShaderVPassId, mat, props); + } + } + + #endregion + + #region IDisposable + + /// + /// Finalizes the effect rendering and releases temporary textures used. Should only be called once. + /// + public void Dispose() + { + _commandBuffer.ReleaseTemporaryRT(_resources.TempTexId); + _commandBuffer.ReleaseTemporaryRT(_resources.MaskTexId); + } + + #endregion + + #region implementation + + private void DrawRenderer(Renderer renderer, IOutlineSettings settings) + { + if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) + { + var alphaTest = (settings.OutlineRenderMode & OutlineRenderFlags.EnableAlphaTesting) != 0; + + // 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); + + if (alphaTest) + { + for (var i = 0; i < _resources.TmpMaterials.Count; ++i) + { + var mat = _resources.TmpMaterials[i]; + + // Use material cutoff value if available. + if (mat.HasProperty(_resources.AlphaCutoffId)) + { + _commandBuffer.SetGlobalFloat(_resources.AlphaCutoffId, mat.GetFloat(_resources.AlphaCutoffId)); + } + else + { + _commandBuffer.SetGlobalFloat(_resources.AlphaCutoffId, settings.OutlineAlphaCutoff); + } + + _commandBuffer.SetGlobalTexture(_resources.MainTexId, _resources.TmpMaterials[i].mainTexture); + _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i, _alphaTestRenderPassId); + } + } + else + { + for (var i = 0; i < _resources.TmpMaterials.Count; ++i) + { + _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i, _defaultRenderPassId); + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Blit(RenderTargetIdentifier src, int shaderPass, Material mat, MaterialPropertyBlock props) + { + // Set source texture as _MainTex to match Blit behavior. + _commandBuffer.SetGlobalTexture(_resources.MainTexId, src); + + // NOTE: SystemInfo.graphicsShaderLevel check is not enough sometimes (esp. on mobiles), so there is SystemInfo.supportsInstancing + // check and a flag for forcing DrawMesh. + if (SystemInfo.graphicsShaderLevel >= 35 && SystemInfo.supportsInstancing && !_resources.UseFullscreenTriangleMesh) + { + _commandBuffer.DrawProcedural(Matrix4x4.identity, mat, shaderPass, MeshTopology.Triangles, 3, 1, props); + } + else + { + _commandBuffer.DrawMesh(_resources.FullscreenTriangleMesh, Matrix4x4.identity, mat, 0, shaderPass, props); + } + } + + #endregion + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index cc39ab0..0d8d261 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -1,455 +1,489 @@ -// 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 UnityEditor; -using UnityEngine; - -namespace UnityFx.Outline -{ - /// - /// This asset is used to store references to shaders and other resources needed at runtime without having to use a Resources folder. - /// - /// - [CreateAssetMenu(fileName = "OutlineResources", menuName = "UnityFx/Outline/Outline Resources")] - public sealed class OutlineResources : ScriptableObject - { - #region data - - [SerializeField] - private Shader _renderShader; - [SerializeField] - private Shader _outlineShader; - [SerializeField] - private bool _enableInstancing; - - private Material _renderMaterial; - private Material _outlineMaterial; - private MaterialPropertyBlock _props; - private Mesh _fullscreenTriangleMesh; - private float[][] _gaussSamples; - private bool _useDrawMesh; - - #endregion - - #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; - - /// - /// Minimum value of outline alpha cutoff parameter. - /// - /// - public const float MinAlphaCutoff = 0; - - /// - /// Maximum value of outline alpha cutoff parameter. - /// - /// - public const float MaxAlphaCutoff = 1; - - /// - /// Name of _MainTex shader parameter. - /// - public const string MainTexName = "_MainTex"; - - /// - /// 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 _Cutoff shader parameter. - /// - public const string AlphaCutoffName = "_Cutoff"; - - /// - /// Name of _GaussSamples shader parameter. - /// - public const string GaussSamplesName = "_GaussSamples"; - - /// - /// Name of the _USE_DRAWMESH shader feature. - /// - 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."; - - /// - /// Tooltip text for outline field. - /// - public const string OutlineLayerMaskTooltip = "Layer mask for outined objects."; - - /// - /// SRP not supported message. - /// - internal const string SrpNotSupported = "{0} works with built-in render pipeline only. It does not support SRP (including URP and HDRP)."; - - /// - /// Post-processing not supported message. - /// - internal const string PpNotSupported = "{0} does not support Unity Post-processing stack v2. It might not work as expected."; - - /// - /// Hashed name of _MainTex shader parameter. - /// - public readonly int MainTexId = Shader.PropertyToID(MainTexName); - - /// - /// Hashed name of _Color shader parameter. - /// - public readonly int ColorId = Shader.PropertyToID(ColorName); - - /// - /// Hashed name of _Width shader parameter. - /// - public readonly int WidthId = Shader.PropertyToID(WidthName); - - /// - /// Hashed name of _Intensity shader parameter. - /// - public readonly int IntensityId = Shader.PropertyToID(IntensityName); - - /// - /// Hashed name of _Cutoff shader parameter. - /// - public readonly int AlphaCutoffId = Shader.PropertyToID(AlphaCutoffName); - - /// - /// Hashed name of _GaussSamples shader parameter. - /// - public readonly int GaussSamplesId = Shader.PropertyToID(GaussSamplesName); - - /// - /// Temp materials list. Used by to avoid GC allocations. - /// - public readonly List TmpMaterials = new List(); - - /// - /// Gets or sets a that renders objects outlined with a solid while color. - /// - public Shader RenderShader - { - get - { - return _renderShader; - } - } - - /// - /// Gets or sets a that renders outline around the mask, that was generated with . - /// - public Shader OutlineShader - { - get - { - return _outlineShader; - } - } - - /// - /// Gets a -based material. - /// - public Material RenderMaterial - { - get - { - if (_renderMaterial == null) - { - _renderMaterial = new Material(RenderShader) - { - name = "Outline - RenderColor", - hideFlags = HideFlags.HideAndDontSave, - enableInstancing = _enableInstancing - }; - } - - return _renderMaterial; - } - } - - /// - /// Gets a -based material. - /// - public Material OutlineMaterial - { - get - { - if (_outlineMaterial == null) - { - _outlineMaterial = new Material(OutlineShader) - { - name = "Outline - Main", - hideFlags = HideFlags.HideAndDontSave, - enableInstancing = _enableInstancing - }; - - if (_useDrawMesh) - { - _outlineMaterial.EnableKeyword(UseDrawMeshFeatureName); - } - } - - return _outlineMaterial; - } - } - - /// - /// Gets a for . - /// - public MaterialPropertyBlock Properties - { - get - { - if (_props is null) - { - _props = new MaterialPropertyBlock(); - } - - return _props; - } - } - - /// - /// 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 - { - if (_fullscreenTriangleMesh == null) - { - _fullscreenTriangleMesh = new Mesh() - { - 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 } - }; - - _fullscreenTriangleMesh.UploadMeshData(true); - } - - return _fullscreenTriangleMesh; - } - set - { - _fullscreenTriangleMesh = value; - } - } - - /// - /// Gets or sets a value indicating whether is used for image effects rendering even when procedural rendering is available. - /// - public bool UseFullscreenTriangleMesh - { - get - { - return _useDrawMesh; - } - set - { - if (_useDrawMesh != value) - { - _useDrawMesh = value; - - if (_outlineMaterial) - { - if (_useDrawMesh) - { - _outlineMaterial.EnableKeyword(UseDrawMeshFeatureName); - } - else - { - _outlineMaterial.DisableKeyword(UseDrawMeshFeatureName); - } - } - } - } - } - - /// - /// Gets or sets a value indicating whether instancing is enabled. - /// - public bool EnableInstancing - { - get - { - return _enableInstancing; - } - set - { - _enableInstancing = value; - - if (_renderMaterial) - { - _renderMaterial.enableInstancing = value; - } - - if (_outlineMaterial) - { - _outlineMaterial.enableInstancing = value; - } - } - } - - /// - /// Gets a value indicating whether the instance is in valid state. - /// - public bool IsValid => RenderShader && OutlineShader; - - /// - /// 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, MaxWidth) - 1; - - if (_gaussSamples is null) - { - _gaussSamples = new float[MaxWidth][]; - } - - if (_gaussSamples[index] is null) - { - _gaussSamples[index] = GetGaussSamples(width, null); - } - - return _gaussSamples[index]; - } - - /// - /// Resets the resources to defaults. - /// - public void ResetToDefaults() - { - _renderShader = Shader.Find("Hidden/UnityFx/OutlineColor"); - _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 - } -} +// 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 UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityFx.Outline +{ + /// + /// This asset is used to store references to shaders and other resources needed at runtime without having to use a Resources folder. + /// + /// + [CreateAssetMenu(fileName = "OutlineResources", menuName = "UnityFx/Outline/Outline Resources")] + public sealed class OutlineResources : ScriptableObject + { + #region data + + [SerializeField] + private Shader _renderShader; + [SerializeField] + private Shader _outlineShader; + + private Material _renderMaterial; + private Material _outlineMaterial; + private MaterialPropertyBlock _props; + private Mesh _fullscreenTriangleMesh; + private float[][] _gaussSamples; + private bool _useDrawMesh; + + #endregion + + #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; + + /// + /// Minimum value of outline alpha cutoff parameter. + /// + /// + public const float MinAlphaCutoff = 0; + + /// + /// Maximum value of outline alpha cutoff parameter. + /// + /// + public const float MaxAlphaCutoff = 1; + + /// + /// Name of _MainTex shader parameter. + /// + public const string MainTexName = "_MainTex"; + + /// + /// Name of _MaskTex shader parameter. + /// + public const string MaskTexName = "_MaskTex"; + + /// + /// Name of _TempTex shader parameter. + /// + public const string TempTexName = "_TempTex"; + + /// + /// 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 _Cutoff shader parameter. + /// + public const string AlphaCutoffName = "_Cutoff"; + + /// + /// Name of _GaussSamples shader parameter. + /// + public const string GaussSamplesName = "_GaussSamples"; + + /// + /// Name of the _USE_DRAWMESH shader feature. + /// + 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."; + + /// + /// Tooltip text for outline field. + /// + public const string OutlineLayerMaskTooltip = "Layer mask for outined objects."; + + /// + /// Index of the HPass in . + /// + public const int OutlineShaderHPassId = 0; + + /// + /// Index of the VPass in . + /// + public const int OutlineShaderVPassId = 1; + + /// + /// SRP not supported message. + /// + internal const string SrpNotSupported = "{0} works with built-in render pipeline only. It does not support SRP (including URP and HDRP)."; + + /// + /// Post-processing not supported message. + /// + internal const string PpNotSupported = "{0} does not support Unity Post-processing stack v2. It might not work as expected."; + + /// + /// Hashed name of _MainTex shader parameter. + /// + public readonly int MainTexId = Shader.PropertyToID(MainTexName); + + /// + /// Texture identifier for _MainTex shader parameter. + /// + public readonly RenderTargetIdentifier MainTex = new RenderTargetIdentifier(MainTexName); + + /// + /// Hashed name of _MaskTex shader parameter. + /// + public readonly int MaskTexId = Shader.PropertyToID(MaskTexName); + + /// + /// Texture identifier for _MaskTex shader parameter. + /// + public readonly RenderTargetIdentifier MaskTex = new RenderTargetIdentifier(MaskTexName); + + /// + /// Hashed name of _TempTex shader parameter. + /// + public readonly int TempTexId = Shader.PropertyToID(TempTexName); + + /// + /// Texture identifier for _TempTex shader parameter. + /// + public readonly RenderTargetIdentifier TempTex = new RenderTargetIdentifier(TempTexName); + + /// + /// Hashed name of _Color shader parameter. + /// + public readonly int ColorId = Shader.PropertyToID(ColorName); + + /// + /// Hashed name of _Width shader parameter. + /// + public readonly int WidthId = Shader.PropertyToID(WidthName); + + /// + /// Hashed name of _Intensity shader parameter. + /// + public readonly int IntensityId = Shader.PropertyToID(IntensityName); + + /// + /// Hashed name of _Cutoff shader parameter. + /// + public readonly int AlphaCutoffId = Shader.PropertyToID(AlphaCutoffName); + + /// + /// Hashed name of _GaussSamples shader parameter. + /// + public readonly int GaussSamplesId = Shader.PropertyToID(GaussSamplesName); + + /// + /// Temp materials list. Used by to avoid GC allocations. + /// + public readonly List TmpMaterials = new List(); + + /// + /// Gets or sets a that renders objects outlined with a solid while color. + /// + public Shader RenderShader + { + get + { + return _renderShader; + } + } + + /// + /// Gets or sets a that renders outline around the mask, that was generated with . + /// + public Shader OutlineShader + { + get + { + return _outlineShader; + } + } + + /// + /// Gets a -based material. + /// + public Material RenderMaterial + { + get + { + if (_renderMaterial == null) + { + _renderMaterial = new Material(RenderShader) + { + name = "Outline - RenderColor", + hideFlags = HideFlags.HideAndDontSave + }; + } + + return _renderMaterial; + } + } + + /// + /// Gets a -based material. + /// + public Material OutlineMaterial + { + get + { + if (_outlineMaterial == null) + { + _outlineMaterial = new Material(OutlineShader) + { + name = "Outline - Main", + hideFlags = HideFlags.HideAndDontSave + }; + + if (_useDrawMesh) + { + _outlineMaterial.EnableKeyword(UseDrawMeshFeatureName); + } + } + + return _outlineMaterial; + } + } + + /// + /// Gets a for . + /// + public MaterialPropertyBlock Properties + { + get + { + if (_props is null) + { + _props = new MaterialPropertyBlock(); + } + + return _props; + } + } + + /// + /// 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 + { + if (_fullscreenTriangleMesh == null) + { + _fullscreenTriangleMesh = new Mesh() + { + 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 } + }; + + _fullscreenTriangleMesh.UploadMeshData(true); + } + + return _fullscreenTriangleMesh; + } + set + { + _fullscreenTriangleMesh = value; + } + } + + /// + /// Gets or sets a value indicating whether is used for image effects rendering even when procedural rendering is available. + /// + public bool UseFullscreenTriangleMesh + { + get + { + 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 . + /// + 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, MaxWidth) - 1; + + if (_gaussSamples is null) + { + _gaussSamples = new float[MaxWidth][]; + } + + if (_gaussSamples[index] is null) + { + _gaussSamples[index] = GetGaussSamples(width, null); + } + + return _gaussSamples[index]; + } + + /// + /// Resets the resources to defaults. + /// + public void ResetToDefaults() + { + _renderShader = Shader.Find("Hidden/UnityFx/OutlineColor"); + _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 + + #region ScriptableObject + + private void OnValidate() + { + if (_renderMaterial) + { + _renderMaterial.shader = _renderShader; + } + + if (_outlineMaterial) + { + _outlineMaterial.shader = _outlineShader; + } + } + + #endregion + } +} diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader index 3862749..01d4da3 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/Outline.shader @@ -9,15 +9,13 @@ Shader "Hidden/UnityFx/Outline" #include "UnityCG.cginc" - CBUFFER_START(UnityPerMaterial) - float _Intensity; - int _Width; - float4 _Color; - CBUFFER_END - UNITY_DECLARE_SCREENSPACE_TEXTURE(_MaskTex); UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); float2 _MainTex_TexelSize; + + float4 _Color; + float _Intensity; + int _Width; float _GaussSamples[32]; #if SHADER_TARGET < 35 || _USE_DRAWMESH @@ -27,7 +25,6 @@ Shader "Hidden/UnityFx/Outline" v2f_img o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = float4(v.vertex.xy, UNITY_NEAR_CLIP_VALUE, 1); @@ -57,7 +54,6 @@ Shader "Hidden/UnityFx/Outline" v2f_img o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = GetFullScreenTriangleVertexPosition(v.vertexID); @@ -84,7 +80,7 @@ Shader "Hidden/UnityFx/Outline" float4 frag_h(v2f_img i) : SV_Target { - UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); float intensity = CalcIntensity(i.uv, float2(_MainTex_TexelSize.x, 0)); return float4(intensity, intensity, intensity, 1); @@ -92,7 +88,7 @@ Shader "Hidden/UnityFx/Outline" float4 frag_v(v2f_img i) : SV_Target { - UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); if (UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MaskTex, i.uv).r > 0) { @@ -115,7 +111,6 @@ Shader "Hidden/UnityFx/Outline" ZTest Always Lighting Off - // 0) HPass Pass { Name "HPass" @@ -131,7 +126,6 @@ Shader "Hidden/UnityFx/Outline" ENDHLSL } - // 1) VPass Pass { Name "VPassBlend" @@ -157,7 +151,6 @@ Shader "Hidden/UnityFx/Outline" ZTest Always Lighting Off - // 0) HPass Pass { Name "HPass" @@ -170,7 +163,6 @@ Shader "Hidden/UnityFx/Outline" ENDHLSL } - // 1) VPass Pass { Name "VPassBlend" diff --git a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader index d44c92b..b57def6 100644 --- a/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader +++ b/Outline.Core/Packages/UnityFx.Outline/Runtime/Shaders/OutlineColor.shader @@ -9,7 +9,7 @@ Shader "Hidden/UnityFx/OutlineColor" #include "UnityCG.cginc" - UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); + UNITY_DECLARE_TEX2D(_MainTex); float _Cutoff; v2f_img vert(appdata_img v) @@ -17,11 +17,11 @@ Shader "Hidden/UnityFx/OutlineColor" v2f_img o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_OUTPUT(v2f_img, o); - UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; + return o; } @@ -32,9 +32,9 @@ Shader "Hidden/UnityFx/OutlineColor" half4 frag_clip(v2f_img i) : SV_Target { - UNITY_SETUP_INSTANCE_ID(i); + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); - half4 c = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); + half4 c = UNITY_SAMPLE_TEX2D(_MainTex, i.uv); clip(c.a - _Cutoff); return 1; } @@ -50,6 +50,8 @@ Shader "Hidden/UnityFx/OutlineColor" Pass { + Name "Opaque" + HLSLPROGRAM #pragma multi_compile_instancing @@ -61,6 +63,8 @@ Shader "Hidden/UnityFx/OutlineColor" Pass { + Name "Transparent" + HLSLPROGRAM #pragma multi_compile_instancing diff --git a/Outline.Core/Packages/UnityFx.Outline/package.json b/Outline.Core/Packages/UnityFx.Outline/package.json index 9f478fc..5ffda80 100644 --- a/Outline.Core/Packages/UnityFx.Outline/package.json +++ b/Outline.Core/Packages/UnityFx.Outline/package.json @@ -1,6 +1,6 @@ { "name": "com.unityfx.outline", - "version": "0.8.1", + "version": "0.8.2", "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", diff --git a/Outline.Core/Packages/manifest.json b/Outline.Core/Packages/manifest.json index 2ca7506..7456bd4 100644 --- a/Outline.Core/Packages/manifest.json +++ b/Outline.Core/Packages/manifest.json @@ -1,7 +1,11 @@ { "dependencies": { - "com.unity.package-manager-ui": "2.0.8", + "com.unity.test-framework": "1.1.18", + "com.unity.ugui": "1.0.0", + "com.unity.xr.management": "3.2.16", + "com.unity.xr.mock-hmd": "1.2.0-preview.1", "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", diff --git a/Outline.Core/ProjectSettings/EditorBuildSettings.asset b/Outline.Core/ProjectSettings/EditorBuildSettings.asset index d5c9d72..aa698d7 100644 --- a/Outline.Core/ProjectSettings/EditorBuildSettings.asset +++ b/Outline.Core/ProjectSettings/EditorBuildSettings.asset @@ -8,4 +8,8 @@ EditorBuildSettings: - enabled: 1 path: Assets/Examples/SimplePerCamera/Outline.unity guid: e1f1f5e7ceb61b746b9f2016f0e53a93 - m_configObjects: {} + m_configObjects: + com.unity.xr.management.loader_settings: {fileID: 11400000, guid: 82aec1eceb005f64292d3e5f6108b4d6, + type: 2} + xr.sdk.mock-hmd.settings: {fileID: 11400000, guid: c3521b75f8cf98d4d90d8baa975f2345, + type: 2} diff --git a/Outline.Core/ProjectSettings/PackageManagerSettings.asset b/Outline.Core/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..9418901 --- /dev/null +++ b/Outline.Core/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,38 @@ +%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: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor:UnityEditor.PackageManager.UI:PackageManagerProjectSettings + m_ScopedRegistriesSettingsExpanded: 1 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_ErrorMessage: + m_Original: + m_Id: + m_Name: + m_Url: + m_Scopes: [] + m_IsDefault: 0 + m_Modified: 0 + m_Name: + m_Url: + m_Scopes: + - + m_SelectedScopeIndex: 0 diff --git a/Outline.Core/ProjectSettings/ProjectSettings.asset b/Outline.Core/ProjectSettings/ProjectSettings.asset index f23af1f..77eb64f 100644 --- a/Outline.Core/ProjectSettings/ProjectSettings.asset +++ b/Outline.Core/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 18 + serializedVersion: 20 productGUID: b364a1e52fff61f4dba1069ff72e90f9 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -52,7 +52,6 @@ PlayerSettings: m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - displayResolutionDialog: 1 iosUseCustomAppBackgroundBehavior: 0 iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 @@ -65,6 +64,7 @@ PlayerSettings: disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 0 + androidUseSwappy: 0 androidBlitType: 0 defaultIsNativeResolution: 1 macRetinaSupport: 1 @@ -79,11 +79,11 @@ PlayerSettings: usePlayerLog: 1 bakeCollisionMeshes: 0 forceSingleInstance: 0 + useFlipModelSwapchain: 1 resizableWindow: 0 useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 0 - graphicsJobs: 0 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -91,7 +91,6 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 - graphicsJobMode: 0 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 @@ -104,6 +103,7 @@ PlayerSettings: xboxOneMonoLoggingLevel: 0 xboxOneLoggingLevel: 1 xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 xboxOnePresentImmediateThreshold: 0 switchQueueCommandMemory: 1048576 switchQueueControlMemory: 16384 @@ -111,7 +111,13 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 + vulkanEnableLateAcquireNextImage: 0 m_SupportedAspectRatios: 4:3: 1 5:4: 1 @@ -125,7 +131,6 @@ PlayerSettings: m_HolographicPauseOnTrackingLoss: 1 xboxOneDisableKinectGpuReservation: 0 xboxOneEnable7thCore: 1 - isWsaHolographicRemotingEnabled: 0 vrSettings: cardboard: depthFormat: 0 @@ -140,6 +145,12 @@ PlayerSettings: hololens: depthFormat: 1 depthBufferSharingEnabled: 1 + lumin: + depthFormat: 0 + frameTiming: 2 + enableGLCache: 0 + glCacheMaxBlobSize: 524288 + glCacheMaxFileSize: 8388608 oculus: sharedDepthBuffer: 1 dashSupport: 1 @@ -147,9 +158,10 @@ PlayerSettings: protectedContext: 0 v2Signing: 0 enable360StereoCapture: 0 - protectGraphicsMemory: 0 + isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 useHDRDisplay: 0 + D3DHDRBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 @@ -158,7 +170,7 @@ PlayerSettings: applicationIdentifier: {} buildNumber: {} AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 16 + AndroidMinSdkVersion: 19 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -173,28 +185,16 @@ PlayerSettings: StripUnusedMeshComponents: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 9.0 + iOSTargetOSVersionString: 10.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 9.0 + tvOSTargetOSVersionString: 10.0 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} appleTVSplashScreen: {fileID: 0} appleTVSplashScreen2x: {fileID: 0} tvOSSmallIconLayers: [] @@ -231,6 +231,7 @@ PlayerSettings: metalEditorSupport: 1 metalAPIValidation: 1 iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: @@ -254,20 +255,60 @@ PlayerSettings: AndroidEnableTango: 0 androidEnableBanner: 1 androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 m_AndroidBanners: - width: 320 height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 - resolutionDialogBanner: {fileID: 0} + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] m_BuildTargetBatching: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: CloudRendering + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: [] - m_BuildTargetVRSettings: [] - m_BuildTargetEnableVuforiaSettings: [] + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - MockHMD openGLRequireES31: 0 openGLRequireES31AEP: 0 + openGLRequireES32: 0 m_TemplateCustomTags: {} mobileMTRendering: Android: 1 @@ -383,6 +424,7 @@ PlayerSettings: switchRatingsInt_9: 0 switchRatingsInt_10: 0 switchRatingsInt_11: 0 + switchRatingsInt_12: 0 switchLocalCommunicationIds_0: switchLocalCommunicationIds_1: switchLocalCommunicationIds_2: @@ -439,6 +481,7 @@ PlayerSettings: ps4ShareFilePath: ps4ShareOverlayImagePath: ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 ps4RemotePlayKeyMappingDir: @@ -451,6 +494,7 @@ PlayerSettings: ps4DownloadDataSize: 0 ps4GarlicHeapSize: 2048 ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ ps4pnSessions: 1 ps4pnPresence: 1 @@ -463,6 +507,7 @@ PlayerSettings: ps4UseResolutionFallback: 0 ps4ReprojectionSupport: 0 ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 ps4SocialScreenEnabled: 0 ps4ScriptOptimizationLevel: 2 ps4Audio3dVirtualSpeakerCount: 14 @@ -479,11 +524,15 @@ PlayerSettings: ps4disableAutoHideSplash: 0 ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 spritePackerPolicy: webGLMemorySize: 256 webGLExceptionSupport: 1 @@ -498,6 +547,7 @@ PlayerSettings: webGLCompressionFormat: 1 webGLLinkerTarget: 1 webGLThreadsSupport: 0 + webGLWasmStreaming: 0 scriptingDefineSymbols: {} platformArchitecture: {} scriptingBackend: {} @@ -507,6 +557,8 @@ PlayerSettings: allowUnsafeCode: 0 additionalIl2CppArgs: scriptingRuntimeVersion: 1 + gcIncremental: 0 + gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} m_RenderingPath: 1 m_MobileRenderingPath: 1 @@ -537,7 +589,6 @@ PlayerSettings: metroFTAName: metroFTAFileTypes: [] metroProtocolName: - metroCompilationOverrides: 1 XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -562,8 +613,8 @@ PlayerSettings: XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - xboxOneScriptCompiler: 0 XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: vrEditorSettings: daydream: daydreamIconForeground: {fileID: 0} @@ -575,18 +626,11 @@ PlayerSettings: m_PortalFolderPath: luminCert: m_CertPath: - m_PrivateKeyPath: + m_SignPackage: 1 luminIsChannelApp: 0 luminVersion: m_VersionCode: 1 m_VersionName: - facebookSdkVersion: - facebookAppId: - facebookCookies: 1 - facebookLogging: 1 - facebookStatus: 1 - facebookXfbml: 0 - facebookFrictionlessRequests: 1 apiCompatibilityLevel: 6 cloudProjectId: framebufferDepthMemorylessMode: 0 diff --git a/Outline.Core/ProjectSettings/ProjectVersion.txt b/Outline.Core/ProjectSettings/ProjectVersion.txt index 895cee8..66132d0 100644 --- a/Outline.Core/ProjectSettings/ProjectVersion.txt +++ b/Outline.Core/ProjectSettings/ProjectVersion.txt @@ -1 +1,2 @@ -m_EditorVersion: 2018.4.13f1 +m_EditorVersion: 2019.4.13f1 +m_EditorVersionWithRevision: 2019.4.13f1 (518737b1de84) diff --git a/Outline.Core/ProjectSettings/XRPackageSettings.asset b/Outline.Core/ProjectSettings/XRPackageSettings.asset new file mode 100644 index 0000000..e6eb497 --- /dev/null +++ b/Outline.Core/ProjectSettings/XRPackageSettings.asset @@ -0,0 +1,6 @@ +{ + "m_Settings": [ + "RemoveLegacyInputHelpersForReload", + "ShouldQueryLegacyPackageRemoval" + ] +} \ No newline at end of file diff --git a/Outline.Core/ProjectSettings/XRSettings.asset b/Outline.Core/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/Outline.Core/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 diff --git a/Outline.URP/Assets/Example/OutlineLayerCollection.asset b/Outline.URP/Assets/Example/OutlineLayerCollection.asset index b09ddfe..c8f68fb 100644 --- a/Outline.URP/Assets/Example/OutlineLayerCollection.asset +++ b/Outline.URP/Assets/Example/OutlineLayerCollection.asset @@ -18,15 +18,18 @@ MonoBehaviour: _outlineColor: {r: 1, g: 0, b: 0, a: 1} _outlineWidth: 25 _outlineIntensity: 2 + _outlineAlphaCutoff: 0.9 _outlineMode: 1 _name: _enabled: 1 - _settings: _outlineSettings: {fileID: 0} _outlineColor: {r: 0, g: 1, b: 0.060156345, a: 1} - _outlineWidth: 7 + _outlineWidth: 16 _outlineIntensity: 2 + _outlineAlphaCutoff: 0.9 _outlineMode: 1 _name: _enabled: 1 - _layerMask: 0 + _layerMask: 2 + _mergeLayerObjects: 0 diff --git a/Outline.URP/Assets/Example/TestScene.unity b/Outline.URP/Assets/Example/TestScene.unity index 20e3d19..ae02d6c 100644 --- a/Outline.URP/Assets/Example/TestScene.unity +++ b/Outline.URP/Assets/Example/TestScene.unity @@ -248,7 +248,7 @@ MonoBehaviour: _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} _content: - Go: {fileID: 958073178} - LayerIndex: 0 + LayerIndex: 1 --- !u!81 &925532358 AudioListener: m_ObjectHideFlags: 0 @@ -312,6 +312,8 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - {fileID: 958073179} + - {fileID: 1993989802} + - {fileID: 1200460296} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -331,7 +333,6 @@ MonoBehaviour: m_RequiresDepthTextureOption: 2 m_RequiresOpaqueTextureOption: 2 m_CameraType: 0 - m_CameraOutput: 0 m_Cameras: [] m_RendererIndex: -1 m_VolumeLayerMask: @@ -343,6 +344,7 @@ MonoBehaviour: m_AntialiasingQuality: 2 m_StopNaN: 0 m_Dithering: 0 + m_ClearDepth: 1 m_RequiresDepthTexture: 0 m_RequiresColorTexture: 0 m_Version: 2 @@ -440,3 +442,189 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 958073178} m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1200460295 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1200460296} + - component: {fileID: 1200460299} + - component: {fileID: 1200460298} + - component: {fileID: 1200460297} + m_Layer: 9 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1200460296 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200460295} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.22, y: 0, z: 3.01} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 925532360} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1200460297 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200460295} + 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 &1200460298 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200460295} + 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: 31321ba15b8f8eb4c954353edc038b1d, 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 &1200460299 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200460295} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1993989801 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1993989802} + - component: {fileID: 1993989805} + - component: {fileID: 1993989804} + - component: {fileID: 1993989803} + m_Layer: 8 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1993989802 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1993989801} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0.78, y: 0, z: 3.58} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 925532360} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &1993989803 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1993989801} + 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 &1993989804 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1993989801} + 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: 31321ba15b8f8eb4c954353edc038b1d, 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 &1993989805 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1993989801} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset index 9540d39..d6be7bc 100644 --- a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset.asset @@ -44,6 +44,7 @@ MonoBehaviour: m_SupportsDynamicBatching: 0 m_MixedLightingSupported: 1 m_DebugLevel: 0 + m_PostProcessingFeatureSet: 0 m_ColorGradingMode: 0 m_ColorGradingLutSize: 32 m_ShadowType: 1 diff --git a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset index df60544..dfe5a30 100644 --- a/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset +++ b/Outline.URP/Assets/URP/UniversalRenderPipelineAsset_Renderer.asset @@ -12,8 +12,20 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: dd37d03d18ee9584d881763c34816b35, type: 3} m_Name: Outline m_EditorClassIdentifier: - _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, type: 2} + m_Active: 1 + _outlineResources: {fileID: 11400000, guid: 231d88937a104094b8e4e0fdb8d2e77b, type: 2} _outlineLayers: {fileID: 11400000, guid: 059d229f23209a74687769672d1084b8, type: 2} + _outlineSettings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 0, a: 1} + _outlineWidth: 11 + _outlineIntensity: 2 + _outlineAlphaCutoff: 0.9 + _outlineMode: 1 + _outlineLayerMask: + serializedVersion: 2 + m_Bits: 256 + _renderPassEvent: 400 --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 @@ -28,6 +40,8 @@ MonoBehaviour: m_EditorClassIdentifier: m_RendererFeatures: - {fileID: -2278397774415627597} + - {fileID: 7677070003599340959} + m_RendererFeatureMap: 9f7558507e6e8a6a postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} shaders: blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} @@ -49,3 +63,30 @@ MonoBehaviour: passOperation: 0 failOperation: 0 zFailOperation: 0 + m_ShadowTransparentReceive: 1 +--- !u!114 &7677070003599340959 +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: Outline2 + m_EditorClassIdentifier: + m_Active: 1 + _outlineResources: {fileID: 11400000, guid: 231d88937a104094b8e4e0fdb8d2e77b, type: 2} + _outlineLayers: {fileID: 0} + _outlineSettings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 0.87176275, a: 1} + _outlineWidth: 4 + _outlineIntensity: 2 + _outlineAlphaCutoff: 0.9 + _outlineMode: 0 + _outlineLayerMask: + serializedVersion: 2 + m_Bits: 512 + _renderPassEvent: 400 diff --git a/Outline.URP/Assets/XR.meta b/Outline.URP/Assets/XR.meta new file mode 100644 index 0000000..3890fc1 --- /dev/null +++ b/Outline.URP/Assets/XR.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 781de6db0bab45440927a6ee375e1f4d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/XR/Loaders.meta b/Outline.URP/Assets/XR/Loaders.meta new file mode 100644 index 0000000..968b0fc --- /dev/null +++ b/Outline.URP/Assets/XR/Loaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d639b41f55f4dca479b013c086776a76 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.asset b/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.asset new file mode 100644 index 0000000..f7b4662 --- /dev/null +++ b/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.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: 0660e8fc444734757ae6f6c40c2d33a0, type: 3} + m_Name: Mock HMD Loader + m_EditorClassIdentifier: diff --git a/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.asset.meta b/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.asset.meta new file mode 100644 index 0000000..a8715ad --- /dev/null +++ b/Outline.URP/Assets/XR/Loaders/Mock HMD Loader.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b47a0f7b0527ae44db15a0764dff21b2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/XR/Settings.meta b/Outline.URP/Assets/XR/Settings.meta new file mode 100644 index 0000000..ef75e74 --- /dev/null +++ b/Outline.URP/Assets/XR/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d8c6947503a4eb64ea86e3f9ccb51ee9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset b/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset new file mode 100644 index 0000000..0acbf62 --- /dev/null +++ b/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset @@ -0,0 +1,15 @@ +%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: c8bf066bf8a4947a1be502d267edb82f, type: 3} + m_Name: Mock HMD Build Settings + m_EditorClassIdentifier: + renderMode: 1 diff --git a/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset.meta b/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset.meta new file mode 100644 index 0000000..a3a4e75 --- /dev/null +++ b/Outline.URP/Assets/XR/Settings/Mock HMD Build Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f4f6d6934c0789498be8661b6841eb3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Assets/XR/XRGeneralSettings.asset b/Outline.URP/Assets/XR/XRGeneralSettings.asset new file mode 100644 index 0000000..681990a --- /dev/null +++ b/Outline.URP/Assets/XR/XRGeneralSettings.asset @@ -0,0 +1,48 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-1144483682558570013 +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: f4c3631f5e58749a59194e0cf6baf6d5, type: 3} + m_Name: Standalone Providers + m_EditorClassIdentifier: + m_RequiresSettingsUpdate: 0 + m_AutomaticLoading: 0 + m_AutomaticRunning: 0 + m_Loaders: + - {fileID: 11400000, guid: b47a0f7b0527ae44db15a0764dff21b2, type: 2} +--- !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: d2dc886499c26824283350fa532d087d, type: 3} + m_Name: XRGeneralSettings + m_EditorClassIdentifier: + Keys: 01000000 + Values: + - {fileID: 4691281026663128798} +--- !u!114 &4691281026663128798 +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: d236b7d11115f2143951f1e14045df39, type: 3} + m_Name: Standalone Settings + m_EditorClassIdentifier: + m_LoaderManagerInstance: {fileID: -1144483682558570013} + m_InitManagerOnStart: 1 diff --git a/Outline.URP/Assets/XR/XRGeneralSettings.asset.meta b/Outline.URP/Assets/XR/XRGeneralSettings.asset.meta new file mode 100644 index 0000000..ad707c1 --- /dev/null +++ b/Outline.URP/Assets/XR/XRGeneralSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eda8954ba10e80042a18b4c29190bbd4 +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 index 1935a50..1be9d9f 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md +++ b/Outline.URP/Packages/UnityFx.Outline.URP/CHANGELOG.md @@ -3,6 +3,16 @@ 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] - 2020.11.10 + +### Added +- Added URP-specific shader versions. +- Added URP layer-based outline rendering ([#9](https://github.com/Arvtesh/UnityFx.Outline/issues/9)). +- Added support for URP Single Pass Instanced XR rendering ([#13](https://github.com/Arvtesh/UnityFx.Outline/issues/13)). + +### Fixed +- Fixed URP outlines rendering issue in Unity 2020.2 ([#21](https://github.com/Arvtesh/UnityFx.Outline/issues/21)). + ## [0.1.0] - 2020.05.30 ### Added diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs.meta new file mode 100644 index 0000000..5e39502 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66d913784d1955a4fbf8279b0a0f5d7b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset new file mode 100644 index 0000000..7a704f1 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset @@ -0,0 +1,17 @@ +%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: b503341e0a514e3489c4851727e68257, type: 3} + m_Name: OutlineResources.URP + m_EditorClassIdentifier: + _renderShader: {fileID: 4800000, guid: 2140fc327e711b549bc9fe301e6f4621, type: 3} + _outlineShader: {fileID: 4800000, guid: da6518c999b52e743bff80732b460ff4, type: 3} + _enableInstancing: 0 diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset.meta new file mode 100644 index 0000000..265eebe --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Prefabs/OutlineResources.URP.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 231d88937a104094b8e4e0fdb8d2e77b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + 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 index 4e2d956..39954df 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlineFeature.cs @@ -1,73 +1,88 @@ -// 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). - /// - /// - /// 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 - { - #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 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(this) - { - renderPassEvent = RenderPassEvent.AfterRenderingSkybox - }; - } - - /// - public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) - { - if (_outlineResources && _outlineResources.IsValid && _outlineLayers) - { - _outlinePass.Setup(renderer.cameraColorTarget, renderer.cameraDepth); - renderer.EnqueuePass(_outlinePass); - } - } - - #endregion - } -} +// 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). + /// + /// + /// 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 + { + #region data + +#pragma warning disable 0649 + + [SerializeField, Tooltip(OutlineResources.OutlineResourcesTooltip)] + private OutlineResources _outlineResources; + [SerializeField, Tooltip(OutlineResources.OutlineLayerCollectionTooltip)] + private OutlineLayerCollection _outlineLayers; + [SerializeField] + private OutlineSettingsWithLayerMask _outlineSettings; + [SerializeField] + private RenderPassEvent _renderPassEvent = RenderPassEvent.AfterRenderingSkybox; + +#pragma warning restore 0649 + + private OutlinePass _outlinePass; + + private string _featureName; + + #endregion + + #region interface + + internal OutlineResources OutlineResources => _outlineResources; + + internal OutlineLayerCollection OutlineLayers => _outlineLayers; + + internal IOutlineSettings OutlineSettings => _outlineSettings; + + internal int OutlineLayerMask => _outlineSettings.OutlineLayerMask; + + internal string FeatureName => _featureName; + + #endregion + + #region ScriptableRendererFeature + + /// + public override void Create() + { + if (_outlineSettings != null) + { + _featureName = OutlineResources.EffectName + '-' + _outlineSettings.OutlineLayerMask; + } + else + { + _featureName = OutlineResources.EffectName; + } + + _outlinePass = new OutlinePass(this) + { + renderPassEvent = _renderPassEvent + }; + } + + /// + public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) + { + if (_outlineResources && _outlineResources.IsValid) + { + _outlinePass.Setup(renderer); + renderer.EnqueuePass(_outlinePass); + } + } + + #endregion + } +} 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 cb0f643..6c8367d 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 @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: - - _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, + - _outlineResources: {fileID: 11400000, guid: 231d88937a104094b8e4e0fdb8d2e77b, type: 2} - _outlineLayers: {instanceID: 0} executionOrder: 0 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 154fde4..977f49f 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs @@ -6,6 +6,7 @@ using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; +using UnityEngine.XR; namespace UnityFx.Outline.URP { @@ -13,44 +14,68 @@ internal class OutlinePass : ScriptableRenderPass { private readonly OutlineFeature _feature; private readonly List _renderObjects = new List(); + private readonly List _shaderTagIdList = new List() { new ShaderTagId("UniversalForward") }; - private RenderTargetIdentifier _rt; - private RenderTargetIdentifier _depth; - private RenderTextureDescriptor _rtDesc; + private ScriptableRenderer _renderer; public OutlinePass(OutlineFeature feature) { _feature = feature; } - public void Setup(RenderTargetIdentifier rt, RenderTargetIdentifier depth) + public void Setup(ScriptableRenderer renderer) { - _rt = rt; - _depth = depth; - } - - public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) - { - _rtDesc = cameraTextureDescriptor; + _renderer = renderer; } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { - var cmd = CommandBufferPool.Get(OutlineResources.EffectName); + var outlineResources = _feature.OutlineResources; + var outlineSettings = _feature.OutlineSettings; - using (var renderer = new OutlineRenderer(cmd, _feature.OutlineResources, _rt, _depth, _rtDesc)) + if (_feature.OutlineLayerMask != 0) { - _renderObjects.Clear(); - _feature.OutlineLayers.GetRenderObjects(_renderObjects); + var cmd = CommandBufferPool.Get(_feature.FeatureName); + var filteringSettings = new FilteringSettings(RenderQueueRange.all, _feature.OutlineLayerMask); + var renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing); + var sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags; + var drawingSettings = CreateDrawingSettings(_shaderTagIdList, ref renderingData, sortingCriteria); + + drawingSettings.enableDynamicBatching = false; + drawingSettings.overrideMaterial = outlineResources.RenderMaterial; - foreach (var obj in _renderObjects) + using (var renderer = new OutlineRenderer(cmd, outlineResources, _renderer.cameraColorTarget, _renderer.cameraDepth, renderingData.cameraData.cameraTargetDescriptor)) { - renderer.Render(obj); + renderer.RenderObjectClear(outlineSettings.OutlineRenderMode); + context.ExecuteCommandBuffer(cmd); + cmd.Clear(); + + context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings, ref renderStateBlock); + renderer.RenderOutline(outlineSettings); } + + context.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); } - context.ExecuteCommandBuffer(cmd); - CommandBufferPool.Release(cmd); + if (_feature.OutlineLayers) + { + var cmd = CommandBufferPool.Get(OutlineResources.EffectName); + + using (var renderer = new OutlineRenderer(cmd, outlineResources, _renderer.cameraColorTarget, _renderer.cameraDepth, renderingData.cameraData.cameraTargetDescriptor)) + { + _renderObjects.Clear(); + _feature.OutlineLayers.GetRenderObjects(_renderObjects); + + foreach (var obj in _renderObjects) + { + renderer.Render(obj); + } + } + + context.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + } } } } 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 index 869a028..5c90ec9 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Scripts/OutlinePass.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b3a7683689e159546992ec0f529efcca +guid: 7fda4bd4356b87c4a93e27fbc5390d5f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders.meta new file mode 100644 index 0000000..b6518ed --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e29d2be8edefda438a2865a7030dad6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader new file mode 100644 index 0000000..017dfe8 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader @@ -0,0 +1,197 @@ +// 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 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.URP" +{ + HLSLINCLUDE + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + + TEXTURE2D_X(_MaskTex); + SAMPLER(sampler_MaskTex); + + TEXTURE2D_X(_MainTex); + SAMPLER(sampler_MainTex); + float2 _MainTex_TexelSize; + + float4 _Color; + float _Intensity; + int _Width; + float _GaussSamples[32]; + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 uv : TEXCOORD0; + UNITY_VERTEX_OUTPUT_STEREO + }; + +#if SHADER_TARGET < 35 || _USE_DRAWMESH + + struct Attributes + { + float4 positionOS : POSITION; + float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + Varyings VertexSimple(Attributes input) + { + Varyings output = (Varyings)0; + + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + float4 pos = TransformObjectToHClip(input.positionOS.xyz); + + output.positionCS = float4(pos.xy, UNITY_NEAR_CLIP_VALUE, 1); + output.uv = ComputeScreenPos(output.positionCS).xy; + + return output; + } + +#else + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + Varyings VertexSimple(Attributes input) + { + Varyings output = (Varyings)0; + + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + output.uv = GetFullScreenTriangleTexCoord(input.vertexID); + + return output; + } + +#endif + + float CalcIntensity(float2 uv, float2 offset) + { + 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 = -_Width; k <= _Width; ++k) + { + intensity += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, uv + k * offset).r * _GaussSamples[abs(k)]; + } + + return intensity; + } + + float4 FragmentH(Varyings i) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + + float2 uv = UnityStereoTransformScreenSpaceTex(i.uv); + float intensity = CalcIntensity(uv, float2(_MainTex_TexelSize.x, 0)); + return float4(intensity, intensity, intensity, 1); + } + + float4 FragmentV(Varyings i) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + + float2 uv = UnityStereoTransformScreenSpaceTex(i.uv); + + if (SAMPLE_TEXTURE2D_X(_MaskTex, sampler_MaskTex, uv).r > 0) + { + // TODO: Avoid discard/clip to improve performance on mobiles. + discard; + } + + float intensity = CalcIntensity(uv, float2(0, _MainTex_TexelSize.y)); + intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity; + return float4(_Color.rgb, saturate(_Color.a * intensity)); + } + + ENDHLSL + + // SM3.5+ + SubShader + { + Tags{ "RenderPipeline" = "UniversalPipeline" } + + Cull Off + ZWrite Off + ZTest Always + Lighting Off + + Pass + { + Name "HPass" + + HLSLPROGRAM + + #pragma target 3.5 + #pragma multi_compile_instancing + #pragma shader_feature_local _USE_DRAWMESH + #pragma vertex VertexSimple + #pragma fragment FragmentH + + ENDHLSL + } + + Pass + { + Name "VPassBlend" + Blend SrcAlpha OneMinusSrcAlpha + + HLSLPROGRAM + + #pragma target 3.5 + #pragma multi_compile_instancing + #pragma shader_feature_local _USE_DRAWMESH + #pragma vertex VertexSimple + #pragma fragment FragmentV + + ENDHLSL + } + } + + // SM2.0 + SubShader + { + Tags { "RenderPipeline" = "UniversalPipeline" } + + Cull Off + ZWrite Off + ZTest Always + Lighting Off + + Pass + { + Name "HPass" + + HLSLPROGRAM + + #pragma vertex VertexSimple + #pragma fragment FragmentH + + ENDHLSL + } + + Pass + { + Name "VPassBlend" + Blend SrcAlpha OneMinusSrcAlpha + + HLSLPROGRAM + + #pragma vertex VertexSimple + #pragma fragment FragmentV + + ENDHLSL + } + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader.meta new file mode 100644 index 0000000..51c28b4 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/Outline.URP.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: da6518c999b52e743bff80732b460ff4 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader new file mode 100644 index 0000000..c7c7969 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader @@ -0,0 +1,66 @@ +// Copyright (C) 2019-2020 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +// Renders everything with while color. +// Modified version of 'Custom/DrawSimple' shader taken from https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/. +Shader "Hidden/UnityFx/OutlineColor.URP" +{ + HLSLINCLUDE + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl" + + TEXTURE2D(_MainTex); + SAMPLER(sampler_MainTex); + + half4 FragmentSimple(Varyings input) : SV_Target + { + return 1; + } + + half4 FragmentAlphaTest(Varyings input) : SV_Target + { + half4 c = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); + AlphaDiscard(c.a, 1); + return 1; + } + + ENDHLSL + + SubShader + { + Tags { "RenderPipeline"="UniversalPipeline" } + + Cull Off + ZWrite Off + ZTest LEqual + Lighting Off + + Pass + { + Name "Opaque" + + HLSLPROGRAM + + #pragma multi_compile_instancing + #pragma vertex Vert + #pragma fragment FragmentSimple + + ENDHLSL + } + + Pass + { + Name "Transparent" + + HLSLPROGRAM + + #pragma shader_feature _ALPHATEST_ON + #pragma multi_compile_instancing + #pragma vertex Vert + #pragma fragment FragmentAlphaTest + + ENDHLSL + } + } +} diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader.meta b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader.meta new file mode 100644 index 0000000..8272b33 --- /dev/null +++ b/Outline.URP/Packages/UnityFx.Outline.URP/Runtime/Shaders/OutlineColor.URP.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2140fc327e711b549bc9fe301e6f4621 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Outline.URP/Packages/UnityFx.Outline.URP/package.json b/Outline.URP/Packages/UnityFx.Outline.URP/package.json index 9c6ce85..c6e50c4 100644 --- a/Outline.URP/Packages/UnityFx.Outline.URP/package.json +++ b/Outline.URP/Packages/UnityFx.Outline.URP/package.json @@ -1,11 +1,11 @@ { "name": "com.unityfx.outline.urp", - "version": "0.1.0", + "version": "0.2.0", "displayName": "Outline toolkit (URP)", "description": "This package contains configurable outline implementation for Universal Render Pipeline.", - "unity": "2019.3", + "unity": "2019.4", "dependencies": { - "com.unityfx.outline": "0.8.0", + "com.unityfx.outline": "0.8.2", "com.unity.render-pipelines.universal": "7.0.0" }, "keywords": [ diff --git a/Outline.URP/Packages/manifest.json b/Outline.URP/Packages/manifest.json index 7c56d24..73115ea 100644 --- a/Outline.URP/Packages/manifest.json +++ b/Outline.URP/Packages/manifest.json @@ -1,6 +1,8 @@ { "dependencies": { - "com.unity.render-pipelines.universal": "7.1.8", + "com.unity.render-pipelines.universal": "7.3.1", + "com.unity.xr.management": "3.2.16", + "com.unity.xr.mock-hmd": "1.2.0-preview.1", "com.unityfx.outline": "file:../../Outline.Core/Packages/UnityFx.Outline", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", diff --git a/Outline.URP/ProjectSettings/EditorBuildSettings.asset b/Outline.URP/ProjectSettings/EditorBuildSettings.asset index 0147887..699bbe9 100644 --- a/Outline.URP/ProjectSettings/EditorBuildSettings.asset +++ b/Outline.URP/ProjectSettings/EditorBuildSettings.asset @@ -5,4 +5,8 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_Scenes: [] - m_configObjects: {} + m_configObjects: + com.unity.xr.management.loader_settings: {fileID: 11400000, guid: eda8954ba10e80042a18b4c29190bbd4, + type: 2} + xr.sdk.mock-hmd.settings: {fileID: 11400000, guid: 9f4f6d6934c0789498be8661b6841eb3, + type: 2} diff --git a/Outline.URP/ProjectSettings/PackageManagerSettings.asset b/Outline.URP/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..9418901 --- /dev/null +++ b/Outline.URP/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,38 @@ +%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: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor:UnityEditor.PackageManager.UI:PackageManagerProjectSettings + m_ScopedRegistriesSettingsExpanded: 1 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_ErrorMessage: + m_Original: + m_Id: + m_Name: + m_Url: + m_Scopes: [] + m_IsDefault: 0 + m_Modified: 0 + m_Name: + m_Url: + m_Scopes: + - + m_SelectedScopeIndex: 0 diff --git a/Outline.URP/ProjectSettings/ProjectVersion.txt b/Outline.URP/ProjectSettings/ProjectVersion.txt index 798259b..66132d0 100644 --- a/Outline.URP/ProjectSettings/ProjectVersion.txt +++ b/Outline.URP/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2019.3.0f6 -m_EditorVersionWithRevision: 2019.3.0f6 (27ab2135bccf) +m_EditorVersion: 2019.4.13f1 +m_EditorVersionWithRevision: 2019.4.13f1 (518737b1de84) diff --git a/Outline.URP/ProjectSettings/TagManager.asset b/Outline.URP/ProjectSettings/TagManager.asset index 1c92a78..832f78b 100644 --- a/Outline.URP/ProjectSettings/TagManager.asset +++ b/Outline.URP/ProjectSettings/TagManager.asset @@ -13,8 +13,8 @@ TagManager: - UI - - - - - - + - OutlineLayer + - OutlineLayer2 - - - diff --git a/Outline.URP/ProjectSettings/XRPackageSettings.asset b/Outline.URP/ProjectSettings/XRPackageSettings.asset new file mode 100644 index 0000000..7e791e1 --- /dev/null +++ b/Outline.URP/ProjectSettings/XRPackageSettings.asset @@ -0,0 +1,5 @@ +{ + "m_Settings": [ + "RemoveLegacyInputHelpersForReload" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 0c4244c..1a4c9c4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ Npm (HDRP) | TODO **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).** +**Compatible with [Universal Render Pipeline](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.1/manual/index.html).**
+**Compatible with [XR](https://docs.unity3d.com/Manual/XR.html) (Multi Pass, Single Pass Instanced).** **Please ask any questions and leave feedback at the [Unity forums](https://forum.unity.com/threads/screen-space-outline-effect-for-unity-free.836908/).** @@ -67,8 +68,8 @@ Npm core package is available at [npmjs.com](https://www.npmjs.com/package/com.u } ], "dependencies": { - "com.unityfx.outline": "0.8.1", - "com.unityfx.outline.urp": "0.1.0", + "com.unityfx.outline": "0.8.2", + "com.unityfx.outline.urp": "0.2.0", } } ``` @@ -204,7 +205,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) -Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources and layer collection are set): +Install the package, add `OutlineFeature` to `ScriptableRendererData`'s list of features. Configure the feature parameters (make sure outline resources reference is set). Outline objects can be selected by layer or explixitly using `OutlineLayerCollection`: ![URP outline settings](Docs/UrpOutlineSettings.png "URP outline settings")