// POV-Ray 3.7 Include File "gradients.inc"
// author : Ingo Janssen
// date : 2009-09-23
// rev. : 2012-11-19, functions from iquilezes.org
// rev. : 2018-12-17, rewrite and scene added, still rather unordered
// sources : Various, but mainly,
// Golan Levin : http://www.flong.com/texts/code/
// Inigo Quilez: http://www.iquilezles.org/www/articles/functions/functions.htm
//
//--------------------------------------------------------------------------
#version 3.7;
#include "math.inc"
//==
//epsilon
#declare eps=0.00001; // a predefined epsilon in POV-Ray would be nice ;)
//==
// clip to range zero-one
// A: input value 0-1
#declare clipzo = function(A){clip(A,0,1)};
//==
// clip to range zero-one +/- epsilon
// A: input value A>0 A<1
#declare clipzo_eps = function(A){clip(A,0+eps,1-eps)};
//==
//fraction of value
#declare fract = function(x){x-floor(x)}; //something for math.inc
//==
// #0
// a noisy function
#declare Noise_sin = function{fract((sin(x)+sin(y)+sin(z))*10000000)};
//==
// #1
// exponential
// P: power
#declare G_expo = function(x,P){pow(x,P)};
//==
// #2
// exponential step funtion
// K:
// N:
#declare G_exp_step = function(x,K,N){exp(-K*pow(x,N))};
//==
// #3
// impulse function, usefull for animation
// K: stretch the impulse width, reaches max 1.0 @ x=1/k
#declare G_impulse = function(x,K){(K*x)*exp(1-(K*x))};
//==
// #4
// from 0 to one with circular transition
#declare G_circ_ease_in = function(x){1-sqrt(1-pow(x,2))};
//==
// #5
// from 1 to zero with circular transition
#declare G_circ_ease_out = function(x){sqrt(1-pow((1-x),2))};
//==
// #6
// approximation to the Raised Inverted Cosine curve but faster to compute
// less than 0.1% error in range 0-1
// use, approximate sin or cos trig functions
#declare G_Blinn_Wyvill = function(x){4/9*pow(x,6)-17/9*pow(x,4)+22/9*pow(x,2)};
//==
// #7
// sigmoid like clamping/clipping function
// x: value
// y: min value
// z: max value
#declare G_smoothstep = function(x,y,z){
(3*pow(clipzo((x-y)/(z-y)),2))-
(2*pow(clipzo((x-y)/(z-y)),3))
};
//==
// #8
// smoother version by K.Perlin
// x: value
// y: min value
// z: max value
#declare G_smootherstep=function(x,y,z){
( 6*pow(clipzo((x-y)/(z-y)),5))-
(15*pow(clipzo((x-y)/(z-y)),4))+
(10*pow(clipzo((x-y)/(z-y)),3))
};
//==
// #9
// Remap the range 0-1 to 0-1 setting the corners at 0 and the centre at 1
// K: power
#declare G_parabola = function(x,K){pow(4.0*x*(1.0-x),K)};
//==
// #10
// Two cubic curves meet with a horizontal inflection point
// at the control coordinate (A,B), within the unit square
#declare G_double_cubic_seat = function(x,A,B){
select(
(x<=clipzo_eps(A)),
-1,
clipzo(B)+(1-clipzo(B))*pow((x-clipzo_eps(A))/(1-clipzo_eps(A)),3),
clipzo(B)-clipzo(B)*pow(1-x/clipzo_eps(A), 3.0)
)
};
//==
// #11
// A: location of inflection on the 0-1 diagonal of unit square
// B: the amount of blend with the identity function, tilt of plateau
#declare G_double_cubic_seat_linear_blend = function(x,A,B){
select(
(x<=clipzo_eps(A)),
-1,
(1-clipzo(B))*x+(1-(1-clipzo(B)))*(clipzo_eps(A)
+(1-clipzo_eps(A))*pow((x-clipzo_eps(A))
/(1-clipzo_eps(A)), 3.0))
,
(1-clipzo(B))*x+(1-(1-clipzo(B)))*clipzo_eps(A)
*(1-pow(1-x/clipzo_eps(A), 3.0))
)
};
//==
// #12
// A:
// B: A,B vicinity of plateau
// N: flattness, breath of plateau, integer 1-20
#declare G_double_odd_polynomial_seat = function(x,A,B,N){
select(
(x<=clipzo_eps(A)),
-1,
clipzo(B)+(1-clipzo(B))*pow((x-clipzo_eps(A))/(1-clipzo_eps(A)),(2*N+1)),
clipzo(B)-clipzo(B)*pow(1-x/clipzo_eps(A),(2*N+1))
)
};
//==
// #13
// A: ease out 0-0.5, ease in 0.5-1.
#declare G_expo_ease_in_out = function(x,A){
select(
(clipzo_eps(A)< 0.5),
-1,
pow(x, 1.0/(1-(2*(clipzo_eps(A)-0.5)))),
pow(x,clipzo_eps(A)*2)
)
};
//==
// #14
// usefull for adjusting contrast
// A: 0-1
#declare G_double_expo_sigmoid = function(x,A){
select(
(x<= 0.5),
-1,
1-(pow(2*(1-x),1/(1-clipzo_eps(A))))/2,
(pow(2*x,1/(1-clipzo_eps(A))))/2
)
};
//==
// #15
// has a very natural rate of change
// A: slope or growth rate.
#declare G_logistic_sigmoid = function(x,A){
(((1/(1+exp(0-((x-0.5)*(1/(1-(clipzo_eps(A)))-1)*2.0))))
-(1/(1+exp((1/(1-(clipzo_eps(A)))-1)))))
/((1/(1+exp(0-(1/(1-(clipzo_eps(A)))-1))))
-(1/(1+exp((1/(1-(clipzo_eps(A)))-1))))))
};
//==
// #16
// two circular arcs with seat
// A: curves inflection point along the diagonal of unit box
#declare G_double_circ_seat = function(x,A){
select(
(x<=clipzo(A)),
-1,
1-sqrt(pow((1-clipzo(A)),2)-pow(x-clipzo(A),2)),
sqrt(pow(clipzo(A),2)-pow(x-clipzo(A),2))
)
};
//==
// #17
// two circular arcs with vertical joit, sigmoid
// A: curves inflection point along the diagonal of unit box
#declare G_double_circ_sigmoid = function(x,A){
select(
(x<=clipzo(A)),
-1,
clipzo(A)+sqrt(pow(1-clipzo(A),2)-pow(x-1,2)),
clipzo(A)-sqrt(clipzo(A)*clipzo(A)-x*x)
)
};
//==
// #18
// A,B: two elliptic arcs meet at within the unit square
#declare G_double_elliptic_seat = function(x,A,B){
select(
(x<=(clipzo_eps(A))),
-1,
1-((1-clipzo(B))/(1-(clipzo_eps(A))))*sqrt(pow(1-(clipzo_eps(A)),2)
- pow(x-(clipzo_eps(A)),2))
,
(clipzo(B)/(clipzo_eps(A))) * sqrt(pow((clipzo_eps(A)),2)
- pow(x-(clipzo_eps(A)),2))
)
};
//==
// #19
// A,B: two elliptic arcs meet at within the unit square
#declare G_double_elliptic_sigmoid = function(x,A,B){
select(
(x<=(clipzo_eps(A))),
-1,
clipzo(B)
+((1-clipzo(B))/(1-(clipzo_eps(A))))*sqrt(pow(1-(clipzo_eps(A)),2)
-pow(x-1,2))
,
clipzo(B)*(1 - (sqrt(pow((clipzo_eps(A)),2)
-pow(x,2))/(clipzo_eps(A))))
)
};
//==
// #20
// quadratic bezier with a single spline control point
// starts at 0,0 ends at 1,1
// A,B : coordinates of the control point
#declare G_quadratic_bezier = function(x,A,B){
select(
(A=0.5),
-1,
(1-2*(clipzo(B)))*((sqrt((clipzo(A))*(clipzo(A))
+(1-2*(clipzo(A)))*x)
-(clipzo(A)))/(1-2*(clipzo(A)))*(sqrt((clipzo(A))*(clipzo(A))
+(1-2*(clipzo(A)))*x)
-(clipzo(A)))/(1-2*(clipzo(A))))
+(2*(clipzo(B)))*(sqrt((clipzo(A))*(clipzo(A))
+(1-2*(clipzo(A)))*x)
-(clipzo(A)))/(1-2*(clipzo(A)))
,
(1-2*(clipzo(B)))*((sqrt((clipzo(A)+eps)*(clipzo(A)+eps)
+(1-2*(clipzo(A)+eps))*x)
-(clipzo(A)+eps))/(1-2*(clipzo(A)+eps))*(sqrt((clipzo(A)+eps)*(clipzo(A)+eps)
+(1-2*(clipzo(A)+eps))*x)
-(clipzo(A)+eps))/(1-2*(clipzo(A)+eps)))
+(2*(clipzo(B)))*(sqrt((clipzo(A)+eps)*(clipzo(A)+eps)
+(1-2*(clipzo(A)+eps))*x)
-(clipzo(A)+eps))/(1-2*(clipzo(A)+eps))
)
};
//==
// #21
// S-shape with flat tangents at 0 and 1
// N: steepness of the curve ~1-~10
#declare G_symm_double_poly_sigmoid = function(x,N){
select(
(even(floor(N))),
-1,
select((x<=0.5),-1,1+pow(2*(x-1),floor(N))/2,pow(2*x,floor(N))/2)//odd poly
,
select ((x<=0.5),-1,1-pow(2*(x-1),floor(N))/2,pow(2*x,floor(N))/2)//even poly
)
};
//==
// #22
//
//symmetric around y-axis x -1,1 got no names? http://www.kynd.info
#declare G_one_ease_in = function(x,P){1-pow(abs(x),P)};
//==
// #23
//
#declare G_one_ease_out= function(x,P){1-pow(abs(1-x),P)};
//==
// #24
//
#declare G_two_ease_in = function(x,P){pow(cos(pi*x/2),P)}
//==
// #25
//
#declare G_two_ease_out= function(x,P){pow(cos(pi*(1-x)/2),P)}
//==
// #26
//
#declare G_three= function(x,P){1-pow(abs(sin(pi*x/2)),P)}
//==
// #27
//
#declare G_four= function(x,P){pow(min(cos(pi*x/2),1-abs(x)),P)}
//==
// #28
//
#declare G_five= function(x,P){1-pow(max(0,abs(x)*2-1),P)}
//==
// #29
// Won't change an input value unless too small
// M = above this threshold there is no change, below a smooth change
// N = replaces a zero value
#declare G_almost_identity = function(x,M,N){
select(
(x>M),
-1,
((2.0*N-M)*(x/M)+(2.0*M-3.0*N))*(x/M)*(x/M)+N,
x
)
}
//==
// #30
// smoothest step version by K.McDonald
// x: value
// y: min value
// z: max value
#declare G_smootheststep=function(x,y,z){
(-20*pow(clipzo((x-y)/(z-y)),7))+
(70*pow(clipzo((x-y)/(z-y)),6))-
(84*pow(clipzo((x-y)/(z-y)),5))+
(35*pow(clipzo((x-y)/(z-y)),4))
};
//==
// #31
// Remapping range 0-1 to 0-1, corners are remapped to 0
// Curve max at 1.0
// A:
// B:
#declare G_power_curve_k=function(x,A,B){
(pow(A+B,A+B)/(pow(A,A)*pow(B,B)))*pow(x,A)*pow(1.0-x,B)
};
//==
// #32
// Remapping range 0-1 to 0-1, corners are remapped to 0
// Curve max defined by S
// A:
// B:
// S: set peak on y
#declare G_power_curve=function(x,S,A,B){
S*pow(x,A)*pow(1.0-x,B)
};
//==
// #33
// K=1 identity curve (in = out)
// K<1 gain shape
// K>1 S-shaped
#declare G_gain = function(x,K){
select(
(x<0.5),
-1,
1-(0.5*pow(2*(select((x<0.5),-1,1-x,x)),K)),
(0.5*pow(2*(select((x<0.5),-1,1-x,x)),K))
)
};
//==
// #34
// C: centre of the curve
// W: half width of the curve
#declare G_cubic_pulse = function(x,C,W){
select((abs(x-C)>W),
-1,
1-(abs(x-C)/W)*(abs(x-C)/W)*(3-2*(abs(x-C)/W)),
0
)
};
//==
// #35
// smoother but more expensive than cubic
// A: 0-1
#declare G_double_expo = function(x,A){
select(
(x<=0.5),
-1,
1.0 - (pow(2.0*(1.0-x), 1-clipzo_eps(A)))/2.0,
(pow(2.0*x, 1-clipzo_eps(A)))/2.0
)
};
//==
// test scene
//
#if(input_file_name="gradients.inc")
//+a0.1 +w400 +h400
global_settings {assumed_gamma 1.0}
#default{ finish{ ambient 1 diffuse 0}}
camera {
orthographic
location <0.5,0.5,-.1>
look_at <0.5,0.5,0>
right x*image_width/image_height
}
#declare Gradient=0;
#if(Gradient=0)
#declare Pigm=pigment{function{Noise_sin(x,y,x)}};
#elseif(Gradient=1)
#declare P=3;
#declare Pigm=pigment{function{G_expo(x,P)}}
#declare Curve=function(I){G_expo(I,P)};
#elseif(Gradient=2)
#declare K=10;
#declare N=1;
#declare Pigm=pigment{function{G_exp_step(x,K,N)}}
#declare Curve=function(I){G_exp_step(I,K,N)}
#elseif(Gradient=3)
#declare K=10;
#declare Pigm=pigment{function{G_impulse(x,K)}};
#declare Curve=function(I){G_impulse(I,K)};
#elseif(Gradient=4)
#declare Pigm=pigment{function{G_circ_ease_in(x)}};
#declare Curve=function(I){G_circ_ease_in(I)};
#elseif(Gradient=5)
#declare Pigm=pigment{function{G_circ_ease_out(x)}};
#declare Curve=function(I){G_circ_ease_out(I)};
#elseif(Gradient=6)
#declare Pigm=pigment{function{G_Blinn_Wyvill(x)}};
#declare Curve=function(I){G_Blinn_Wyvill(I)};
#elseif(Gradient=7)
#declare Low = 0.2;
#declare High = 0.3;
#declare Pigm=pigment{function{G_smoothstep(x,Low,High)}};
#declare Curve=function(I){G_smoothstep(I,Low,High)};
#elseif(Gradient=8)
#declare Low = 0.2;
#declare High = 0.76;
#declare Pigm=pigment{function{G_smootherstep(x,Low,High)}};
#declare Curve=function(I){G_smootherstep(I,Low,High)};
#elseif(Gradient=9)
#declare P = 1;
#declare Pigm=pigment{function{G_parabola(x,P)}};
#declare Curve=function(I){G_parabola(I,1)};
#elseif(Gradient=10)
#declare X = 0.1;
#declare Y = 0.7
#declare Pigm=pigment{function{G_double_cubic_seat(x,X,Y)}};
#declare Curve=function(I){G_double_cubic_seat(I,X,Y)};
#elseif(Gradient=11)
#declare A = 0.3;
#declare B = 0.9;
#declare Pigm=pigment{function{G_double_cubic_seat_linear_blend(x,A,B)}};
#declare Curve=function(I){G_double_cubic_seat_linear_blend(I,A,B)};
#elseif(Gradient=12)
#declare X = 0.5;
#declare Y = 0.6;
#declare Breath = 2;
#declare Pigm=pigment{function{G_double_odd_polynomial_seat(x,X,Y,Breath)}};
#declare Curve=function(I){G_double_odd_polynomial_seat(I,X,Y,Breath)};
#elseif(Gradient=13)
#declare Pigm=pigment{function{G_expo_ease_in_out(x,0.8)}};
#declare Curve=function(I){G_expo_ease_in_out(I,0.8)};
#elseif(Gradient=14)
#declare Pigm=pigment{function{G_double_expo_sigmoid(x,0.6)}};
#declare Curve=function(I){G_double_expo_sigmoid(I,0.6)};
#elseif(Gradient=15)
#declare Pigm=pigment{function{G_logistic_sigmoid(x,0.8)}};
#declare Curve=function(I){G_logistic_sigmoid(I,0.8)};
#elseif(Gradient=16)
#declare Pigm=pigment{function{G_double_circ_seat(x,0.5)}};
#declare Curve=function(I){G_double_circ_seat(I,0.5)};
#elseif(Gradient=17)
#declare Pigm=pigment{function{G_double_circ_sigmoid(x,0.3)}};
#declare Curve=function(I){G_double_circ_sigmoid(I,0.3)};
#elseif(Gradient=18)
#declare Pigm=pigment{function{G_double_elliptic_seat(x,0.3,0.7)}};
#declare Curve=function(I){G_double_elliptic_seat(I,0.3,0.7)};
#elseif(Gradient=19)
#declare Pigm=pigment{function{G_double_elliptic_sigmoid(x,0.7,0.5)}};
#declare Curve=function(I){G_double_elliptic_sigmoid(I,0.7,0.5)};
#elseif(Gradient=20)
#declare Pigm=pigment{function{G_quadratic_bezier(x,0.94,0.3)}};
#declare Curve=function(I){G_quadratic_bezier(I,0.94,0.3)};
#elseif(Gradient=21)
#declare Exponent = 3;
#declare Pigm=pigment{function{G_symm_double_poly_sigmoid(x,Exponent)}};
#declare Curve=function(I){G_symm_double_poly_sigmoid(I,Exponent)};
#elseif(Gradient=22)
#declare Exponent = .5;
#declare Pigm=pigment{function{G_one_ease_in(x,Exponent)}};
#declare Curve=function(I){G_one_ease_in(I,Exponent)};
#elseif(Gradient=23)
#declare Exponent = .5;
#declare Pigm=pigment{function{G_one_ease_out(x,Exponent)}};
#declare Curve=function(I){G_one_ease_out(I,Exponent)};
#elseif(Gradient=24)
#declare Exponent = .5;
#declare Pigm=pigment{function{G_two_ease_in(x,Exponent)}};
#declare Curve=function(I){G_two_ease_in(I,Exponent)};
#elseif(Gradient=25)
#declare Exponent = .5;
#declare Pigm=pigment{function{G_two_ease_out(x,Exponent)}};
#declare Curve=function(I){G_two_ease_out(I,Exponent)};
#elseif(Gradient=26)
#declare Exponent = .5;
#declare Pigm=pigment{function{G_three(x,Exponent)}};
#declare Curve=function(I){G_three(I,Exponent)};
#elseif(Gradient=27)
#declare Exponent = 0.5;
#declare Pigm=pigment{function{G_four(x,Exponent)}};
#declare Curve=function(I){G_four(I,Exponent)};
#elseif(Gradient=28)
#declare Exponent = 0.5;
#declare Pigm=pigment{function{G_five(x,Exponent)}};
#declare Curve=function(I){G_five(I,Exponent)};
#elseif(Gradient=29)
#declare M = 0.2;//threshold |Extreme example values to show result
#declare N = 0.1;//if x is zero |M=0.05 N=0.01 or N=eps may make more sense
#declare Pigm=pigment{function{G_almost_identity(x,M,N)}};
#declare Curve=function(I){G_almost_identity(I,M,N)};
#elseif(Gradient=30)
#declare Low = 0.2;
#declare High = 0.76;
#declare Pigm=pigment{function{G_smootheststep(x,Low,High)}};
#declare Curve=function(I){G_smootheststep(I,Low,High)};
#elseif(Gradient=31)
#declare A = 2;
#declare B = 5;
#declare S = 30;
#declare Pigm=pigment{function{G_power_curve_k(x,A,B)}};
#declare Curve=function(I){G_power_curve_k(I,A,B)};
#elseif(Gradient=32)
#declare A = 2;
#declare B = 5;
#declare S = 50;
#declare Pigm=pigment{function{G_power_curve(x,S,A,B)}};
#declare Curve=function(I){G_power_curve(I,S,A,B)};
#elseif(Gradient=33)
#declare K = .2; //#declare K = 5;
#declare Pigm=pigment{function{G_gain(x,K)}};
#declare Curve=function(I){G_gain(I,K)};
#elseif(Gradient=34)
#declare C = .4; //centre of curve
#declare W = .2; //half width of curve
#declare Pigm=pigment{function{G_cubic_pulse(x,C,W)}};
#declare Curve=function(I){G_cubic_pulse(I,C,W)};
#elseif(Gradient=35)
#declare A = .3; //0-1
#declare Pigm=pigment{function{G_double_expo(x,A)}};
#declare Curve=function(I){G_double_expo(I,A)};
#end
box {0,1 texture {pigment {Pigm}}}
#ifdef(Curve)
#for (I,0,1,0.001)
sphere{,0.005 pigment{rgb <.5,0,0>}}
#end
#end
#end
/*
// Splines are nice to define al kind of curves, but handing/control
// with functions is a tad cumbersome. Best defined per use case.
#declare S= 0.5;
#declare G = function{
spline{
linear_spline
0, 0
S, 0.5
1, 1
}
};
box {
<0, 0, 0>, <1, 1, 1>
texture {
pigment {
function{G(x).gray}
}
finish {
ambient 1.0
diffuse 0.0
}
}
}
#for (I,0,1,0.001)
sphere{,0.005 pigment{rgb x}}
#end
sphere{<1,1,0>,0.05}
*/