Showing posts with label lace. Show all posts
Showing posts with label lace. Show all posts

OSL Lace curtain shader for Blender Cycles, part II

In our first attempt to craft a shader that can mimic sheer fabric like lace curtains we approximated the fibers by filaments with a square cross section. In this version we see if we can work with a slightly more realistic model.
Fibers are generally not square. Their cross section more often approximates a circle. This does affect the occlusion a little bit because unlike a square the apparent cross section does not change with the angle of incidence. This means that we can approximate the transmission factor the apparent surface minus the diameter of the fiber as shown in the diagram below:

If the angle of incidence α is so large that cos(α) < 2r there will be no transmission at all.
So far this doesn't differ that much from a square cross section, however there is another phenomenon that we want to model: the sharpness of the specular reflection changes with the angle of incidence.
This happens once the angle of incidence is so large that the fiber start to occlude each other. As the occlusion increases, we see effectively a smaller segment of a circle (orange arc in left circlebin lower part of the diagram) and therefore we see less different normals. As we approach a grazing angle we effectively see just the top of the circle with normals nearly identical to the surface normal. It can be shown that the size of the circle segment we see is proportional to the angle of incidence as well.
If we compare the old and the new shader the result looks quite different:

The old equation

With new equation

Code and example node setup

The code is rather self explanatory:
shader sheet_occlusion2 (
  normal Normal=N,
  float Radius=0.05,

  output float Fac=1,
  output float Var=1
){
  // calculate angle of incidence
  float alpha = acos(dot(I,Normal));
  // treat front and back the same
  alpha = alpha > M_PI_2 ? M_PI - alpha : alpha;
  // calculate the non occluded fraction 
  Fac = cos(alpha) - 2 * Radius;
  // calculate the range of the visible normals
  if( Fac < 0 ){
    Fac = 0;
    Var = cos(alpha) / (2 * Radius);
  }
}
And the sample node setup mixes transparent shader with a non transparent shader just like before but uses the Var output to modify the shininess of the non transparent shader:

Code availability

The shader is available on GitHub. If you would like to know more about programming OSL you might be interested in my book "Open Shading Language for Blender". More on the availability of this book and a sample can be found on this page.

OSL Lace curtain shader for Blender Cycles

Lace curtains and sheer nylon stockings are partially transparent but not the way frosted glass is. Frosted glass transmits light but also diffuses it, making it almost impossible to see anything through it. Lace curtains on the other hand only obscure what's behind them if the threads of the fabric block the line of sight.

This results in the effect that you can see through lace curtains quite well if they are more or less straight and you are viewing them head on but that it is impossible to see anything behind them if seen from a glancing angle. The effect is visible quite well on the part of the curtain in front of the blue cube. Even though there isn't much specular light on the rightmost fold in front of the blue cube, it still looks brighter.

Calculating occlusion

This behavior is reminiscent of fresnel reflection but the formula is a bit different. In the diagram below the threads of the fabric are approximated by black squares. In the gap between these squares a portion is obscured from view depending on the angle α between the surface normal N and the incident ray I. The ratio between the occluded portion (pink) and the side of the square is tan(α). From the diagram it can be seen that at a certain point α is so large that the occluded portion is bigger than the gap is wide, rendering the surface effectively opaque.

Code sample and node setup

The code implementing this setup is very short and straightforward:
shader sheet_occlusion (
  normal Normal=N,
  float Radius=0.05,

  output float Fac=1
){
  // calculate angle of incidence
  float alpha = acos(dot(I,Normal));
  // treat front and back the same
  alpha = alpha > M_PI_2 ? M_PI - alpha : alpha;
  //printf("%.2f %.2f\n",alpha,tan(alpha));
  // calculate the non occluded fraction 
  Fac = 1 - Radius - Radius * tan(alpha);
}
The Fac output can be used to mix a fabric shader and a transparent shader as shown in the node setup below:

To get a pattern you could plug a black and white texture of real lace into the Radius socket.

Code availability

The shader is available on GitHub. If you would like to know more about programming OSL you might be interested in my book "Open Shading Language for Blender". More on the availability of this book and a sample can be found on this page.