Files
Ipseity-Demo/Assets/_Content/Shaders/EnkiBilal/Include/Stripes.hlsl
T
2026-07-07 19:49:54 +02:00

179 lines
4.8 KiB
HLSL

#ifndef STRIPES_INCLUDED
#define STRIPES_INCLUDED
/*
STRIPES - MEDIUM VERSION
Goal:
Reduce the GPU cost of the procedural stripe pattern.
Changes from the original version:
- Removed the dynamic loop over the full stripe count.
Original behavior: evaluate every stripe from 0 to Count.
New behavior: evaluate only 6 nearby stripe candidates.
- Clamped Count to 32 to prevent expensive high-count cases.
- Kept Van der Corput distribution to preserve stable pseudo-random variation.
- Kept the two distortion paths to preserve part of the organic look.
- Visual result is an approximation of the original, but much cheaper.
*/
float VanDerCorput(uint index)
{
return (float)reversebits(index) * 2.3283064365386963e-10;
}
int WrapIndex(int x, int count)
{
int r = x % count;
return r < 0 ? r + count : r;
}
float EvalStripeCandidate(
uint index,
uint stripeCount,
float wrappedXA,
float wrappedXB,
float stripDistanceY,
float density,
float thicknessInput
)
{
float vdc = VanDerCorput(index);
/*
Same progressive reveal logic as the original shader.
Original:
saturate(density * stripeCount - vdc * stripeCount)
Equivalent simplified form:
saturate((density - vdc) * stripeCount)
*/
float localProgress = saturate((density - vdc) * stripeCount);
if (localProgress <= 0.0001)
return 0.0;
/*
Keep the original two distortion paths.
Each stripe chooses one path based on its pseudo-random value.
*/
float wrappedX = vdc >= 0.5 ? wrappedXB : wrappedXA;
/*
Keep the original thickness variation.
This prevents the stripes from looking too uniform.
*/
float thickness = vdc < 0.3 ? 1.0 : (vdc < 0.6 ? 1.8 : 2.6);
thickness *= saturate(thicknessInput);
float stripeCenterX = ((float)index + 0.5) / (float)stripeCount;
float stripDistanceX = abs(wrappedX - stripeCenterX);
stripDistanceX = min(stripDistanceX, 1.0 - stripDistanceX);
float stepX = (1.0 / (float)stripeCount) * localProgress * thickness * 0.5;
float stepY = localProgress * 0.5 - 0.01;
/*
Soft edges are kept from the original shader.
If more performance is needed, these smoothstep calls can be replaced
with step calls, but the result will look harsher.
*/
float widthMask = 1.0 - smoothstep(stepX - 0.01, stepX, stripDistanceX);
float heightMask = 1.0 - smoothstep(stepY - 0.05, stepY, stripDistanceY);
return widthMask * heightMask;
}
void Stripes_float(
float2 UV,
float Density,
float Count,
float Thickness,
float Offset,
float DistortionAmplitude,
float DistortionFrequency,
out float Stripes
)
{
float density = saturate(Density);
float offset = frac(Offset);
/*
Intentional clamp.
Above 32 stripes, the cost increases while the visual gain is usually limited,
especially on distant objects or in a strongly stylized render.
*/
uint stripeCount = max((uint)round(Count), 1u);
stripeCount = min(stripeCount, 32u);
float distortionAmplitude = DistortionAmplitude * 0.1;
float2 uv = UV;
uv.x = frac(uv.x + offset);
/*
The two distortion paths are computed once and reused for all nearby candidates.
*/
float wrappedXA = frac(
uv.x + cos((uv.y + offset) * sin(uv.x) * DistortionFrequency + offset * 7.8)
* distortionAmplitude
);
float wrappedXB = frac(
uv.x + sin((uv.y + offset) * cos(uv.x) * DistortionFrequency + offset * 5.3)
* distortionAmplitude
);
float stripDistanceY = abs(saturate(uv.y) - 0.5);
int sc = (int)stripeCount;
/*
Find the nearest stripe indices for both distortion paths.
Original shader tested every stripe.
Medium version tests only base - 1, base, base + 1 for A and B.
*/
int baseA = (int)floor(wrappedXA * sc);
int baseB = (int)floor(wrappedXB * sc);
float stripeMax = 0.0;
[unroll]
for (int k = -1; k <= 1; k++)
{
uint idxA = (uint)WrapIndex(baseA + k, sc);
uint idxB = (uint)WrapIndex(baseB + k, sc);
stripeMax = max(
stripeMax,
EvalStripeCandidate(
idxA,
stripeCount,
wrappedXA,
wrappedXB,
stripDistanceY,
density,
Thickness
)
);
stripeMax = max(
stripeMax,
EvalStripeCandidate(
idxB,
stripeCount,
wrappedXA,
wrappedXB,
stripDistanceY,
density,
Thickness
)
);
}
Stripes = stripeMax;
}
#endif