317 lines
6.8 KiB
HLSL
317 lines
6.8 KiB
HLSL
#ifndef ENKI_BILLAL_INCLUDED
|
|
#define ENKI_BILLAL_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 DetailSize,
|
|
float LODJitter,
|
|
out float DetailSizeA,
|
|
out float DetailSizeB,
|
|
out float LODBlend
|
|
)
|
|
{
|
|
const float lodRatio = 4;
|
|
const float lodSize = DetailSize / 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);
|
|
|
|
DetailSizeA = lodSize * pow(lodRatio, lodFloor);
|
|
DetailSizeB = 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 DetailSize,
|
|
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 detailSizeA;
|
|
float detailSizeB;
|
|
float lodBlend;
|
|
|
|
GetDetailLOD
|
|
(
|
|
Depth,
|
|
DetailSize,
|
|
lodJitter,
|
|
detailSizeA,
|
|
detailSizeB,
|
|
lodBlend
|
|
);
|
|
|
|
float4 detailA = SampleBombedTexture
|
|
(
|
|
DetailTex,
|
|
projections.uv[i] / detailSizeA
|
|
);
|
|
|
|
float4 detailB = SampleBombedTexture
|
|
(
|
|
DetailTex,
|
|
projections.uv[i] / detailSizeB
|
|
);
|
|
|
|
detail += lerp(detailA, detailB, lodBlend) * mask;
|
|
totalMask += mask;
|
|
}
|
|
|
|
return detail / max(totalMask, 1e-5);
|
|
}
|
|
|
|
void EnkiBillal_float
|
|
(
|
|
float4 Color,
|
|
UnityTexture2D DetailTex,
|
|
float2 ScreenUV,
|
|
float3 PositionWS,
|
|
float3 NormalWS,
|
|
float ProjectionsBlend,
|
|
float DetailSize,
|
|
float4 FogColor,
|
|
float FogMin,
|
|
float FogMax,
|
|
out float3 Output
|
|
)
|
|
{
|
|
// 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 detail = SampleProjectedDetailLOD
|
|
(
|
|
DetailTex,
|
|
positionOS,
|
|
normalOS,
|
|
ProjectionsBlend,
|
|
DetailSize,
|
|
depth
|
|
|
|
);
|
|
|
|
float detailMask = smoothstep(0, .8, detail.a);
|
|
|
|
// Fog
|
|
|
|
// Output
|
|
|
|
Output = Color.rgb;
|
|
Output = lerp(Output.rgb, detail.rgb, detailMask);
|
|
Output = lerp(Output.rgb, FogColor.rgb, smoothstep(FogMin, FogMax, depth) * FogColor.a);
|
|
}
|
|
|
|
#endif |