Files
Ipseity-Demo/Assets/_Content/Shaders/Postprocess/Include/EnkiBillalFullscreen.hlsl
T

131 lines
5.5 KiB
HLSL

#ifndef ENKI_BILLAL_FULLSCREEN_INCLUDED
#define ENKI_BILLAL_FULLSCREEN_INCLUDED
#include "Assets/_Content/Shaders/Include/Noises.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl"
#include "Assets/_Content/Shaders/Postprocess/Include/BlurFullscreen.hlsl"
TEXTURE2D_X(_BlurredTexture);
SAMPLER(sampler_BlurredTexture);
// ─── OUTLINE ────────────────────────────────────────────────────────────────
// Width is expressed as a fraction of screen height.
// Both depth discontinuities and normal discontinuities contribute.
float ComputeOutline(float2 uv, float outlineWidthPx, float depthThreshold, float normalThreshold)
{
// Pixel size in UV space, scaled by desired width
float2 texel = outlineWidthPx / float2(_ScreenParams.x, _ScreenParams.y);
// ── Sample depth at 4 neighbours (Roberts Cross pattern) ────────────────
float d0 = LinearEyeDepth(SampleSceneDepth(uv + float2(texel.x, texel.y)), _ZBufferParams);
float d1 = LinearEyeDepth(SampleSceneDepth(uv + float2(-texel.x, texel.y)), _ZBufferParams);
float d2 = LinearEyeDepth(SampleSceneDepth(uv + float2(texel.x, -texel.y)), _ZBufferParams);
float d3 = LinearEyeDepth(SampleSceneDepth(uv + float2(-texel.x, -texel.y)), _ZBufferParams);
// Roberts Cross gradient magnitude on depth
float depthEdge = sqrt(pow(d0 - d3, 2) + pow(d1 - d2, 2));
// Normalise by depth so far geometry doesn't get thick outlines
float dCenter = LinearEyeDepth(SampleSceneDepth(uv), _ZBufferParams);
depthEdge /= (dCenter + 1e-4);
// ── Sample normals at the same 4 neighbours ──────────────────────────────
float3 n0 = SampleSceneNormals(uv + float2(texel.x, texel.y));
float3 n1 = SampleSceneNormals(uv + float2(-texel.x, texel.y));
float3 n2 = SampleSceneNormals(uv + float2(texel.x, -texel.y));
float3 n3 = SampleSceneNormals(uv + float2(-texel.x, -texel.y));
// Dot-product difference: 0 = identical normals, 1 = orthogonal / flipped
float normalEdge = 0;
normalEdge += 1.0 - saturate(dot(n0, n3));
normalEdge += 1.0 - saturate(dot(n1, n2));
normalEdge *= 0.5;
// ── Combine and threshold ────────────────────────────────────────────────
float edge = max(
step(depthThreshold, depthEdge),
step(normalThreshold, normalEdge)
);
return edge;
}
void EnkiBillalFullscreen_float
(
float2 UV,
float Test,
out float3 Output
)
{
float2 screenUV = UV;
// DEPTH
float rawDepth = SampleSceneDepth(screenUV);
float depthMeters = LinearEyeDepth(rawDepth, _ZBufferParams); // linear eye-space depth in metres
float depth01 = Linear01Depth(rawDepth, _ZBufferParams); // normalised linear depth [0..1]
// POSITION WORLD SPACE
// Remap depth for non-reversed-Z platforms before reconstruction
float depthForReconstruct = rawDepth;
#if !UNITY_REVERSED_Z
depthForReconstruct = lerp(UNITY_NEAR_CLIP_VALUE, 1.0, rawDepth);
#endif
// ComputeWorldSpacePosition handles perspective divide and platform differences
float3 positionWS = ComputeWorldSpacePosition(screenUV, depthForReconstruct, UNITY_MATRIX_I_VP);
// NORMAL WORLD SPACE
// Requires DepthNormals PrePass to be enabled in the URP Renderer
float3 normalWS = SampleSceneNormals(screenUV);
// SCENE COLOR
float3 originColor = SampleSceneColor(screenUV);
float3 sceneColorBlurred = SAMPLE_TEXTURE2D_X(_BlurredTexture, sampler_BlurredTexture, screenUV).rgb;
float greyscale = (originColor.x + originColor.y + originColor.z);
float greyscaleBlurred = (sceneColorBlurred.x + sceneColorBlurred.y + sceneColorBlurred.z);
float hilightMask = smoothstep(.7, 1, greyscale);
hilightMask = lerp(hilightMask, smoothstep(.7, 1, greyscaleBlurred), .5);
hilightMask *= pow(smoothstep(3, 20, depthMeters), 2);
float offsetMask = hilightMask;
float3 offset3D = PerlinColor3D(positionWS * float3(1, 6, 1), 1);
offset3D = smoothstep(.45, .55, offset3D);
float3 offsetUV = offset3D * offsetMask * .4 / depthMeters;
float3 sceneColor = SampleSceneColor(screenUV + offsetUV);
sceneColor = lerp(sceneColor, sceneColorBlurred, hilightMask);
sceneColor = lerp(sceneColor, originColor, .5);
sceneColor = lerp(sceneColor * .5, sceneColor * 1, hilightMask);
//float3 sceneColor = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_PointClamp, screenUV).rgb;
// OUTLINE
float OutlineWidthPx = max(PerlinNoise3D(positionWS, 1) * 3 - 1, 0);
float OutlineDepthThreshold = .03;
float OutlineNormalThreshold = .35;
float OutlineColor = float3(0, 0, 0);
// Width is normalised to screen height so it stays consistent at any resolution.
float widthInPixels = OutlineWidthPx * (_ScreenParams.y / 1080.0);
float outline = ComputeOutline(screenUV, widthInPixels, OutlineDepthThreshold, OutlineNormalThreshold);
sceneColor = lerp(sceneColor, OutlineColor, outline);
// OUTPUT
Output = sceneColor; //BlurSceneColor(screenUV, .1);
//Output = offsetMask;
//Output = hilightMask; //BlurSceneColor(screenUV, .1);
//Output = lerp(originColor, sceneColorBlurred, smoothstep(3, 20, depthMeters));
}
#endif