![]() |
Maybe this shader can also be called Mummy OSL Shader. |
I know I am still very much a beginner in Shader Writing. There are still plenty of things about OSL that I honestly do not understand. For most of part, I understand it in certain way, but maybe someone in the future will correct me or help me to understand it better.
I am still confused about Closure in OSL, for example. So far, I am only dealing with Procedural Texture creation in OSL.
With better understanding of the code, I think we can create our own Closure. However, we can actually mix and match the pre-built closures like Diffuse, Glass, Glossy, etc. within a single node. Lots of power. But I think before we get there, I like to focus with procedural Texture creation and design.
This post is a little intermezzo to note down what I have learned so far on OSL, how I got this far. Hopefully if you are also starting to write OSL from zero, you can pickup a thing or two.
TEXTURE CREATIONS: NODE OR CODE?
Things are surely a lot easier when we connect nodes to create Shader, right? Cycles Node Network is brilliant as it is, so easy to use to create beautiful render using the built in nodes. It is quite a robust system already.The additional Script Node that allows us to write our own node using OSL is even making Cycles in Blender more amazing. It is not yet GPU accelerated as of today, OSL is still CPU only render, but I still find it pretty fast and great to try ideas.
Interestingly enough, I found that whenever I rewrite a snippet of code that actually recreates the same thing of what the built-in node can already do (Noise, Voronoi, Cellnoise, etc), I gain a little more layers of knowledge.
I figure that a lot of interesting procedural textures are all based on Noise function. By layering Noise function, we create turbulance. And turbulance texture itself is really good powerful for adding details.
With a bit of knowledge of shader writing, it is as if now I am starting to be able to see better, to break down and to think about Texture (procedurally or non procedurally) in more details and also simplified at the same time.
Shader writing (RSL, OSL, GLSL, etc) is really quite challenging area but also rewarding experience. Perhaps shader writing is not for everyone, but you should try first.
As a prequisite, it helps to know a little bit about programming (Python is my basis, but I knew a bit of MEL scripting which is a little bit like C) in order to learn to write and code shader. Good grasp of programming concept should be ok to get you started in shader writing.
I remember the first time writing OSL, by following and rewriting code that is shown by other great Blender Artists and Developers out there.
- Thomas Dingto
- Geofrey..
RSL to OSL
"I have to learn and understand RSL (RenderMan Shading Language) in order to understand OSL!". That is the sentence that kept telling myself whenever I am stuck.There are materials out there that talk about Shader Writing. I tried to read and digest all the available RenderMan books at the library that I (am lucky enough) to have access to. Some of the RenderMan books are already pretty dusty and many years old.
Here are list of the books I could find at the UTS (University of Technology of Sydney) Library:
- The RenderMan Shading Language Guide
- Advanced RenderMan: Creating CGI for Motion Pictures
http://www.larrygritz.com/arman/materials.html - Essential RenderMan
- Rendering for beginners : image synthesis using RenderMan
- The RenderMan companion : a programmer's guide to realistic computer graphics
I probably can grasp about 25-30% of those materials, I have to re-read them again in the near future if I need to get deeper.
There are so many amazing RSL Shaders I discover along the way.
Some shaders are SIMPLE but very CLEVER and actually a good exercise for beginner:
- Bowling Pin
- Pencil
- Ruled Paper
- Watermelon
- Banana
- Woods
The issue with learning RenderMan is ACCESS to it. Like everything in life, often it is all about ACCESS to the tool and the materials.
I am currently using Pixar Photorealistic RenderMan (PRMan) to dig RenderMan. I happened to have access to it, thanks to one nice guy from Pixar. Since I have this privilege, I definitely MUST take this opportunity to study and use the tool while I can.
However, if one does not have access to PRMan, 3Delight is a good alternative.
It is only recently that I look into RenderMan properly and its latest development with their Physically Plausible GPShaders (General Purpose Shaders), I can see how things have changed over the years. PRMan implementation inside Maya is fantastic. It is really a lot easier to get a highly realistic render.
ONLINE SOURCES FOR RSL AND OSL
Ok, so apart from those great legacy books on RenderMan to read, there are plenty of online materials that are really helpful.Pixar's documentation of RenderMan:
http://renderman.pixar.com/resources/current/rps/rslFunctions.html
Although RSL is not OSL, they have similarities.
This online note by Steve May (Pixar) actually the one that finally clicks with my brain.
http://accad.osu.edu/~smay/RManNotes/index.html
Malcolm Kesson's priceless RSL materials at FUNDZA
http://www.fundza.com/
Inigo Quilez notes and YouTube
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
http://www.iquilezles.org/www/articles/functions/functions.htm
Check ShaderToy:
https://www.shadertoy.com/
MY FIRST SHADER: OSL Wooly
I hope that this shader is pretty original.![]() |
This took nearly 3 hours to render... but looks quite nice. |
It is very simple actually, started with just 2 stripes, originated from this RLS shader:
http://accad.osu.edu/~smay/RManNotes/RegularPatterns/transitions.html#cross_tile
I also found some hints from:
http://www.fundza.com/rman_shaders/surface/index.html
http://www.fundza.com/rman_shaders/displacement/index.html
I figure that I could introduce 2 kind of "randomization". We don't really use random function in shader writing I think.
Let me quote Larry Gritz from OSL Developer Thread:
"I can't really think of a good use for random(), since you can't guarantee the order of shading, it wouldn't be stable from run to run. The only thing I can think of is for use in sampling, but (a) the whole point of OSL is that you don't need to be doing sampling in the shader anymore, and (b) even if you did, it would be better for us to think of a way to provide specialized functions that were reproducible and better-stratified than just having a uniform RNG.
As for hash(), the idea there was something like the cellnoise trick. What I had in mind was just using a strong has on the floating point bits of whatever you passed in (like the hash we use on the integer lattice values to generate infinite, non-repeating cellnoise values).
Since nobody seems to care enough to notice that these are unimplemented, I'm fine with removing them from the spec. We can always add them back if we decide that there is a legit use case. "
The "random" and "details" can apparently come from:
1. Random color per object.
http://blenderartists.org/forum/archive/index.php/t-277986.html
2. Random by multi-layering the same texture using simple loops.
This one post from BlendBits actually has snippet of "random function" using Cellnoise function.
http://blendbits.blogspot.com.au/2013/05/lens-flare-shader-for-blender-cycles.html
![]() |
Champagne Gold with lots of Colors stripes. Sounds familiar? |
Wooly OSL Shader is very simple. Just repetition of lines that is rotated slightly. It is a 2D texture.
Maybe with the same idea, we can create Pokemon Ball OSL Shader.
Here, at BlenderThings blog, again it introduces one shader that uses "randomization".
http://blenderthings.blogspot.com.au/2012/12/a-hagelslag-sprinkles-osl-shader-for.html
Out of curiosity, I often plug one OSL Shader into another Shader. In this case below I plug the Sprinkles OSL into my Wooly OSL Shader:
![]() |
Interesting cartoony style NPR shader, not perfect, but has potential. |
Shaders that are using multi-layers randomization is indeed slow to render, but looks nice and detailed. With Blender, "slow render" is not an easy, we can always have unlimited render farm.
![]() |
Over one hour and still rendering a single frame... |
TAKING WOOLY OSL SHADER TO THE NEXT STAGE
At current stage, I think Wooly OSL Shader is still a work in progress. I would like so that each line is more 3D like thread, with a bit of shadowing whenever it overlaps layer below it.I think some OSL experts out there can probably take it to high level production ready shader.
These concepts below are crucial to understand and able to write OSL:
- PROGRAMMING CONCEPT >> Variable declaration, Loop, ....
- STRUCTURE & CONSTRUCT >> we can write OSL in whatever way we like, however without proper planning, we could easily get lost with the code. following a good construct and having a plan will help us to have manageable and flexible reusable code.
- MATH & BASIC FUNCTIONS: sin(), cos(), atan2(), smoothstep(),
- INCLUDE >> When you see word INCLUDE, usually that is when we source some snippet or macro or helper functions that is bundled as external file.
- LAYERS & BLENDING >> I only found this concept quite recently and I would like to implement my previous OSL writing so that every "shape" or "texture" created procedurally can be easily layered on top of one another.
REWRITING THE WOOLY SHADER FROM SCRATCH...
The whole code is like this:THE CODE: WOOLY OSL SHADER
(TO BE CLEANED UP)
/* ALL HELPER FUNCTIONS COME BEFORE THE ACTUAL SHADER */
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)));
}
/* THE ACTUAL SHADER CODE BELOW */
shader crosstile(
float rot = 45,
color Cs = color(1.0),
color Os = color(1.0),
float fuzz = 0.05,
int seed = 231,
int iteration = 10,
vector Pos = P,
output color Oi = color(0.2),
// output color Ci = color(0.2),
output color Col_Out = color(0.5)
)
{
// we have to do this in OSL
// becayse we do not have Global Variable s and t
float s = Pos[0];
float t = Pos[1];
// background layer
color surface_color = Cs;
color surface_opac = Os;
// initialize layer
color layer_color = color(0.1);
color layer_opac = color(0.2);
/*
// vertical bar layer
layer_color = color(0.1,0.5,0.22);
layer_opac = pulse(0.35, 0.65, fuzz, s);
surface_color = blend(surface_color, layer_color, layer_opac);
*/
// THANKS FOR CODE SNIPPET
// http://blendbits.blogspot.com.au/2013/05/lens-flare-shader-for-blender-cycles.html
// Generate repeatable sequences of 'random' numbers - based on nrand and seed settings.
float nrand = 0;
// Random helper function
float urand () {
nrand += 1;
return cellnoise(nrand, seed);
}
// multiple rotating bars with random values
float ss;
float tt;
float power;
for (float i=0.0; i<iteration; i++){
// want random
float Random=0;
float R=0;
float G=0;
float B=0;
getattribute("object:random", Random);
R=trunc(Random*100.0)/100.0;
G=trunc((Random*100.0-trunc(Random*100.0))*100.0)/100.0;
B=trunc((Random*10000.0-trunc(Random*10000.0))*100.0)/100.0;
rotate2d(s,t,radians(rot * i * urand()), 0.5*urand(), 0.5*urand(), ss, tt);
//layer_color = color(0,(i+1)/iteration,0);
layer_color = color((i+1)/iteration * urand(), G*0.5 , B*0.4);
layer_opac = pulse(0.50, 0.55, fuzz, tt);
surface_color = blend(surface_color, layer_color, layer_opac);
}
for (float i=0.0; i<iteration; i++){
// want random
float Random=0;
float R=0;
float G=0;
float B=0;
getattribute("object:random", Random);
R=trunc(Random*100.0)/100.0;
G=trunc((Random*100.0-trunc(Random*100.0))*100.0)/100.0;
B=trunc((Random*10000.0-trunc(Random*10000.0))*100.0)/100.0;
rotate2d(s,t,radians(rot * i * urand()), 0.5*urand(), 0.5*urand(), ss, tt);
//layer_color = color(0,(i+1)/iteration,0);
layer_color = color((i+1)/iteration * urand(), G*0.5 , B*0.4);
layer_opac = pulse(0.50, 0.55, fuzz, ss);
surface_color = blend(surface_color, layer_color, layer_opac);
}
/*
// horizontal bar layer
layer_color = color(0.1,0.1,0.3);
layer_opac = pulse(0.35, 0.65, fuzz, t);
surface_color = blend(surface_color, layer_color, layer_opac);
*/
// output if we need to specify CLOSURE
Oi = surface_opac;
// Ci = surface_opac * surface_color;
Col_Out = surface_opac * surface_color;
}
I want to show step by step process how I get to the current look of Wooly OSL Shader.
(TO BE ADDED)
BONUS: SPLINE FUNCTION
Spline function is like Color Ramp node in Cycles. Allowing us to have multiple color array to blend. Useful for things like FIRE.
color colorarray[X] = { .... }
spline("linear", colorarray ....
BONUS: PULSE FUNCTION
Pulse is like the combination of smoothstep...
Post a Comment
Click to see the code!
To insert emoticon you must added at least one space before the code.