goofi v3.0.0

Math

Scale and shift texture channels, then remap their range.

The order is (input + pre_add) * multiply + post_add, followed by range mapping. RGB leaves alpha unchanged; alpha leaves RGB unchanged; RGBA applies the same math to all four channels. A zero-width source range gives to_low. Reversed ranges are supported. Bounds use the sorted target endpoints: clamp holds values at the edges; wrap repeats the range; fold halves or doubles positive values into a positive range, as in signal Math. Fold ranges narrower than an octave can leave values outside. Values are not clamped unless clamp is selected.

Math wgsl
input
out
Type name
graphics:Math
Plane
graphics
Tags
imagetransform
Language
wgsl
Tier
shader
Bundle
graphics
Source
node-bundles/graphics/Math.wgsl
Availability
available

Slots

SlotDirectionType
inputinputTEXTURE
outoutputTEXTURE

Parameters

math

NameTypeDefaultRangeDoc
channelsstringrgbrgb | rgba | alpha
pre_addfloat0-1000000000 … 1000000000
multiplyfloat1-1000000000 … 1000000000
post_addfloat0-1000000000 … 1000000000

range

NameTypeDefaultRangeDoc
from_lowfloat0-1000000000 … 1000000000
from_highfloat1-1000000000 … 1000000000
to_lowfloat0-1000000000 … 1000000000
to_highfloat1-1000000000 … 1000000000
boundstringnonenone | clamp | wrap | fold

common

NameTypeDefaultRangeDoc
widthint00 … 8192Texture size in pixels; 0 follows the first wired texture input. A node that makes its own frames follows the patch's default instead.
heightint00 … 8192Texture size in pixels; 0 follows the first wired texture input. A node that makes its own frames follows the patch's default instead.

Source

The current source of this node, as it stands in the goofi repository at node-bundles/graphics/Math.wgsl.

node-bundles/graphics/Math.wgsl
/* goofi
{ "doc": "Scale and shift texture channels, then remap their range.\nThe order is (input + pre_add) * multiply + post_add, followed by range mapping. RGB leaves alpha unchanged; alpha leaves RGB unchanged; RGBA applies the same math to all four channels. A zero-width source range gives to_low. Reversed ranges are supported. Bounds use the sorted target endpoints: clamp holds values at the edges; wrap repeats the range; fold halves or doubles positive values into a positive range, as in signal Math. Fold ranges narrower than an octave can leave values outside. Values are not clamped unless clamp is selected.",
  "tags": ["image", "transform"],
  "inputs": [{"name": "input", "kind": "TEXTURE"}],
  "params": [
    {"group": "math", "name": "channels", "kind": "str", "default": "rgb", "options": ["rgb", "rgba", "alpha"]},
    {"group": "math", "name": "pre_add", "kind": "float", "default": 0.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "math", "name": "multiply", "kind": "float", "default": 1.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "math", "name": "post_add", "kind": "float", "default": 0.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "range", "name": "from_low", "kind": "float", "default": 0.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "range", "name": "from_high", "kind": "float", "default": 1.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "range", "name": "to_low", "kind": "float", "default": 0.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "range", "name": "to_high", "kind": "float", "default": 1.0, "min": -1000000000.0, "max": 1000000000.0},
    {"group": "range", "name": "bound", "kind": "str", "default": "none", "options": ["none", "clamp", "wrap", "fold"]} ] }
*/
fn map_channel(value: f32) -> f32 {
    let span = p.from_high - p.from_low;
    var mapped = p.to_low;
    if span != 0.0 {
        let scaled = (value + p.pre_add) * p.multiply + p.post_add;
        mapped += (scaled - p.from_low) * ((p.to_high - p.to_low) / span);
    }
    let lo = min(p.to_low, p.to_high);
    let hi = max(p.to_low, p.to_high);
    switch p.bound {
        case 1u: { return clamp(mapped, lo, hi); }
        case 2u: {
            if hi > lo { return lo + (mapped - lo) - floor((mapped - lo) / (hi - lo)) * (hi - lo); }
        }
        case 3u: {
            // An infinite value cannot reach the range by repeated halving.
            if mapped > 0.0 && mapped <= 3.402823e38 && lo > 0.0 && hi > lo {
                while mapped > hi { mapped *= 0.5; }
                while mapped < lo { mapped *= 2.0; }
            }
        }
        default: {}
    }
    return mapped;
}

fn shade(uv: vec2f) -> vec4f {
    let color = textureSample(input, samp, uv);
    var result = color;
    if p.channels != 2u {
        result = vec4f(map_channel(color.r), map_channel(color.g), map_channel(color.b), color.a);
    }
    if p.channels != 0u { result.a = map_channel(color.a); }
    return result;
}

← All nodes