/// <summary> /// Renders outline around a single object. /// </summary> /// <param name="renderer">A <see cref="Renderer"/> representing an object to be outlined.</param> /// <param name="settings">Outline settings.</param> /// <param name="sampleName">Optional name of the sample (visible in profiler).</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(OutlineRenderObject)"/> /// <seealso cref="Render(IReadOnlyList{Renderer}, IOutlineSettings, string)"/> 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); }
private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings) { // Setup shader parameter overrides. var props = resources.VPassBlendProperties; props.SetFloat(resources.WidthId, settings.OutlineWidth); props.SetColor(resources.ColorId, settings.OutlineColor); if (settings.OutlineMode == OutlineMode.Solid) { props.SetFloat(resources.IntensityId, SolidIntensity); } else { props.SetFloat(resources.IntensityId, settings.OutlineIntensity); } // Set source texture as _MainTex to match Blit behavior. _commandBuffer.SetGlobalTexture(_mainRtId, _source); // Set destination texture as render target. #if UNITY_2018_2_OR_NEWER _commandBuffer.SetRenderTarget(_destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); #else _commandBuffer.SetRenderTarget(_destination); #endif // Blit fullscreen triangle. _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, 0, props); }
/// <summary> /// Renders outline around a single object. This version allows enumeration of <paramref name="renderers"/> with no GC allocations. /// </summary> /// <param name="renderers">One or more renderers representing a single object to be outlined.</param> /// <param name="settings">Outline settings.</param> /// <param name="sampleName">Optional name of the sample (visible in profiler).</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(OutlineRenderObject)"/> /// <seealso cref="Render(Renderer, IOutlineSettings, string)"/> public void Render(IReadOnlyList <Renderer> 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); } }
/// <summary> /// Renders outline around a single object. This version allows enumeration of <paramref name="renderers"/> with no GC allocations. /// </summary> /// <param name="renderers">One or more renderers representing a single object to be outlined.</param> /// <param name="settings">Outline settings.</param> /// <param name="sampleName">Optional name of the sample (visible in profiler).</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(OutlineRenderObject)"/> /// <seealso cref="Render(Renderer, IOutlineSettings, string)"/> public void Render(IReadOnlyList <Renderer> 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); } }
/// <summary> /// Renders outline around a single <paramref name="renderer"/>. /// </summary> /// <param name="renderer">A <see cref="Renderer"/> representing an object to be outlined.</param> /// <param name="settings">Outline settings.</param> /// <param name="sampleName">Optional name of the sample (visible in profiler).</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(IReadOnlyList{Renderer}, IOutlineSettings, string)"/> 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)); } // NOTE: Remove BeginSample/EndSample for now (https://github.com/Arvtesh/UnityFx.Outline/issues/44). //if (string.IsNullOrEmpty(sampleName)) //{ // sampleName = renderer.name; //} // NOTE: Remove this for now (https://github.com/Arvtesh/UnityFx.Outline/issues/44). //_commandBuffer.BeginSample(sampleName); { RenderObjectClear(settings.OutlineRenderMode); DrawRenderer(renderer, settings); RenderOutline(settings); } //_commandBuffer.EndSample(sampleName); }
/// <summary> /// Renders outline. Do not use if not sure. /// </summary> 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); } }
/// <summary> /// Renders outline around multiple <paramref name="renderers"/>. /// </summary> /// <param name="renderers">One or more renderers representing a single object to be outlined.</param> /// <param name="settings">Outline settings.</param> /// <param name="sampleName">Optional name of the sample (visible in profiler).</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(Renderer, IOutlineSettings, string)"/> public void Render(IReadOnlyList <Renderer> 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) { // NOTE: Remove BeginSample/EndSample for now (https://github.com/Arvtesh/UnityFx.Outline/issues/44). //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); } }
private void RenderObject(IOutlineSettings settings, IReadOnlyList <Renderer> renderers) { RenderObjectClear(settings.OutlineRenderMode); for (var i = 0; i < renderers.Count; ++i) { DrawRenderer(renderers[i], settings); } }
public static bool Equals(IOutlineSettings lhs, IOutlineSettings rhs) { if (lhs == null || rhs == null) { return(false); } return(lhs.OutlineColor == rhs.OutlineColor && lhs.OutlineWidth == rhs.OutlineWidth && lhs.OutlineRenderMode == rhs.OutlineRenderMode && Mathf.Approximately(lhs.OutlineIntensity, rhs.OutlineIntensity)); }
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, _hPassId, mat, props); // VPassBlend _commandBuffer.SetRenderTarget(_rt, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store); Blit(_commandBuffer, _hPassRtId, _resources, _vPassId, mat, props); }
/// <summary> /// Resets materials state. /// </summary> /// <seealso cref="SetColor(Color)"/> /// <seealso cref="SetWidth(int)"/> /// <seealso cref="SetMode(OutlineMode)"/> public void Reset(IOutlineSettings settings) { ThrowIfDisposed(); if (settings == null) { throw new ArgumentNullException("settings"); } SetColor(settings.OutlineColor); SetIntensity(settings.OutlineIntensity); SetWidth(settings.OutlineWidth); SetMode(settings.OutlineMode); UpdateGaussSamples(); }
private void RenderObject(IOutlineSettings settings, Renderer renderer) { RenderObjectClear(settings.OutlineRenderMode); if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. renderer.GetSharedMaterials(_resources.TmpMaterials); for (var i = 0; i < _resources.TmpMaterials.Count; ++i) { _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i); } } }
private void DrawRenderer(Renderer renderer, IOutlineSettings settings) { if (renderer && renderer.enabled && renderer.isVisible && renderer.gameObject.activeInHierarchy) { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. renderer.GetSharedMaterials(_resources.TmpMaterials); if (_resources.TmpMaterials.Count > 0) { if (settings.IsAlphaTestingEnabled()) { 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, OutlineResources.RenderShaderAlphaTestPassId); } } else { for (var i = 0; i < _resources.TmpMaterials.Count; ++i) { _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, i, OutlineResources.RenderShaderDefaultPassId); } } } else { // NOTE: No materials set for renderer means we should still render outline for it. _commandBuffer.DrawRenderer(renderer, _resources.RenderMaterial, 0, OutlineResources.RenderShaderDefaultPassId); } } }
private void RenderHPass(OutlineResources resources, IOutlineSettings settings) { // Setup shader parameter overrides. var props = resources.HPassProperties; props.SetFloat(resources.WidthId, settings.OutlineWidth); // Set source texture as _MainTex to match Blit behavior. _commandBuffer.SetGlobalTexture(_mainRtId, _maskRtId); // Set destination texture as render target. #if UNITY_2018_2_OR_NEWER _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); #else _commandBuffer.SetRenderTarget(_hPassRtId); #endif // Blit fullscreen triangle. _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, 0, props); }
private void RenderObject(OutlineResources resources, IOutlineSettings settings, IEnumerable <Renderer> renderers) { RenderObjectClear((settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0); // NOTE: Calling IEnumerable.GetEnumerator() triggers GC.Alloc. foreach (var r in renderers) { if (r && r.enabled && r.gameObject.activeInHierarchy) { // NOTE: Accessing Renderer.sharedMaterials triggers GC.Alloc. That's why we use a temporary // list of materials, cached with the outline resources. r.GetSharedMaterials(resources.TmpMaterials); for (var j = 0; j < resources.TmpMaterials.Count; ++j) { _commandBuffer.DrawRenderer(r, resources.RenderMaterial, j); } } } }
public static void Render(IOutlineSettings settings, UnityEngine.Object undoContext) { var color = EditorGUILayout.ColorField("Color", settings.OutlineColor); if (settings.OutlineColor != color) { Undo.RecordObject(undoContext, "Color"); settings.OutlineColor = color; } var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); if (settings.OutlineWidth != width) { Undo.RecordObject(undoContext, "Width"); settings.OutlineWidth = width; } var blurred = EditorGUILayout.Toggle("Blurred", settings.OutlineMode == OutlineMode.Blurred); if (blurred) { EditorGUI.indentLevel += 1; var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); if (!Mathf.Approximately(settings.OutlineIntensity, i)) { Undo.RecordObject(undoContext, "Blur Intensity"); settings.OutlineIntensity = i; } EditorGUI.indentLevel -= 1; } if (blurred != (settings.OutlineMode == OutlineMode.Blurred)) { Undo.RecordObject(undoContext, "Blur"); settings.OutlineMode = blurred ? OutlineMode.Blurred : OutlineMode.Solid; } }
/// <summary> /// Returns a <see cref="MaterialPropertyBlock"/> instance initialized with values from <paramref name="settings"/>. /// </summary> 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); }
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); } } } }
/// <summary> /// Renders outline around a single object. /// </summary> /// <param name="renderer">A <see cref="Renderer"/> representing an object to be outlined.</param> /// <param name="resources">Outline resources.</param> /// <param name="settings">Outline settings.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings) { if (renderer == null) { throw new ArgumentNullException("renderers"); } if (resources == null) { throw new ArgumentNullException("resources"); } if (settings == null) { throw new ArgumentNullException("settings"); } Init(resources, settings); RenderObject(renderer, resources.RenderMaterial); RenderHPass(resources, settings); RenderVPassBlend(resources, settings); }
/// <summary> /// Renders outline around a single object. This version allows enumeration of <paramref name="renderers"/> with no GC allocations. /// </summary> /// <param name="renderers">One or more renderers representing a single object to be outlined.</param> /// <param name="resources">Outline resources.</param> /// <param name="settings">Outline settings.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments is <see langword="null"/>.</exception> /// <seealso cref="Render(IEnumerable{Renderer}, OutlineResources, IOutlineSettings)"/> /// <seealso cref="Render(Renderer, OutlineResources, IOutlineSettings)"/> public void Render(IList <Renderer> renderers, OutlineResources resources, IOutlineSettings settings) { if (renderers == null) { throw new ArgumentNullException("renderers"); } if (resources == null) { throw new ArgumentNullException("resources"); } if (settings == null) { throw new ArgumentNullException("settings"); } Init(resources, settings); RenderObject(resources, settings, renderers); RenderHPass(resources, settings); RenderVPassBlend(resources, settings); }
public static void Render(IOutlineSettings settings, UnityEngine.Object undoContext) { var color = EditorGUILayout.ColorField("Color", settings.OutlineColor); if (settings.OutlineColor != color) { Undo.RecordObject(undoContext, "Color"); settings.OutlineColor = color; } var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineResources.MinWidth, OutlineResources.MaxWidth); if (settings.OutlineWidth != width) { Undo.RecordObject(undoContext, "Width"); settings.OutlineWidth = width; } var prevRenderMode = settings.OutlineRenderMode; var renderMode = (OutlineRenderFlags)EditorGUILayout.EnumFlagsField("Render Flags", prevRenderMode); if (renderMode != prevRenderMode) { Undo.RecordObject(undoContext, "Render Flags"); settings.OutlineRenderMode = renderMode; } if ((renderMode & OutlineRenderFlags.Blurred) != 0) { var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineResources.MinIntensity, OutlineResources.MaxIntensity); if (!Mathf.Approximately(settings.OutlineIntensity, i)) { Undo.RecordObject(undoContext, "Blur Intensity"); settings.OutlineIntensity = i; } } }
public static bool IsBlurEnabled(this IOutlineSettings settings) { return((settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0); }
/// <summary> /// Initializes a new instance of the <see cref="OutlineRenderObject"/> struct. /// </summary> public OutlineRenderObject(IReadOnlyList <Renderer> renderers, IOutlineSettings outlineSettings, string tag = null) { _renderers = renderers; _outlineSettings = outlineSettings; _tag = tag; }
/// <inheritdoc/> public bool Equals(IOutlineSettings other) { return(OutlineSettings.Equals(_outlineSettings, other)); }
/// <summary> /// Initializes a new instance of the <see cref="OutlineRenderObject"/> struct. /// </summary> public OutlineRenderObject(GameObject go, IReadOnlyList <Renderer> renderers, IOutlineSettings outlineSettings) { _go = go; _renderers = renderers; _outlineSettings = outlineSettings; }
private void RenderObject(IOutlineSettings settings, Renderer renderer) { RenderObjectClear(settings.OutlineRenderMode); DrawRenderer(renderer, settings); }
public static void Render(IOutlineSettings settings, UnityEngine.Object undoContext) { var color = EditorGUILayout.ColorField("Color", settings.OutlineColor); if (settings.OutlineColor != color) { Undo.RecordObject(undoContext, "Color"); settings.OutlineColor = color; } var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); if (settings.OutlineWidth != width) { Undo.RecordObject(undoContext, "Width"); settings.OutlineWidth = width; } var prevBlurred = (settings.OutlineRenderMode & OutlineRenderFlags.Blurred) != 0; var blurred = EditorGUILayout.Toggle("Blurred", prevBlurred); if (blurred) { EditorGUI.indentLevel += 1; var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); if (!Mathf.Approximately(settings.OutlineIntensity, i)) { Undo.RecordObject(undoContext, "Blur Intensity"); settings.OutlineIntensity = i; } EditorGUI.indentLevel -= 1; } if (blurred != prevBlurred) { Undo.RecordObject(undoContext, "Blur"); if (blurred) { settings.OutlineRenderMode |= OutlineRenderFlags.Blurred; } else { settings.OutlineRenderMode &= ~OutlineRenderFlags.Blurred; } } var prevDepthTestEnabled = (settings.OutlineRenderMode & OutlineRenderFlags.EnableDepthTesting) != 0; var depthTestEnabled = EditorGUILayout.Toggle("Depth Test", prevDepthTestEnabled); if (depthTestEnabled != prevDepthTestEnabled) { Undo.RecordObject(undoContext, "Depth Test"); if (depthTestEnabled) { settings.OutlineRenderMode |= OutlineRenderFlags.EnableDepthTesting; } else { settings.OutlineRenderMode &= ~OutlineRenderFlags.EnableDepthTesting; } } }
private void Init(OutlineResources resources, IOutlineSettings settings) { _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth)); }
protected void Init(IOutlineSettings settings) { _settings = settings; _changeTracking = settings as IChangeTracking; }
/// <inheritdoc/> public bool Equals(IOutlineSettings other) { return(Equals(this, other)); }