Hexagon Tiles basic is not so basic. |
Nothing quite original in this post, I am just trying to make sense of this Hexagon Tile Shader which originally was written by Larry Gritz.
http://www.renderman.org/RMR/Shaders/LGShaders/
Which then I found out at Blender Forum, already translated by Charlie:
http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness&p=2253925&viewfull=1#post2253925
The original RSL for Hexagon Tile has extra additional layer of texture that is not really related to the hexagon tiling (stain and scuff). So, I stripped those out.
I made a slight modification and I am commenting out some more of the code, so that the shader goes back to the very basic.
OSL HEXAGON TILE
CODE: (with all the commented out codes)
/*
SHADER HISTORY 20140205
1.
Originally written by Larry Gritz
http://www.renderman.org/RMR/Shaders/LGShaders/
2.
Modified by Charlie as posted here:
http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness/page9
3.
Jimmy Gunawan of Blender Sushi (me) decided to study this shader...
Stripped out to the basic of the procedural texture only. Without Closure.
*/
//////////
/*
* {converted/hacked to OSL from http://www.renderman.org/RMR/Shaders/LGShaders/LGHexTile.sl}
* hextile.sl -- surface shader for hexagonal tiles in st space
*
* DESCRIPTION
* This surface shader operates in s-t space and gives a pattern of
* hexagonal tiles, similar to that found as floor patterns in public
* places and such.
* The basic pattern is a hexagona
l tiling, with a little bit of
* color variation from tile to tile. On top of that is some staining
* (presumably due to water or something), which darkens the tile or
* mortar underneath it. Finally, there is scuffing due to people's
* shoes, which really only affects the tile part not the mortar part.
*
*
* PARAMTERS
* Ka, Kd, Ks, roughness, specularcolor - work just like plastic
* tilecolor - the color of the tiles
* mortarcolor - the color of the mortar (space between the tiles)
* tileradius - the "radius" (in s-t units) of a single tile
* mortarwidth - the width of the mortar (in s-t units)
* tilevary - the color variance from tile to tile
*
* ANTIALIASING
* Some rudimentary antialiasing is performed on the borders between
* tile and mortar.
*
* HINTS & APPLICATIONS
* If all of the default parameters are used, the tiles look just like
* the floors in the public areas of the Washington DC subway system.
*
* AUTHOR: written by Larry Gritz, 1994
*
* HISTORY:
* 15 Feb 1994 -- written by lg
*
* last modified 15 Feb 94 by Larry Gritz
*/
shader
LGHexTile (
point Pos = P,
//float Ka = .5,
float Kd = .5,
//float Ks = .2,
//float roughness = .1,
//color specularcolor = 1,
color tilecolor = color(.55,0,0),
color mortarcolor = color(.5,.5,.5),
float tileradius = 0.2,
float mortarwidth = 0.02,
float tilevary = 0.15,
float stretchH = 1.0,
float stretchV = 1.0,
//float scuffing = 0.5,
//float stains = 0.4,
//float stainfrequency = 2,
//float scufffrequency = 4,
//color scuffcolor = color (.05,.05,.05),
//output closure color Closure = diffuse(N),
int Seed = 41,
output color Col = color(1,0,0)
)
{
#define snoise(x) (2*noise(x)-1)
#define snoise2(x,y) (2*noise((x),(y))-1)
#define MINFILTERWIDTH 1.0e-7
#define M_SQRT3 1.7320508 /* sqrt(3) */
point Nf;
color Ct, Ctile;
float tilewidth;
float ss, tt;
float ttile, stile;
float x, y;
float mortar;
float swidth, twidth, sfuzz, tfuzz, fuzzmax;
float mw2, mw2srt3;
float tileindex;
float stain, scuff;
float ks;
float s = Pos[0] * stretchH;
float t = Pos[1] * stretchV;
swidth = abs(Dx(s)) + abs(Dy(s));
twidth = abs(Dx(t)) + abs(Dy(t));
sfuzz = .5 * swidth; // blurred lines
tfuzz = .5 * twidth; // blurred lines
fuzzmax = max(sfuzz, tfuzz);
//Nf = N;
tilewidth = tileradius * M_SQRT3;
tt = mod (t, 1.5*tileradius);
ttile = floor(t/(1.5*tileradius));
if (mod(ttile/2, 1) == 0.5)
ss = s + tilewidth/2;
else ss = s;
stile = floor(ss / tilewidth);
ss = mod(ss, tilewidth);
mortar = 0;
mw2 = mortarwidth/2;
if (tt < tileradius)
{
mortar = 1 - (smoothstep(mw2,mw2+sfuzz,ss) *
(1 - smoothstep(tilewidth-mw2-sfuzz,tilewidth-mw2,ss)));
}
else
{
x = tilewidth/2 - abs(ss - tilewidth/2);
y = M_SQRT3 * (tt - tileradius);
if (y > x)
{
if (mod (ttile/2, 1) == 0.5)
stile -= 1;
ttile += 1;
if (ss > tilewidth/2)
stile += 1;
}
mw2srt3 = M_SQRT3*mw2;
mortar = (smoothstep(x-mw2srt3-tfuzz, x-mw2srt3, y) *
(1 - smoothstep(x+mw2srt3, x+mw2srt3+tfuzz, y)));
}
tileindex = stile + Seed * ttile;
Ctile = tilecolor * (1 + tilevary * snoise(tileindex+0.5));
//stain = stains * smoothstep (.5,1, noise(s*stainfrequency,t*stainfrequency));
//scuff = scuffing * smoothstep (.6,1, noise(t*scufffrequency-90.26,s*scufffrequency+123.82));
//ks = Ks * (1-scuff/2);
//Ct = (1-stain) * mix(mix(Ctile, scuffcolor, scuff), mortarcolor, mortar);
Ct = mix(Ctile, mortarcolor, mortar);
//Nf = normalize(N); //no faceforward function
//Closure = Ct*Kd*diffuse(Nf); //no aambient function
//Closure += specularcolor*ks*microfacet_beckmann(Nf,roughness);
Col = Ct * Kd;
}
CODE: (cleaned up, but I need to ensure I leave credit and source information)
/*
SHADER HISTORY 20140205
1.
Originally written by Larry Gritz
http://www.renderman.org/RMR/Shaders/LGShaders/
2.
Modified by Charlie as posted here:
http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness/page9
3.
Jimmy Gunawan of Blender Sushi decided to study this shader...
Stripped out to the basic of the procedural texture only. Without Closure.
*/
//////////
/*
* {converted/hacked to OSL from http://www.renderman.org/RMR/Shaders/LGShaders/LGHexTile.sl}
* hextile.sl -- surface shader for hexagonal tiles in st space
*
* DESCRIPTION
* This surface shader operates in s-t space and gives a pattern of
* hexagonal tiles, similar to that found as floor patterns in public
* places and such.
* The basic pattern is a hexagona
l tiling, with a little bit of
* color variation from tile to tile. On top of that is some staining
* (presumably due to water or something), which darkens the tile or
* mortar underneath it. Finally, there is scuffing due to people's
* shoes, which really only affects the tile part not the mortar part.
*
*
* PARAMTERS
* Ka, Kd, Ks, roughness, specularcolor - work just like plastic
* tilecolor - the color of the tiles
* mortarcolor - the color of the mortar (space between the tiles)
* tileradius - the "radius" (in s-t units) of a single tile
* mortarwidth - the width of the mortar (in s-t units)
* tilevary - the color variance from tile to tile
*
* ANTIALIASING
* Some rudimentary antialiasing is performed on the borders between
* tile and mortar.
*
* HINTS & APPLICATIONS
* If all of the default parameters are used, the tiles look just like
* the floors in the public areas of the Washington DC subway system.
*
* AUTHOR: written by Larry Gritz, 1994
*
* HISTORY:
* 15 Feb 1994 -- written by lg
*
* last modified 15 Feb 94 by Larry Gritz
*/
shader
LGHexTile (
point Pos = P,
float Kd = .5,
color tilecolor = color(.55,0,0),
color mortarcolor = color(.5,.5,.5),
float tileradius = 0.2,
float mortarwidth = 0.02,
float tilevary = 0.15,
float stretchH = 1.0,
float stretchV = 1.0,
int Seed = 41,
output color Col = color(1,0,0)
)
{
#define snoise(x) (2*noise(x)-1)
#define snoise2(x,y) (2*noise((x),(y))-1)
#define MINFILTERWIDTH 1.0e-7
#define M_SQRT3 1.7320508 /* sqrt(3) */
point Nf;
color Ct, Ctile;
float tilewidth;
float ss, tt;
float ttile, stile;
float x, y;
float mortar;
float swidth, twidth, sfuzz, tfuzz, fuzzmax;
float mw2, mw2srt3;
float tileindex;
float stain, scuff;
float ks;
float s = Pos[0] * stretchH;
float t = Pos[1] * stretchV;
swidth = abs(Dx(s)) + abs(Dy(s));
twidth = abs(Dx(t)) + abs(Dy(t));
sfuzz = .5 * swidth; // blurred lines
tfuzz = .5 * twidth; // blurred lines
fuzzmax = max(sfuzz, tfuzz);
tilewidth = tileradius * M_SQRT3;
tt = mod (t, 1.5*tileradius);
ttile = floor(t/(1.5*tileradius));
if (mod(ttile/2, 1) == 0.5)
ss = s + tilewidth/2;
else ss = s;
stile = floor(ss / tilewidth);
ss = mod(ss, tilewidth);
mortar = 0;
mw2 = mortarwidth/2;
if (tt < tileradius)
{
mortar = 1 - (smoothstep(mw2,mw2+sfuzz,ss) *
(1 - smoothstep(tilewidth-mw2-sfuzz,tilewidth-mw2,ss)));
}
else
{
x = tilewidth/2 - abs(ss - tilewidth/2);
y = M_SQRT3 * (tt - tileradius);
if (y > x)
{
if (mod (ttile/2, 1) == 0.5)
stile -= 1;
ttile += 1;
if (ss > tilewidth/2)
stile += 1;
}
mw2srt3 = M_SQRT3*mw2;
mortar = (smoothstep(x-mw2srt3-tfuzz, x-mw2srt3, y) *
(1 - smoothstep(x+mw2srt3, x+mw2srt3+tfuzz, y)));
}
tileindex = stile + Seed * ttile;
Ctile = tilecolor * (1 + tilevary * snoise(tileindex+0.5));
Ct = mix(Ctile, mortarcolor, mortar);
// FINALLY...
Col = Ct * Kd;
}
This Shader Writing business always seems really complicated when the code is revealed like above.
Actually if you take time to write the code line by line and try to see the result, it will be a bit easier to understand. Lots of cryptic Math formula in Shader writing, processing all kind of INPUT values.
- mix()
- max()
- smoothstep()
- abs()
- etc...
For most basic shaders, we usually only use global variable P, which assigned to our own custom variable Pos. Of course there are many other Global Variables and values we can use.
INPUT
P (position of point of surface)
The output, we usually only care how it looks like.
OUTPUT
Col (our own custom variable)
What happened in between the INPUT P and OUTPUT Col is a lot of Math and computer graphics magics. Would be wise is to be able to observe step by step and see the resulting "color/image" texture line by line, simply by assigning it to the Col (our output).
The Math part is "hard", especially for non-Math person. Hard because of multifolds of problems.
A really good Math teacher can explain it well, but not always visually well.
TRY:
Go and YouTube search "Shader LIVE Coding" and see how the brain of good shader writers is working. I think they are not normal, they are amazing.
It is a rare to find someone with both VISUAL and MATH minded. Anyway, visualizing each step is a good start.
A really good Math teacher can explain it well, but not always visually well.
TRY:
Go and YouTube search "Shader LIVE Coding" and see how the brain of good shader writers is working. I think they are not normal, they are amazing.
It is a rare to find someone with both VISUAL and MATH minded. Anyway, visualizing each step is a good start.
Not all values can be visualized as texture, some of them is just values, you can actually printing out the values. Read this:
SEEING CODE EVOLVES
CODE: (if we want to see how the texture evolving.... do not copy paste the code below)
shader
LGHexTile (
point Pos = P,
float Kd = .5,
color tilecolor = color(.55,0,0),
color mortarcolor = color(.5,.5,.5),
float tileradius = 0.2,
float mortarwidth = 0.02,
float tilevary = 0.15,
float stretchH = 1.0,
float stretchV = 1.0,
int Seed = 41,
output color Col = color(1,0,0)
)
{
#define snoise(x) (2*noise(x)-1)
#define snoise2(x,y) (2*noise((x),(y))-1)
#define MINFILTERWIDTH 1.0e-7
#define M_SQRT3 1.7320508 /* sqrt(3) */
point Nf;
color Ct, Ctile;
float tilewidth;
float ss, tt;
float ttile, stile;
float x, y;
float mortar;
float swidth, twidth, sfuzz, tfuzz, fuzzmax;
float mw2, mw2srt3;
float tileindex;
float stain, scuff;
float ks;
float s = Pos[0] * stretchH;
float t = Pos[1] * stretchV;
swidth = abs(Dx(s)) + abs(Dy(s));
twidth = abs(Dx(t)) + abs(Dy(t));
sfuzz = .5 * swidth; // blurred lines
tfuzz = .5 * twidth; // blurred lines
fuzzmax = max(sfuzz, tfuzz);
tilewidth = tileradius * M_SQRT3;
tt = mod (t, 1.5*tileradius);
ttile = floor(t/(1.5*tileradius));
if (mod(ttile/2, 1) == 0.5)
ss = s + tilewidth/2;
else ss = s;
stile = floor(ss / tilewidth);
ss = mod(ss, tilewidth);
mortar = 0;
mw2 = mortarwidth/2;
if (tt < tileradius)
mortar = 1 - (smoothstep(mw2,mw2+sfuzz,ss) *
}
else
{
x = tilewidth/2 - abs(ss - tilewidth/2);
y = M_SQRT3 * (tt - tileradius);
if (y > x)
{
if (mod (ttile/2, 1) == 0.5)
stile -= 1;
ttile += 1;
if (ss > tilewidth/2)
stile += 1;
}
mortar = (smoothstep(x-mw2srt3-tfuzz, x-mw2srt3, y) *
(1 - smoothstep(x+mw2srt3, x+mw2srt3+tfuzz, y)));
}
tileindex = stile + Seed * ttile;
Ctile = tilecolor * (1 + tilevary * snoise(tileindex+0.5));
Ct = mix(Ctile, mortarcolor, mortar);
}
MEANWHILE IN HOUDINI ...
In Houdini, there is a node called HEXTILE to generate hexagonal tile.Blender can easily have this hexagonal tile texture as a built-in node as well like the nice Brick Texture node, but what would be nice for us is to understand how this texture tiling was created in the first place.
I tried digging down into the code in Houdini, but the code is hidden inside the #INCLUDE. I have to investigate this further... I am using Mac here and lots of files is inside package, I must check again on the Windows version.
Ok, basically Houdini's VEX Shader Programming Language is more similar to Renderman RSL. OSL is probably "simpler" and I think the nicest part of OSL is being easy to compile in Blender Cycles.
Anyway, if you are like me, always challenged to understand "complexity" and love "procedurality", use all the available tools. Houdini can be your best tool beside Blender.
You see below the difference between Shader Writing VS Node.
OpenGL Programming and such and such...
I am also looking into Shader Writing in Unity, which uses CG language where we need to think about Vertex Shader and Fragment (Pixel) Shader, which of course relates to OpenGL programming.There is this nice intro video talking about OpenGL Shader Programming from SIGGRAPH 2013:
http://www.youtube.com/watch?v=T8gjVbn8VBk
Shader Writing is certainly something that one needs to study over a very long period of time. It is very abstract like Fractal.
It is unlike Game Programming or other kind of programming, it is simply bizarre. Looking at what people creates using codes is just mind-boggling:
https://www.shadertoy.com
I am still reading this invaluable book by Michel Anders, there is a really well written foundation on shader writing there.
REFERENCES AND INSPIRATIONS
I took a little walk around city of Bandung (West Java, Indonesia) and took some photos. This city that is an ex-Dutch colonization still shows the architecture from the past.
Anyway, writing shader is always a nice brain exercise, now back to Sverchok stuff :)
Post a Comment