#include "rhfunctions.h" /* archGlass_mat_v002 By Rens Heeren (mail [at] rensheeren [dot] com) Info Page: http://www.rensheeren.com/blog/osl-archglass/ Use as an OSL material, not as an OSL texture. An OSL shader for creating realistic glass window panes. Window reflections are amazingly complex; you get for one pane of glass reflections from the front, back, and scattering from inbetween, light gets absorbed and passed through to the other side only to be reflected back by the next pane of glass. This shader allows you to simulate full window glass geometry with only one plane. Useful for everything but close-ups. Features: - Specify the amount of window panes (1-3). - Absorbtion/tint colour. - Reflective coating layer, for example a one-way mirror or high reflectance building glass. - Dirt layer, like a layer of dust or sand on the outside. - IOR of glass and surrounding medium (air usually). - Normal map inputs for creating warped reflections for each pane separately. - Supports ray traced refraction, transparency, and black opaque for the refraction/transmission. Usage: - Set how many panes are in your window. Most modern windows in temperate and cooler climates have two panes for insulation. - Optionally set a colour for the reflective coating if your window needs one. - Same for the dirt. The colour is usually fine, you define how much dirt there is on top of the windows with the dirt amount input. - Set the refraction mode, 1 - ray traced refraction, 2 - transparency, 3 - no refraction, just black, for mixing with a self-illuminated interior or to just have only the glass reflection. - Normal map inputs need a normal map with RGB 0.5 0.5 1.0 as the 'base', meaning that there won't be any normal difference with that colour. Use at your own risk. 2016-02-21 - v001 - Created (rh) 2016-06-15 - v002 - UI Tweaks, logic tweaks, added dirt, normal map inputs. (rh) */ ///////////////////////////////////////////////////////// #if defined(OSL_VERSION) && (OSL_VERSION>10300) closure color microfacet_ggx(normal N, float alpha, float eta) { return microfacet("ggx", N, alpha, eta, 0/*reflect*/); } #endif surface archGlass_mat_v002 ( int number_of_glass_panes = 1, color pane_absorbtion_tint = color(0.957, 0.975, 0.965), color front_reflective_coating = color(0), color front_dirt_color = color(0.035, 0.027, 0.024), float dirt_amount = 0.0, float ior_out = 1, float ior_glass = 1.55, int refraction_mode = 2 [[ string widget = "mapper", string description = "1 - Refraction, 2 - Transparency, 3 - Opaque", string options = "Refraction:1|Transparency:2|Opaque:3" ]], string normalmap_pane1 = "", int use_normalmap1 = 0 [[ string widget = "checkBox" ]], string normalmap_pane2 = "", int use_normalmap2 = 0 [[ string widget = "checkBox" ]], string normalmap_pane3 = "", int use_normalmap3 = 0 [[ string widget = "checkBox" ]], int use_first_normalmap_for_all = 1 [[ string widget = "checkBox" ]], string pane_absorbtion_tint_tex = "", int use_absorbtion_tex = 0 [[ string widget = "checkBox" ]], string front_reflective_coating_tex = "", int use_coating_tex = 0 [[ string widget = "checkBox" ]], string front_dirt_color_tex = "", int use_dirt_col_tex = 0 [[ string widget = "checkBox" ]], string dirt_amount_tex = "", int use_dirt_amount_tex = 0 [[ string widget = "checkBox" ]], string info_page = "www.rensheeren.com/blog/osl-archglass/" [[ string widget = "string" ]] ) /////////////////////////////////////////////////// { int i_refrMode = refraction_mode; int i_numPanes = number_of_glass_panes; int i_useN1 = use_normalmap1; int i_useN2 = use_normalmap2; int i_useN3 = use_normalmap3; int i_useN1ForAll = use_first_normalmap_for_all; int i_useAbsTex = use_absorbtion_tex; int i_useCoatTex = use_coating_tex; int i_useDirtTex = use_dirt_col_tex; int i_useDirtAmtTex = use_dirt_amount_tex; color c_absorbtion = color(0); if (i_useAbsTex) { c_absorbtion = texture(pane_absorbtion_tint_tex, u, v); } else { c_absorbtion = pane_absorbtion_tint; } color c_coating = color(0); if (i_useCoatTex) { c_coating = texture(front_reflective_coating_tex, u , v); } else { c_coating = front_reflective_coating; } color c_dirtCol = color(0); if (i_useDirtTex) { c_dirtCol = texture(front_dirt_color_tex, u , v); } else { c_dirtCol = front_dirt_color; } float f_dirtAmt = 0; if (i_useDirtAmtTex) { color c_dirtAmt = texture(dirt_amount_tex, u , v); f_dirtAmt = c_dirtAmt[0]; } else { f_dirtAmt = dirt_amount; } color c_n1 = texture(normalmap_pane1, u, v); color c_n2 = texture(normalmap_pane2, u, v); color c_n3 = texture(normalmap_pane3, u, v); normal n_n1 = N; normal n_n2 = N; normal n_n3 = N; if (i_useN1) { n_n1 = normal(c_n1[0], c_n1[1], c_n1[2]); n_n1 = (n_n1 * 2) - 1; n_n1 = transform ("shader", "world", n_n1); } if (i_useN1ForAll) { n_n2 = n_n1; n_n3 = n_n1; } else { if (i_useN2) { n_n2 = normal(c_n2[0], c_n2[1], c_n2[2]); n_n2 = (n_n2 * 2) - 1; n_n2 = transform ("shader", "world", n_n2); } if (i_useN3) { n_n3 = normal(c_n3[0], c_n3[1], c_n3[2]); n_n3 = (n_n3 * 2) - 1; n_n3 = transform ("shader", "world", n_n3); } } f_dirtAmt = clamp(f_dirtAmt, 0, 1); color c_refl1 = color(0); color c_transmitted1 = color(0); color c_refl2 = color(0); color c_transmitted2 = color(0); color c_refl3 = color(0); color c_transmitted3 = color(0); color c_transmittedOut = color(0); float f_iorOut = ior_out; float f_iorIn = ior_glass; int i_noTransp = 0; if (refraction_mode == 3) { i_noTransp = 1; } //////////////// float f_angle = abs(dot(-I,N)); float f_reflFrontSide = fn_FresnelSchlickDiDi(f_angle, f_iorOut, f_iorIn); color c_reflAllPanes = fn_windowReflectance(f_angle, f_reflFrontSide); // mix curve for coating blend float f_reflZeroAngle = fn_FresnelSchlickDiDi(0.0, f_iorOut, f_iorIn); float f_mixCurve = ((f_reflFrontSide - 1) * (1 + f_reflZeroAngle)) + 1; // half of absorbtion for back face reflection absorbtion color c_absHalf = 1 - ((1 - c_absorbtion) / 2.0); // coating blended down to 0 towards 90 degrees (grazing) to add onto Fresnel curve. color c_coatingFresnel = mix((c_coating / 2.0), 0, f_mixCurve); c_refl1 = clamp((c_reflAllPanes[0] + c_coatingFresnel), 0, 1); c_transmitted1 = (1 - c_refl1) * c_absorbtion; c_refl1 = clamp(((c_reflAllPanes[0] * c_absHalf) + c_coatingFresnel), 0, 1); c_transmittedOut = c_transmitted1; closure color cl_refl = emission(); if (i_numPanes == 1) { //closure color cl_refl = reflection(normal(0,0,0)) * c_refl1; cl_refl = microfacet_ggx(n_n1, 0, 150) * c_refl1; } if (i_numPanes == 2) { if (i_useN1ForAll) { c_refl2 = clamp((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) + c_refl1), 0 ,1); c_transmitted2 = (1 - c_refl2) * c_absorbtion; c_refl2 = clamp(((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) * c_absHalf) + c_refl1), 0 ,1); cl_refl = microfacet_ggx(n_n1, 0, 150) * c_refl2; } else { c_refl2 = clamp((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) + c_refl1), 0 ,1); c_transmitted2 = (1 - c_refl2) * c_absorbtion; c_refl2 = clamp(((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) * c_absHalf)), 0 ,1); cl_refl = microfacet_ggx(n_n2, 0, 150) * c_refl2 + microfacet_ggx(n_n1, 0, 150) * c_refl1; } c_transmittedOut = c_transmitted2; } if (i_numPanes == 3) { if (i_useN1ForAll) { c_refl2 = clamp((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) + c_refl1), 0 ,1); c_transmitted2 = (1 - c_refl2) * c_absorbtion; c_refl2 = clamp(((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) * c_absHalf) + c_refl1), 0 ,1); c_refl3 = clamp((((c_reflAllPanes[2] - c_reflAllPanes[0]) * c_transmitted2) + c_refl2), 0 ,1); c_transmitted3 = (1 - c_refl3) * c_absorbtion; c_refl3 = clamp(((((c_reflAllPanes[2] - c_reflAllPanes[0]) * c_transmitted2) * c_absHalf) + c_refl2), 0 ,1); cl_refl = microfacet_ggx(n_n1, 0, 150) * c_refl2; } else { c_refl2 = clamp((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) + c_refl1), 0 ,1); c_transmitted2 = (1 - c_refl2) * c_absorbtion; c_refl2 = clamp(((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) * c_absHalf) + c_refl1), 0 ,1); c_refl3 = clamp((((c_reflAllPanes[2] - c_reflAllPanes[0]) * c_transmitted2) + c_refl2), 0 ,1); c_transmitted3 = (1 - c_refl3) * c_absorbtion; c_refl2 = clamp(((((c_reflAllPanes[1] - c_reflAllPanes[0]) * c_transmitted1) * c_absHalf)), 0 ,1); c_refl3 = clamp(((((c_reflAllPanes[2] - c_reflAllPanes[0]) * c_transmitted2) * c_absHalf)), 0 ,1); cl_refl = microfacet_ggx(n_n3, 0, 150) * c_refl3 + microfacet_ggx(n_n2, 0, 150) * c_refl2 + microfacet_ggx(n_n1, 0, 150) * c_refl1; } c_transmittedOut = c_transmitted3; } closure color cl_transp1 = emission() * color(0); if (i_refrMode == 1) { cl_transp1 = refraction(N, 1.001, "auto", 1) * c_transmittedOut; } if (i_refrMode == 2) { cl_transp1 = transparent() * c_transmittedOut; } Ci = cl_refl + cl_transp1; if (f_dirtAmt > 0) { Ci = (f_dirtAmt * (diffuse(n_n1, "roughness", 0.3) * c_dirtCol)) + ((1 - f_dirtAmt) * Ci); } }