That’s an artefact of local normalisation on an image where all pixels are the same value. Setting the density to 0 does that.
Edit: I’ll stick with the distance-to-nearest-edge approach but with a smoothed gradient norm weighting thing instead. I’ve swapped the segmentation for the mosaic thing instead, but still no progress with the AA.
The old 'cubism' command right now
#@gui Cubism: fx_jr_rep_cubism_preview
#@gui : sep = separator()
#@gui : 0. Recompute = button()
#@gui : 1. Density=float(15,0,100)
#@gui : 2. Details Influence=float(50,0,100)
#@gui : 3. X Offset Centre=float(0,-100,100)
#@gui : 4. X Offset Range=float(25,0,200)
#@gui : 5. Y Offset Centre=float(0,-100,100)
#@gui : 6. Y Offset Range=float(25,0,200)
#@gui : 7. Z Offset Centre=float(0,-100,100)
#@gui : 8. Z Offset Range=float(0,0,200)
#@gui : 9. Rot Angle Centre=float(0,-360,360)
#@gui : 10. Rot Angle Range=float(360,0,360)
#@gui : 11. Rot Axis X Centre=float(0,-1,1)
#@gui : 12. Rot Axis X Range=float(0,0,2)
#@gui : 13. Rot Axis Y Centre=float(0,-1,1)
#@gui : 14. Rot Axis Y Range=float(0,0,2)
#@gui : 15. Rot Axis Z Centre=float(1,-1,1)
#@gui : 16. Rot Axis Z Range=float(0,0,2)
#@gui : 17. AA Iterations=int(16,0,100)
#@gui : 18. Sharpness=float(0,0,2)
#@gui : 19. AA Anisotropy=float(1,0,1)
#@gui : 20. AA Gradient Smoothness=float(1,0,10)
#@gui : 21. Tensor Smoothness=float(5,0,10)
#@gui : 22. Time Step=float(15,5,50)
fx_jr_rep_cubism:
to_gray
# initial parameters for all images
rotac=$9
rotar=$10
rotxxc=$11
rotxxr=$12
rotxyc=$13
rotxyr=$14
rotxzc=$15
rotxzr=$16
aa=$17
repeat $! l[$>]
# initial parameters for each image
ww={w}
hh={h}
dd={d}
xoffc=$3*0.01*$ww
xoffr=$4*0.01*$hh
yoffc=$5*0.01*$dd
yoffr=$6*0.01*$ww
zoffc=$7*0.01*$hh
zoffr=$8*0.01*$dd
+gradient_norm
100%,100%,100%,2,'begin(n=-1);u<lerp(0.5,i(-1),$2%)*($1%)^4?(n+=1;[u,1])' s. c
distance. 1 *. -1 watershed.. . rm[1,3]
label. # labelling the segments of the copied image
l[1]
# get the edges of the segment and find the distance to the nearest pixel on the other side of the nearest edge for each pixel in terms of x, y and z components
# this will be used for the anti-aliasing later on
+gradient_orientation. 3
a[^0] c
100%,100%,100%,1,"min(1,ceil(norm(I(#1))))"
rm[1]
distance. 1
+gradient_orientation. 3
f[1] "-(i+0.5)" # experimenting with this to find a good distance offset, should really be (i+0.5) for true distance to edge
a[1-4] c
endl
# uncomment this to blur this distance-to-edge image, was just another experiment but could be used to highlight the problem in a clearer way
# b. 2
# approximate the centre of each segment and store the x, y and z components in a new image which will store more parameters later
# this image's x coordinate is the segment id as specified in the labelled segment image (#1)
initsize={1+iM#1}
$initsize,10,1,1
vsize={$initsize*3}
eval ${-math_lib}"
coordinates_per_val=vector"$vsize"(0);
count_per_val=vector"$initsize"(0);
for(px=0,px<w#1,px++,
for(py=0,py<h#1,py++,
for(pz=0,pz<d#1,pz++,
pos=i(#1,px,py,pz);
coordinates_per_val[pos*3]+=px;
coordinates_per_val[pos*3+1]+=py;
coordinates_per_val[pos*3+2]+=pz;
count_per_val[pos]++;
);
);
);
for(n=0,n<"$initsize",n++,
coordinates_per_val[n*3]/=count_per_val[n];
coordinates_per_val[n*3+1]/=count_per_val[n];
coordinates_per_val[n*3+2]/=count_per_val[n];
I(n,0)=coordinates_per_val[n*3];
I(n,1)=coordinates_per_val[n*3+1];
I(n,2)=coordinates_per_val[n*3+2];
);
"
# add pseudo-randomised parameters for each segment id to the parameters image
sh. 3,9,0,0 f. ">begin(randm=u(100,200);randa=u(1,3));srand((x+(randa)+(u))*(randm+y));u(-1,1)"
eval. "begin(multvec=["$xoffr","$yoffr","$zoffr","$rotar","$rotxxr","$rotxyr","$rotxzr"];
addvec=["$xoffc","$yoffc","$zoffc","$rotac","$rotxxc","$rotxyc","$rotxzc"]);
for(n=0,n<w,n++,
strip=crop(n,0,0,0,1,7,1,1);
draw(#4,(strip*multvec)+addvec,n,0,0,0,1,7,1,1,1))"
rm.
# get the edges, subtract a smoothed copy in order to create a mask for the anti-aliasing
+gradient_norm[1] f. "i>0?255:0"
smooth. $aa,${18-22},0
/. 255
# let's put all of this together now
f[0] "critical(begin(const spec=s;aa="$aa";
cubism(id,xx,yy,zz)=( # this function warps a given pixel using the parameters assigned to a specified id within the parameters image
params=crop(#3,id,0,0,0,1,10,1,1);
# get segment centre
xc=params[0];
yc=params[1];
zc=params[2];
# get offsets
xoff=params[3];
yoff=params[4];
zoff=params[5];
# get rotation angle and axis
ang=params[6];
xa=params[7];
ya=params[8];
za=params[9];
# rotate and offset
vx=xx-xc-xoff;
vy=yy-yc-yoff;
vz=zz-zc-zoff;
pix=[xa,ya,za];
select=(rot(asin(pix/norm(pix))*2/pi,ang)*[vx,vy,vz])+[xc,yc,zc];
# return the new pixel value
I(select,1,3)));
# anti-aliasing only if the setting's enabled and we're at a pixel where the mask (#4) has a non-zero value
(aa&&(i(#4)>0))?(
# get the displacements necessary to reach the nearest pixel on the other side of the nearest edge
dist=i(#2,x,y,z,0);
xdist=-i(#2,x,y,z,1)*dist;
ydist=-i(#2,x,y,z,2)*dist;
zdist=-i(#2,x,y,z,3)*dist;
# trilinear interpolation to determine the value of the nearest pixel behind the nearest edge
# we don't have to cubism() eight times for each pixel here since we can instead make a weighted histogram of ids
idlist=vector(#8,-1);
freqlist=vector(#8,0);
idnum=0;
xint=floor(xdist);yint=floor(ydist);zint=floor(zdist);
xo=xdist-xint;yo=ydist-yint;zo=zdist-zint;
gridmult=[(1-xo)*(1-yo)*(1-zo),xo*(1-yo)*(1-zo),(1-xo)*yo*(1-zo),xo*yo*(1-zo),(1-xo)*(1-yo)*zo,xo*(1-yo)*zo,(1-xo)*yo*zo,xo*yo*zo];
for(pz=0,pz<2,pz++,
for(py=0,py<2,py++,
for(px=0,px<2,px++,
curr=i(#1,x+xint+px,y+yint+py,z+zint+pz,0,1,1);
pos=find(idlist,curr);
pos==-1?(idnum+=1;pos=find(idlist,-1);idlist[pos]=curr);
freqlist[pos]+=gridmult[pz*4+py*2+px];
);
);
);
val=0; # val=vector(#spec,0);
for(n=0,n<idnum,n++,
# construct the final value for the interpolated pixel
val+=idlist[n]*freqlist[n]);
# interpolate between that pixel and the current one in accordance with the AA mask
lerp(val,i(#1,x,y,z,0,1,1),i(#4))):
# if we don't need any AA, we can just use the current pixel
(i(#1,x,y,z,0,1,1)))
"
# clean up now that we're done
display
rm[^0]
endl done
to_rgb
n 0,255
fx_jr_rep_cubism_preview:
fx_jr_rep_cubism ${2-23}