Procedural texture generator (example and wishes)

so pretty =0

1 Like

Spiral logarithmic can be coded in as part of the gradient preset instead. I should do that later as I did Spiral gradient. Thanks for the code.

2 Likes

Oh, that would be cool.
My anti-alias strategy for it is not great, it fails on high frequency details. I couldn’t figure out a good way to get a numerical derivative without being able to define local functions at all, or a built-in SeExpr one.

Aw, i was hoping for Lisp s-expressions, as GIMP has Scheme.
I’m not a fan of the perl-like syntax, is seexpr even GPU accelerated?
Krita already has OpenGL, GLSL would be far more useful.

You can alway try to make a patch. I think the syntax is ok to work with, but that has to do with my gmic knowledge.

As far as I’m aware it’s just CPU interpreted, but could be just-in-time compiled with LLVM as an added dependency.
I would love using Krita as a GLSL editor too, but I remember a dev saying that may be too out of scope in any case.

You don’t actually need to use $, and then there is nothing inherently perl-like there :wink: especially since it has printf and sprintf…

I’m not sure how it would be more out of scope than this, since GL is already being used for canvas rendering. Adding a plane shader doesn’t require any additional dependencies and would probably fit in a single page of code, most of the work would be GUI binding.

Upon reading the seexpr ref, i do like its builtin functions, and the function partial-application syntax -> is super useful.

The big problem with using GLSL for filters and fill layers is that it is easy to sent things to the GPU, but it’s not easy to get it back from the GPU to the RAM without serious slow down, to the point we are not sure it wouldn’t end up being super slow instead.

On top of that, the question remains how long openGL is going to stay around, on Windows we are constantly dealing with driver bugs, and Apple hates openGL. Right now our openGL integration is rather superficial (we only sent things to the GPU), introducing GLSL for fill and filters will force more integration.

Finally, to pull this back to seexpr, this was a library already written by Walt Disney Animation studios, Amyspark just integrated it. Scheme would have definitely required them to write a whole API from scratch which meant we wouldn’t have had all the other fill layer improvements we got (Multithreading, better preview).

1 Like

Hey, I experimented a bit with SeExpr to generate hexagonal patterns.

Hexagonal tiles

seexpr-test

$color1 = [0,0.431373,0.470588];
$color2 = [0,0.25098,0.278431];
$color3 = [0,0.721569,0.784314];

# absolute coordinates
$X = 0.01*$u*$w;
$Y = 0.01*$v*$h;

# lattice generators
$a = [0.5, -1/(2*sqrt(3))];
$b = [0.5, 1/(2*sqrt(3))];

# lattice coordinates
$s = $X + sqrt(3)*$Y;
$t = $X - sqrt(3)*$Y;

# now we have to find out which lattice point is nearest to our point
$S = floor($s);
$T = floor($t);

$v = [$s, $t, 0];

$A = [1/2, 1/2, 0];
$B = [1/(2*sqrt(3)), -1/(2*sqrt(3)), 0];

$v1 = [$S,     $T, 0];
$v2 = [$S,   $T+1, 0];
$v3 = [$S+1,   $T, 0];
$v4 = [$S+1, $T+1, 0];

$M = v1;
$d = dist([dot(A,v), dot(B,v), 0], [dot(A,v1), dot(B,v1), 0]);

$d2 = dist([dot(A,v), dot(B,v), 0], [dot(A,v2), dot(B,v2), 0]);
if ($d2 < $d) {
	$M = v2;
	$d = $d2;
}

$d3 = dist([dot(A,v), dot(B,v), 0], [dot(A,v3), dot(B,v3), 0]);
if ($d3 < $d) {
	$M = v3;
	$d = $d3;
}

$d4 = dist([dot(A,v), dot(B,v), 0], [dot(A,v4), dot(B,v4), 0]);
if ($d4 < $d) {
	$M = v4;
	$d = $d4;
}

$color = swatch(0.34*(($M[0]+2*$M[1]) % 3), $color1, $color2, $color3);

$color

Dots in a hexagonal pattern

hexagonal_dots

$color1 = [0,0.431373,0.470588];
$color2 = [0,0.25098,0.278431];
$radius = 0.14286;
$spacing = 0.51288;

# absolute coordinates
$X = $u*$w / (100*$spacing);
$Y = $v*$h / (100*$spacing);

# lattice coordinates
$s = $X + sqrt(3)*$Y;
$t = $X - sqrt(3)*$Y;

# now we have to find out which lattice point is nearest to our point
$S = floor($s);
$T = floor($t);

$v = [$s, $t, 0];
$w1 = [$S,		$T, 	0];
$w2 = [$S,		$T+1, 	0];
$w3 = [$S+1,	$T,	0];
$w4 = [$S+1,	$T+1,	0];

# used to transform lattice coordinates into euclidean coordinates,
# to compute euclidean distance
$A = [1/2, 1/2, 0];
$B = [1/(2*sqrt(3)), -1/(2*sqrt(3)), 0];


# calculate euclidean distances to lattice points
$d1 = dist([dot(A,v), dot(B,v), 0], [dot(A,w1), dot(B,w1), 0]);
$d2 = dist([dot(A,v), dot(B,v), 0], [dot(A,w2), dot(B,w2), 0]);
$d3 = dist([dot(A,v), dot(B,v), 0], [dot(A,w3), dot(B,w3), 0]);
$d4 = dist([dot(A,v), dot(B,v), 0], [dot(A,w4), dot(B,w4), 0]);

$color = $color1;

# check if point is near one of the lattice points
if (min($d1, min($d2, min($d3, $d4))) < $radius) {
	$color = $color2;
}

$color

Hexagonal lines

hexagonal_lines

$color1 = [0,0.431373,0.470588];
$color2 = [0,0.25098,0.278431];
$radius = 0.16628;
$spacing = 0.637;

# absolute coordinates
$X = $u*$w / (100*$spacing);
$Y = $v*$h / (100*$spacing);

# lattice coordinates
$s = $X + sqrt(3)*$Y;
$t = $X - sqrt(3)*$Y;

$color = $color1;

# if the point lies on one of the right lines, in the correct segment, draw it
# this was produced mainly by trial and error, might be overcomplicated
if (abs($s - floor($s)) < $radius && ($s % 3) < 1 && (($t) % 3) < 1) {
	$color = $color2;
}

if (abs($s - floor($s)) < $radius && (($s) % 3) < 1 && (($t) % 3) < 1) {
	$color = $color2;
}

if (abs($s - floor($s)) < $radius && (($s+2) % 3) < 1 && (($t+2) % 3) < 1) {
	$color = $color2;
}

if (abs($s - floor($s)) < $radius && (($s+1) % 3) < 1 && (($t+1) % 3) < 1) {
	$color = $color2;
}

if (abs($t - floor($t)) < $radius && ($t % 3) < 1 && (($s+1) % 3) < 1) {
	$color = $color2;
}

if (abs($t - floor($t)) < $radius && (($t+2) % 3) < 1 && (($s) % 3) < 1) {
	$color = $color2;
}

if (abs($t - floor($t)) < $radius && (($t+1) % 3) < 1 && (($s+2) % 3) < 1) {
	$color = $color2;
}

if (abs($X - floor($X)) < $radius/sqrt(3) && ((sqrt(3) * $Y) % 3) < 1) {
	$color = $color2;
}

if (abs(2*$X - floor(2*$X)) < 2*$radius/sqrt(3) && ((2*$X +1) % 2) < 1 && ((sqrt(3) * $Y+1.5) % 3) < 1) {
	$color = $color2;
}

$color

I’m not quite satisfies with the last one, as the line width are not really consistent, and the lines do not meet properly.

6 Likes

I had the seexpr hexagonal pattern somewhere… I hope I’ll remember tomorrow to find it.

1 Like

I’ve found it:

## CC-BY copyright @tiar@krita-artists.org

$a = 100; # 5, 1000
$thickness = 10; # 1, 50

$direction = 0; # 0, 1
$border = [0.533333,0.215686,0.152941];
$background = [1,1,1];

# for ease of use later
$th = $thickness/2;


# create a variable that will be added to everything
# that doesn't need a widget
# 0 + 0, because it needs to be 0 to not impact anything
# and needs to be an expression to not create a widget
$nowidget = 0 + 0;



$x = $u*$w;
$y = $v*$h;

if($direction)
{
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$h = $a*sqrt(3)/2;
$xrest = $x%(3*$a);
$yrest = $y%(2*$h);

# now we're just in the rectangle 3a, 2h
$isborder = 0 + $nowidget;

# all horizontal
if($xrest > $a - $th && $xrest < 2*$a + $th && ($yrest < $th || $yrest > 2*$h - $th)) {
    $isborder = 1 + $nowidget;
}

if($xrest < $a/2 + $th || $xrest > 2.5*$a - $th) {
    if($yrest > $h - $th && $yrest < $h + $th) {
        $isborder = 1 + $nowidget;
    }
}

# top-left, bottom-right
$d0 = sqrt($xrest*$xrest + $yrest*$yrest);
if($d0 > $a - $th && $d0 < 2*$a + $th) {
    # to get the thickness right, we need to use
    # equation for a line with two points
    # and the distance from this line
    # here line:
    # 0.5*a*y - h*x = 0
    # and distance:
    # 
    
    $dp = abs(-$h*$xrest + 0.5*$a*$yrest)/sqrt($h*$h - 0.25*$a*$a);
    if($dp < $th) {
        $isborder = 1 + $nowidget;
    }
}

$d0 = sqrt(($xrest-2*$a)*(($xrest-2*$a)) + $yrest*$yrest);
if($d0 < $a + $th) {
    $xtemp = $xrest - 2*$a;
    $dp = abs(-$h*$xtemp + 0.5*$a*$yrest)/sqrt($h*$h - 0.25*$a*$a);
    if($dp < $th) {
        $isborder = 1 + $nowidget;
    }
}

# top-right, bottom-left
$d0 = sqrt(($xrest-$a)*(($xrest-$a)) + $yrest*$yrest);
if($d0 < $a + $th) {
    $dp = abs(-$h*$xrest - 0.5*$a*$yrest + $a*$h)/sqrt($h*$h + 0.25*$a*$a);
    if($dp < $th) {
        $isborder = 1 + $nowidget;
    }
}

$d0 = sqrt(($xrest-3*$a)*(($xrest-3*$a)) + ($yrest)*($yrest));
if($d0 < 2*$a + $th && $d0 > $a - $th) {
    $xtemp = $xrest - 2*$a;
    $dp = abs(-$h*$xtemp - 0.5*$a*$yrest + $a*$h)/sqrt($h*$h + 0.25*$a*$a);
    if($dp < $th) {
        $isborder = 1 + $nowidget;
    }
}


# setting up colors
if($isborder) {
    $color = $border;
}
else 
{
    $color = $background;
}

$color
1 Like

What is the limitation or gotcha with SeExpr? It looks like perl or bourne shell, which is really cool, but are there any limitations like cannot do looped things such as TV Static or perhaps distort the image/layer?

Only reason why I’m posting here is because the krita docs linked to this thread, so if I should have made a new thread, let me know.

1 Like

Hi! Has anyone already create Cloud on SeExpr?

Oops. Sorry, never mind. Got ahead of myself. I think your questions was about something else.