An OSL wood shader with knots for Blender Cycles

In a previous article I presented a shader that could be used to create the impression of knots in wood. This was accomplished by warping the texture coordinates around randomly distributed points in space.

Knots however do not resemble spheres but are more like cylinders that are cut under a slight angle. This distinction is not that important but for completeness sake we present this new implementation here together with a node setup that combines these knots with the wood shader we presented a while ago. An example result is shown below.

Code and example node setup

The implementation differs from the previous one in generating random lines (represented by a random point plus a random direction) instead of points. The texture coordinates are bent proportional to the distance to the closest point on this random line, so the bend() is a little bit more complicated than before.


vector random_sphere(point p, int n, float zdistribution){
float t = M_2PI*noise("cell",p,n*2+0);
float u = 2*noise("cell",p,n*2+1)-1;
float s,c,a;
sincos(t,s,c);
a = sqrt(1-u*u);
float x = a*c;
float y = a*s;
float z = u*zdistribution;
return vector(x,y,z);
}

int bend(vector p, vector k, vector kv, float r, float a, float m, output vector B){
vector pk = k - p;
vector t = dot(pk,kv)/dot(kv,kv);
vector D = k + t * kv - p;
float L = length(D);
if( L < r ){
float c = L/r;
float d = m * pow( 1 - c , a);
if( d < L ){
B = d * normalize(D);
return 1;
}else{
B = D;
return 2;
}
}
return 0;
}

shader knot(
vector Pos = P,
float Scale = 1.5,

float R = 2.9,
float Falloff = 2,
float Strength = 1,
float Knots=0.1,
float Z=1,

output vector Vec = P,
output float Fac = 0
){
vector p = Scale * Pos;
vector sdp = 0;

float TR = ceil(R);
for(float dx=-TR; dx <= TR; dx++){
for(float dy=-TR; dy <= TR; dy++){
for(float dz=-TR; dz <= TR; dz++){
vector ip = floor(p)+vector(dx,dy,dz);
for(int ik=0; ik < (int)Knots; ik++){
vector k = noise("cell",ip,ik);
vector kv= random_sphere(ip,ik+1000,Z);
vector dp= 0;
int ret = bend(p,ip+k,kv,R,Falloff,Strength,dp);
if(ret != 0){
Fac=max(Fac,ret==2);
sdp+=dp;
}
}
if( noise("cell",ip,-1) < mod(Knots,1.0) ){
vector k = noise("cell",ip,-2);
vector kv= random_sphere(ip,998,Z);
vector dp= 0;
int ret = bend(p,ip+k,kv,R,Falloff,Strength,dp);
if(ret != 0){
Fac=max(Fac,ret==2);
sdp+=dp;
}
}
}
}
}
if( Fac < 1 ){
Vec = p + sdp;
}else{
Vec = sdp;
}
}
Note that the function random_sphere() is modified from the one presented in a previous article to bias the vectors that are returned. This allows us to tweak the orientation of the generated knots, which might give more realisted results because branches (the source of the knots) are not pointing in all directions from the stem.

The node setup used to create the material in the example image is shown below (click to enlarge).

Room for improvement

The distribution of the knots might be convincing enough for our purposes but the material is now just another (darker) wood mzterial, rings and all. Quits a number of wood knots do look like that but a significant fraction shows characteristic radial cracks. This is caused when the wood is dried because the material properties of the knot are different from the surrounding wood. It would be nice if we could implement this in some way as well.

No comments:

Post a Comment