Starting again from scratch
@prawnsushi wrote this interesting comment:
and that got me thinking about how I could bend the branches…
And the more I thought about solutions using the 3D meshes of the branches generated by my previous algorithm, the more I found them inelegant and complicated to implement.
For example, when generating branch meshes one by one, how do I ensure that these meshes, once assembled together, won’t touch or cross each other?
I needed to find another solution that would generate a tree in its entirety, potentially allowing me to delete intersecting branches, and more generally giving me finer control over the overall result I wanted to achieve.
So I decided to start again from scratch!
I’m going to make sure that my 3D tree model is generated directly in a (binary-valued) volumetric image, and that the corresponding 3D mesh can be extracted in its entirety using just a standard marching cube.
That means, each branch has to be drawn as a thick curve directly in this volumetric image, connected to other branches (in a recursive way). Not that simple to implement!
So maybe, it’s better to experiment it first in 2D, and extend the algorithm to 3D afterwards.
So here we go, I’m going to use splines to model the branches, and I’m going to add smaller ones, recursively on the existing branches. With a few well-thought-out heuristics, it should do the trick!
So after playing with code and tweaking it, this is what I get (in 2D only for now):
with the following code:
foo :
# Build structure of the tree.
1,1,1,7 => active
1,1,1,7 => done
eval "
const nbp = 512;
add_branch(__P0,__P1,__level) = (
ref(__P0,_P0); ref(__P1,_P1); ref(__level,_level);
_dP = _P1 - _P0;
_length = norm(_dP);
_U = unitnorm(_dP);
_V = [ _U[1],-_U[0] ];
_alpha = u(0.35,0.85);
_beta = u(0.15*_level^0.5)*(u<0.5?-1:1);
_Pc = _P0 + _length*(_alpha*_U + _beta*_V);
da_push(#$active,[ _P0,_Pc,_P1,_level] );
);
# Generate trunk
add_branch([0.5,1],[0.5 + 0.025*g,0.45],1);
# Recursively add sub-branches.
while (siz = da_size(#$active),
ind = v(siz - 1);
B = I[#$active,ind];
level = B[6];
level<4?(
P0 = [ B[0],B[1] ];
Pc = [ B[2],B[3] ];
P1 = [ B[4],B[5] ];
xs = resize([ P0[0],Pc[0],P1[0] ],nbp,5);
ys = resize([ P0[1],Pc[1],P1[1] ],nbp,5);
length = norm(P1 - P0);
repeat (int(v(10,20)/level),
nind = v(nbp/(4 + level),nbp - 1);
nP0 = [ xs[nind],ys[nind] ];
ang = atan2(ys[nind -1] - nP0[1],xs[nind - 1] - nP0[0]);
twist = u(pi/6,pi/3);
nang = ang + pi/2 + (u<0.5?twist:pi - twist);
nU = [ cos(ang),sin(ang) ];
nV = [ cos(nang),sin(nang) ];
nlength = u(0.1,0.5)*length;
nP1 = nP0 + nlength*nV;
add_branch(nP0,nP1,level + 1);
);
);
da_push(#$done,B);
da_remove(#$active,ind);
);
da_freeze(#$done)"
rm[active]
# Draw the tree.
500,500 => canvas
eval[done] ">
const nbp = 512;
B = I;
P0 = [ B[0],B[1] ];
Pc = [ B[2],B[3] ];
P1 = [ B[4],B[5] ];
xs = resize([ P0[0],Pc[0],P1[0] ],nbp,5)*(w#$canvas - 1);
ys = resize([ P0[1],Pc[1],P1[1] ],nbp,5)*(h#$canvas - 1);
ox = oy = -1;
repeat (nbp,k,
x = xs[k]; y = ys[k];
x!=ox || y!=oy?(i(#$canvas,xs[k],ys[k])+=1);
ox = x;
oy = y;
)"
rm[done]
normalize_local. , pow. 0.25 autocrop. frame. xy,10,0 n. 0,255
All those are drawn as series of 2D splines, so extending this algorithm to 3D should be straightforward (hopefully). And the structure we get starts to look like trees at least 
But before going into 3D, I’m going to try and thicken things up a bit, because at the moment they look more like little plants than trees. With a thick, fat, trunk, it should look better…
Stay tuned!