Files
Ipseity-Demo/Assets/_Content/Shaders/EnkiBillal/Include/EnkiBiIlal.hlsl
T
2026-05-28 01:27:15 +02:00

422 lines
12 KiB
HLSL

#ifndef ENKI_BILLAL_INCLUDED
#define ENKI_BILLAL_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
//#include "Assets/_Content/Shaders/EnkiBillal/Stripes.hlsl"
#include "Assets/_Content/Shaders/Include/Noises.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
float MainLightShadowAtten(float3 PositionWS, float3 NormalWS, float CastAtten)
{
float4 shadowCoord = TransformWorldToShadowCoord(PositionWS);
Light mainLight = GetMainLight(shadowCoord);
float lightGradient = dot(normalize(NormalWS), normalize(mainLight.direction));
lightGradient = smoothstep(-.5, 1, lightGradient);
float shadow = 1 - mainLight.shadowAttenuation;
shadow = lerp(0, shadow, lightGradient) * CastAtten;
shadow = lerp(1, shadow, lightGradient);
shadow = 1 - shadow;
return shadow;
}
float3 TriplanarMask(float3 NormalWS, float Sharpness)
{
float sharpness = Remap(0, 1, 1, 16, smoothstep(0, .9, Sharpness));
float3 hard = abs(NormalWS) == max(abs(NormalWS.x), max(abs(NormalWS.y), abs(NormalWS.z)));
float3 blend = pow(abs(NormalWS), sharpness);
blend /= max(dot(blend, float3(1, 1, 1)), 0.0001);
blend = lerp(blend, hard, smoothstep(.9, 1, Sharpness));
return blend;
}
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 StableStripes(float x, float depth, float width, float smooth)
{
float phase = frac(depth);
float index = floor(depth);
float scale = exp2(-index);
float rawX = x * scale - 0.5;
float cellIndex = floor(rawX);
float2 uv = float2(frac(rawX), phase);
float isContinuing = abs(fmod(cellIndex, 2));
float w = lerp(width, lerp(-smooth, width * 2, isContinuing), uv.y);
float s = smooth;
return smoothstep(w + s, w - s, abs(uv.x - .5) * 2);
}
float WorldStripes()
{
/*float StripesScale = StripesDensity;
//float StripesWidth = .5;
//float StripesSmooth = .05;
// 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
float3 stripesPos = PositionWS;
float3 stripesPos0 = stripesPos; // + PerlinColor3D(PositionWS, .63) * .10;
float3 stripesPos1 = stripesPos; // + PerlinColor3D(PositionWS, 5.7) * .02;
float width = StripesWidth; // * .5;
float smooth = max(StripesSmooth, 1e-5);
float stripes0 = 0;
float stripes1 = 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));
float3 ref = normalize(mainLightDir - dot(mainLightDir, n) * n);
float3 axis = normalize(up - dot(up, n) * n);
float angle = -atan2(dot(cross(axis, ref), n), dot(axis, ref));
float2 p0 = RotateUV(float2(dot(stripesPos0, tangent), dot(stripesPos0, bitangent)), 0, angle) * StripesScale;
float2 p1 = (RotateUV(float2(dot(stripesPos1, tangent), dot(stripesPos1, bitangent)), 0, angle) + .5) * StripesScale;
float stripe0 = StableStripes(p0.x, log2(depth), width, smooth);
float stripe1 = StableStripes(p1.x + p1.y, log2(depth), width, smooth);
stripes0 += stripe0 * octaMask[i];
stripes1 += stripe1 * octaMask[i];
}
//float stripes = stripes0 * smoothstep(.5, 0, lightGradient);
float stripes = max(stripes0, stripes1 * .5);
stripes *= smoothstep(.5, 0, lightGradient) * smoothstep(.97, .93, ao);*/
return 0;
}
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 ProjectionMask(
float3 PositionWS,
float3 CamPositionWS,
float3 RectPositionWS,
float3 RectNormalWS,
float3 RectUpWS,
float2 RectSize,
float Oval)
{
// Build the rectangle local frame
float3 N = normalize(RectNormalWS);
float3 U = normalize(RectUpWS);
float3 R = normalize(cross(N, U)); // Right axis
U = normalize(cross(R, N)); // Recompute Up orthogonally in case RectUpWS is not perfectly perpendicular to RectNormalWS
// Ray from camera toward the fragment
float3 rayDir = normalize(PositionWS - CamPositionWS);
// Ray-plane intersection
// Plane equation: dot(P - RectPositionWS, N) = 0
float denom = dot(rayDir, N);
// Ray is parallel to the plane or facing away — no hit
if (abs(denom) < 1e-6)
return 0;
float t = dot(RectPositionWS - CamPositionWS, N) / denom;
// Intersection must be in front of the camera (t > 0)
// and not beyond the fragment (t <= distance from camera to fragment)
float tFrag = dot(PositionWS - CamPositionWS, rayDir);
if (t < 0.0 || t > tFrag + 1e-4)
return 0;
// Compute the hit point on the plane
float3 hitPoint = CamPositionWS + rayDir * t;
// Project hit point into the rectangle local space
float3 localVec = hitPoint - RectPositionWS;
float localU = dot(localVec, R); // horizontal axis
float localV = dot(localVec, U); // vertical axis
float halfW = RectSize.x * 0.5;
float halfH = RectSize.y * 0.5;
// Corner radius: 0 = rectangle, min(halfW, halfH) = oval
float radius = saturate(Oval) * min(halfW, halfH);
// Rounded rectangle SDF
float2 uv = float2(localU, localV);
float2 ext = float2(halfW, halfH);
float2 q = abs(uv) - ext + radius;
float sdf = length(max(q, 0.0)) - radius;
return sdf <= 0.0 ? 1.0 : 0.0;
}
float SampleProjectionMask(float3 PositionWS, float4x4 M)
{
if (M[0].w == 0)
return 0;
return ProjectionMask(
PositionWS,
M[0].xyz, // CamPositionWS
M[1].xyz, // RectPositionWS
M[3].xyz, // RectNormalWS
M[2].xyz, // RectUpWS
float2(M[2].w, M[3].w), // RectSize
M[1].w // Shape
);
}
void EnkiBillal_float
(
float4 Color,
float2 ScreenUV,
float3 PositionWS,
float3 PositionOS,
float3 NormalWS,
float3 NormalOS,
float3 ObjectScale,
float TriplanarBlend,
float StripesDensity,
float StripesWidth,
float StripesSmooth,
int Step,
float MaskID,
float4x4 Mask0,
float4x4 Mask1,
float4x4 Mask2,
out float3 Output,
out float Alpha
)
{
float3 scaledPositionOS = PositionOS * ObjectScale;
float depth = length(PositionWS - _WorldSpaceCameraPos.xyz);
//Light mainLight = GetMainLight(0);
float3 mainLightDir = normalize(float3(1, -1, 1)); //normalize(float3(0, 13, 8) - PositionWS); //float3(0, -1, 0);//normalize(mainLight.direction);
float lightGradient = dot(normalize(NormalWS), normalize(mainLightDir));
lightGradient = smoothstep(-.5, 1, lightGradient);
//float ao = GetScreenSpaceAmbientOcclusion(ScreenUV).directAmbientOcclusion;
// Shadow
float shadowMask = lightGradient;//MainLightShadowAtten(PositionWS, NormalWS, .8);
float shadowAtten = Remap(0, 1, .6, 1, shadowMask);
// Grain
/*float grain = ValueNoise3DLOD(PositionWS, scaledPositionOS, 600, 3.5);
float grainMin = lerp(.4, .8, shadowMask);
float grainAtten = Remap(0, 1, grainMin, 1, grain);
// Dirt
float dirt = FBMNoise3D(scaledPositionOS, 1, 3, 2, .5);
float dirtMin = lerp(.2, .7, shadowMask);
float dirtAtten = Remap(0, 1, dirtMin, 1, dirt);*/
// Stripes
// float stripes = WorldStripes();
// Test
//float test = ValueNoise3D(PositionWS, 40);
//float test = PerlinNoise3D(PositionWS, 40);
//float test = PerlinNoise3DLOD(PositionWS, 100, 3.5);
//float test = SimplexNoise3D(PositionWS, 40);
//float test = WorleyNoise3D(PositionWS, 40, 1);
//float id;
//float test = VoronoiNoise3D(PositionWS, 10, 1, .05, id);
//float test = FBMNoise3D(PositionWS, 10, 2, 2, .5);
//float test = RidgedNoise3D(PositionWS, 10, 2, 2, .5);
/*float3 pWS = scaledPositionOS;
float n0 = PerlinNoise3D(pWS, 2);
float distort = WorldDistort(pWS + n0 * .2, NormalWS, 1, TriplanarBlend);
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;
float3 c = Color * lerp(.9, 1, v);*/
// Output
//Output = 1;
//if (Step > 0 ) Output *= Color;
//if (Step > 1 ) Output *= grainAtten;
//if (Step > 2 ) Output *= dirtAtten;
//if (Step > 3 ) Output *= shadowAtten;
//if (Step > 4 ) Output = lerp(Output, Output * .1, stripes * .8);
Output = Color;
//Output = PerlinColor3D(PositionWS, 5);
//Output = smoothstep(.97, .93, ao);
// Mask
if (Mask2[0].w == 1)
{
float mask = SampleProjectionMask(PositionWS, Mask2);
Alpha = (MaskID <= 1) ? 1 - mask : mask;
}
else if (MaskID == 0)
{
Alpha = 1;
}
else
{
float Active = Mask0[0].w + Mask1[0].w; // + Mask2[0].w;
if (Active > 0)
{
float mask = saturate(
SampleProjectionMask(PositionWS, Mask0) +
SampleProjectionMask(PositionWS, Mask1) // +
//SampleProjectionMask(PositionWS, Mask2)
);
Alpha = (MaskID == 1) ? 1 - mask : mask;
}
else
{
Alpha = (MaskID == 1) ? 0 : 1;
}
}
}
#endif