200 lines
4.9 KiB
HLSL
200 lines
4.9 KiB
HLSL
#ifndef STRIPES_INCLUDED
|
|
#define STRIPES_INCLUDED
|
|
|
|
/*
|
|
STRIPES - AGGRESSIVE / HEAVY HATCH VERSION
|
|
|
|
Goal:
|
|
Make the hatch pattern much stronger, darker and more visible.
|
|
|
|
Changes from the Medium version:
|
|
- Stronger width multiplier.
|
|
- Stronger final mask shaping.
|
|
- Weak strokes are boosted aggressively.
|
|
- Output saturates faster, producing a harsher graphic look.
|
|
*/
|
|
|
|
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);
|
|
|
|
/*
|
|
Stronger reveal than the Medium version.
|
|
This makes stripes appear earlier and more densely.
|
|
*/
|
|
float localProgress = saturate((density - vdc) * stripeCount * 1.35);
|
|
|
|
if (localProgress <= 0.0001)
|
|
return 0.0;
|
|
|
|
float wrappedX = vdc >= 0.5 ? wrappedXB : wrappedXA;
|
|
|
|
/*
|
|
Original random thickness variation, but heavily boosted.
|
|
*/
|
|
float thickness = vdc < 0.3 ? 1.0 : (vdc < 0.6 ? 1.8 : 2.6);
|
|
|
|
/*
|
|
Aggressive thickness boost.
|
|
Raise this if you want even fatter strokes.
|
|
*/
|
|
const float HATCH_WIDTH_BOOST = 2.4;
|
|
|
|
thickness *= saturate(thicknessInput) * HATCH_WIDTH_BOOST;
|
|
|
|
float stripeCenterX = ((float)index + 0.5) / (float)stripeCount;
|
|
|
|
float stripDistanceX = abs(wrappedX - stripeCenterX);
|
|
stripDistanceX = min(stripDistanceX, 1.0 - stripDistanceX);
|
|
|
|
/*
|
|
Wider X footprint = thicker hatch lines.
|
|
*/
|
|
float stepX = (1.0 / (float)stripeCount) * localProgress * thickness * 0.5;
|
|
|
|
/*
|
|
Taller Y footprint = hatch bands cover more vertical space.
|
|
*/
|
|
float stepY = localProgress * 0.65;
|
|
|
|
/*
|
|
Softer but larger edge zone.
|
|
This makes strokes bleed more into nearby pixels.
|
|
*/
|
|
float softEdgeX = 0.025;
|
|
float softEdgeY = 0.085;
|
|
|
|
float widthMask = 1.0 - smoothstep(stepX - softEdgeX, stepX, stripDistanceX);
|
|
float heightMask = 1.0 - smoothstep(stepY - softEdgeY, 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
|
|
)
|
|
{
|
|
/*
|
|
Aggressive density boost.
|
|
Even if the material density is moderate, the shader pushes it harder.
|
|
*/
|
|
float density = saturate(Density * 1.45);
|
|
|
|
float offset = frac(Offset);
|
|
|
|
/*
|
|
Keep the optimized candidate-based approach.
|
|
Count is clamped to avoid bringing back the old expensive behavior.
|
|
*/
|
|
uint stripeCount = max((uint)round(Count), 1u);
|
|
stripeCount = min(stripeCount, 32u);
|
|
|
|
/*
|
|
Stronger distortion for a more nervous hand-drawn look.
|
|
*/
|
|
float distortionAmplitude = DistortionAmplitude * 0.16;
|
|
|
|
float2 uv = UV;
|
|
uv.x = frac(uv.x + offset);
|
|
|
|
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;
|
|
|
|
int baseA = (int)floor(wrappedXA * sc);
|
|
int baseB = (int)floor(wrappedXB * sc);
|
|
|
|
float stripeMax = 0.0;
|
|
|
|
/*
|
|
Still only 6 candidates total:
|
|
- 3 around distortion A
|
|
- 3 around distortion B
|
|
|
|
So this remains much cheaper than the original full Count loop.
|
|
*/
|
|
[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
|
|
)
|
|
);
|
|
}
|
|
|
|
/*
|
|
Brutal final shaping.
|
|
|
|
- smoothstep makes weak strokes become visible sooner.
|
|
- pow with low exponent pulls mid/low values upward.
|
|
- final multiplier forces a strong black graphic result downstream.
|
|
*/
|
|
stripeMax = smoothstep(0.02, 0.28, stripeMax);
|
|
|
|
const float HATCH_POWER = 0.38;
|
|
const float HATCH_FINAL_BOOST = 2.8;
|
|
|
|
Stripes = saturate(pow(stripeMax, HATCH_POWER) * HATCH_FINAL_BOOST);
|
|
}
|
|
|
|
#endif |