Files
Ipseity-Demo/Assets/_Content/Shaders/EnkiBillal/Include/EnkiBiIal.hlsl
T

342 lines
7.4 KiB
HLSL

#ifndef ENKI_BILAL_INCLUDED
#define ENKI_BILAL_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Assets/_Content/Shaders/Include/Noises.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
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;
}
float3 GetScale(float3 PivotWS)
{
return float3
(
length(TransformObjectToWorld(float3(1, 0, 0)) - PivotWS),
length(TransformObjectToWorld(float3(0, 1, 0)) - PivotWS),
length(TransformObjectToWorld(float3(0, 0, 1)) - PivotWS)
);
}
float GetShadow(float3 PositionWS)
{
float4 shadowCoord = TransformWorldToShadowCoord(PositionWS);
Light mainLight = GetMainLight(shadowCoord);
float shadow = 1 - mainLight.shadowAttenuation;
#if defined(_ADDITIONAL_LIGHTS)
uint lightsCount = GetAdditionalLightsCount();
[loop]
for (uint i = 0; i < lightsCount; i++)
{
Light light = GetAdditionalLight(i, PositionWS);
shadow = max(shadow, 1 - light.shadowAttenuation);
}
#endif
return saturate(shadow);
}
void GetDetailLOD
(
float Depth,
float DetailSizeA,
float LODJitter,
out float DetailSizeAA,
out float DetailSizeAB,
out float LODBlend
)
{
const float lodRatio = 4;
const float lodSize = DetailSizeA / lodRatio * 2;
float dist = max(Depth, 1e-5);
float lod = log(dist) / log(lodRatio) + LODJitter; // log2(dist);
float lodFloor = floor(lod);
float lodFrac = lod - lodFloor;
LODBlend = lodFrac * lodFrac * (3 - 2 * lodFrac);
DetailSizeAA = lodSize * pow(lodRatio, lodFloor);
DetailSizeAB = lodSize * pow(lodRatio, lodFloor + 1);
}
float4 SampleBombedTexture
(
UnityTexture2D Tex,
float2 UV
)
{
const float cellBlend = 4;
float2 cell = floor(UV);
float2 local = frac(UV);
float4 result = 0;
float weightSum = 0;
[unroll]
for (int y = 0; y < 2; y++)
{
[unroll]
for (int x = 0; x < 2; x++)
{
float2 currentCell = cell + float2(x, y);
float2 randomOffset = (Hash2D(currentCell) - .5) * .35;
float randomAngle = Hash1From2D(currentCell) * TWO_PI;
float2 center = float2(x, y) + randomOffset;
float2 delta = local - center;
float weight =
pow(saturate(1 - abs(delta.x)), cellBlend) *
pow(saturate(1 - abs(delta.y)), cellBlend);
float2 sampleUV = UV + randomOffset;
sampleUV = RotateUV
(
sampleUV,
currentCell + .5,
randomAngle
);
result += Tex.tex.Sample
(
Tex.samplerstate,
sampleUV
) * weight;
weightSum += weight;
}
}
return result / max(weightSum, 1e-5);
}
struct ProjectionData
{
float2 uv[7];
float mask[7];
};
ProjectionData GetProjections
(
float3 PositionOS,
float3 NormalOS,
float ProjectionBlend
)
{
ProjectionData data;
float3 normal = normalize(NormalOS);
float3 projectionNormals[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 sharpness = lerp(2, 32, saturate(ProjectionBlend));
float maskSum = 0;
[unroll]
for (int i = 0; i < 7; i++)
{
float3 n = projectionNormals[i];
float d = abs(dot(normal, n));
data.mask[i] = pow(saturate(d), sharpness);
maskSum += data.mask[i];
float3 up = abs(n.y) < .999
? float3(0, 1, 0)
: float3(1, 0, 0);
float3 tangent = normalize(cross(up, n));
float3 bitangent = normalize(cross(n, tangent));
data.uv[i] = float2
(
dot(PositionOS, tangent),
dot(PositionOS, bitangent)
);
}
maskSum = max(maskSum, 1e-5);
[unroll]
for (int i = 0; i < 7; i++)
data.mask[i] /= maskSum;
return data;
}
float4 SampleProjectedDetailLOD
(
UnityTexture2D DetailTex,
float3 PositionOS,
float3 NormalOS,
float ProjectionBlend,
float DetailSizeA,
float Depth
)
{
const float lodJitterStrength = .8;
const float lodJitterSize = 1.5;
float4 detail = 0;
float totalMask = 0;
ProjectionData projections = GetProjections
(
PositionOS,
NormalOS,
ProjectionBlend
);
[unroll]
for (int i = 0; i < 7; i++)
{
float mask = projections.mask[i];
float lodJitter = (Hash1From2D(floor(projections.uv[i] * lodJitterSize) + i * 17.13) - .5) * lodJitterStrength;
float DetailSizeAA;
float DetailSizeAB;
float lodBlend;
GetDetailLOD
(
Depth,
DetailSizeA,
lodJitter,
DetailSizeAA,
DetailSizeAB,
lodBlend
);
float4 detailA = SampleBombedTexture
(
DetailTex,
projections.uv[i] / DetailSizeAA
);
float4 detailB = SampleBombedTexture
(
DetailTex,
projections.uv[i] / DetailSizeAB
);
detail += lerp(detailA, detailB, lodBlend) * mask;
totalMask += mask;
}
return detail / max(totalMask, 1e-5);
}
void EnkiBillal_float
(
float4 Color,
UnityTexture2D DetailTexA,
UnityTexture2D DetailTexB,
float2 ScreenUV,
float3 PositionWS,
float3 NormalWS,
float ProjectionsBlend,
float DetailIntensityA,
float DetailIntensityB,
float DetailSizeA,
float DetailSizeB,
uint FogUse,
float4 FogColor,
float FogMin,
float FogMax,
out float3 Output,
out float Alpha
)
{
// Common
float depth = length(PositionWS - _WorldSpaceCameraPos.xyz);
float3 pivotWS = TransformObjectToWorld(float3(0, 0, 0));
float3 scale = GetScale(pivotWS);
float3 positionOS = TransformWorldToObject(PositionWS) * scale;
float3 normalOS = normalize(TransformWorldToObjectDir(NormalWS));
//float ao = GetScreenSpaceAmbientOcclusion(ScreenUV).directAmbientOcclusion;
// Shadow
float shadow = GetShadow(PositionWS);
float shadowAtten = Remap(1, 0, .6, 1, shadow);
// Detail
float4 detailA = SampleProjectedDetailLOD
(
DetailTexA,
positionOS,
normalOS,
ProjectionsBlend,
DetailSizeA,
depth
);
float4 detailB = SampleProjectedDetailLOD
(
DetailTexB,
positionOS,
normalOS,
ProjectionsBlend,
DetailSizeB,
depth
);
float detailMaskA = smoothstep(0, .8, detailA.a);
float detailMaskB = smoothstep(0, .8, detailB.a);
// Fog
// Output
Output = Color.rgb;
Output = lerp(Output.rgb, detailA.rgb, detailMaskA * DetailIntensityA);
Output = lerp(Output.rgb, detailB.rgb, detailMaskB * DetailIntensityB);
if (FogUse)
{
Output = lerp(Output.rgb, FogColor.rgb, smoothstep(FogMin, FogMax, depth) * FogColor.a);
}
Alpha = Color.a;
}
#endif