#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