I want to touch few OSL functions to create basic procedural texture (regular pattern).
This writing about basic OSL functions will be based on:
http://accad.osu.edu/~smay/RManNotes/RegularPatterns/transitions.html
http://accad.osu.edu/~smay/RManNotes/RegularPatterns/mod.html
And I will also reference the "Open Shading Language Specification" PDF.
On top of that, I also will use the concept of LAYERING in the code. Read my 2 previous posts before this one to be clear.
STEP() FUNCTION
You are probably familiar with step keys in animation curve which result in having "no transition" whatsoever between 2 keyframes.
There is a built in function called step() in OSL, it takes 2 values.
From OSL specs:
float step (float edge, float x)
Returns 0 if x<edge and 1 if x >= edge.
We can pass in point, vector, normal, or color into step function, as long we do it separately per value.
It will be clear when we use it in code, let me show you.
NOTE:
In my code, I almost always do this below in regards to assigning vector P to vector Pos and the using the Pos values as s, t, and u.
EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
output color Col_Out = color(0.2)
)
{
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// here we use the function
layer_opac = step(s, 0);
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
THE RESULT:
If I modify the step(s,0) to step(t,0), we get result like below:
For beginner, I think it is OKEY to think our procedural texture in 2D coordinate.
My plane geometry above is 1 x 1 in dimension. We can modify the "bias" in step() function to adjust the edge position. For example:
step(s, 0.2);
step(s, -0.5);
step(s, 4);
That will slide or offset the edge.
WAVE FUNCTION: sin(), cos()
We will get a more interesting result when we start to mix other Math function, such as the SINE and COSINE function that is basically going up and down like wave, where we usually can modify: frequency, amplitude and offset the wave.
EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
output color Col_Out = color(0.2)
)
{
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// here we use the function
layer_opac = step(sin(s * 20), 0);
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
THE RESULT:
That seems like a quick and fast way to get repeating stripes. But later below you will see that we can also use mod() aka modulus function to get repeating stripes.
And look if I change the function slightly:
layer_opac = step(s, sin(t * 4));
SEE ALSO:
Repater.osl from Geoffrey
MOD() FUNCTION
Mod (%) or modulus or modulation is an interesting function. It gives an effect of repeating pattern. If we use number:
10 % 5 = 0
9 % 5 = 4
8 % 5 = 3
7 % 5 = 2
6 % 5 = 1
5 % 5 = 0
It gives a see-saw pattern when drawn as curve. Let's try that:
EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
output color Col_Out = color(0.2)
)
{
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// here we use the function
layer_opac = step(s, mod(t,2));
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
THE RESULT:
Later on, we will be using repeat() function, which is basically a modified version of mod(), where we have additional frequency input.
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
The thing with having "no transition" using step() is that it tends to result in noise or jaggy or moire pattern when texture get complex. This was actually mentioned few times in many books. So later on, we learn how to code anti-aliasing.
But for our SIMPLE texture, we can simply use smoothstep() function instead of step()
SMOOTHSTEP() FUNCTION
This smoothstep() function allows us to have blending effect, similar to mix() function.
EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
int freq = 5,
output color Col_Out = color(0.2)
)
{
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// ss, tt, because of modulus inside repeat function
float ss;
float tt;
ss = repeat(ss, freq);
tt = repeat(tt, freq);
// here we use the function
layer_opac = smoothstep(-2, 2, s);
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
THE RESULT:
Blurred lines effect can be created by modifying the smoothstep function like below:
layer_opac = smoothstep(-2, 2, sin(s));
PULSE() FUNCTION
Now, we also have a modification of smoothstep() which is called pulse(). This pulse gives additional control over the fuzziness, the MIN and MAX of "the stripe".
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
int freq = 5,
float fuzzy = 0.2,
output color Col_Out = color(0.2)
)
{
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// ss, tt, because of modulus inside repeat function
float ss;
float tt;
ss = repeat(ss, freq);
tt = repeat(tt, freq);
// here we use the function
layer_opac = pulse(-4, 4, fuzzy, s);
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
THE RESULT:
MODIFICATION #001
layer_opac = pulse(-4, sin(t), fuzzy, s);
MODIFICATION #002
layer_opac = pulse(-cos(t*5)-3, sin(t), fuzzy, s);
MODIFICATION #003
layer_opac = pulse(sin(t)-2, sin(t), fuzzy, s);
ABS() / ABSOLUTE FUNCTION
Just to add one more useful function, the abs() function. It takes any positive or negative values and return positive values. This is often used to create a "bouncing ball" effect. The value never goes below the zero.
layer_opac = pulse(-2, abs(sin(t)), fuzzy, s);
SPLINE() / RAMP FUNCTION
I decided to add one more function to this post.EXAMPLE CODE:
// Helper Function
// We will always need this blend() function
// to help to do the layering effect
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
shader simpleStep(
color ColA = color(1,0,0), // red
color ColB = color(0,1,0), // green
vector Pos = P,
output color Col_Out = color(0.2)
)
{
// declare the SPLINE COLOR ARRAY
color MYSPLINE = color(1,0,0);
color colorarray[17]= {color(0,0,0),
color(0,0,0),
color(0.10588235294117647, 0.0, 0.0),
color(0.21176470588235294, 0.0, 0.0),
color(0.3176470588235294, 0.0, 0.0),
color(0.42745098039215684, 0.0, 0.0),
color(0.5333333333333333, 0.0, 0.0),
color(0.6509803921568628, 0.0196078431372549, 0.0),
color(0.6509803921568628, 0.0196078431372549, 0.0),
color(0.8274509803921568, 0.23529411764705882, 0.0),
color(0.9058823529411765, 0.3568627450980392, 0.0),
color(0.9333333333333333, 0.5019607843137255, 0.0),
color(0.9568627450980393, 0.6352941176470588, 0.047058823529411764),
color(0.9725490196078431, 0.7333333333333333, 0.22745098039215686),
color(0.984313725490196, 0.8196078431372549, 0.45098039215686275),
color(0.996078431372549, 0.9254901960784314, 0.8235294117647058),
color(1.0, 0.9450980392156862, 0.9019607843137255),
color(1.0, 0.9450980392156862, 0.9019607843137255)
};
// initialize color value into our LAYERING concept
color surface_color = ColA; // assign ColA as base color
color layer_color = ColB; // assign ColB as the layer on top of base
color layer_opac = color(1);
// s, t value from Pos
float s = Pos[0];
float t = Pos[1];
// here we use the function
layer_opac = step(sin(s * 20), 0);
// spline color, similar to ramp
MYSPLINE = spline("constant",s,colorarray);
// layering
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = MYSPLINE;
}
THE RESULT:
That fire-ish Color Array was borrowed from:
http://blenderartists.org/forum/showthread.php?274730-OSL-Porting-from-RSL
But you could always make your own Color Array preset, simply by modifying and writing your own color "Ramp", for example below only creates 3 colors R, G, B:
color colorarray[3]= {color(1,0,0),
color(0,1,0),
color(0,0,1)
};
You can plug ColorRamp node after the code like this to adjust and remap the Color gradient, even after the OSL code:
You may also notice the notation/syntax we use for spline() function:
spline("constant",s,colorarray);
From the OSL specification document, it mentions something like below:
spline(string basis, float x, type y[] array)
That just means for input of spline() function, we need to give it 3 inputs:
- string --> "constant", "linear", "bspline", "cardinal", "ease"
- float --> any float number or changing float numbers
- array --> the color array
That is pretty much it with basic functions.
I gotta mention Inigo Quilez again and his notes and videos below:
http://www.iquilezles.org/www/articles/functions/functions.htm
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
http://www.youtube.com/user/mari1234mari
https://www.shadertoy.com/
With Shader Writing and Procedural Texture, again, I must say this is pretty abstract and not everyone's cup of tea. However, even by typing and attempting to understand the OSL syntax, we can started to see the capability of OSL in other areas, such as for utilities.
ADDITIONAL NOTE 2014.02.14:
CODE:
#include "/Users/jimmygunawan/Desktop/rmannotes.sl"
//#include "/Users/jimmygunawan/Desktop/patterns.h"
shader
blah
(
vector Pos = P,
color ColA = color(1,0,0),
color ColB = color(0,1,0),
float Scale = 1.0,
float Fuzz = 0.5,
float Freq = 10,
float Blah = 0.2,
float Amp = 0.2,
float Min = 0.5,
float Max = 0.6,
output color ColOut = 0
)
{
float x,y,z;
x = Pos[0] * 1/Scale;
y = Pos[1] * 1/Scale;
z = Pos[2] * 1/Scale;
float f = sin(x) + atan(y);
float sf = smoothstep(0.5, 0.6, abs(f));
float pf = pulse(0.5, 0.8, Fuzz, abs(f));
float steppy = step(x, sin(y));
float xx = repeat(x, Freq);
float yy = repeat(y, Freq);
float sforce = pulse(Min * noise(0.02 * Pos) + Amp*sin(y*Blah), Max* noise(0.02 * Pos) + Amp*sin(y*Blah), Fuzz, xx);
ColOut = mix(ColA, ColB, sforce );
}
Post a Comment
Click to see the code!
To insert emoticon you must added at least one space before the code.