Continuing from my previous post....
As you may notice, I was kind of stuck with the previous code.
This time I will follow this example closely first:
http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
WISHLIST
I had some thoughts while writing this kind of scattering shading:
I wonder if we could just separate parts of code and making the more generic nodes that can be easily plugged?
1. Create Shape (Circle, Star, Ring, Box, or use Image Texture)
2. Create Grid of Shape or Scatter Grid of Shape
3. Distort the Shape
4. Randomize the Size of each Shape
There is this OSL Repeater by Gottfried, which can be studied further.
http://blendersushi.blogspot.com.au/2013/08/osl-sun-flower.html?q=gottfried
So far, the code has been written in 2D Texture Coordinate, I am also wondering how it would work in 3D Coordinate?
1. GRID OF DIAMOND
Just translating is actually straight forward, but let's try to understand what is going on with the code.
For the grid of diamond below, the process goes like this:
- Specify the coordinate (s, t)
- Specify the background/base color, black in this case
- Repeat the coordinate using repeat() function.
- Rotate the whole coordinate 45 degree
- Create the actual "TILE" or "SHAPE" we like to repeat as grid
- Blend or overlay the tile into base layer
CODE:
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
// RSL intersection(a,b) ((a) * (b))
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
vector Pos = P,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
float fuzz = 0.02;
float freq = 4;
// initialize
surface_color = color(0); // black background
// computer texture coordinates
tmps = repeat(s, freq);
tmpt = repeat(t, freq);
rotate2d(tmps, tmpt, radians(45), 0.5, 0.5, ss, tt);
// generate tile
layer_color = color(0.1, 1, 0.1);
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss),
pulse(0.35, 0.65, fuzz, tt));
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
2. BOMBING TECHNIQUE - BOMBED, ROTATED SQUARE
From Steve May's note:
"The shifting is based on the tile coordinates (column & row of the tile) and not the texture coordinates. By using the tile coordinates as the seed (input) to noise, we get the same pseudo-random value (ouput) for every point inside that tile. And that's why the regular shape is maintained. If different random values are obtained within each tile, the diamond shapes will become irregular in shape."
CODE:
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
vector Pos = P,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
float fuzz = 0.02;
float freq = 4;
float noi;
// initialize
surface_color = color(0); // black background
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * 10 + 0.5, row * 10 + 0.5);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by 45 */
tmps = repeat(s, freq) + udn(noi * 1183, -0.35, 0.35);
tmpt = repeat(t, freq) + udn(noi * 999, -0.35, 0.35);
rotate2d(tmps, tmpt, radians(45), 0.5, 0.5, ss, tt);
// generate tile
layer_color = color(0.1, 1, 0.1);
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss),
pulse(0.35, 0.65, fuzz, tt));
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
Strange enough, I am getting result that is a bit different to RSL render. Not quite perfect as expected:
At this stage, I will shuffle some of the Shader parameters to give user a bit of control on the OSL node:
CODE:
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
float fuzz = 0.02,
float freq = 4,
float Rotation = 45,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
//float fuzz = 0.02;
//float freq = 4;
float noi;
// initialize
surface_color = color(0); // black background
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by 45 */
tmps = repeat(s, freq) + udn(noi * 1183, -0.35, 0.35);
tmpt = repeat(t, freq) + udn(noi * 999, -0.35, 0.35);
rotate2d(tmps, tmpt, radians(Rotation), 0.5, 0.5, ss, tt);
// generate tile
layer_color = color(0.1, 1, 0.1);
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss),
pulse(0.35, 0.65, fuzz, tt));
surface_color = blend(surface_color, layer_color, layer_opac);
// output
Col_Out = surface_color;
}
The Tile still does not look right. Anyway, moving on to the next step...
3. BOMBED, RANDOMLY COLORED, ROTATED
As we can see, we still see the glitch where our "TILE" is unwantedly cropped. I guess the quick cheat is to scale each tile slightly.
With this code, we need to use #include "stdosl.h" because we need to do Color Conversion function that converts color from HSV to RGB.
CODE:
#include "stdosl.h"
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* rotblocks.3.sl
*
* bombed, randomly colored, rotated squares
*
*/
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
float fuzz = 0.02,
float freq = 4,
float Rotation = 45,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
//float fuzz = 0.02;
//float freq = 4;
float noi;
float choice;
// initialize
surface_color = color(0); // black background
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by random amount (0-360) */
tmps = repeat(s, freq) + udn(noi * 1183, -0.35, 0.35);
tmpt = repeat(t, freq) + udn(noi * 999, -0.35, 0.35);
rotate2d(tmps, tmpt, radians(udn(noi * 777, 0, 360)), 0.5, 0.5, ss, tt);
/* generate tile 50% of the time & choose random hue */
if (udn(noi * 313, 0, 1) > 0.5) {
// layer_color = color "hsv" (udn(noi * 8181, 0, 1), 1, 1);
layer_color = transformc("hsv", "rgb", color(udn(noi * 8181, 0, 1), 1, 1));
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss), pulse(0.35, 0.65, fuzz, tt));
surface_color = blend(surface_color, layer_color, layer_opac);
}
// output
Col_Out = surface_color;
}
I quite like what is happening with the Diamond Colors though. It's random color via Noise, very neat! I did not know that was possible.
Further on, we can tidy up the code a little, giving user a bit more ability to modify the OSL node, such as:
- Seed
- Min and Max Rotation
- Ability to Scale the Cube slightly.
CODE:
#include "stdosl.h"
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
int Seed = 0,
float Scale = 1.0,
float fuzz = 0.02,
float freq = 4,
float MinRot = 0,
float MaxRot = 360,
// float Rotation = 45,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
//float fuzz = 0.02;
//float freq = 4;
float noi;
float choice;
// initialize
surface_color = color(0); // black background
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by random amount (0-360) */
tmps = repeat(s, freq) + udn(noi * (Seed+1183), -0.35, 0.35);
tmpt = repeat(t, freq) + udn(noi * (Seed+999), -0.35, 0.35);
rotate2d(tmps, tmpt, radians(udn(noi * (Seed+777), MinRot, MaxRot)), 0.5, 0.5, ss, tt);
/* generate tile 50% of the time & choose random hue */
if (udn(noi * (Seed+313), 0, 1) > 0.5) {
// layer_color = color "hsv" (udn(noi * 8181, 0, 1), 1, 1);
layer_color = transformc("hsv", "rgb", color(udn(noi * (Seed+8181), 0, 1), 1, 1));
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss/Scale), pulse(0.35, 0.65, fuzz, tt/Scale));
surface_color = blend(surface_color, layer_color, layer_opac);
}
// output
Col_Out = surface_color;
}
I think the code above just have 1 screw missing that is causing the unwanted cropping of the tile. Do you have any idea how to fix it? Please let me know....
4. BACK TO OUR CIRCLE BOMBING...
I try to take a step back and not to make things complicated with Scatter thing yet, but focusing more on the Bombing and Grid, so below is the latest modification of the code.After few tinkerings with the code and numbers, I finally figured out the thing that makes "unwanted cropping" of our Tile. The noise was doing a little too much offset.
I highlighted the culprit in bold as below. Obviously, we cannot have overlapping with Grid of Tiles.
The actual "overlapping" will come a bit later.
CODE:
#include "stdosl.h"
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
float noiseMag = 0.35,
float OffsetX = 0.5,
float OffsetY = 0.5,
float Radius = 1.0,
int Seed = 0,
float fuzz = 0.02,
float freq = 4,
float MinRot = 0,
float MaxRot = 360,
// float Rotation = 45,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
output color Col_Out = color(0.1)
)
{
// Initialize coordinate
point center = point (OffsetX, OffsetY, 0.0);
float s = Pos[0];
float t = Pos[1];
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
//float fuzz = 0.02;
//float freq = 4;
float noi;
float choice;
// initialize
surface_color = color(0); // black background
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by random amount (0-360) */
tmps = repeat(s, freq) + udn(noi * (Seed+1183), -noiseMag, noiseMag);
tmpt = repeat(t, freq) + udn(noi * (Seed+999), -noiseMag, noiseMag);
rotate2d(tmps, tmpt, radians(udn(noi * (Seed+777), MinRot, MaxRot)), 0.5, 0.5, ss, tt);
/* generate tile 50% of the time & choose random hue */
if (udn(noi * (Seed+313), 0, 1) > 0.5) {
layer_color = transformc("hsv", "rgb", color(udn(noi * (Seed+8181), 0, 1), 1, 1));
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss), pulse(0.35, 0.65, fuzz, tt));
// Create Circle on top of background layer
point here = point (ss, tt, 0);
float dist = distance(center, here);
float inDisk = 1 - smoothstep(Radius/2.0 - fuzz, Radius/2.0+fuzz, dist);
surface_color = blend(surface_color, layer_color, inDisk);
}
// output
Col_Out = surface_color;
}
I believe all this "complex" matters of TILING, BOMBING, SCATTERING will eventually come to complex shader like the Clover Shader:
http://blendersushi.blogspot.com.au/2013/08/osl-clover-x-flower.html
The funny thing is, once we understand the concept of:
- Creating Basic Shape
- Create Tile
- Create Bombing (randomly hiding some tiles)
- Create Layering
We can start to add complexity.
5. FINAL STAGE FOR THIS...
Ok, now we get to the most complicated part.... Well, not really complicated, we are going to use the FOR LOOP ITERATION to go through each lines and add MULTI LAYER TEXTURE to give complexity. We have done something like this before.
The hardest part, I think, is to control and organize the code so that they are manage-able and can be re-used. It is very easy to get lost. We want "organized chaos" so that we can have natural looking pattern.
Let's do it!
CODE:
#include "stdosl.h"
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
int Seed = 0,
float Scale = 1.0,
float MinRot = 0,
float MaxRot = 360,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
int layers = 10,
float FuzzMag = 0.005,
output color Col_Out = color(0.1)
)
{
float s = Pos[0];
float t = Pos[1];
float fuzz;
int freq;
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
float noi;
float choice;
// initialize
surface_color = color(0); // black background
for (int i = 1; i <= layers; i += 1) {
/* set freq and fuzz of pattern based on layer # */
freq = i;
fuzz = FuzzMag * freq;
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile) * noise(i * 10 + 0.5);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by random amount (0-360) */
tmps = repeat(s, freq) + udn(noi * (Seed+1183), -0.1, 0.1);
tmpt = repeat(t, freq) + udn(noi * (Seed+999), -0.1, 0.1);
rotate2d(tmps, tmpt, radians(udn(noi * (Seed+777), MinRot, MaxRot)), 0.5, 0.5, ss, tt);
/* generate tile 50% of the time & choose random hue */
if (udn(noi * (Seed+313), 0, 1) > 0.5) {
// layer_color = color "hsv" (udn(noi * 8181, 0, 1), 1, 1);
layer_color = transformc("hsv", "rgb", color(udn(noi * (Seed+8181), 0, 1), 1, 1));
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss/Scale), pulse(0.35, 0.65, fuzz, tt/Scale));
surface_color = blend(surface_color, layer_color, layer_opac);
}
}
// output
Col_Out = surface_color;
}
OTHER VARIATIONS
6. FINALLY: TILING, BOMBING, LAYERING OF CIRCLES = SCATTER.
CODE:
#include "stdosl.h"
// ORIGINATED FROM
// http://accad.osu.edu/~smay/RManNotes/StochasticPatterns/bombing.html
// Translated by Jimmy Gunawan 2013 @ Blender Sushi
/* Helper functions */
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
float udn(
float x,
float lo,
float hi
)
{
return ( smoothstep(.25, .75, noise(x)) * ((hi) - (lo)) + (lo) );
}
float whichtile (
float x,
float freq
)
{
return (floor( (x) * (freq) ));
}
float intersection(
float a,
float b
)
{
return( (a) * (b) );
}
void rotate2d (
float x,
float y,
float rad,
float ox,
float oy,
float rx,
float ry
)
{
rx = ((x) - (ox)) * cos(rad) - ((y) - (oy)) * sin(rad) + (ox);
ry = ((x) - (ox)) * sin(rad) + ((y) - (oy)) * cos(rad) + (oy);
}
color blend(
color a,
color b,
color x
)
{
return ((a) * (1-(x)) + (b) * (x));
}
float pulse (
float a,
float b,
float fuzz,
float x
)
{
return (smoothstep((a)-(fuzz), (a), (x)) - smoothstep((b)-(fuzz), (b), (x)));
}
float repeat(
float x,
float freq
)
{
return (mod((x) * (freq), 1.0));
}
/* Shader Code */
surface
rotblocks (
float Radius = 0.5,
int Seed = 0,
float OffsetX = 0.5,
float OffsetY = 0.5,
//float Scale = 1.0,
float MinRot = 0,
float MaxRot = 360,
int TileCol = 5,
int TileRow = 5,
float OffsetTile = 0.2,
vector Pos = P,
int layers = 10,
float FuzzMag = 0.005,
output color Col_Out = color(0.1)
)
{
// Initialize coordinate
point center = point (OffsetX, OffsetY, 0.0);
float s = Pos[0];
float t = Pos[1];
float fuzz;
int freq;
color surface_color;
color layer_color;
color layer_opac;
float ss;
float tt;
float tmps;
float tmpt;
float col;
float row;
float noi;
float choice;
// initialize
surface_color = color(0); // black background
for (int i = 1; i <= layers; i += 1) {
/* set freq and fuzz of pattern based on layer # */
freq = i;
fuzz = FuzzMag * freq;
/* base seed to udn on current row and column of tile */
col = whichtile(s, freq);
row = whichtile(t, freq);
noi = noise(col * TileCol + OffsetTile, row * TileRow + OffsetTile) * noise(i * 10 + 0.5);
/* repeat texture coords, jitter tiles by plus or minus 0.35,
and rotate by random amount (0-360) */
tmps = repeat(s, freq) + udn(noi * (Seed+1183), -0.1, 0.1);
tmpt = repeat(t, freq) + udn(noi * (Seed+999), -0.1, 0.1);
rotate2d(tmps, tmpt, radians(udn(noi * (Seed+777), MinRot, MaxRot)), 0.5, 0.5, ss, tt);
/* generate tile 50% of the time & choose random hue */
if (udn(noi * (Seed+313), 0, 1) > 0.5) {
layer_color = transformc("hsv", "rgb", color(udn(noi * (Seed+8181), 0, 1), 1, 1));
layer_opac = intersection(pulse(0.35, 0.65, fuzz, ss), pulse(0.35, 0.65, fuzz, tt));
// Create Circle on top of background layer
point here = point (ss, tt, 0);
float dist = distance(center, here);
float inDisk = 1 - smoothstep(Radius/2.0 - fuzz, Radius/2.0+fuzz, dist);
surface_color = blend(surface_color, layer_color, inDisk);
}
}
// output
Col_Out = surface_color;
}
The code above can be tidied up further.
If we apply the OSL Shader like this to 3D object (instead of flat plane), we will get texture stretching. This is the expected behaviour because we have been working on 2D Procedural Texture. The advantage of 2D Procedural Texture is that we can actually "bake" it and re-apply it as normal 2D Image Texture.
Depending on the needs, sometimes I just plug one of built in 3D Procedural Textures in Cycles into the vector Pos input of our 2D OSL to see the result:
That is of course a cheat, but interesting result, nevertheless.
Hopefully one day we get to 3D Procedural Texture and scatter some 3D Spheres that behaves more like 3D Volumetric. That sounds really complicated, but also interesting.
2D PROCEDURAL to 3D PROCEDURAL?
If we apply the OSL Shader like this to 3D object (instead of flat plane), we will get texture stretching. This is the expected behaviour because we have been working on 2D Procedural Texture. The advantage of 2D Procedural Texture is that we can actually "bake" it and re-apply it as normal 2D Image Texture.
Depending on the needs, sometimes I just plug one of built in 3D Procedural Textures in Cycles into the vector Pos input of our 2D OSL to see the result:
![]() |
Noise plug. |
![]() |
Voronoi plug. |
![]() |
Play with LAYER BLENDING. |
Hopefully one day we get to 3D Procedural Texture and scatter some 3D Spheres that behaves more like 3D Volumetric. That sounds really complicated, but also interesting.
TIPS AND TRICK WHEN WRITING CODE
- Ctrl+Shift+ UP or DOWN will shift the highlighted part of code.
- To quickly refresh the node, simply re-select the script inside Script Node drop down.
- Comments whenever you can and be clear
- Visual coding is very dynamic and having instant feedback (change values, see result) is something that we can take advantage of.
LINKS
Post a Comment