sk-client/Assets/Scripts/UI/OutlineSystem.cs

132 lines
4.1 KiB
C#

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();
}
}