Kaleidoscope Layer Cake problems

I’ve wanted to combine the kaleidoscope and layer cake scripts for around a year and I have been trying for a few months to get this script to work as it I think it should. I finished a script but I wanted to add anti-aliasing which doesn’t involve simply resizing the image since it takes a long time - I wanted proper linear interpolation instead like with my Layer Cake 2 script. This has given me a lot of stress and I simply don’t know how I’m going to do this at all.

I’ve made an updated script where the only attempt at antialiasing is with the radial strips and not the circular layers, but as you can see from the example, it’s not working properly.

#@gui Kaleidoscope Layer Cake : fx_jr_klc, fx_jr_klc_preview(1)
#@gui : sep = separator()
#@gui : Kaleidoscope Mirrors = int(6,1,64)
#@gui : Mirror Rotation = float(0,-360,360)
#@gui : Result Rotation = float(0,-360,360)
#@gui : Centre (%) = point(50,50,0,1)
#@gui : Mirror Offset (%) = point(50,50,0,1)
#@gui : Scale (%) = float(100,0,1000)
#@gui : Scale Bend (%) = float(0,-5,5)
#@gui : Broken Mirrors = choice("Off","On","Reverse")
#@gui : Layer Cake Density = float(30,0,100)
#@gui : Angle = float(0,-360,360)
#@gui : Angle Mode = choice("Normal","Divide by mirror quantity")
#@gui : Anti-Alias = float(2,0,20)
#@gui : Interpolation = choice(2,"None","Linear","Bicubic")
#@gui : Boundary = choice(3,"Transparent","Nearest","Periodic","Mirror")
fx_jr_klc:
to_rgb
aa=($14)
num=$1
mrot={$2/180*pi}
rrot={$3/180*pi}
cx=$4*w/100
cy=$5*h/100
ox=$6*w/100
oy=$7*h/100
scale=$8/100
sbend=$9
broken=$10
lcd=$11
lcang={$12/180*pi}
lcam=$13
inter=$15
bound=$16
f "begin(mrot="$mrot";rrot="$rrot";cx="$cx";cy="$cy";ox="$ox";oy="$oy";num="$num";scale="$scale";sbend="$sbend";broken="$broken";inter="$inter";bound="$bound";lcd="$lcd";ilcang="$lcang"/("$lcam"?num:1);aa="$aa");
vx=x-cx+0.5;vy=y-cy-0.5;
maxr=sqrt((w+0.5)^2+(h+0.5)^2)/2;
ra=sqrt(vx^2+vy^2);
rad=ra/maxr;
radius=((rad)^(2^sbend));
ang=atan2(vy,vx)-mrot-rrot-((lcd==0?(radius*scale):(floor(radius*lcd*scale)/lcd))*ilcang);
awidth=pi/num;
mult=ang/awidth;
multint = floor(mult);
multintaa = floor(mult+aa/ra);
angle = ang-multint*awidth;
broken==1?(angle=angle):broken==2?(angle=awidth-angle;awidth*=-1):(multint%2==1)?(angle=awidth-angle;awidth*=-1);
xwarp00=radius*scale*maxr*cos(angle+mrot)+ox-0.5;
ywarp00=radius*scale*maxr*sin(angle+mrot)+oy-0.5;
xwarp01=radius*scale*maxr*cos(angle+mrot-awidth)+ox-0.5;
ywarp01=radius*scale*maxr*sin(angle+mrot-awidth)+oy-0.5;
xwarp10=radius*scale*maxr*cos(angle+mrot+ilcang)+ox-0.5;
ywarp10=radius*scale*maxr*sin(angle+mrot+ilcang)+oy-0.5;
xwarp11=radius*scale*maxr*cos(angle+mrot-awidth+ilcang)+ox-0.5;
ywarp11=radius*scale*maxr*sin(angle+mrot-awidth+ilcang)+oy-0.5;
kfunc=min(((mult-multintaa)*ra/(aa*2)+0.5),1);
lcfunc=1;
I=I(xwarp00,ywarp00,z,inter,bound)*(kfunc)+I(xwarp01,ywarp01,z,inter,bound)*(1-kfunc);"
c 0,255
n 0,255
fx_jr_klc_preview:
fx_jr_klc $*

fx_jr_klc 7,0,0,46.5776,54.591,50,50,100,0,0,30,0,0,5,2,3

I have absolutely no idea about how I can fix this. kfunc is supposed to allow for a linear crossfading between the strips it’s actually crossfading between parts of the image which follow a discontinuous function. I want to crossfade between rotated versions of the same image with the transitions corresponding to where the strips should be rather than an image which is already partitioned into strips.

I think that I made a similar solution to the one I need in the Layer Cake 2 script but I have no idea how I’d implement such a thing here.

I’m not working with g’mic now, but I can leave a tip. Would using shift before fill function and implementing rotx() and roty() in reptorian.gmic help? Maybe some more fill macro? See modf and floor via wikipedia for boundary conditions.

What about inserting vec=vector$(0), then using for loop to define each part of vector?$ means variable size.

That wouldn’t automatically allow me to crossfade between the different strips.

Here’s another unsuccessful try:

#@gui Kaleidoscope Layer Cake 2 : fx_jr_klc_2, fx_jr_klc_2_preview(1)
#@gui : sep = separator()
#@gui : Kaleidoscope Mirrors = int(6,1,64)
#@gui : Mirror Rotation = float(0,-360,360)
#@gui : Result Rotation = float(0,-360,360)
#@gui : Centre (%) = point(50,50,0,1)
#@gui : Mirror Offset (%) = point(50,50,0,1)
#@gui : Anti-Alias = float(2,0,20)
#@gui : Mode = choice("Symmetric","Asymmetric","Reverse Asymmetric")
fx_jr_klc_2:
num=$1
mrot={$2/180*pi}
rrot={$3/180*pi}
cx=$4*w/100
cy=$5*h/100
ox=$6*w/100
oy=$7*h/100
aa=$8
symm=$9
f "begin(num="$num";cx="$cx";cy="$cy";ox="$ox";oy="$oy";aa="$aa";symm="$symm";mrot="$mrot";rrot="$rrot");
vx=x-cx+0.5;vy=y-cy-0.5;
iang=atan2(vy,vx)-rrot;
irad=sqrt(vx^2+vy^2);
awidth=pi/num;
mult=iang/awidth;
multint=floor(mult);
multintaa = floor(mult+(aa*0.5)/(irad));
angle0=iang-multint*awidth;
angle1=iang-(multint+1)*awidth;
symm==1?(angle1=angle1):symm==2?(angle0=awidth-angle0;angle1=awidth-angle1;awidth*=-1):(multint%2==1)?(angle0=awidth-angle0;angle1=awidth-angle1;awidth*=-1);
angle0+=mrot;
angle1+=mrot;
xwarp00=irad*cos(angle0)+ox-0.5;
ywarp00=irad*sin(angle0)+oy-0.5;
xwarp01=irad*cos(angle1)+ox-0.5;
ywarp01=irad*sin(angle1)+oy-0.5;
kfunc=min(((mult-multintaa)*irad/(aa)+0.5),1);
lcfunc=1;
I=I(xwarp00,ywarp00,z,2,3)*(kfunc)+I(xwarp01,ywarp01,z,2,3)*(1-kfunc)
"
fx_jr_klc_2_preview:
fx_jr_klc_2 $*

I’m making my own attempt at combining layercake and kaleidoscope. Just to let you know.


@Joan_Rake1 I had a idea on creating sharp version of the idea of combining them.
Below is my WIP, you may gather some idea here. skip might be used in the same way as modf. mode defines whether to use smooth layer cake or sharp layer cake (I have yet to define it).

to_gray
f "begin(convert2ang(a)=pi*(a/180);

    skip=1;
    mode=0;
    boundary=1;
    
    ww=w-1;
    hh=h-1;
    
    sd=max(w,h)/min(w,h);
    sx=w>h?sd:1;
    sy=w>h?1:sd;
    sx*=2;
    sy*=2;
    
    offx=-.5+(0*-.5);
    offy=-.5+(0*-.5);

    surface_ang=50;
    shift_surface_ang=40;
    shift_surface_ang=convert2ang(shift_surface_ang);
    
    surface_rot_x(a,b)=a*cos(surface_ang)-b*sin(surface_ang);
    surface_rot_y(a,b)=a*sin(surface_ang)+b*cos(surface_ang);
    
    const split_radial=5;
    
    multiang_surface=vectorsplit_radial(0);
    for(n=0,n<split_radial,n++,
        multiang_surface[n]=convert2ang(multiang_surface[n]);
    );
    
    start_ang=20*-1;
    krot_x(a,b)=a*cos(convert2ang(start_ang))-b*sin(convert2ang(start_ang));
    krot_y(a,b)=a*sin(convert2ang(start_ang))+b*cos(convert2ang(start_ang));
    split_line_radius_count=ceil(6);
    pieces_max=floor(6);
    split_line_radius_angle=360/6;
    add_angle=50;
    
    new_rot_x(a,b,c)=a*cos(convert2ang(c))-b*sin(convert2ang(c));
    new_rot_y(a,b,c)=a*sin(convert2ang(c))+b*cos(convert2ang(c));
    
    boundary_line_radius=1;
    temp=0;
);
orig_surface_x=(x/ww+offx)*sx;
orig_surface_y=(y/hh+offx)*sy;
targ_surface_x=surface_rot_x(orig_surface_x,orig_surface_y);
targ_surface_y=surface_rot_y(orig_surface_x,orig_surface_y);
if(mode,
    for(n=0,n<split_radial,n++,
    );
,
    for(n=0,n<split_radial,n++,
    );
);

kaleidopiece_x=krot_x(targ_surface_x,targ_surface_y);
kaleidopiece_y=krot_y(targ_surface_x,targ_surface_y);
kaleido_surface=(1-(atan2(kaleidopiece_x,kaleidopiece_y)+pi)/(2*pi))*360;
kaleido_surface=int(kaleido_surface/split_line_radius_angle)%pieces_max;
kaleido_rotate_angle=kaleido_surface/split_line_radius_count*360+add_angle;
"

I managed to find an algorithm on my own to generate antialiased patterns for the asymmetric modes (previously called the ‘broken’ modes).

#@gui Kaleidoscope Layer Cake 2 : fx_jr_klc_2, fx_jr_klc_2_preview(1)
#@gui : sep = separator()
#@gui : Kaleidoscope Mirrors = int(6,1,64)
#@gui : Mirror Rotation = float(0,-360,360)
#@gui : Result Rotation = float(0,-360,360)
#@gui : Centre (%) = point(50,50,0,1)
#@gui : Mirror Offset (%) = point(50,50,0,1)
#@gui : Anti-Alias = float(2,0,20)
#@gui : Mode = choice("Symmetric","Asymmetric","Reverse Asymmetric")
fx_jr_klc_2:
num=$1
mrot={$2/180*pi}
rrot={$3/180*pi}
cx=$4*w/100
cy=$5*h/100
ox=$6*w/100
oy=$7*h/100
aa=$8
symm=$9
f[0] "begin(num="$num";cx="$cx";cy="$cy";ox="$ox";oy="$oy";aa="$aa";symm="$symm";mrot="$mrot";rrot="$rrot");
vx=x-cx;vy=y-cy;
iang=atan2(vy,vx)-rrot-mrot;
irad=sqrt(vx^2+vy^2);
awidth=pi/num;
mult=iang/awidth - 1;
multint=floor(mult);
multintaa = floor(mult+(aa*0.5*num)/(irad));
angle0=iang-multintaa*awidth;
angle1=iang-(multintaa+1)*awidth;
symm==1?(angle1=angle1):symm==2?(angle0=awidth-angle0;angle1=awidth-angle1;awidth*=-1):(multint%2==1)?(angle0=angle0):(angle0=awidth-angle0;angle1=awidth-angle1;awidth*=-1);
angle0+=mrot;
angle1+=mrot;
xwarp00=irad*cos(angle0)+ox;
ywarp00=irad*sin(angle0)+oy;
xwarp01=irad*cos(angle1)+ox;
ywarp01=irad*sin(angle1)+oy;
kfunc=min(((mult-multintaa)*irad/(aa*num)+0.5),1);
isnan(kfunc)?kfunc=1;
lcfunc=1;
I=I(xwarp00,ywarp00,z,2,3)*(1-kfunc)+I(xwarp01,ywarp01,z,2,3)*(kfunc);

"
fx_jr_klc_2_preview:
fx_jr_klc_2 $*

I’ve stripped out the layer cake part of the script for now so that I can focus on this. For asymmetric modes it’s fine:

…but for the symmetric mode I have a problem.

I haven’t yet found a way to get rid of these ghostly things.

1 Like

There might be some subpixel miscalculation. If you can address that, that would be fix it. I would have done that slightly differently as you can see from the kaleido code-lines.

I’ve just figured out what the error is likely to be and it’s nothing to do with subpixels. The crossfading is bidirectional and it’s probably selecting the wrong angles for the parts which overlap. I just don’t know how to make it select the right ones.

I do think you should try resize commands for anti-aliasing as a last resort. If antialiasing is what cause the issue.

I tried that before and it became very slow, which is why I want to use this different method in the first place.

I know they are unintended but I like their glitchiness. :space_invader:

I could always add that in as some kind of mode.

I like restrained glitchiness. :wink:

The antialiasing for the main part of the script is done, including the layer cake part!

#@gui Kaleidoscope Layer Cake 2 : fx_jr_klc_2, fx_jr_klc_2_preview(1)
#@gui : sep = separator()
#@gui : Kaleidoscope Mirrors = int(6,1,64)
#@gui : Mirror Rotation = float(0,-360,360)
#@gui : Result Rotation = float(0,-360,360)
#@gui : Centre (%) = point(50,50,0,1)
#@gui : Mirror Offset (%) = point(50,50,0,1)
#@gui : Mode = choice("Symmetric","Asymmetric","Reverse Asymmetric")
#@gui : sep = separator()
#@gui : Layer Cake Density = float(30,0,100)
#@gui : Angle = float(0,-360,360)
#@gui : sep = separator()
#@gui : Scale (%) = float(100,0,1000)
#@gui : Anti-Alias = float(1,0,2)
#@gui : Interpolation = choice(2,"None","Linear","Bicubic")
#@gui : Boundary = choice(3,"Transparent","Nearest","Periodic","Mirror")
fx_jr_klc_2:
num=$1
mrot={$2/180*pi}
rrot={$3/180*pi}
cx=$4*w/100
cy=$5*h/100
ox=$6*w/100
oy=$7*h/100
symm=$8
lcd=$9
lcang={$10/180*pi}
scale=$11*0.01
aa=$12*0.25
inter=$13
bound=$14
f "begin(const num="$num";const cx="$cx";const cy="$cy";const ox="$ox";const oy="$oy";const aa="$aa";const symm="$symm";const mrot="$mrot";const rrot="$rrot";
const awidth=pi/num;const interpolation="$inter";const boundary="$bound";const scale="$scale";const lcd="$lcd";const ilcang="$lcang";const diag=sqrt(w^2+h^2));
vx=x-cx;vy=y-cy;
iang=atan2(vy,vx)-rrot-mrot;
irad=norm(vx,vy);
lnum=max((irad/diag*2-(4*aa/diag))*lcd*scale,0);
lnumint=floor(lnum);
ang=iang-(((lcd==0?(irad/diag*2-(4*aa/diag))*scale:(lnumint))+[0,1])*ilcang);
mult=ang/awidth - 1;
multint=floor(mult);
multintaa = floor(mult+min((aa*0.5*num)/(irad),irad*0.5/(pi*num)));
angle0=ang-multintaa*awidth;
angle1=ang-(multintaa+1)*awidth;
for(i=0,i<2,i++,
symm==1?(angle1[i]=angle1[i]):symm==2?(angle0[i]=awidth-angle0[i];angle1[i]=awidth-angle1[i]):
((multint[i]%2==1)?(multintaa[i]>multint[i]?(angle1[i]=awidth-angle1[i]):(angle0[i]=awidth-angle0[i])):(multintaa[i]>multint[i]?(angle0[i]=awidth-angle0[i]):(angle1[i]=awidth-angle1[i]))));
angle0+=mrot;
angle1+=mrot;
frad=irad*scale;
xwarp00=frad*cos(angle0[0])+ox;
ywarp00=frad*sin(angle0[0])+oy;
xwarp01=frad*cos(angle1[0])+ox;
ywarp01=frad*sin(angle1[0])+oy;
xwarp10=frad*cos(angle0[1])+ox;
ywarp10=frad*sin(angle0[1])+oy;
xwarp11=frad*cos(angle1[1])+ox;
ywarp11=frad*sin(angle1[1])+oy;
kfunc=[min(((mult[0]-multintaa[0])*irad/(aa*num)+0.5),1),min(((mult[1]-multintaa[1])*irad/(aa*num)+0.5),1)];
for(i=0,i<2,i++,isnan(kfunc[i])?kfunc[i]=1);
lcfunc=min((lnumint+1-lnum)/(aa*lcd*scale)*diag*0.125,1); # HERE
(I(xwarp00,ywarp00)*(1-kfunc[0])+I(xwarp01,ywarp01)*(kfunc[0]))*(lcfunc)+(I(xwarp10,ywarp10)*(1-kfunc[1])+I(xwarp11,ywarp11)*(kfunc[1]))*(1-lcfunc);"

fx_jr_klc_2_preview:
fx_jr_klc_2 $*
c 0,255

One feature remains: there’s a special smooth twirl mode which activates when the layer cake density is 0. The antialiasing for that is a tough one to crack.

2 Likes

Now that you’re almost done with it, let me know when it’s ready so I can push it.

I like the last one: it is like the sun in the sky.

@Joan_Rake1 Is this done? I pushed your pull request regardless.

I think it is for now, thanks for pushing it.

You’re welcome. By the way, I have tested this filter with architecture pictures, I love this filter!

This is true! Here’s a fairly-mangled photo from Pexels:

image

1 Like