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.
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.
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.
No comments:
Post a Comment