OSL
Helix


return to main index



Introduction

This page presents a shader that can be used to "cut" a helix with a central axis aligned to the Y axis.



Figure 1


Listing 1 - helix.osl


// Author: Malcolm Kesson
// May 2019
shader
helix
(    float    pitch = 1
        [[
        string label = "Pitch",
        ]],
    float    width = 0.5 
        [[
        string label = "Width",
        ]],
    int        coordspace = 0 
        [[
        string label = "Coordinate Space",
        string widget = "mapper",
        string options = "object:0|world:1|camera:2|user defined:3",
        ]],
    string  userspace = "place3dTexture1"
        [[
        string label = "User Defined",
        ]],
    output float resultMask = 0)
{
float half_width = width/2;
  
// Convert the shading point to a specific coordinate system.
point p;
if(coordspace == 0)
    p = transform("object", P);
else if(coordspace == 1)
    p = transform("world", P);
else if(coordspace == 2)
    p = transform("camera", P);
else
    p = transform(userspace, P);
    
// Get the coordinates of the transformed shading point.
float x = p[0];
float y = p[1];
float z = p[2];
  
// Count the number of times the helix has looped around.
float loops = floor( fabs(y) / pitch);
  
// Calculate for the current loop the percentage rotation (theta)
// the shading point.
float theta = (atan2(x, z));
  
// To prevent a counter-rotation of the helix when the shading 
// point is below the origin of the coordinate system...
if(y < 0)
    theta = theta * -1.0;
theta = (theta + M_PI) / M_2PI;    
  
// When the shading point is near to the bottom or the top of the
// current loop we ensure the final test takes lower and top
// loops into consideration. 
float y_prev_loop = theta * pitch + (loops - 1) * pitch;
float y_this_loop = theta * pitch + loops * pitch;
float y_next_loop = theta * pitch + (loops + 1) * pitch;
  
y = fabs(y);
if( fabs(y - y_prev_loop) <= half_width ||
    fabs(y - y_this_loop) <= half_width ||
    fabs(y - y_next_loop) <= half_width) {
    resultMask = 1;
    }
else
    {
    resultMask = 0;
    }
}