LYGIA Shader Library

bracketing (lygia/space/bracketing)

Bracketing technique maps a texture to a plane using any arbitrary 2D vector field to give orientation. From https://www.shadertoy.com/view/NddcDr

Dependencies:

Use:

sampleBracketing(<SAMPLER_TYPE> texture, <vec2> st, <vec2> direction [, <float> scale] )

Check it on Github




// Parameter for bracketing - bracket size in radians. Large values create noticeable linear structure,
// small values prone to simply replicating the issues with the brute force approach. In my use cases it
// was quick and easy to find a sweet spot.
#ifndef BRACKETING_ANGLE_DELTA
#define BRACKETING_ANGLE_DELTA PI / 20.0
#endif

#ifndef FNC_BRACKETING
#define FNC_BRACKETING

// Vector field direction is used to drive UV coordinate frame, but instead
// of directly taking the vector directly, take two samples of the texture
// using coordinate frames at snapped angles, and then blend them based on
// the angle of the original vector.
void bracketing(vec2 dir, out vec2 vAxis0, out vec2 vAxis1, out float blendAlpha) {
    // Heading angle of the original vector field direction
    float angle = atan(dir.y, dir.x) + TWO_PI;

    float AngleDelta = BRACKETING_ANGLE_DELTA;

    // Snap to a first canonical direction by subtracting fractional angle
    float fractional = mod(angle, AngleDelta);
    float angle0 = angle - fractional;

    // Compute one V axis of UV frame. Given angle0 is snapped, this could come from LUT, but would
    // need testing on target platform to verify that a LUT is faster.
    vAxis0 = vec2(cos(angle0), sin(angle0));

    // Compute the next V axis by rotating by the snap angle size
    mat2 RotateByAngleDelta = mat2( cos(AngleDelta), sin(AngleDelta), 
                                    -sin(AngleDelta), cos(AngleDelta));

    vAxis1 = RotateByAngleDelta * vAxis0;

    // Blend to get final result, based on how close the vector was to the first snapped angle
    blendAlpha = fractional / AngleDelta;
}

#endif

Dependencies:

Use:

sampleBracketing(<SAMPLER_TYPE> texture, <float2> st, <float2> direction [, <float> scale] )

Check it on Github



// Parameter for bracketing - bracket size in radians. Large values create noticeable linear structure,
// small values prone to simply replicating the issues with the brute force approach. In my use cases it
// was quick and easy to find a sweet spot.

#ifndef BRACKETING_ANGLE_DELTA
#define BRACKETING_ANGLE_DELTA PI / 20.0
#endif

#ifndef FNC_BRACKETING
#define FNC_BRACKETING

// Vector field direction is used to drive UV coordinate frame, but instead
// of directly taking the vector directly, take two samples of the texture
// using coordinate frames at snapped angles, and then blend them based on
// the angle of the original vector.
void bracketing(float2 dir, out float2 vAxis0, out float2 vAxis1, out float blendAlpha) {
    // Heading angle of the original vector field direction
    float angle = atan2(dir.y, dir.x) + TWO_PI;

    float AngleDelta = BRACKETING_ANGLE_DELTA;

    // Snap to a first canonical direction by subtracting fractional angle
    float fractional = mod(angle, AngleDelta);
    float angle0 = angle - fractional;

    // Compute one V axis of UV frame. Given angle0 is snapped, this could come from LUT, but would
    // need testing on target platform to verify that a LUT is faster.
    vAxis0 = float2(cos(angle0), sin(angle0));

    // Compute the next V axis by rotating by the snap angle size

    float2x2 RotateByAngleDelta = float2x2( cos(AngleDelta), sin(AngleDelta), 
                                            -sin(AngleDelta), cos(AngleDelta));
    vAxis1 = mul(RotateByAngleDelta, vAxis0);

    // Blend to get final result, based on how close the vector was to the first snapped angle
    blendAlpha = fractional / AngleDelta;
}

#endif

License

MIT license (MIT) Copyright Huw Bowles May 2022

Get the latest news and releases

Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository