205 lines
8.4 KiB
HLSL

#ifndef BEAUTIFY_PPSOUTLINE
#define BEAUTIFY_PPSOUTLINE
// Copyright 2016-2021 Ramiro Oliva (Kronnect) - All Rights Reserved.
#include "BeautifyCommon.hlsl"
TEXTURE2D_X(_MainTex);
float4 _MainTex_TexelSize;
float4 _MainTex_ST;
TEXTURE2D_X_FLOAT(_OutlineDepth);
TEXTURE2D_X_FLOAT(_OutlineObjectId);
float4 _Outline;
#define OUTLINE_EDGE_THRESHOLD _Outline.a
float4 _OutlineData;
#define OUTLINE_INTENSITY_MULTIPLIER _OutlineData.x
#define OUTLINE_DISTANCE_FADE _OutlineData.y
#define OUTLINE_MIN_DEPTH_THRESHOLD _OutlineData.z
#define OUTLINE_MIN_SATURATION_THRESHOLD _OutlineData.w
half _BlurScale;
#define OUTLINE_MIN_SEPARATION _OutlineData.z
struct VaryingsOutline {
float4 positionCS : SV_POSITION;
float2 uv: TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
struct VaryingsCross {
float4 positionCS : SV_POSITION;
float2 uv: TEXCOORD0;
BEAUTIFY_VERTEX_CROSS_UV_DATA
UNITY_VERTEX_OUTPUT_STEREO
};
VaryingsOutline VertOutline(AttributesSimple input) {
VaryingsOutline output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = input.positionOS;
output.positionCS.y *= _ProjectionParams.x * _FlipY;
output.uv = input.uv;
return output;
}
float OutlinePass(VaryingsOutline i) {
float3 uvInc = float3(_MainTex_TexelSize.x, _MainTex_TexelSize.y, 0);
#if BEAUTIFY_DEPTH_FADE || !BEAUTIFY_OUTLINE_SOBEL
#if BEAUTIFY_OUTLINE_CUSTOM_DEPTH || BEAUTIFY_OUTLINE_OBJECT_ID
float depth = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv);
float sceneDepth = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv);
if (sceneDepth < depth * 0.999) return 0;
#else
float depth = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv);
if (depth >= 1.0) return 0;
#endif
#endif
float outline = 0;
#if BEAUTIFY_OUTLINE_OBJECT_ID && !BEAUTIFY_OUTLINE_SOBEL
float objS = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv - uvInc.zy).x;
float objN = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv + uvInc.zy).x;
float objW = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv - uvInc.xz).x;
float objE = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv + uvInc.xz).x;
float maxObj = max( max(objS, objN), max(objW, objE) );
float minObj = min( min(objS, objN), min(objW, objE) );
float objDiff = maxObj - minObj;
outline = objDiff > 0.01;
#if BEAUTIFY_OUTLINE_OUTER_ONLY
float depthN = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv + uvInc.zy);
float depthS = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv - uvInc.zy);
float depthW = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv - uvInc.xz);
float depthE = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv + uvInc.xz);
float objM = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv).x;
if ( (depth < depthN && abs(objN - objM) > 0.01) ||
(depth < depthS && abs(objS - objM) > 0.01) ||
(depth < depthW && abs(objW - objM) > 0.01) ||
(depth < depthE && abs(objE - objM) > 0.01))
outline = 0;
#endif
// check object is big enough
#if BEAUTIFY_OUTLINE_MIN_SEPARATION
uvInc *= OUTLINE_MIN_SEPARATION;
float objS2 = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv - uvInc.zy).x;
float objN2 = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv + uvInc.zy).x;
if (abs(objN2 - objN) > 0.01 && abs(objS2 - objS) > 0.01) outline *= 0.25 / OUTLINE_INTENSITY_MULTIPLIER;
float objW2 = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv - uvInc.xz).x;
float objE2 = SAMPLE_TEXTURE2D_X(_OutlineObjectId, sampler_PointClamp, i.uv + uvInc.xz).x;
if (abs(objE2 - objE) > 0.01 && abs(objW2 - objW) > 0.01) outline *= 0.25 / OUTLINE_INTENSITY_MULTIPLIER;
#endif
#else
float3 rgbS = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv - uvInc.zy).rgb;
float3 rgbN = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv + uvInc.zy).rgb;
float3 rgbW = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv - uvInc.xz).rgb;
float3 rgbE = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv + uvInc.xz).rgb;
#if BEAUTIFY_OUTLINE_CUSTOM_DEPTH || !BEAUTIFY_OUTLINE_SOBEL
#if BEAUTIFY_OUTLINE_CUSTOM_DEPTH
float depthS = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv - uvInc.zy);
float depthW = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv - uvInc.xz);
float depthE = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv + uvInc.xz);
float depthN = BEAUTIFY_GET_CUSTOM_DEPTH_01(_OutlineDepth, i.uv + uvInc.zy);
#else
float depthS = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv - uvInc.zy);
float depthW = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv - uvInc.xz);
float depthE = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv + uvInc.xz);
float depthN = BEAUTIFY_GET_SCENE_DEPTH_01(i.uv + uvInc.zy);
#endif
float maxDepth = max(depth, max(max(depthS, depthN), max(depthW, depthE)));
float minDepth = min(depth, min(min(depthS, depthN), min(depthW, depthE)));
float depthDiff = maxDepth - minDepth;
float3 normalNW = getNormal(depth, depthN, depthW, uvInc.zy, float2(-uvInc.x, -uvInc.z));
float3 normalSE = getNormal(depth, depthS, depthE, -uvInc.zy, uvInc.xz);
float dnorm = dot(normalNW, normalSE);
float satN = getSaturation(rgbN);
float satS = getSaturation(rgbS);
float satW = getSaturation(rgbW);
float satE = getSaturation(rgbE);
float maxSat = max( max(satN, satS), max(satW, satE) );
float minSat = min( min(satN, satS), min(satW, satE) );
float dSat = maxSat - minSat;
outline = dSat > OUTLINE_MIN_SATURATION_THRESHOLD && dnorm < OUTLINE_EDGE_THRESHOLD && depthDiff > OUTLINE_MIN_DEPTH_THRESHOLD;
#else
float3 rgbSW = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv - uvInc.xy).rgb;
float3 rgbNE = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv + uvInc.xy).rgb;
float3 rgbSE = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv + float2( uvInc.x, -uvInc.y)).rgb;
float3 rgbNW = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv + float2(-uvInc.x, uvInc.y)).rgb;
float3 gx = rgbSW * -1.0;
gx += rgbSE * 1.0;
gx += rgbW * -2.0;
gx += rgbE * 2.0;
gx += rgbNW * -1.0;
gx += rgbNE * 1.0;
float3 gy = rgbSW * -1.0;
gy += rgbS * -2.0;
gy += rgbSE * -1.0;
gy += rgbNW * 1.0;
gy += rgbN * 2.0;
gy += rgbNE * 1.0;
outline = (length(gx * gx + gy * gy) - _Outline.a) > 0.0;
#endif
#endif
#if BEAUTIFY_DEPTH_FADE
float factor = max(0, (OUTLINE_DISTANCE_FADE - depth) / OUTLINE_DISTANCE_FADE);
outline *= factor;
#endif
return outline;
}
float4 fragOutline (VaryingsOutline i) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
float outline = OutlinePass(i);
return outline;
}
VaryingsCross VertBlur(AttributesSimple v) {
VaryingsCross o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionCS = v.positionOS;
o.positionCS.y *= _ProjectionParams.x * _FlipY;
o.uv = v.uv;
BEAUTIFY_VERTEX_OUTPUT_GAUSSIAN_UV(o)
return o;
}
half4 FragBlur (VaryingsCross i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
BEAUTIFY_FRAG_SETUP_GAUSSIAN_UV(i)
half4 pixel = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv) * 0.2270270270
+ (SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv1) + SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv2)) * 0.3162162162
+ (SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv3) + SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv4)) * 0.0702702703;
return pixel;
}
half4 FragCopy (VaryingsSimple i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
half outline = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv).r;
half4 color = half4(_Outline.rgb, _Outline.a * outline);
color *= OUTLINE_INTENSITY_MULTIPLIER;
color.a = saturate(color.a);
return color;
}
#endif