Search code examples
filterluagraphicsscriptingforge

How to create a spherical angular gradient around y-axis using Lua in Filter Forge?


I am working on a Spherical Map Script that generates a linear gradient along the y-axis and an angular gradient around the y-axis in the green and red channels, respectively. I have been unable to find any documentation suited to this online, but have experimented using examples in Javascript and C#. The linear gradient has worked out fine, but the angular gradient (one describing a 360 degree arc around the y-axis) continues to elude me.

My working script is as follows.

-- 3d sphere 
    -- produces rgb gradudient mapped to a 3d sphere, but not correctly. 
    -- this is basically missing an angle gradient around the y-axis...
function prepare()
    -- tilt & rotation precalc
    toRad = 180/math.pi
    -- toCir = 360/math.p -- may or may not work for circumference...

    radius = get_slider_input(RADIUS)

    angle = get_angle_input(ROTATION)/toRad
    cosa = math.cos(angle)
    sina = math.sin(angle)

    tilt = get_angle_input(TILT)/toRad
    cosa2 = math.cos(tilt)
    sina2 = math.sin(tilt)
end;


function get_sample(x, y)
    local r, g, b, a = get_sample_map(x, y, SOURCE)
    -- color gradient example
    --  local r = x
    --  local g = y
    --  local b = (x + y) / 2
    --  local a = 1
    -- spherical mapping formulae (polar to cartesian, apparently)
    --  local x = x * math.pi -- * aspect 
    --  local y = y * math.pi
    --  local nx = math.cos(x) * math.sin(y) 
    --  local ny = math.sin(x) * math.sin(y) 
    --  local nz = math.cos(y) 
    -- cartesian to polar (reference)
    --  example 1
    --  r = math.sqrt(((x * x) + (y * y) + (z * z))) 
    --  long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0 ? -1 : 1) 
    --  lat = math.acos(z / radius) * (z < 0 ? -1 : 1) 
    --  example 2
    --      r = math.sqrt((x * x) + (y * y) + (z * z)) 
    --      long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0 ? -1 : 1) 
    --  lat = math.acos(z / r) 
            -- equations cannot accept boolean comparison
            -- boolean syntax may not be valid in lua
   
    -- image generation
    -- shift origin to center and set radius limits
    local px = (x*2.0) - 1.0
    local py = (y*2.0) - 1.0
    px = px/radius
    py = py/radius
    local len = math.sqrt((px*px)+(py*py))
    if len > 1.0 then return 0,0,0,0 end

    local z = -math.sqrt(1.0 - ((px*px)+(py*py)))

    -- cartesian to polar
        -- r = math.sqrt((x * x) + (y * y) + (z * z))
        -- lat = math.acos(z / r)
        -- long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0) ? -1 : 1) 

    -- apply rotaqtion and tilt (order is important)
    local tz = (cosa2 * z) - (sina2 * py) 
    local ty = (sina2 * z) + (cosa2 * py) -- gradient along y-axis is correct
    z = tz 
    py = ty

    local tx = (cosa * px) - (sina * z) -- gradient needs to go around y-axis
    local tz = (sina * px) + (cosa * z)
    px = tx
    z = tz

        -- r = math.sqrt((x * x) + (y * y) + (z * z)) 
        -- lat = math.acos(z / r) -- invalid z for this; what is correct source?
        -- long = math.acos(x / math.sqrt((x * x) + (y * y))) -- map -1 : 1 needed
        -- long = (sina * px) + (cosa * z) -- ok;  2 full rotations

    -- return r, g, b, a
    -- return px,py,z,a 
    return px/2+.5,py/2+.5,z/2+.5,a 
    -- return px/2+.5,px/2+.5,px/2+.5,a 
    -- return long,long,long,a 
    -- return px/2+.5,py/2+.5,long,a 
end;

Solution

  • I found a way to construct a spherical angular gradient from the hemispherical axis gradients I started with, by using three as the RBG channels in an RBG to HSL conversion. I've used this to map textures to spheres in Filter Forge in map scripts like this.

    I thought I'd share the solution for anyone who's followed my question here.