Skip to content

Instantly share code, notes, and snippets.

@Vengarioth
Created November 3, 2015 11:25
Show Gist options
  • Save Vengarioth/6be186a7d02448b47773 to your computer and use it in GitHub Desktop.
Save Vengarioth/6be186a7d02448b47773 to your computer and use it in GitHub Desktop.
Shader "Outline/OutlineBlendPass" {
Properties {
[HideInInspector] _MainTex ("Base (RGB)", 2D) = "white" {}
[HideInInspector] _OutlineBuffer ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Pass
{
Name "OutlineBlendPass"
Blend Off
AlphaTest Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _OutlineBuffer;
float4 color0;
float4 color1;
float4 color2;
float4 color3;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
float4 frag (v2f i) : COLOR
{
float4 background = tex2D(_MainTex, i.uv);
float4 factor = tex2D(_OutlineBuffer, i.uv);
float4 c;
if(factor.r > 0.1 && factor.r < 0.9) {
c = color0;
}else if(factor.g > 0.1 && factor.g < 0.9) {
c = color1;
}else if(factor.b > 0.1 && factor.b < 0.9) {
c = color2;
}else if(factor.a > 0.1 && factor.a < 0.9) {
c = color3;
}else{
c = background;
}
return c;
}
ENDCG
}
}
}
Shader "Outline/OutlineBlurPass" {
Properties {
[HideInInspector] _MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Pass
{
Name "HorizontalBlur"
Blend Off
AlphaTest Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
float4 frag (v2f i) : COLOR
{
float blurAmount = 0.00035;
float4 fragment = tex2D(_MainTex, i.uv);
float4 sum = half4(0.0, 0.0, 0.0, 0.0);
sum += tex2D(_MainTex, float2(i.uv.x - 4.0 * blurAmount, i.uv.y)) * 0.05;
sum += tex2D(_MainTex, float2(i.uv.x - 3.0 * blurAmount, i.uv.y)) * 0.09;
sum += tex2D(_MainTex, float2(i.uv.x - 2.0 * blurAmount, i.uv.y)) * 0.12;
sum += tex2D(_MainTex, float2(i.uv.x - blurAmount, i.uv.y)) * 0.15;
sum += fragment * 0.16;
sum += tex2D(_MainTex, float2(i.uv.x + blurAmount, i.uv.y)) * 0.15;
sum += tex2D(_MainTex, float2(i.uv.x + 2.0 * blurAmount, i.uv.y)) * 0.12;
sum += tex2D(_MainTex, float2(i.uv.x + 3.0 * blurAmount, i.uv.y)) * 0.09;
sum += tex2D(_MainTex, float2(i.uv.x + 4.0 * blurAmount, i.uv.y)) * 0.05;
return sum;
}
ENDCG
}
Pass
{
Name "VerticalBlur"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
float4 frag (v2f i) : COLOR
{
float blurAmount = 0.00035;
float4 fragment = tex2D(_MainTex, i.uv);
float4 sum = half4(0.0, 0.0, 0.0, 0.0);
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y - 4.0 * blurAmount)) * 0.05;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y - 3.0 * blurAmount)) * 0.09;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y - 2.0 * blurAmount)) * 0.12;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y - blurAmount)) * 0.15;
sum += fragment * 0.16;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y + blurAmount)) * 0.15;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y + 2.0 * blurAmount)) * 0.12;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y + 3.0 * blurAmount)) * 0.09;
sum += tex2D(_MainTex, float2(i.uv.x, i.uv.y + 4.0 * blurAmount)) * 0.05;
return sum;
}
ENDCG
}
}
}
using UnityEngine;
using System.Collections;
public enum OutlineColor {
Color0,
Color1,
Color2,
Color3
}
public class OutlineEffect : MonoBehaviour {
public GameObject TargetMesh;
public OutlineColor OutlineColor = OutlineColor.Color0;
public bool Active { get; set; }
}
Shader "Outline/OutlineObjectPass" {
SubShader {
Pass {
Blend Off
Lighting Off
AlphaTest Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
sampler2D _CameraDepthNormalsTexture;
half4 weights;
struct vertOut {
float4 pos:SV_POSITION;
float4 screenPos:TEXCOORD1;
};
vertOut vert(appdata_base v) : POSITION {
vertOut o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.screenPos = ComputeScreenPos(o.pos);
return o;
}
half4 frag(vertOut i) : COLOR {
i.screenPos.xyz /= i.screenPos.w;
#ifdef SHADER_API_D3D11
float fragDepth = i.screenPos.z;
#else
float fragDepth = (i.screenPos.z + 1) / 2;
#endif
float3 normalValues;
float depthValue;
float4 x = tex2D(_CameraDepthNormalsTexture, i.screenPos.xy);
DecodeDepthNormal(x, depthValue, normalValues);
if(depthValue < (Linear01Depth(fragDepth) - 0.0005))
{
return half4(0.0, 0.0, 0.0, 0.0);
}
return weights;
}
ENDCG
}
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class OutlineRenderer : LocatableByType<OutlineRenderer>
{
public Shader outlineObjectShader;
public Shader outlineBlurShader;
public Shader outlineBlendShader;
private Material outlineObjectMaterial;
private Material outlineBlurMaterial;
private Material outlineBlendMaterial;
public Color color0;
public Color color1;
public Color color2;
public Color color3;
private RenderTexture outlineBuffer;
private RenderTexture outlineBuffer2;
// Use this for initialization
void Start () {
outlineObjectMaterial = new Material(outlineObjectShader);
outlineBlurMaterial = new Material(outlineBlurShader);
outlineBlendMaterial = new Material(outlineBlendShader);
var camera = Camera.main;
camera.depthTextureMode = DepthTextureMode.DepthNormals;
outlineBuffer = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 16);
outlineBuffer.Create();
outlineBuffer2 = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 16);
outlineBuffer2.Create();
}
void OnRenderImage (RenderTexture src, RenderTexture dest) {
var outlineEffects = GameObject.FindObjectsOfType<OutlineEffect>();
var lastActiveRenderTexture = RenderTexture.active;
var camera = Camera.main;
if(camera.pixelWidth != outlineBuffer.width || camera.pixelHeight != outlineBuffer.height)
{
outlineBuffer.Release();
outlineBuffer.width = camera.pixelWidth;
outlineBuffer.height = camera.pixelHeight;
outlineBuffer.Create();
outlineBuffer2.Release();
outlineBuffer2.width = camera.pixelWidth;
outlineBuffer2.height = camera.pixelHeight;
outlineBuffer2.Create();
}
RenderTexture.active = outlineBuffer2;
GL.Clear(true, true, new Color(0f, 0f, 0f, 0f));
RenderTexture.active = outlineBuffer;
GL.Clear(true, true, new Color(0f, 0f, 0f, 0f));
foreach(var outlineEffect in outlineEffects)
{
if (!outlineEffect.Active)
continue;
switch(outlineEffect.OutlineColor)
{
case OutlineColor.Color0:
outlineObjectMaterial.SetVector("weights", new Vector4(1.0f, 0f, 0f, 0f));
break;
case OutlineColor.Color1:
outlineObjectMaterial.SetVector("weights", new Vector4(0f, 1.0f, 0f, 0f));
break;
case OutlineColor.Color2:
outlineObjectMaterial.SetVector("weights", new Vector4(0f, 0f, 1.0f, 0f));
break;
case OutlineColor.Color3:
outlineObjectMaterial.SetVector("weights", new Vector4(0f, 0f, 0f, 1.0f));
break;
}
//needs to be set after all material properties have been set
while(!outlineObjectMaterial.SetPass(0)) { Debug.Log("Could not render with material, repeating..."); }
var go = outlineEffect.TargetMesh;
var m = go.transform.localToWorldMatrix;
var meshFilter = go.GetComponent<MeshFilter>();
if(meshFilter != null) {
Graphics.DrawMeshNow(meshFilter.sharedMesh, m);
}else{
var skinnedMeshRenderer = go.GetComponentInChildren<SkinnedMeshRenderer>();
if(skinnedMeshRenderer != null)
{
var mesh = new Mesh();
skinnedMeshRenderer.BakeMesh(mesh);
Graphics.DrawMeshNow(mesh, m);
}
}
}
Graphics.Blit(outlineBuffer, outlineBuffer2, outlineBlurMaterial, 0);
Graphics.Blit(outlineBuffer2, outlineBuffer, outlineBlurMaterial, 1);
outlineBlendMaterial.SetTexture("_OutlineBuffer", outlineBuffer);
outlineBlendMaterial.SetColor("color0", color0);
outlineBlendMaterial.SetColor("color1", color1);
outlineBlendMaterial.SetColor("color2", color2);
outlineBlendMaterial.SetColor("color3", color3);
RenderTexture.active = lastActiveRenderTexture;
Graphics.Blit(src, dest, outlineBlendMaterial);
}
}
Deferred outlines for Unity3d (Unoptimized, proof of concept)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment