A Hexagon OSL shader

Now that the Blender Cycles render engine can work with Open Shading Language (OSL) shaders the first task I've set out for myself is to recreate some of the textures I implemented before and the first one we tackle is the hexagon shader.


using an OSL shader in Blender

The hexagon shader in the code below was used to create both the colorfull cube and the chickenwire-like plane in the picture. Provided that you have a Blender build that supports OSL, using the code below requires just two simple steps:
  1. Enable the OSL features in the Cycles render settings (the 'Shading syst')
  2. Load to code below in the text editor
Now you can insert an OSL node anywhere in your node setup by clicking Add -> Script and selecting the name of your text editor buffer in the drop down.

#define A 0.86602540378443864676372317075294 // sqrt(3)/2
#define A2 (2*A)
#define A4 (4*A)
#define SY (1/A)

shader hexagons(
    color Diffuse_Color1 = color(0.2, 0.8, 0.2),
    color Diffuse_Color2 = color(0.8, 0.2, 0.2),
    color Diffuse_Color3 = color(0.2, 0.2, 0.8),
    vector Coordinates = 0,
    output color Color = 0,
    output int Index = 1,
    output float Distance = 0)
{
    // calculate the color
    
    color colors[3] = {Diffuse_Color1,
                       Diffuse_Color2,
                       Diffuse_Color3};   
 
    // we warp the grid so that two adjacent equilateral triangles
    // are mapped to two triangles that fit in a square
    float syc = Coordinates[1] * SY;
    float sxc = Coordinates[0] + 0.5 * syc;
 
    int ind[18] = {1,1,3,3,3,1, 2,2,2,3,3,3, 1,2,2,2,1,1};
 
    int iy = int(mod(syc,3.0));
    int ix = int(mod(sxc,3.0));
    ix = iy * 6 + ix * 2 + ( mod(sxc,1.0) > mod(syc,1.0) );    
 Index = ind[ix];
    Color = colors[Index-1];    
 
    // calculate the distance to the center of the hexagon
       
    float sx = mod(Coordinates[0],3);
    float sy = mod(Coordinates[1]+0.75,A4); 

    // map everthing to a single quadrant
    if ( sx > 1.5 ) sx = 3 - sx;
    if ( sy > A2 ) sy = A4 - sy;
    
    // the distance were interested in is the distance to 
    // the *closest* center point 
    float d1 = distance(vector(sx,sy,0),vector(1.5,A2,0));
    float d2 = distance(vector(sx,sy,0),vector(0,A,0));
    float d6 = distance(vector(sx,sy,0),vector(1.5,0,0));
        
    Distance = min(min(d1,d2), d6);
 
}
The code is a generic shader, i.e. its output color does not take any lighting calculations into account and a more familiar way to refer to such a shader would be a custom texture or pattern. Obviously you can plug its calculated color into a diffuse shader for example but you could also combine it with other textures.
The shader has 3 different colors as input parameters and a coordinate. Its outputs are not only a color, but also an integer color index and the distance to the center of the hexagonal cell. The latter can be used for all sorts of displacement tricks while an index is usefull if you want to change not just the color of a cell but use a completely different texture or shader for each cell.
The noodle for the colorful cube looks like this (click to get a better view):
The noodle for the chickenwire like material looks like this:

Future steps

In the next article I will probably focus on implementing a scales pattern that can either be used for fish scales or roof tiles (shingles).

No comments:

Post a Comment