OSL goodness in Vray

I thought it would be cool to share OSL shaders that folks have been writing for Vray. So in the spirit of the thread of the same name for a certain other software that uses OSL, I thought I’d start one here for Vray. I’ll kick it off by sharing an OSL fabric shader I wrote:

fabric.osl

This is an artist friendly fabric shader. It’s basically an anisotropic Blinn with added sheen and tint terms to capture how the tiny fibers of fabric pick up light at incident angles, and how the specular color of fabrics are often tinted by the diffuse color. The sheen color can also be used to darken the sheen as some fabrics (for example black nylon) are darker at the edges, rather than brighter.

I’d love to hear feedback on the shader, and things that could be done to make it better.

Note that with the current implementation of OSL in Vray the diffuse color slider defaults to black. So you need to change it to be able to see the diffuse contribution. Also since OSL widgets are not implemented yet, the dropdown menu for ramp_type does not work and you need to manually choose one of the 6 options. These options are explained in the comments within the shader code below.


/*
 *
 * fabric.osl shader by Derek Flood (c)2015
 * from http://sharktacos.com/Forums/misc.php?action=help&hid=66
 *
 */

float fresnelReflectionFactor(normal bumped_normal, float ior)
{
    float c = abs(dot(I, bumped_normal));
    float g = ior * ior - 1.0 + c * c;

    if (g > 0.0) {
        g = sqrt (g);
        float A = (g - c) / (g + c);
        float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
        return 0.5 * A * A * (1.0 + B * B);
    }

    return 1.0;
}

normal getBumpedNormal(color centerColor, color uColor, color vColor, float inverseBumpAmount)
{
    vector worldTangent = normalize(dPdu);
    vector worldBitangent = normalize(dPdv);
    vector worldNormal = normalize(N);

    vector average = vector(0.3333333);
    float center = dot (average, vector(centerColor));
    float ddu = center - dot(average, vector(uColor));
    float ddv = center - dot(average, vector(vColor));

    return normalize(ddu * worldTangent + ddv * worldBitangent + inverseBumpAmount * worldNormal);
}

surface fabric
    [[ string description = "artist based fabric material" ]]
(
    /* Diffuse section */   
    color Sheen_color = color(1.0, 1.0, 1.0),     //This color can be black for nylon sheen.
    float Sheen_opacity = 1.0,           // Determines amount of sheen effect as fibres pick up light at incident angle.
    float Sheen_tint = 0.5,             // Tints both the sheen and specular.
    string Diffuse_color = "",
    float Diffuse_weight = 0.8,
    float Roughness = 0.4,
    int ramp_type = 3              // Six types of interpolation for sheen. 1-3 are sharper, 4-6 are softer.
        [[ string widget = "mapper",
        string options = "linear:1|exponential:2|Smooth:3|Sigmoid:4|Square_root:5|Fresnel:6" ]],

    /* Spec section */
    color Spec_color = 1.0,
    float Spec_amount = 0.5,
    float Glossiness = 0.6,
    float IOR = 1.33,              // Fabric generally has low frontal reflections.
    int Subdivs = 8,
    int Trace_reflections = 1
        [[ string widget = "checkBox" ]],
    int Fresnel = 1
        [[ string widget = "checkBox" ]],

    /* Anisotropy section */
    float Anisotropy = 0.25,         // Fabric is anisotropic due to weave.
    float Aniso_rotation = 0,

    /* Bump section */
    string Bump_texture = "bump.png",
    float Bump_amount = 1.0,

    output color result = 1 )

{
    /* Define Bump */
    normal bumped_normal = N;
    if (Bump_amount > 0.0)
    {
        float delta = 0.004;
        color center = texture(Bump_texture, u, v);
        color uColor = texture(Bump_texture, u + delta, v);
        color vColor = texture(Bump_texture, u, v + delta);

        bumped_normal = getBumpedNormal(center, uColor, vColor, 1.0 / Bump_amount);

    }

    /* Define Main color */
        color MainColor = texture (Diffuse_color, u, v, "missingcolor", color(1,0,0));
        MainColor = pow (MainColor, 2.2);

    /* Define Edge color */
        color TintBoost = transformc("hsl", MainColor);
        TintBoost[2] = pow (TintBoost[2], 0.2);
        TintBoost[2] = clamp(TintBoost[2],0,1);
        TintBoost = transformc("hsl","rgb", TintBoost);

        color EdgeColor =  Sheen_color / 10;
        color TintEdge = EdgeColor * TintBoost;
        EdgeColor = mix (EdgeColor, TintEdge, Sheen_tint);
        EdgeColor = clamp (EdgeColor, 0, 1);

    /* Define Spec color */
        color SpecColor = Spec_color;
        color TintedSpec = SpecColor * TintBoost;
        SpecColor = mix (SpecColor, TintedSpec, Sheen_tint);

    /* Define Ramp */

        float facingRatio = 1 - abs(dot(I, bumped_normal));

        if( ramp_type == 1) // linear             
            {facingRatio = facingRatio; }

        if( ramp_type == 2) // exponential (Down) 
            { facingRatio *= facingRatio;  }  

        if( ramp_type == 3) // smooth      
            { facingRatio = smoothstep (0,1, facingRatio ); }

        if( ramp_type == 4) // sigmoid S-curve
            {
            float Sigmoid = facingRatio / (1 + abs(facingRatio));
            facingRatio = clamp( 2 * Sigmoid, 0, 1);
            }
        if( ramp_type == 5) //  square root   
            { facingRatio = sqrt (facingRatio); }

        if( ramp_type == 6) // fresnel          
            { facingRatio = 2 * fresnelReflectionFactor(bumped_normal, IOR);  }

    /* Fresnel */
        if (Fresnel)
        { SpecColor *= fresnelReflectionFactor(bumped_normal, IOR); }
        if (Trace_reflections)
        { MainColor *= (1.0 - SpecColor); }

    /* BRDF Mixes*/
        color SheenMix = EdgeColor * facingRatio * Sheen_opacity;
        color EdgeMask = mix(1, Sheen_color, (facingRatio * Sheen_opacity) );
        MainColor *= EdgeMask;
        MainColor *= (1.0 - SheenMix);       

        closure color sheen_component = SheenMix * diffuse(bumped_normal, "roughness", Roughness);
        closure color diffuse_component =  MainColor * Diffuse_weight * diffuse(bumped_normal, "roughness", Roughness);
        closure color specular_component = Spec_amount * SpecColor *       
            vray_blinn (bumped_normal, Glossiness, Anisotropy, Aniso_rotation,       
            "subdivs", Subdivs, "trace_reflections", Trace_reflections);       

        closure color reflect_component = SpecColor * reflection(bumped_normal, IOR);

        Ci = diffuse_component + specular_component + reflect_component + sheen_component;

} 

Nice! Can I add this to the repository of OSL shaders here?

Best regards,
Vlado

Absolutely!

Ok, I will just add some tooltips for the parameters.

Best regards,
Vlado

Thanks for the shader :slight_smile:

Here I’ve added tooltips to some parameters and renamed others to be perhaps a bit clearer:

@Derek: do you want me to add some additional information to the page (like a link to your website)?

Best regards,
Vlado

Hello,

I tried to use the Frabic file from OSLShaders in the V-Ray for Maya 2015 SP6, Win 8.1 (version 3.05.04, revision 25954 from Jun 29 2015) But once I load the file I get fatal error. Is there any other step that I did not understand?

Thanks for OSL and attention!

There is a bug in the OSL library that manifests itself on Windows 8.1; we’ve fixed this and submitted a patch, but for the moment you will need a nightly build to get it working. You can email support@chaosgroup.com to get that.

Best regards,
Vlado

Looks great. It makes sense to rename things more explicitly as you have (Spec_glossiness instead of Glossiness etc). Hopefully once widgets are implemented in OSL one can use the “page” widget to organize the sliders the way a VrayMtl is (diffuse section, spec section, and so on).

The pic would look better if it were lit by a directional light (it looks like it has HDRI lighting on it now), and was on a model of draped cloth like this: http://i.ytimg.com/vi/hmPHq0WTt-k/maxresdefault.jpg

I’ll see if I can render something, and email it to you along with the Maya scene.

Let me also mention that the bump map behavior is not the same as a VrayMtl. It looks to me like it is off by a factor of around 100, so to get the same bump as a vrayMtl with a bump value of 1.0 the OSL needs a bump value of 100. A quick and dirty workaround is just to add a multiplication like this: float Bump_amount = Bump_amount * 100; but I thought I’d mention it as I’m sure there must be a more elegant/accurate way to address it in the code so it matches the behavior of a VrayMtl more precisely.

Here’s another OSL shader I thought was cool. It was originally posted in the Max forums here: - Chaos Forums.

It uses the complex fresnel equation for metals, but to make it more artist friendly it remaps the refractive index (n) and extinction coefficient (k) to the more intuitive reflectivity (r) and edge tint (g) which are input as RGB colors. You use it just like the complex_IOR.osl (i.e. in a VrayOSLTex mapped to the reflection with Fresnel off).

I tweaked it so it would work in Maya, and hard-coded in the gamma correction:


//--Artist Friendly Metallic Fresnel--
    // BY Ole Gulbrandsen - Framestore
    //olegul@hotmail.com
    //http://jcgt.org/published/0003/04/03/
    //OSL version by JayCMiller
    //jcmiller.web@gmail.com

float n_min( float r )
{ return (1-r )/(1+ r ); }

float n_max( float r )
{ return (1+ sqrt ( r ))/(1- sqrt ( r )); }

float get_n ( float r , float g)
{ return n_min( r )*g + (1-g)*n_max( r ); }

float get_k2 ( float r , float n)
{ 
float nr = (n+1)*(n+1)*r-(n-1)*(n-1);
return nr/(1-r );
}

float get_r ( float n, float k)
{ return ((n-1)*(n-1)+k*k )/(( n+1)*(n+1)+k*k);  }

float get_g ( float n, float k)
{
float r = get_r (n,k);
return (n_max( r)-n )/( n_max( r)-n_min( r ));
}

float AFMF ( float r , float g, float theta )
{
//clamp parameters
float _r = clamp(r ,0 ,0.99);

//compute n and k
float n = get_n (_r ,g);
float k2 = get_k2 (_r ,n);
float c = cos ( theta );
float rs_num = n*n + k2 - 2*n*c + c*c;
float rs_den = n*n + k2 + 2*n*c + c*c;
float rs = rs_num/ rs_den ;
float rp_num = (n*n + k2)*c*c - 2*n*c + 1;
float rp_den = (n*n + k2)*c*c + 2*n*c + 1;
float rp = rp_num/ rp_den ;

return 0.5*( rs+rp );
}

shader AFMFresnelTex
(

color Reflectivity = color(0.9451,0.7294,0.3725),
color Edgetint = color(0.9961,0.9725,0.7333),
//float Color_Gamma = 0.4545,

output color result = color(0.5)
)

{
float thetaB = acos(dot(-I,N));
float RCH = AFMF(Reflectivity[0],Edgetint[0],thetaB);
float GCH = AFMF(Reflectivity[1],Edgetint[1],thetaB);
float BCH = AFMF(Reflectivity[2],Edgetint[2],thetaB);

//result = pow(color(RCH,GCH,BCH), 1/Color_Gamma);

result = pow(color(RCH,GCH,BCH), 2.2);

}

Joconnell asked elsewhere > Actually that’s a thing too - your cloth shader looks great, do you have any links for intro to osl stuff or did you just jump in and start messing with other peoples examples?

What I basically did was create shader in Maya by connecting a bunch of stuff in the Hypershade of Maya to mock it up, then I built that in OSL, adding more functionality as I went beyond what I could do with just a node tree.

Here are some links to stuff that helped me get my head around OSL:

Manuals First is the Chaos OSL help.
One thing to note is a lot of the metadata widgets are not yet implemented yet which impact the user interface (sliders, dropdown menus, etc). Also the print functions do not currently work which would help a lot with debugging. Now it either works or doesn’t with no way to know what is broken.

Next is the official manual: SPI OSL manual (pdf)

Examples the next thing, as you said, is to learn from examples of what other folks are doing.
First up, of course, are the examples from Chaos: Chaos OSL respository
Then there are lots of Maya nodes here OpenMaya example OSL (remember that as the Chaos help says “The VRayOSLMtl takes into account only closure color output parameters.” So all of these need to have the output changed to color so they will work)
and some fun textures here Sambler example OSL dfggd
and some examples from Sony too SPI example OSL

Since OSL is C-based, it’s pretty easy to take a shader from a paper that was written in C++ and re-write it in OSL which means all those Siggraph papers with new cool functionality can be used in Vray with OSL.

You’re a superstar - much appreciated for that.

Drop-down menus actually do work in the latest builds - you used that in the fabric shader…

Best regards,
Vlado

LOL, I put the code in, but it was not working in my version. I’m glad it is now.
I looked in the release notes in the nightlies and I do not see this mentioned there. Where could I get a list of the changes to OSL that have been implemented?

It is in the changelog for the 3.20 releases:

(*) VRayOSLMtl/VRayOSLTex: Support for drop-down controls;

The nightly builds release notes are pulled automatically from Mantis, but this is not very reliable.

Best regards,
Vlado

Are you possibly referring to Max? I do see a 3.20 release for Max (which we don’t use), but I only see 3.0 for Maya in the downloads section. Thanks :slight_smile:

sorry for that dumb question, but how to wire up the nodes in order to get the osl shader to work?

Depends on the OSL shader. Which one are you using? Most are meant to go in the reflection with Fresnel off on the material.

I’m trying to get the complex_ior to run …

when i plug the shader nothing changes and i wonder where the interface is?