When we look at images the addition of veins greatly adds to the preceived realism of rendered leaves and in this article I present a simple veins shader that complements the leaf shader discussed previously.
Leaf veins
I forgot to update the page that describes equations.h (thanks samblerdevel for pointing that out). I just corrected that so if you had any errors complaining abot a function splinedist()
that was missing, download & install equations.h and try again
The code for this node is shown below makes use of the equations.h include discussed in the article on leaf shapes.
#include "equations.h"
shader arcuateveins(
point Pos = P,
int Veins = 7,
int Seed = 42,
float Var = 0,
float Width = 0.05,
float NWidth = 0.25, // size of the reticulated area
float Squish = 0.5, // distribution of endpoints on edge
float Squish2 = 0.5, // distribution of controlpoints
float Squish3 = 0.5, // distribution of starting points
float Up = 0.5,
float Angle1 = 70,
float L1 = 1,
float Angle2 = 70,
float L2 = 1,
output float Vein = 0,
output float Net = 0,
output float Fac = 0
){
float delta = 1.0/((float)Veins+1);
float delta2= delta/2;
float delta4= delta/4;
// calculate the four control points of the cubic spline that defines the leaf edge
float x1,y1,x2,y2;
sincos(radians(Angle1),y1,x1);
sincos(radians(Angle2),y2,x2);
point P0 = point(0 , 0 ,0);
point P1 = point(x1 , y1,0)*L1;
point P2 = point(1-x2*L2, y2*L2,0);
point P3 = point(1 , 0 ,0);
point P0q = point(P0[0],P0[1]*Up,P0[2]);
point P1q = point(P1[0],P1[1]*Up,P1[2]);
point P2q = point(P2[0],P2[1]*Up,P2[2]);
point P3q = point(P3[0],P3[1]*Up,P3[2]);
int i;
for(i=0;i < Veins;i++){
// determine the starting points of the veins
float x = (i*delta+delta2*Var*cellnoise(i+10+Seed))*Squish3;
float dx = (delta4*Var*cellnoise(i+17+Seed))*Squish3;
point P0up = point(delta2+x+dx,0,0);
point P0down = point(delta2+x,0,0);
// determine the endpoints on the leaf edge
float t=(i*delta+delta2)*Squish+1-Squish;
point P2up = cubicspline(t,P0,P1,P2,P3);
point P2down = point(P2up[0],-P2up[1],P2up[2]);
// the veins are quadratic splines, so need one additional control point
t=(i*delta+delta2)*Squish2+1-Squish2;
point P1up = cubicspline(t,P0q,P1q,P2q,P3q);
point P1down = point(P1up[0],-P1up[1],P1up[2]);
float r;
int f = splinedist(P0up, P1up, P2up, Pos, r, t);
if ( f && (r < NWidth ) ) Net = 1 ;
if ( f && (r < Width * ( 1- t) * (1-Pos[0]) ) ) { Vein = 1; Fac = sqrt(1-r/Width); break; }
f = splinedist(P0down, P1down, P2down, Pos, r , t);
if ( f && (r < NWidth ) ) Net = 1 ;
if ( f && (r < Width * ( 1- t) * (1-Pos[0]) ) ) { Vein = 1; Fac = sqrt(1-r/Width); break; }
}
// the central vein
float d = distance(point(0,0,0),point(1,0,0),Pos);
if ( d < NWidth ) Net = 1 ;
if (d < (Width * (1-Pos[0])) ) { Vein = 1; Fac = sqrt(1-d/Width);}
}
Relation to real venation patterns in leaves
The shader in its current form is able to model pinnate and arcuate venation patters and intermediate forms of these. (For an explanation of terminolgy refer to Wikipedia, especially this overview sheet). Its spline-based modelling of the veins is not based on any underlying theory of the formation of veins as it happens in nature, as these reaction-diffusion equations cannot so easily be implemented in an OSL shader (at least not at present: we wouldn't want to redo such a costly simulation again and again for each point being shaded so we would need peform the simulation before we start shading each pixel. Currently there is no facility for adding something to a shader that will be executed once beforehand, although there might be in the future. An alternative approach might be to perform the simulation, maybe in a Python add-on, and store the result in a texture. Here we opted for art before science: if it looks all right we don't care what it is based on).
Controlling the curve shape of the veins
In the following images I have illustrated how you can control the shape of the veins. How much the starting points on the central vein and the control points in the middle and the end points on the leaf edge are bunched up, is controlled by the Squish parameters. The blue control points all lie on a spline that is a copy of the spline that defines the leaf edge by scaled by the Up parameter. Some experimenting shows that is is possible to create both pinnate venation patterns as well as arcuate patterns:Example node setup
The leaves in the image at the top of this article were created with the following node setup:
The values in the blue box simultaneously control the shape of the leaf edge both in the leaf shader and in the vein shader. The leaf coloring is controled by the nodes in the green box (leaves are both glossy and translucent) while the vein coloring is is defined by the nodes in the red box, the choice being determined by the Vein output socket of the vein shader. The yellow box provides some noisy patterns to drive both the colloration of the leaf as well as mix with the bump patern from the vein shader to drive the displacement. The exact contribution of these displacements is controlled by the purple nodes.Room for improvement
Although the shader is already quite versatile there is ample room for imrpovement. For example, I would like it to be able to produce palmate vein patters and to control the narrowing towards the tips of the veins. On the other hand the shader is not limited to producing vein pattersn: I imagine it can be used to produce fish bones and bird feather patterns (barbs) as well. I might expand on that in the future.
I'm guessing that splinedist() is a new function added to equations.h that you haven't updated yet?
ReplyDelete