Behold! The Reflector is here!
(Page WIP)
Download links
http://www.rensheeren.com/osl/reflector_tex_v002.osl
http://www.rensheeren.com/osl/rhfunctions.h
Save both in the same folder, both are needed for the shader to work.
Features
– Polarisation (to simulate sky polarisation or sunglasses if you would ever want to 😉 )
– Simple rough Fresnel setup, where the reflection falls off towards the camera facing
angle reflection colour depending on surface roughness. This is to have a more realistic
reflection for rough surfaces where you wouldn’t see very reflective grazing angle or
side edges (the Fresnel falloff smoothes out with increased roughness).
– IOR for the incoming/outside medium, for air this can stay at 1.0, but for example
underwater (n = 1.333) the look of non-metals especially can change a lot.
– Complex IOR for the transmissive/inside medium, in other words the object you would apply
this shader to. You can use values from http://refractiveindex.info/ for example.
Use the k values only for metals. Leave at 0 for non-metals, the shader will then use a
quicker function to calculate reflections.
How to use
VRay:
– Create a VRay OSL Texture map.
– Load in the download OSL shader.
– Create a VRayMtl and disable Fresnel reflections.
– Plug the OSL map into the reflection.
– You may want to create a VRayColor map to drive the roughness/glossiness values of both the OSL shader and the VRayMtl. Plus it into roughness_tex for the OSL shader and in Refl Gloss for the VrayMtl.
Options
– n_out
IOR (N) value for the outside material, usually air (1.0), or water (1.333).
– n_in
IOR (N) data for RGB separately.
– k_in
Exctinction (K) data for RGB separately.
– use_first_input_only
Use the R values for G and B. In other words use R for all.
– polarisation
Polarisation of the incoming light, default 0.5.
– roughness
How rough the material surface is.
– invert_to_glossiness
Use Glossiness instead of Roughness (f.e. VRay).
– roughness_falloff
How quick the grazing side reflections get levelled off with increasing roughness. Default 0.3.
– rgh_darken_brighten
Brightens the side reflections for rougher surfaces with values >0.5, darkens with <0.5, default 0.51.
Two comparisons with rough Fresnel enabled on the left:

A look at how the reflection amount differs with rough Fresnel enabled (left):

#include "rhfunctions.h" /* reflector_tex_v002 By Rens Heeren (mail [at] rensheeren [dot] com) Use as an OSL texture, not as an OSL material. Full complex Fresnel reflection calculator. Features: - Polarisation (to simulate sky polarisation or sunglasses if you would ever want to 😉 ) - Simple rough Fresnel setup, where the reflection falls off towards the zero incidence angle reflection colour depending on surface roughness. This is to have a more realistic reflection for rough surfaces where you wouldn't see very reflective grazing angle or side edges (the Fresnel falloff smoothes out with increased roughness). - IOR for the incoming/outside medium, for air this can stay at 1.0, but for example underwater (n = 1.333) the look of non-metals especially can change a lot. - Complex IOR for the transmissive/inside medium, in other words the object you would apply this shader to. You can use values from http://refractiveindex.info/ for example. Use the k values only for metals. Leave at 0 for non-metals, the shader will then use a quicker function to calculate reflections. Fresnel function for metals from Memo on Fresnel equations (http://www.cs.virginia.edu/~jdl/bib/globillum/shirley_thesis.pdf) Use at your own risk. 2016/03/23 - Created (rh) 2016/05/23 - v002 (rh) nm n k GOLD 611.36 nm 0.22213 3.0363 548.96 nm 0.42814 2.3340 464.28 nm 1.2570 1.7531 WATER (one wavelength example, first input only) - 1.5 0 - 0 0 - 0 0 */ float fn_rghCC(float f_rghCCIn, float f_zeroIn) { if (f_rghCCIn < 0.5) { f_rghCCIn = f_rghCCIn * 2; f_zeroIn *= f_rghCCIn; } else { f_rghCCIn = (f_rghCCIn * 2) - 1.0; f_zeroIn = mix(f_zeroIn, 1.0, f_rghCCIn); } return f_zeroIn; } shader reflector_tex_v002 ( float n_out = 1.0 [[ string description = "IOR (N) value for the outside material, usually air (1.0), or water (1.333)." ]], #ifdef __VRAY_OSL__ vector n_in = vector(1.5, 0, 0) [[ string description = "IOR (N) data for RGB separately." ]], vector k_in = vector(0) [[ string description = "Exctinction (K) data for RGB separately." ]], int use_first_input_only = 1 [[ string widget = "checkBox", string description = "Use the R values for G and B."]], float polarisation = 0.5 [[ string description = "Polarisation of the incoming light, default 0.5." ]], float roughness = 1 [[ string description = "How rough the material surface is." ]], int invert_to_glossiness = 1 [[ string widget = "checkBox", string description = "Use Glossiness instead of Roughness (f.e. VRay)." ]], float roughness_falloff = 0.3 [[ string description = "How quick the grazing side reflections get levelled off with increasing roughness. Default 0.3." ]], float rgh_darken_brighten = 0.51 [[ string description = "Brightens the side reflections for rougher surfaces with values >0.5, darkens with <0.5, default 0.51." ]], string n_out_tex = "" [[ string description = "Texture to use for the outside material IOR." ]], int use_n_out_tex = 0 [[ string widget = "checkBox", string description = "Use the texture instead of the value for the outside IOR." ]], string n_in_tex = "" [[ string description = "Texture to use for the N values (RGB)." ]], int use_n_in_tex = 0 [[ string widget = "checkBox", string description = "Use the texture instead of the value for the N values (RGB)." ]], string k_in_tex = "" [[ string description = "Texture to use for the K values (RGB)." ]], int use_k_in_tex = 0 [[ string widget = "checkBox", string description = "Use the texture instead of the value for the K values (RGB)." ]], string polarisation_tex = "" [[ string description = "Texture to use for the polarisation." ]], int use_polarisation_tex = 0 [[ string widget = "checkBox", string description = "Use the texture instead of the value for the polarisation." ]], string roughness_tex = "" [[ string description = "Texture to use for the roughness/glossiness." ]], int use_roughness_tex = 0 [[ string widget = "checkBox", string description = "Use the texture instead of the value for the roughness/glossiness." ]], #else color n_in = color(1.5, 0, 0) [[ string description = "IOR (N) data for RGB separately." ]], color k_in = color(0) [[ string description = "Exctinction (K) data for RGB separately." ]], int use_first_input_only = 1 [[ string widget = "checkBox", string description = "Use the R values for G and B." ]], float polarisation = 0.5 [[ string description = "Polarisation of the incoming light, default 0.5." ]], float roughness = 0 [[ string description = "How rough the material surface is." ]], int invert_to_glossiness = 0 [[ string widget = "checkBox", string description = "Use Glossiness instead of Roughness (f.e. VRay)." ]], float roughness_falloff = 0.3 [[ string description = "How quick the grazing side reflections get levelled off with increasing roughness. Default 0.3." ]], float rgh_darken_brighten = 0.51 [[ string description = "Brightens the side reflections for rougher surfaces with values >0.5, darkens with <0.5, default 0.51." ]], #endif output color out_col = color(0), output float out_alpha = 1, output float out_angleIncoming = 0 //output float out_angleTrans = 0 ) { // outer (incoming) and inner (transmitted) IOR, outer is usually air (~ 1.0) float f_ni = n_out; vector v_nt = n_in; vector v_kt = k_in; float f_pol = polarisation; float f_rgh = roughness; float f_rghFalloff = roughness_falloff; float f_rghCC = rgh_darken_brighten; int i_rghInv = invert_to_glossiness; #ifdef __VRAY_OSL__ if (use_n_out_tex) { color c_ni = texture(n_out_tex, u, v); f_ni = c_ni[0]; } if (use_n_in_tex) { color c_nt = texture(n_in_tex, u, v); v_nt = (vector)c_nt; } if (use_k_in_tex) { color c_kt = texture(k_in_tex, u, v); v_kt = (vector)c_kt; } if (use_polarisation_tex) { f_pol = texture(polarisation_tex, u, v); } if (use_roughness_tex) { color c_rgh = texture(roughness_tex, u, v); f_rgh = c_rgh[0]; } #endif f_pol = clamp(f_pol, 0, 1); f_rgh = clamp(f_rgh, 0, 1); f_rghCC = clamp(f_rghCC, 0, 1); int i_firstOnly = use_first_input_only; if ((v_nt[1] == 0) && (v_nt[2] == 0)) { i_firstOnly = 1; } if (i_rghInv) { f_rgh = 1.0 - f_rgh; } if (f_rghFalloff != 1.0) { if (f_rghFalloff < 0.001) { f_rghFalloff = 0.001; } f_rgh = pow(f_rgh, f_rghFalloff); } // is complex Fresnel? int i_complex = 0; if (i_firstOnly) { if (v_kt[0] != 0){i_complex = 1;} } else { float f_ktSum = v_kt[0] + v_kt[1] + v_kt[2]; if (f_ktSum != 0){i_complex = 1;} } float f_cosai = abs(dot(-I, N)); vector v_rzero = vector(0); float f_rzero = 0; float f_nt = v_nt[0]; float f_kt = v_kt[0]; vector v_fresnelR = vector(0); vector v_fresnelG = vector(0); vector v_fresnelB = vector(0); float f_cosatOut = 0; float f_rR = 0; float f_rG = 0; float f_rB = 0; if (i_complex) { if (i_firstOnly) { f_rzero = fn_FresnelFullDiMeZero(f_ni, f_nt, f_kt); if (f_rghCC != 0.5) { f_rzero = fn_rghCC(f_rghCC, f_rzero); } v_fresnelR = fn_FresnelFullDiMe(f_cosai, f_ni, f_nt, f_kt); f_rR = (v_fresnelR[0] * f_pol) + (v_fresnelR[1] * (1.0 - f_pol)); if (f_rgh > 0) { f_rR = (f_rR * (1.0 - f_rgh)) + (f_rzero * f_rgh); } f_rG = f_rR; f_rB = f_rR; f_cosatOut = v_fresnelR[0]; } else { v_rzero[0] = fn_FresnelFullDiMeZero(f_ni, v_nt[0], v_kt[0]); v_rzero[1] = fn_FresnelFullDiMeZero(f_ni, v_nt[1], v_kt[1]); v_rzero[2] = fn_FresnelFullDiMeZero(f_ni, v_nt[2], v_kt[2]); if (f_rghCC != 0.5) { v_rzero[0] = fn_rghCC(f_rghCC, v_rzero[0]); v_rzero[1] = fn_rghCC(f_rghCC, v_rzero[1]); v_rzero[2] = fn_rghCC(f_rghCC, v_rzero[2]); } v_fresnelR = fn_FresnelFullDiMe(f_cosai, f_ni, v_nt[0], v_kt[0]); v_fresnelG = fn_FresnelFullDiMe(f_cosai, f_ni, v_nt[1], v_kt[1]); v_fresnelB = fn_FresnelFullDiMe(f_cosai, f_ni, v_nt[2], v_kt[2]); f_rR = (v_fresnelR[0] * f_pol) + (v_fresnelR[1] * (1 - f_pol)); f_rG = (v_fresnelG[0] * f_pol) + (v_fresnelG[1] * (1 - f_pol)); f_rB = (v_fresnelB[0] * f_pol) + (v_fresnelB[1] * (1 - f_pol)); if (f_rgh > 0) { f_rR = (f_rR * (1 - f_rgh)) + (v_rzero[0] * f_rgh); f_rG = (f_rG * (1 - f_rgh)) + (v_rzero[1] * f_rgh); f_rB = (f_rB * (1 - f_rgh)) + (v_rzero[2] * f_rgh); } f_cosatOut = v_fresnelR[0]; } } else { if (i_firstOnly) { f_rzero = fn_FresnelFullDiDiZero(f_ni, f_nt); if (f_rghCC != 0.5) { f_rzero = fn_rghCC(f_rghCC, f_rzero); } v_fresnelR = fn_FresnelFullDiDi(f_cosai, f_ni, f_nt); f_rR = (v_fresnelR[0] * f_pol) + (v_fresnelR[1] * (1 - f_pol)); f_rR = (f_rR * (1 - f_rgh)) + (f_rzero * f_rgh); f_rG = f_rR; f_rB = f_rR; f_cosatOut = v_fresnelR[0]; } else { v_rzero[0] = fn_FresnelFullDiDiZero(f_ni, v_nt[0]); v_rzero[1] = fn_FresnelFullDiDiZero(f_ni, v_nt[1]); v_rzero[2] = fn_FresnelFullDiDiZero(f_ni, v_nt[2]); if (f_rghCC != 0.5) { v_rzero[0] = fn_rghCC(f_rghCC, v_rzero[0]); v_rzero[1] = fn_rghCC(f_rghCC, v_rzero[1]); v_rzero[2] = fn_rghCC(f_rghCC, v_rzero[2]); } v_fresnelR = fn_FresnelFullDiDi(f_cosai, f_ni, v_nt[0]); v_fresnelG = fn_FresnelFullDiDi(f_cosai, f_ni, v_nt[1]); v_fresnelB = fn_FresnelFullDiDi(f_cosai, f_ni, v_nt[2]); f_rR = (v_fresnelR[0] * f_pol) + (v_fresnelR[1] * (1 - f_pol)); f_rG = (v_fresnelG[0] * f_pol) + (v_fresnelG[1] * (1 - f_pol)); f_rB = (v_fresnelB[0] * f_pol) + (v_fresnelB[1] * (1 - f_pol)); f_rR = (f_rR * (1 - f_rgh)) + (v_rzero[0] * f_rgh); f_rG = (f_rG * (1 - f_rgh)) + (v_rzero[1] * f_rgh); f_rB = (f_rB * (1 - f_rgh)) + (v_rzero[2] * f_rgh); f_cosatOut = v_fresnelR[0]; } } out_col = color(f_rR, f_rG, f_rB); out_angleIncoming = f_cosai; }


