Nodes/Jovi_GLSL/CONICAL GRADIENT (JOV_GL)
ComfyUI Node

CONICAL GRADIENT (JOV_GL)

Conical gradients for masks, backgrounds, and 'it should fade around a point' problems

By Amorano·Created 2 years ago·Updated about a year ago· 20
CONICAL GRADIENT (JOV_GL)
  • origin
  • range
  • iRes
  • RGBA
  • RGB
  • MASK
angle0.0
FRAGMENT// name: CONICAL GRADIENT // desc: Generate a conical gradient from black to white // category: CREATE // control: res, #ifndef LIB_CONST #define LIB_CONST //------------------------------------------------------------------------------ // CONSTANT //------------------------------------------------------------------------------ #define M_EPSILON 1.0e-10 // zero value for float comparisons #define M_DEG2RAD 0.017453292519943 // Degree to radian conversion factor #define M_RAD2DEG 57.29577951308232 // Radian to degree conversion factor #define M_TAU 6.283185307179586 // TAU (2 * π) #define M_TAU_INV 0.159154943091895 // TAU Inverse (1 / TAU) #define M_PI 3.141592653589793 // π #define M_PI_INV 0.318309886183790 // π Inverse (1 / π) #define M_PI_2 1.570796326794896 // π divided by 2 (π / 2) #define M_PI_4 0.785398163397448 // π divided by 4 (π / 4) #define M_3PI_4 2.356194490192345 // 3 * π divided by 4 (3π / 4) #define M_PHI 1.618033988749895 // Golden ratio (φ) #define M_PHI_INV 0.618033988749895 // Inverse of golden ratio (1 / φ) #define M_PHI_SQ 2.618033988749895 // Square of the golden ratio (φ^2) #define M_PHI_SQRT5 0.723606797749979 // φ / √5 (useful for fibonacci spherical distribution) #define M_GOLD_ANG 2.399963229728653 // Golden angle in radians #define M_E 2.718281828459045 // Euler's number (base of natural logarithm) #define M_LOG2E 1.442695040888963 // Log base 2 of e #define M_LOG10E 0.434294481903252 // Log base 10 of e #define M_LN2 0.693147180559945 // Natural log of 2 #define M_LN10 2.302585092994046 // Natural log of 10 #define M_SQRT2 1.414213562373095 // Square root of 2 #define M_SQRT3 1.732050807568877 // Square root of 3 #define M_SQRT2_INV 0.707106781186547 // 1 divided by square root of 2 (1 / sqrt(2)) #define M_SQRT3_INV 0.577350269189626 // 1 divided by square root of 3 (1 / sqrt(3)) #define M_SQRT5 2.236067977499790 // Square root of 5 //------------------------------------------------------------------------------ // GENERAL //------------------------------------------------------------------------------ // useful for triangle interpolation vec3 barycentricCoords(vec2 p, vec2 a, vec2 b, vec2 c) { vec2 v0 = b - a; vec2 v1 = c - a; vec2 v2 = p - a; float d00 = dot(v0, v0); float d01 = dot(v0, v1); float d11 = dot(v1, v1); float d20 = dot(v2, v0); float d21 = dot(v2, v1); float denom = d00 * d11 - d01 * d01; vec3 result; result.y = (d11 * d20 - d01 * d21) / denom; result.z = (d00 * d21 - d01 * d20) / denom; result.x = 1.0 - result.y - result.z; return result; } #endif uniform vec2 origin; // 0.5,0.5; 0; 1; 0.01 | Intensity of base normal uniform vec2 range; // 0.0,1.0; 0; 1; 0.01 | start of range. 0=start. size of range. 1=full range. uniform float angle; // 0.0; ; ; 0.5 | offset of the gradient starting angle void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord / iResolution.xy - origin; float normAngle = atan(uv.y, uv.x) - (angle * M_TAU / 360); float t = fract(normAngle * M_TAU_INV); float norm = mix(range.x, range.y, t); fragColor = vec4(norm, norm, norm, 1.0); }

Every time you need something to fade around a point instead of across a line - a vignette with character, a directional light feel, a mask that wraps around a subject - you end up hand-drawing it or hacking together a linear gradient and rotating it. This node gives you the honest version: a conical gradient, one color smoothly wrapping a full 360° around an origin you choose. It generates a black-to-white ramp by default, which makes it a ridiculously flexible mask factory.

How it works

For each pixel it computes the angle from the gradient's origin using atan, adds your angle offset, and maps that angle into the 0–1 range to produce a grayscale value. Because it's a fragment shader running on the GPU, the whole thing renders in one pass and updates live as you drag the origin around - no waiting, no preview lag.

There's no image input; this is a pure generator like the other CREATE nodes in the pack. You get a grayscale image out, sized by iRes (default 512×512).

The inputs that matter

  • origin - where the gradient's center sits, as a VEC2 in normalized 0–1 space. Default 0.5, 0.5 (dead center). This is the "where does the angle pivot" control, and it's the one you'll actually drag.
  • range - start and size of the ramp, default 0 to 1. Crank it to start the gradient partway around the circle, or shrink it so the falloff is tighter.
  • angle - rotates where the gradient starts. Handy for aligning the "seam" so it hides behind something.
  • iRes - output resolution.

Outputs are the pack's usual RGBA, RGB, and MASK. Here the MASK output is arguably the star - a conical gradient as a mask is exactly what you want for radial compositing or for feeding into a workflow as a soft selection.

Install

Standard pack install. Via ComfyUI Manager, search Jovi_GLSL; or:

cd ComfyUI/custom_nodes
git clone https://github.com/Amorano/Jovi_GLSL.git
cd Jovi_GLSL
pip install -r requirements.txt

Restart ComfyUI. Same dependencies as every node here - PyOpenGL, glfw, opencv-contrib-python, cozy_comfyui from git - and it needs an OpenGL context at runtime. No models, no keys. It sits in JOVI_GLSL 🌈 → CREATE.

Gotchas

The origin tooltip in the current build says "Intensity of base normal," which is a copy-paste from the NORMAL node - ignore it; origin is a position, not an intensity. Also remember the gradient is black-to-white by default, so if you want a colored background, route the output through a colorize or tint step rather than expecting color controls here. For a two-color conical gradient the pack's sibling (LINEAR/CIRCULAR GRADIENT) nodes are closer to what you want; this one is the angle-driven, mask-oriented workhorse.

CategoryJOV_GL 🌈/CREATE

Inputs (5)

NameTypeDefaultDescription
originoptVEC20.5,0.5Intensity of base normal
rangeoptVEC20,1start of range. 0=start. size of range. 1=full range.
angleoptFLOAT0.0-9223372036854776000–9223372036854776000offset of the gradient starting angle
iResoptVEC2INT512,512Width and Height as a Vector2 Integer (x, y)
FRAGMENToptSTRING// name: CONICAL GRADIENT // desc: Generate a conical gradient from black to white // category: CREATE // control: res, #ifndef LIB_CONST #define LIB_CONST //------------------------------------------------------------------------------ // CONSTANT //------------------------------------------------------------------------------ #define M_EPSILON 1.0e-10 // zero value for float comparisons #define M_DEG2RAD 0.017453292519943 // Degree to radian conversion factor #define M_RAD2DEG 57.29577951308232 // Radian to degree conversion factor #define M_TAU 6.283185307179586 // TAU (2 * π) #define M_TAU_INV 0.159154943091895 // TAU Inverse (1 / TAU) #define M_PI 3.141592653589793 // π #define M_PI_INV 0.318309886183790 // π Inverse (1 / π) #define M_PI_2 1.570796326794896 // π divided by 2 (π / 2) #define M_PI_4 0.785398163397448 // π divided by 4 (π / 4) #define M_3PI_4 2.356194490192345 // 3 * π divided by 4 (3π / 4) #define M_PHI 1.618033988749895 // Golden ratio (φ) #define M_PHI_INV 0.618033988749895 // Inverse of golden ratio (1 / φ) #define M_PHI_SQ 2.618033988749895 // Square of the golden ratio (φ^2) #define M_PHI_SQRT5 0.723606797749979 // φ / √5 (useful for fibonacci spherical distribution) #define M_GOLD_ANG 2.399963229728653 // Golden angle in radians #define M_E 2.718281828459045 // Euler's number (base of natural logarithm) #define M_LOG2E 1.442695040888963 // Log base 2 of e #define M_LOG10E 0.434294481903252 // Log base 10 of e #define M_LN2 0.693147180559945 // Natural log of 2 #define M_LN10 2.302585092994046 // Natural log of 10 #define M_SQRT2 1.414213562373095 // Square root of 2 #define M_SQRT3 1.732050807568877 // Square root of 3 #define M_SQRT2_INV 0.707106781186547 // 1 divided by square root of 2 (1 / sqrt(2)) #define M_SQRT3_INV 0.577350269189626 // 1 divided by square root of 3 (1 / sqrt(3)) #define M_SQRT5 2.236067977499790 // Square root of 5 //------------------------------------------------------------------------------ // GENERAL //------------------------------------------------------------------------------ // useful for triangle interpolation vec3 barycentricCoords(vec2 p, vec2 a, vec2 b, vec2 c) { vec2 v0 = b - a; vec2 v1 = c - a; vec2 v2 = p - a; float d00 = dot(v0, v0); float d01 = dot(v0, v1); float d11 = dot(v1, v1); float d20 = dot(v2, v0); float d21 = dot(v2, v1); float denom = d00 * d11 - d01 * d01; vec3 result; result.y = (d11 * d20 - d01 * d21) / denom; result.z = (d00 * d21 - d01 * d20) / denom; result.x = 1.0 - result.y - result.z; return result; } #endif uniform vec2 origin; // 0.5,0.5; 0; 1; 0.01 | Intensity of base normal uniform vec2 range; // 0.0,1.0; 0; 1; 0.01 | start of range. 0=start. size of range. 1=full range. uniform float angle; // 0.0; ; ; 0.5 | offset of the gradient starting angle void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord / iResolution.xy - origin; float normAngle = atan(uv.y, uv.x) - (angle * M_TAU / 360); float t = fract(normAngle * M_TAU_INV); float norm = mix(range.x, range.y, t); fragColor = vec4(norm, norm, norm, 1.0); }

Outputs (3)

NameTypeDescription
RGBAIMAGEFull channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output.
RGBIMAGEThree channel [RGB] image. There will be no alpha.
MASKMASKSingle channel mask output.