C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class Outline : PostEffectsBase
{
public bool inBufferMode = false;
[Range(0, 1)]
public float _OutlineWidth;
public Color _OutlineColor;
public float _SimpleDistance;
public Material writeMaterial;
CommandBuffer commandBuffer = null;
public List<Renderer> outlinedObjects = new List<Renderer>();
public bool Initialized
{
get { return commandBuffer != null; }
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
bool hitSelectable = Physics.Raycast(ray, out var hit) && hit.transform.CompareTag("Selectable");
if (hitSelectable)
{
Renderer[] renderers = hit.transform.GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
if (outlinedObjects.Contains(renderer))
{
outlinedObjects.Remove(renderer);
}
else
{
outlinedObjects.Add(renderer);
}
}
}
else
{
outlinedObjects.Clear();
}
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Material != null)
{
Material.SetFloat("_OutlineWidth", _OutlineWidth);
Material.SetColor("_OutlineColor", _OutlineColor);
Material.SetFloat("_SimpleDistance", _SimpleDistance);
}
commandBuffer = new CommandBuffer();
commandBuffer.name = "Outline";
int selectionBuffer = Shader.PropertyToID("_SelectionBuffer");
commandBuffer.GetTemporaryRT(selectionBuffer, source.descriptor);
commandBuffer.SetRenderTarget(selectionBuffer);
commandBuffer.ClearRenderTarget(true, true, Color.clear);
if (outlinedObjects != null && outlinedObjects.Count > 0)
{
for (int i = 0; i < outlinedObjects.Count; i++)
{
commandBuffer.DrawRenderer(outlinedObjects[i], writeMaterial);
}
}
if (inBufferMode)
{
commandBuffer.Blit(selectionBuffer, destination);
}
else
{
commandBuffer.Blit(source, destination, Material);
}
commandBuffer.ReleaseTemporaryRT(selectionBuffer);
Graphics.ExecuteCommandBuffer(commandBuffer);
commandBuffer.Dispose();
}
}
Shader:
Shader "LSQ/Render Pipeline/Command Buffer/Outline"
{
Properties
{
[HideInInspector]_MainTex ("Texture", 2D) = "white" {}
_OutlineWidth ("OutlineWidth", Range(0, 1)) = 1
_OutlineColor ("OutlineColor", Color) = (1, 1, 1, 1)
_SimpleDistance ("SimpleDistance", float) = 0.01
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _OutlineWidth;
float4 _OutlineColor;
float _SimpleDistance;
sampler2D _SelectionBuffer;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
#define DIV_SQRT_2 0.70710678118
float2 directions[8] =
{
float2(1, 0), float2(0, 1), float2(-1, 0), float2(0, -1),
float2(DIV_SQRT_2, DIV_SQRT_2), float2(-DIV_SQRT_2, DIV_SQRT_2),
float2(-DIV_SQRT_2, -DIV_SQRT_2), float2(DIV_SQRT_2, -DIV_SQRT_2)
};
float aspect = _ScreenParams.x * (_ScreenParams.w - 1);
float2 sampleDistance = float2(_OutlineWidth / aspect, _OutlineWidth) * _SimpleDistance;
float maxAlpha = 0;
for(uint index = 0; index < 8; index++)
{
float2 sampleUV = i.uv + directions[index] * sampleDistance;
maxAlpha = max(maxAlpha, tex2D(_SelectionBuffer, sampleUV).a);
}
float border = max(0, maxAlpha - tex2D(_SelectionBuffer, i.uv).a);
fixed4 col = tex2D(_MainTex, i.uv);
col = lerp(col, _OutlineColor, border);
return col;
}
ENDCG
}
}
}
|