#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