305 lines
8.9 KiB
HLSL
305 lines
8.9 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);
|
|
|
|
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 ComputeOutline(float2 uv, float2 texel, float depthMeters, float3 normalWS, float3 positionWS)
|
|
{
|
|
// DEPTH OUTLINE
|
|
|
|
float depthL = LinearEyeDepth(SampleSceneDepth(uv + float2(-texel.x, 0)), _ZBufferParams);
|
|
float depthR = LinearEyeDepth(SampleSceneDepth(uv + float2(texel.x, 0)), _ZBufferParams);
|
|
float depthD = LinearEyeDepth(SampleSceneDepth(uv + float2(0, -texel.y)), _ZBufferParams);
|
|
float depthU = LinearEyeDepth(SampleSceneDepth(uv + float2(0, texel.y)), _ZBufferParams);
|
|
|
|
float depthDiff =
|
|
max(abs(depthMeters - depthL), abs(depthMeters - depthR)) +
|
|
max(abs(depthMeters - depthD), abs(depthMeters - depthU));
|
|
|
|
float viewFacing = abs(dot(normalWS, normalize(_WorldSpaceCameraPos - positionWS)));
|
|
float grazingMask = smoothstep(0.08, 0.35, viewFacing);
|
|
|
|
float depthThreshold = max(0.01, depthMeters * 0.03);
|
|
float depthOutline = smoothstep(depthThreshold, depthThreshold * 3.0, depthDiff);
|
|
depthOutline *= grazingMask;
|
|
|
|
// NORMAL OUTLINE
|
|
|
|
float3 normalL = normalize(SampleSceneNormals(uv + float2(-texel.x, 0)));
|
|
float3 normalR = normalize(SampleSceneNormals(uv + float2(texel.x, 0)));
|
|
float3 normalD = normalize(SampleSceneNormals(uv + float2(0, -texel.y)));
|
|
float3 normalU = normalize(SampleSceneNormals(uv + float2(0, texel.y)));
|
|
|
|
float normalDiff =
|
|
distance(normalWS, normalL) +
|
|
distance(normalWS, normalR) +
|
|
distance(normalWS, normalD) +
|
|
distance(normalWS, normalU);
|
|
|
|
float normalOutline = smoothstep(0.6, 0.8, normalDiff);
|
|
|
|
return saturate(normalOutline + depthOutline);
|
|
}
|
|
|
|
void EnkiBillalFullscreen_float
|
|
(
|
|
float2 UV,
|
|
out float3 Output
|
|
)
|
|
{
|
|
// DEPTH
|
|
|
|
float rawDepth = SampleSceneDepth(UV);
|
|
float depthMeters = LinearEyeDepth(rawDepth, _ZBufferParams);
|
|
float depth01 = Linear01Depth(rawDepth, _ZBufferParams);
|
|
|
|
// POSITION WORLD SPACE
|
|
|
|
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);
|
|
|
|
// NORMAL WORLD SPACE
|
|
|
|
float3 normalWS = normalize(SampleSceneNormals(UV));
|
|
|
|
// SCENE COLOR
|
|
|
|
float3 sceneColor = SampleSceneColor(UV);
|
|
|
|
// SETTINGS
|
|
|
|
float outlineAtten = smoothstep(3, 30, depthMeters);
|
|
|
|
float thicknessNoise = (PerlinNoise3D(positionWS, 1.7) - .4) * 18;
|
|
thicknessNoise *= sqrt(1 - outlineAtten);
|
|
|
|
float thicknessRaw = lerp(thicknessNoise, 1, outlineAtten);
|
|
float thicknessA = floor(thicknessRaw);
|
|
float thicknessB = thicknessA + 1;
|
|
float thicknessBlend = frac(thicknessRaw);
|
|
|
|
float2 texelA = (thicknessA * _ScreenParams.y / 1080) / _ScreenParams.xy;
|
|
float2 texelB = (thicknessB * _ScreenParams.y / 1080) / _ScreenParams.xy;
|
|
|
|
// OUTLINE
|
|
|
|
float2 uvA = UV;
|
|
float2 uvB = UV;
|
|
|
|
float outlineA = ComputeOutline(uvA, texelA, depthMeters, normalWS, positionWS);
|
|
float outlineB = ComputeOutline(uvB, texelB, depthMeters, normalWS, positionWS);
|
|
|
|
float outline = lerp(outlineA, outlineB, thicknessBlend);
|
|
|
|
// COLOR (WIP)
|
|
|
|
float3 c = sceneColor;
|
|
|
|
/*float3 pWS = positionWS; //scaledPositionOS;
|
|
float n0 = PerlinNoise3D(pWS, 2);
|
|
float distort = WorldDistort(pWS + n0 * .2, normalWS, 1, .1);
|
|
float3 p = pWS + n0 * 2 + distort * smoothstep(.5, .7, n0) * .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, n0) * 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 hatchNoise = PerlinNoise3D(positionWS, .85);
|
|
float hatchLayerMask = smoothstep(.35, .75, hatchNoise);
|
|
|
|
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 = lerp(c, float3(0.0, 0.0, 0.0), outline);
|
|
//Output = hatchMask;
|
|
}
|
|
#endif |