Showing posts with label gabor. Show all posts
Showing posts with label gabor. Show all posts

Noise experiment with Open Shading Language

I am still looking for good procedural noise to be used as the basis for bark materials. Such noise would need some anisotropy because the cracks in bark are almast always oriented: either along the direction of the trunk or perpendicular to it, depending on the stretching characteristics during growth. Now you could scale for example Perlin noise or use Gabor noise (the latter is available in OSL as well, check for example this article), but we could also create it from scratch.

Theory

In the shader we randomly distribute a number of line segments through space and calculate the distance to these line segments. If we are close enough to a segment we add a value to our sum and in the end the value for a pixel is the sum of all these contributions. Now the essence is in the distribution of those line segments because we do not only control their length but also how far they may deviate from a preferred direction.
The code for the shader itself is quite simple (I have omitted all auxiliary functions):
shader dtnoise(
 point  Pos = P,            // texture position and scale
 float  Scale = 1,
 
 int    Np = 15,            // number of ticks (impulse) per cell
 
 int    Seed = 42,          // random seed
 
 float  Radius = 0.3,       // distance to impulse that will add to result
 float  Size = 0.7,         // length of an impulse
 vector Dir = vector(1,0,0),// direction of anisotropy
 float  Theta = M_PI/2,     // cone (half)angle. The default = 90% which means no anisotropy
 
 float  Step = 0.3,         // cutoff value for Fac output
 float  Gain = 0.3,         // brightness of the result
 
 output float Sum = 0,      // the sum of all the tick values
 output float Fac = 0       // the 
){
 point p = Pos * Scale;
 point f = floor(p);

 vector an= normalize(Dir);
 vector r = vector(an[2],an[1],an[0]); //no need to norm again
 vector uv = cross(an,r);
 vector vv = cross(an,u);

 
 int xx,yy,zz, np;
 
 int nn[3];
 
 for( xx=-1; xx<=1; xx++){
  for( yy=-1; yy<=1; yy++){
   for( zz=-1; zz<=1; zz++){
    point ff = f + vector(xx,yy,zz);
    int s=Seed;
    
    nn[0] = int(ff[0]);
    nn[1] = int(ff[1]);
    nn[2] = int(ff[2]);
    
    for( np=0; np < Np; np++){
     vector pd1 = noise("cell",ff,s);
     vector pd2 = randomcone(uv, vv, an, Theta, nn, s+1);
    
     point p1 = ff + pd1;
     point p2 = p1 + Size * pd2;
    
     float d = distance(p1,p2,p);     
     Sum += (1 - smoothstep(0, Radius, d));
     
     s+=3;
    }
   }
  }
 }
 
 Sum *= Gain;
 Fac = smoothstep(0, Step, Sum);
}
The essence is in line 44 and 45: here we pick a random point and another point along a random direction, where this random direction is restricted to a cone whose narrowness we can control with the Theta parameter. Those two points make up the start and end points of a line segment and if the distance to this line segment is small enough we a a value. (make sure that the sum of Size and Length < 1 to prevent artifacts.

Samples

With few points per cell the anisotropy is very clear (left: Theta = 0.05, right Theta = 1.51 (approx. 90 degrees):
   
 Adding points increases the complexity of the noise (we reduced the gain, the number of points is 40):
 
If we compare our noise to gabor and perlin noise (each thresholded and suitably scaled in a preferred direction) we see that the patterns are similar but each with its own character.

How useful this all is, it up to you of course :-) It is nice to have a different procedural noise in your toolbox but on the other hand, it ties you to OSL (i.e. you can't use it on the GPU) and it is relatively slow.

Code availability

As usual the full code is available on GitHub.

Mmmm, maybe this advertising widget below is a bit over sized. Still, if you would like to learn some more about Open Shading Language for Blender, you might check it out.





An overview of Gabor noise parameters

In this post we tabulate some of the parameters of Gabor noise as provided in Cycles'Open Shading Language.

In a previous post I presented a small OSL node that gives access to the fairly new Gabor noise that is available in OSL. I already showed some examples of how to use it and made an attempt to implement a fabric shader based on this noise. To help visualize the parameters of this noise I made the overview shown below (click to enlarge):

Gabor noise has tree modes:

  • Isotropic
  • Anisotropic
  • Mixed
These modes are triggered by the values 0, 1 and 2 of the anisotropic parameter. In isotropic mode the direction parameter is ignored but in the other modes the length and direction of this vector determine the frequency and the direction of the anistropy.

The impulses parameter determines the number of features (bumps) present per unit area, whereas the bandwidth parameter determines how much detail of these bumps is visible.

In the image above the colored squares show a systematic variation of these parameters. Gabor noise has a value between [-1, 1] centered around zero (the green in the colored examples). The black and white examples show some specific patterning that is possible if you choose suitable cutoffs for the noise values. They we created using the following node setup:

Note that the add/divide nodes on the left to nothing more than map the [-1, 1] range to [0, 1]. The less than/ more than nodes in combination with the multiply node pass on a value if its between the two limits or zero otherwise.

A fabric shader using Gabor noise

A combination of two perpendiclar anisotropic Gabor textures is an easy way to create textures that mimic fabrics. In this post we use this to create a simple denim fabric.

In a previous post I presented a simple node to provide Gabor noise. Anisotropic Gabor noise with a large direction vector has slightly undulating parallel lines. Two of these perpendicular to each other are an easy way to create a fabric like structure.

(Click to enlarge if you cannot see the individual threads of the fabric)

The material that is presented here is probably not as versatile or fast as the fabric node I presented earlier, but it does give a somewhat more natural result (at least in my opinion) and is foremost an example of how versatile Gabor noise is. Also, because a Gabor noise node is farly high on the todo list for Cycles this means in the future we might not be dependent on custom nodes as presented here.

Example node setup

The node setup here isn't exactly pretty (click to enlarge) but the main idea is the combination of two Gabor noise nodes (show in a previous post):

As indicated in the image both nodes have a fairly large direction vector which gives small lines. Both vectors are prependicular. The resulting noise is a value that may be less than zero and adding a value to the result as we do here allows for control over the apparent gap between the threads of the fabric. A hight value gives less visible space between the threads. Note that the scale value on the left controls the scaling of the UV-space. It has an effect on the variation of the noise but not on the number of threads per centimeter, that is completely controlled byt the direction vectors. The bandwidth value controls the quality: changing it gives less or more of a 'fluffy' appearence to the threads.

Gabor noise for Cycles OSL

Hidden in the the treasure trove that is OSL lies a spanking new noise type: Gabor noise. Surprisingly this not yet exposed as a node for artists to explore. This article remedies that situation.

And now for something completely different

Gabor noise is fairly new and has some interesting qualities. Apart from the mathematical properties the most important aspects for the artist are that it is easy to tinker with and offers a change from the ubiquitous Perlin noise.

The shader is almost to simple to show here:


shader gabor(
point Pos = P,
int anisotropic = 0,
vector direction = vector(1,0,0),
int do_filter = 1,
float bandwidth = 1.0,
float impulses = 16,
output float Noise = 0
){
Noise = noise("gabor",Pos,
"anisotropic", anisotropic,
"direction", direction,
"do_filter", do_filter,
"bandwidth", bandwidth,
"impulses", impulses);
}
It offers all the options documented in the OSL language specification and produces a single float value. This can of course be adapted easily to take for example 4 dimensions (position and time) as input and produce a 3D noise vector as OSLs noise() is very versatile but this is left as an excercise for the reader.

Example node setup

Suzanne was patterned with the following node setup:

Gabor noise is of course capable of much more: there is plenty of room to experiment. You might like to show some results on Blender Artists. Some examples are shown below:

Recently I reread a long running thread on Blender Artists and saw that phoneybone implemented a pure OSL version of Gabor noise that gives a bit more control than the built-in function. Do read on his solution because it is interesting to compare.