Thin film OSL shader

Don’t know if this is relevant in Max, but in Maya the outputs and results need to be called “color”. Try this:


/* Amplitude reflection coefficient (s-polarized) */
float rs(float n1, float n2, float cosI, float cosT) {
    return (n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT);
}

/* Amplitude reflection coefficient (p-polarized) */
float rp(float n1, float n2, float cosI, float cosT) {
    return (n2 * cosI - n1 * cosT) / (n1 * cosT + n2 * cosI);
}

/* Amplitude transmission coefficient (s-polarized) */
float ts(float n1, float n2, float cosI, float cosT) {
    return 2 * n1 * cosI / (n1 * cosI + n2 * cosT);
}

/* Amplitude transmission coefficient (p-polarized) */
float tp(float n1, float n2, float cosI, float cosT) {
    return 2 * n1 * cosI / (n1 * cosT + n2 * cosI);
}

// cosI is the cosine of the incident angle, that is, cos0 = dot(view angle, normal)
// lambda is the wavelength of the incident light (e.g. lambda = 510 for green)
// From http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/thin-film-interference-for-computer-graphics-r2962
float thinFilmReflectance(float cos0, float lambda, float thickness, float n0, float n1, float n2) {
    //float PI=3.1415926535897932384626433832795;
    float PI=M_PI;

    // compute the phase change term (constant)
    float d10 = (n1 > n0) ? 0 : PI;
    float d12 = (n1 > n2) ? 0 : PI;
    float delta = d10 + d12;

    // now, compute cos1, the cosine of the reflected angle
    float sin1 = pow(n0 / n1, 2) * (1 - pow(cos0, 2));
    if (sin1 > 1) return 1.0; // total internal reflection
    float cos1 = sqrt(1 - sin1);

    // compute cos2, the cosine of the final transmitted angle, i.e. cos(theta_2)
    // we need this angle for the Fresnel terms at the bottom interface
    float sin2 = pow(n0 / n2, 2) * (1 - pow(cos0, 2));
    if (sin2 > 1) return 1.0; // total internal reflection
    float cos2 = sqrt(1 - sin2);

    // get the reflection transmission amplitude Fresnel coefficients
    float alpha_s = rs(n1, n0, cos1, cos0) * rs(n1, n2, cos1, cos2); // rho_10 * rho_12 (s-polarized)
    float alpha_p = rp(n1, n0, cos1, cos0) * rp(n1, n2, cos1, cos2); // rho_10 * rho_12 (p-polarized)

    float beta_s = ts(n0, n1, cos0, cos1) * ts(n1, n2, cos1, cos2); // tau_01 * tau_12 (s-polarized)
    float beta_p = tp(n0, n1, cos0, cos1) * tp(n1, n2, cos1, cos2); // tau_01 * tau_12 (p-polarized)

    // compute the phase term (phi)
    float phi = (2 * PI / lambda) * (2 * n1 * thickness * cos1) + delta;

    // finally, evaluate the transmitted intensity for the two possible polarizations
    float ts = pow(beta_s, 2) / (pow(alpha_s, 2) - 2 * alpha_s * cos(phi) + 1);
    float tp = pow(beta_p, 2) / (pow(alpha_p, 2) - 2 * alpha_p * cos(phi) + 1);

    // we need to take into account conservation of energy for transmission
    float beamRatio = (n2 * cos2) / (n0 * cos0);

    // calculate the average transmitted intensity (if you know the polarization distribution of your
    // light source, you should specify it here. if you don't, a 50%/50% average is generally used)
    float t = beamRatio * (ts + tp) / 2;

    // and finally, derive the reflected intensity
    return 1 - t;
}

shader irridescence
[[ string description = "Thin film coating shader. Use as reflection color for the material, with Fresnel for the material OFF (this texture computes its own Fresnel)" ]]
(   
 float thicknessMin = 250 [[ string description = "Minimum thickness of the film, in nm" ]],
 float thicknessMax = 400 [[ string description = "Maximum thickness of the film, in nm" ]],
 string thickness = "test.png" [[ string description = "Texture map (usually noise) that determines the thickness of the film as fraction between the min and max" ]],
 float nmedium = 1 [[ string description = "Refractive index of the outer medium (typically air)" ]], // approximate refractive index of air   
 float nfilm = 1.5 [[ string description = "Refractive index of the thin film itself" ]] , // approximate refractive index of water   
 float ninternal = 1 [[ string description = "Refractive index of the material below the film" ]], // approximate refractive index of the lower material
 output color result = 0   
)   
{   
 float cos0 = abs(dot(I , N));

 color thickTex=texture(thickness, u, v);
 float t=(thickTex[0]+thickTex[1]+thickTex[2])/3.0;
 float thick=thicknessMin*(1.0-t)+thicknessMax*t;

 float red=thinFilmReflectance(cos0, 650, thick, nmedium, nfilm, ninternal);
 float green=thinFilmReflectance(cos0, 510, thick, nmedium, nfilm, ninternal);
 float blue=thinFilmReflectance(cos0, 475, thick, nmedium, nfilm, ninternal);

 result=color(red, green, blue);
}

Any news on building this into the Vray Shader? (perhaps under its own tab?)

I’m sure this could be used to create dichroic glass, could it not?

Hi everyone.

I looking for some iridescent reflection…I tried OSL thin film,
but not working in Maya 2016-sp6.same osl working very well in max.

Thank you!
Djordje

Which V-Ray version and which OS?

Best regards,
Vlado

Instead of adding this to the VrayMtl (if folks are worried about clutter), how about having this as a new VrayTexture that ships with Vray?

I second that!

I third it. Although I’d rather see it inside the VRayMtl itself. F*** clutter. This is professional software where you just have to know what buttons to push and what checkboxes to set to achieve your goal. If you want a very beginner-friendly version just make a VRay-Lite or something similar.

Art48,
What would be the advantage of having it in the VrayMtl? Personally I would rather see a clearcoat / secondary reflection section added to the VrayMtl, but that’s just me.

Vlado et al.,

As you consider adding clearcoat to the VrayMtl, it would be worth taking a look at the PxrSurface shader. It has a lot of physically based parameters included for this, including Energy Compensation, Iridescence, Thin Film Thickness, Layer thickness, and Absorption Tint.
https://rmanwiki.pixar.com/display/REN/PxrSurface#PxrSurface-Iridescence

I would add this to th VrayMtl for purposes of physically correct energy conservation. As Art48 says, awesome > clutter.

I just tried this and it is awesome! Thanks Vlado!!!

My two cents, I’d definitely add it to the VRayMTL. However, if you are going to start doing a more complex material for VRay 4.0 or something, something that is more “Advanced user” sort of speak, then maybe you can create a second type of VRay Material and eventually I’ll guess the one will fade away and the most used will win and stay.

Testing this out with the scene Vlado posted (Vray Next in Max 2020) I am wondering if I’m missing something: I do not see any parameters for the OSL texture. There is no shader parameter rollout and no apparent way to edit the thickness etc. Is there something I need to do to expose those controls in Max?

This works fine for me actually. Can you show me a screengrab of the material editor?

Best regards,
Vlado

Thanks for the reply Vlado. I went back to the file to grab a screen shot and now I can see it. There is also a rollout for OSL include Paths that wasn’t showing up before too. I am *reasonably* certain that it was not just me failing to scroll down far enough - that was the first thing I checked. Anyway, only thing that changed is a reboot of the computer in between. Seems solved for now anyway.

loving this shader but i’m having a few crashes using it (similarly with the osl glass shader - OSL – ArchGlass – Rens Heeren but only now we’ve updated from 3ds max 2016 to 2019 - it didn’t crash at all in 2016). any pointers or ideas i can look at to help? at the moment either in new scenes or adding this osl shader to current proects i get random crashes at the point i hit render.