OSL – Reflector

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.

reflector_screen

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.

reflector_nodescreen

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: reflector_sphere2

reflector_sphere1

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

#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;
}