Skip to content

Instantly share code, notes, and snippets.

@lyuma
Created August 5, 2019 23:46
Show Gist options
  • Save lyuma/c552d926815c4f9eeb590e439a642349 to your computer and use it in GitHub Desktop.
Save lyuma/c552d926815c4f9eeb590e439a642349 to your computer and use it in GitHub Desktop.
// Copyright (C) 2019 Lyuma (Lyuma#0781) (xn.lyuma@gmail.com)
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Shader "LyumaShader/ThiccnessCombined" {
// CAVEAT: This will not work if any other objects in the scene use the same shader.
// To fix, this must be split up into three materials/queues, with the GrabPass
// combined with rendering in the last queue.
Properties
{
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent+30"}
LOD 100
Lighting Off
CGINCLUDE
#pragma target 4.5
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_Position;
float3 viewNormal : TEXCOORD0;
float viewDepthFromCenter : TEXCOORD1;
float4 screenPos : TEXCOORD2;
};
#define ANGLE_STAGES 13
#define EPSILON 0.0078125
#define HALF_MINUS_EPSILON 0.4921875
#define THICKNESS_SCALE 4.0
v2f vert(appdata_full v) {
v2f o = (v2f)0;
o.pos = UnityObjectToClipPos(v.vertex);
//o.worldNormal = mul((float3x3)unity_ObjectToWorld, v.normal.xyz);
o.viewNormal = mul((float3x3)UNITY_MATRIX_V, mul((float3x3)unity_ObjectToWorld, v.normal.xyz));
float3 viewPos = UnityObjectToViewPos(v.vertex).xyz;
float3 centerViewPos = UnityObjectToViewPos(float4(0,0,0,1)).xyz;
o.viewDepthFromCenter = centerViewPos.z - viewPos.z;
o.screenPos = ComputeGrabScreenPos(o.pos);
return o;
}
// Normal encoding as power of two (exponent portion)
// ALU noise in Next-gen post processing in COD:AW
float InterleavedGradientNoise( float2 screenUV )
{
float3 magic = { 0.06711056, 0.00583715, 52.9829189 };
return frac( magic.z * frac( dot( screenUV, magic.xy ) ) );
}
float encodeBackfaceNormal(float3 viewNormal, float2 ditherUV) {
float2 normalXY = normalize(viewNormal.xy);
float angle = atan2(normalXY.y, normalXY.x);
float angleToQuantize = (angle * ANGLE_STAGES / UNITY_TWO_PI + 127);
float noise01 = InterleavedGradientNoise(ditherUV);
float quantizedAngle = (noise01 < frac(angleToQuantize) ? 1.0 : 0.0) + floor(angleToQuantize);
precise uint exponentBits = (((uint)quantizedAngle) << 23);
precise float powOfTwo = asfloat(exponentBits);
return powOfTwo;
}
float3 decodeBackfaceNormal(float alphaChannel) {
precise uint bits = asuint(alphaChannel);
float exponent = float((bits >> 23) & 0xff) - 127;
float quantizedAngle = exponent.r * UNITY_TWO_PI / ANGLE_STAGES;
float3 normal = normalize(float3(cos(quantizedAngle), sin(quantizedAngle), -1.0));
return normal;
}
static float objectScaledThickness = THICKNESS_SCALE;// * length(unity_ObjectToWorld._11_12_13);
// Thickness encoding as fractional part:
float encodeViewDistance(float viewDepthFromCenter) {
return 0.25 * clamp(viewDepthFromCenter / objectScaledThickness, -0.99, 0.99);
}
float decodeThickness(float alphaChannel) {
precise uint bits = asuint(alphaChannel);
precise uint exponentBits = (((bits >> 23) & 0xff) << 23);
float powOfTwo = asfloat(exponentBits);
float thickness = (frac(abs(alphaChannel) / powOfTwo) - EPSILON) * objectScaledThickness;
return thickness;
}
ENDCG
Pass {
// Backface Depth Prepass: we can only afford to subtract depth once
ZWrite On
ColorMask RA
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 frag(v2f i) : SV_Target {
return float4(1,0,0,0);
}
ENDCG
}
Pass {
// Compute frontface depth in alpha mantissa channel
ZWrite Off
ZTest LEqual
Cull Back
ColorMask RA
Blend One One
BlendOp Min
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 frag(v2f i) : SV_Target {
return float4(1,0,0, -1.5 + encodeViewDistance(i.viewDepthFromCenter));
}
ENDCG
}
Pass {
// Subtract backface depth in alpha mantissa channel
ZWrite Off
ZTest Equal
Cull Front
ColorMask RA
Blend One One
BlendOp Add
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 frag(v2f i) : SV_Target {
float HalfMinusEpsilon = 0.4921875;
return float4(1,0,0, HALF_MINUS_EPSILON - encodeViewDistance(i.viewDepthFromCenter));
}
ENDCG
}
Pass {
// Store backface normal direction in alpha exponent channel
ZWrite Off
ZTest Equal
Cull Front
ColorMask RA
Blend DstAlpha Zero
BlendOp Add
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 frag(v2f i) : SV_Target {
float2 ditherUV = _ScreenParams.xy * (i.screenPos.xy / i.screenPos.w);
return float4(1, 0, 0, encodeBackfaceNormal(i.viewNormal, ditherUV));
}
ENDCG
}
GrabPass {
"_ColorNormalThickness"
// Grab screen
}
Pass {
// FInal Render
ZWrite Off
ZTest LEqual
Cull Back
ColorMask RGBA
Blend One Zero
BlendOp Add
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _ColorNormalThickness;
float4 frag(v2f i) : SV_Target {
float4 texRead = tex2Dproj(_ColorNormalThickness, i.screenPos);
if (0) {//texRead.a >= 0) {
// We did not write any data.
return texRead;
} else {
float3 backfaceNormal = decodeBackfaceNormal(texRead.a);
float thickness = decodeThickness(texRead.a);
// Show all parts visually.
return float4(texRead.rgb * 0 + 1 * ((thickness / objectScaledThickness) * (.5 + .5 * (i.viewNormal.xyz - backfaceNormal.xyz))), 1.0);
}
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment