#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); float2 RotateUV(float2 UV, float2 Pivot, float Angle) { float s = sin(Angle); float c = cos(Angle); UV -= Pivot; float2 rotated = float2( UV.x * c - UV.y * s, UV.x * s + UV.y * c ); return rotated + Pivot; } float WorldDistort(float3 PositionWS, float3 NormalWS, float Angle, float TriplanarBlend) { float StripesScale = 60; // Octahedral face normals (4 faces + 3 world axes) float3 octaFaceNormals[7] = { normalize(float3(1, 1, 1)), normalize(float3(-1, 1, 1)), normalize(float3(1, -1, 1)), normalize(float3(-1, -1, 1)), float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1) }; // Octahedral blending mask float sharpness = Remap(0, 1, 1, 16, smoothstep(0, .9, TriplanarBlend)); float octaMask[7]; float hardMax = -1; int hardIdx = 0; for (int i = 0; i < 7; i++) { float d = abs(dot(NormalWS, octaFaceNormals[i])); octaMask[i] = pow(saturate(d), sharpness); if (d > hardMax) { hardMax = d; hardIdx = i; } } float maskSum = 0; for (int i = 0; i < 7; i++) maskSum += octaMask[i]; for (int i = 0; i < 7; i++) octaMask[i] /= max(maskSum, 0.0001); float hardFactor = smoothstep(.9, 1, TriplanarBlend); for (int i = 0; i < 7; i++) { float hard = (i == hardIdx) ? 1.0 : 0.0; octaMask[i] = lerp(octaMask[i], hard, hardFactor); } // Patern float stripes = 0; [unroll] for (int i = 0; i < 7; i++) { float3 n = octaFaceNormals[i]; float3 up = abs(n.y) < 0.999 ? float3(0, 1, 0) : float3(1, 0, 0); float3 tangent = normalize(cross(up, n)); float3 bitangent = normalize(cross(n, tangent)); float angle = i / 7.0 * PI; float2 p = RotateUV(float2(dot(PositionWS, tangent), dot(PositionWS, bitangent)), 0, angle) * StripesScale; float stripe = cos(p.x); stripes += stripe * octaMask[i]; } return stripes; } float Hash21(float2 p) { p = frac(p * float2(123.34, 456.21)); p += dot(p, p + 45.32); return frac(p.x * p.y); } void GetBasisFromNormal(float3 n, out float3 tangent, out float3 bitangent) { float3 up = abs(n.y) < 0.999 ? float3(0, 1, 0) : float3(1, 0, 0); tangent = normalize(cross(up, n)); bitangent = normalize(cross(n, tangent)); } float BipyramidHatch(float3 PositionWS, float3 NormalWS, float Angle, float Scale, float Width) { float3 faceNormals[7] = { normalize(float3(1, 1, 1)), normalize(float3(-1, 1, 1)), normalize(float3(1, -1, 1)), normalize(float3(-1, -1, 1)), float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1) }; float hatchSum = 0; float weightSum = 0; float projectionBlend = 32.0; float hardBlend = 0.85; [unroll] for (int i = 0; i < 7; i++) { float3 n = faceNormals[i]; float w = saturate(abs(dot(NormalWS, n))); w = pow(w, projectionBlend); float hard = step(0.999, w); w = lerp(w, hard, hardBlend); float3 tangent; float3 bitangent; GetBasisFromNormal(n, tangent, bitangent); float2 p = float2(dot(PositionWS, tangent), dot(PositionWS, bitangent)); p = RotateUV(p, 0, Angle); float lines = abs(frac(p.x * Scale) - 0.5); float hatch = smoothstep(Width, Width * 0.65, lines); hatchSum += hatch * w; weightSum += w; } return hatchSum / max(weightSum, 0.0001); } float SampleSceneDepthMeter(float2 UV) { float rawDepth = SampleSceneDepth(UV); #if UNITY_REVERSED_Z bool isSky = rawDepth <= 0.00001; rawDepth = isSky ? 0.0 : rawDepth; #else bool isSky = rawDepth >= 0.99999; rawDepth = isSky ? 1.0 : rawDepth; #endif float depthMeters = isSky ? _ProjectionParams.z : LinearEyeDepth(rawDepth, _ZBufferParams); return depthMeters; } float ComputeOutline(float2 UV, float2 Thickness, float3 NormalWS, float3 ViewDir, float DepthAtten) { // DEPTH OUTLINE float2 o = Thickness * lerp(1, .5, DepthAtten); float d0 = SampleSceneDepthMeter(UV); float d1 = SampleSceneDepthMeter(UV + float2(-o.x,0)); float d2 = SampleSceneDepthMeter(UV + float2( o.x,0)); float d3 = SampleSceneDepthMeter(UV + float2(0,-o.y)); float d4 = SampleSceneDepthMeter(UV + float2(0, o.y)); float depthDiff = max(max(abs(d0 - d1), abs(d0 - d2)), max(abs(d0 - d3), abs(d0 - d4))); float incidence = abs(dot(NormalWS, ViewDir)); float incidenceAtten = smoothstep(.22, .35, incidence); float2 depthMinRange = float2(.15, 0.3); float2 depthMaxRange = float2(0.5, 1.1); float2 depthRange = lerp(depthMinRange, depthMaxRange, DepthAtten); float depthOutline = smoothstep(depthRange.x, depthRange.y, depthDiff); depthOutline *= incidenceAtten; // NORMAL OUTLINE o *= .5; float3 n0 = normalize(SampleSceneNormals(UV)); float3 n1 = normalize(SampleSceneNormals(UV + float2(-o.x, 0))); float3 n2 = normalize(SampleSceneNormals(UV + float2( o.x, 0))); float3 n3 = normalize(SampleSceneNormals(UV + float2(0, -o.y))); float3 n4 = normalize(SampleSceneNormals(UV + float2(0, o.y))); float normalDiff = distance(n0, n1) + distance(n0, n2) + distance(n0, n3) + distance(n0, n4); float normalOutline = smoothstep(0.6, 0.8, normalDiff) * smoothstep(10, 3, d0); return saturate(depthOutline + normalOutline * .8); //return depthOutline; } void EnkiBillalFullscreen_float ( float2 UV, out float3 Output ) { // INPUTS float rawDepth = SampleSceneDepth(UV); #if UNITY_REVERSED_Z bool isSky = rawDepth <= .00001; rawDepth = isSky ? 0 : rawDepth; #else bool isSky = rawDepth >= .99999; rawDepth = isSky ? 1 : rawDepth; #endif float depthMeters = isSky ? _ProjectionParams.z : LinearEyeDepth(rawDepth, _ZBufferParams); float depthForReconstruct = rawDepth; #if !UNITY_REVERSED_Z depthForReconstruct = lerp(UNITY_NEAR_CLIP_VALUE, 1.0, rawDepth); #endif float3 positionWS = ComputeWorldSpacePosition(UV, depthForReconstruct, UNITY_MATRIX_I_VP); float3 normalWS = normalize(SampleSceneNormals(UV)); float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - positionWS); float time = _Time.y; // NOISES float noiseAtten = pow(smoothstep(1, 10, depthMeters), 2); float np0 = PerlinNoise3D(positionWS, 80); float np1 = PerlinNoise3D(positionWS , 1.7) * 2 - 1; float np2 = PerlinNoise3D(positionWS + floor(time * 3.) * 2.6, 0.8) * 2 - 1; float np3 = PerlinNoise3D(positionWS + floor(time * 5.) * 6.1, 0.1) * 2 - 1; float np4 = PerlinNoise3D(positionWS + floor(time * 9.) * 9.2, .03) * 2 - 1; // UVs float2 uv0 = UV; float2 uv1 = uv0 + np1 * lerp(.001, .002, noiseAtten); float2 uv2 = uv1 + (np1 * .3 + np2 * .7) * lerp(.003, .006, noiseAtten); float2 uv3 = uv2 + (np2 * .3 + np3 * .7) * lerp(.015, .029, noiseAtten); float2 uv4 = uv3 + (np3 * .3 + np4 * .7) * lerp(.019, .032, noiseAtten); // SCENE COLOR float3 sceneColor = SampleSceneColor(uv0 + (np0 * 2 - 1) * noiseAtten * .003); float greyscale = (sceneColor.r + sceneColor.g + sceneColor.b) / 3.; // DISTORTION float distortAtten = pow(smoothstep(5, 20, depthMeters), 2); float nDistort0 = FBMNoise3D(positionWS * float3(1, 2.0, 1) - time * .2 - np0 * .5, 1.5, 1, 2, .5) * 2 - 1; float nDistort1 = FBMNoise3D(positionWS * float3(1, 1.5, 1) - time * .2 - np0 * .5, 1.5, 1, 2, .5) * 2 - 1; float2 uvDistort0 = uv0 + nDistort0 * .005; float2 uvDistort1 = uv0 + nDistort1 * .025; float3 sceneColor2 = SampleSceneColor(uvDistort0); sceneColor2 = lerp(sceneColor2, SampleSceneColor(uvDistort1), .3); float3 cDistort = saturate(sceneColor2 - sceneColor) * distortAtten; // OUTLINE float3 outlineColor = float3(.001, .002, .0015); float outlineAtten = smoothstep(3, 30, depthMeters); float outline = 0; float outlineWeight = 0; float2 uvs[4]; uvs[0] = uv1; uvs[1] = uv2; uvs[2] = uv3; uvs[3] = uv4; [Unroll] for (float i = 0; i < 4; i++) { float t = floor(cos((_Time.y + positionWS) * (4 + i * 3) * .8) * .1); t = 0; float2 thickness = 8 - i * .9; thickness = thickness * lerp(.05, 1, np2 * .5 + .5); thickness = thickness * _ScreenParams.y / 1080 / _ScreenParams.xy; float2 uv = uvs[i]; float w = 1 - i * .3; outline += ComputeOutline(uv, thickness, normalWS, viewDir, outlineAtten) * w; outlineWeight += w; } outline /= outlineWeight; // COLOR (WIP) float3 c = sceneColor; //c = lerp(sceneColor, sceneColor2, smoothstep(1, .9, (sceneColor2.r + sceneColor2.g + sceneColor2.b) / 3)); //c = (sceneColor2.r + sceneColor2.g + sceneColor2.b) / 3.; //c = lerp(c, sceneColor2, (greyscale + smoothstep(5, 35, depthMeters) * .8) * .5); //c += sceneColor2 * greyscale * .5; c = lerp(c, outlineColor, outline); c += cDistort * 1.5; //c = ((c + 1) * (sceneColor2 + 0)); //c = smoothstep(-.1, 0, np2); //c = greyscale; /*float3 pWS = positionWS; //scaledPositionOS; //float np0 = PerlinNoise3D(pWS, 2); float distort = WorldDistort(pWS + np0 * .2, normalWS, 1, .1); float3 p = pWS + np0 * 2 + distort * smoothstep(.5, .7, np0) * .06; float grad = 0; float cell = 0; VoronoiNoise3D_float(p, 2, 1, 1, grad, cell); float3 v = cell * .8; // * (grad + distort * .1); v += smoothstep(.05, .02, grad) * smoothstep(.4, .7, np0) * 2; c *= lerp(.9, 1, v); // DIRT float dirtNoise0 = PerlinNoise3D(positionWS, 30); float dirtNoise1 = PerlinNoise3D(positionWS, 5); float dirt0 = smoothstep(.2, .22, dirtNoise0); float dirt1 = saturate(smoothstep(.01, .02, abs(dot(dirtNoise0, dirtNoise1) - .4)) + dirtNoise1 + outlineAtten); c *= dirt0 * dirt1;*/ // SHADOW /*float sceneLuminance = dot(sceneColor, float3(.299, .587, .114)); float hatchAtten = smoothstep(15, 1, depthMeters); float hatchMask = smoothstep(.012, .004, sceneLuminance) * hatchAtten; float hatchWidth = lerp(.025, .18, hatchMask) * hatchAtten; float hatchLayerMask = smoothstep(.35, .75, np3 + np0); float hatch0 = BipyramidHatch(positionWS, normalWS, .35, 28, hatchWidth); float hatch1 = BipyramidHatch(positionWS + 13.7, normalWS, 1.75, 21, hatchWidth * .85); float hatch2 = BipyramidHatch(positionWS + 31.3, normalWS, 2.45, 26, hatchWidth * .9); float hatch3 = BipyramidHatch(positionWS + 47.9, normalWS, .95, 19, hatchWidth * .8); float hatchesA = saturate(hatch0 + hatch1 * .45); float hatchesB = saturate(hatch2 + hatch3 * .45); float hatches = saturate(hatchesA + hatchesB * hatchLayerMask * .55); c = lerp(c, float3(0, 0, 0), hatches * hatchMask * .3);*/ // OUTPUT Output = c; //Output = nDistort * .5 + .5; //Output = np2; //Output = sceneColor2; //Output = hatchMask; //Output = dot(normalWS, viewDir); } #endif