using UnityEngine; public class OutlineSystem : MonoBehaviour { [Header("Outline Settings")] public bool solidOutline = false; [Range(0, 10)] public float outlineStrength = 1f; [Tooltip("Which layers should this outline system display on")] public LayerMask outlineLayer; public Color outlineColor; [Tooltip("How many times should the render be downsampled")] [Range(0, 4)] public int downsampleAmount = 2; [Range(0.0f, 10.0f)] public float outlineSize = 1.5f; [Tooltip("How many times should the blur be performed")] [Range(1, 10)] public int outlineIterations = 2; [Range(0.1f, 5)] public float outlineUpscale = 1f; public Camera mainCamera; public Material blurMaterial; public Material outlineMaterial; private RenderTexture renTexInput; private RenderTexture renTexRecolor; private RenderTexture renTexDownsample; private RenderTexture renTexBlur; private RenderTexture renTexOut; private Vector2 prevSize; void Awake() { if(mainCamera == null) { mainCamera = Camera.main; } UpdateRenderTextureSizes(); } void UpdateRenderTextureSizes() { Vector2 screenDims = ScreenDimension(); int x = Mathf.FloorToInt(Mathf.FloorToInt(screenDims.x) * outlineUpscale); int y = Mathf.FloorToInt(Mathf.FloorToInt(screenDims.y) * outlineUpscale); renTexInput = new RenderTexture(x, y, 1); renTexDownsample = new RenderTexture(x, y, 1); renTexRecolor = new RenderTexture(x, y, 1); renTexOut = new RenderTexture(x, y, 1); renTexBlur = new RenderTexture(x, y, 1); } public Vector2 ScreenDimension() { Vector2 size = Vector2.one; size = new Vector2(Screen.width, Screen.height); return size; } void RunCalcs() { outlineMaterial.SetColor("_OutlineCol", outlineColor); outlineMaterial.SetFloat("_GradientStrengthModifier", outlineStrength); RenderTexture prevRenTex = mainCamera.targetTexture; int prevCullGroup = mainCamera.cullingMask; CameraClearFlags prevClearFlags = mainCamera.clearFlags; Color prevColor = mainCamera.backgroundColor; mainCamera.cullingMask = outlineLayer.value; mainCamera.targetTexture = renTexInput; mainCamera.clearFlags = CameraClearFlags.SolidColor; mainCamera.backgroundColor = new Color(1f, 0f, 1f, 1f); mainCamera.Render(); mainCamera.backgroundColor = prevColor; mainCamera.clearFlags = prevClearFlags; mainCamera.targetTexture = prevRenTex; mainCamera.cullingMask = prevCullGroup; float widthMod = 1.0f / (1.0f * (1 << downsampleAmount)); blurMaterial.SetVector("_Parameter", new Vector4(outlineSize * widthMod, -outlineSize * widthMod, 0.0f, 0.0f)); Graphics.Blit(renTexInput, renTexRecolor, outlineMaterial, 0); Graphics.Blit(renTexRecolor, renTexDownsample, blurMaterial, 0); for (int i = 0; i < outlineIterations; i++) { float iterationOffs = (i * 1.0f); blurMaterial.SetVector("_Parameter", new Vector4(outlineSize * widthMod + iterationOffs, -outlineSize * widthMod - iterationOffs, 0.0f, 0.0f)); Graphics.Blit(renTexDownsample, renTexBlur, blurMaterial, 1); Graphics.Blit(renTexBlur, renTexDownsample, blurMaterial, 2); } outlineMaterial.SetFloat("_Solid", solidOutline ? 1f : 0f); outlineMaterial.SetTexture("_BlurTex", renTexDownsample); Graphics.Blit(renTexRecolor, renTexOut, outlineMaterial, 1); } void LateUpdate() { Vector2 currentSize = new Vector2(Screen.width, Screen.height); if (prevSize != currentSize) { UpdateRenderTextureSizes(); } prevSize = currentSize; RunCalcs(); } void OnGUI() { GL.PushMatrix(); GL.LoadPixelMatrix(0, Screen.width, Screen.height, 0); Graphics.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), renTexOut); GL.PopMatrix(); } }