1// 2// Base library functions and types 3// 4// Author: Dan Gudmundsson 5// 6// Extensions must always be on top of the file load them here 7// and include this file first 8 9#ifndef lib_base 10#define lib_base 1 11 12#ifdef GL_ARB_shader_texture_lod 13#extension GL_ARB_shader_texture_lod : enable 14#endif 15 16const float M_PI = 3.14159265359; 17 18// Encapsulate the various inputs used by the various functions in the shading equation 19struct PBRInfo 20{ 21 float NdotL; // cos angle between normal and light direction 22 float NdotV; // cos angle between normal and view direction 23 float NdotH; // cos angle between normal and half vector 24 float LdotH; // cos angle between light direction and half vector 25 float VdotH; // cos angle between view direction and half vector 26 float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) 27 float metalness; // metallic value at the surface 28 vec3 reflectance0; // full reflectance color (normal incidence angle) 29 vec3 reflectance90; // reflectance color at grazing angle 30 float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) 31 vec3 diffuseColor; // color contribution from diffuse lighting 32 vec3 specularColor; // color contribution from specular lighting 33 float occlusion; 34 float opaque; 35}; 36 37vec4 SRGBtoLINEAR(vec4 srgbIn) 38{ 39 vec3 bLess = step(vec3(0.04045),srgbIn.xyz); 40 vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess ); 41 return vec4(linOut,srgbIn.w); 42} 43 44PBRInfo calc_views(vec3 Norm, vec3 View, vec3 Light) 45{ 46 PBRInfo pbr; 47 vec3 Half = normalize(Light+View); // halfv between l and v 48 pbr.NdotL = clamp(dot(Norm, Light), 0.001, 1.0); 49 pbr.NdotV = abs(dot(Norm, View)) + 0.001; 50 pbr.NdotH = clamp(dot(Norm, Half), 0.0, 1.0); 51 pbr.LdotH = clamp(dot(Light, Half), 0.0, 1.0); 52 pbr.VdotH = clamp(dot(View, Half), 0.0, 1.0); 53 return pbr; 54} 55 56// The following equation models the Fresnel reflectance term of the spec equation (aka F()) 57// Implementation of fresnel from [4], Equation 15 58vec3 specularReflection(PBRInfo pbrInputs) 59{ 60 return pbrInputs.reflectance0 + 61 (pbrInputs.reflectance90 - pbrInputs.reflectance0) 62 * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); 63} 64 65// This calculates the specular geometric attenuation (aka G()), 66// where rougher material will reflect less light back to the viewer. 67// This implementation is based on [1] Equation 4, and we adopt their modifications to 68// alphaRoughness as input as originally proposed in [2]. 69float geometricOcclusion(PBRInfo pbrInputs) 70{ 71 float NdotL = pbrInputs.NdotL; 72 float NdotV = pbrInputs.NdotV; 73 float r = pbrInputs.alphaRoughness*pbrInputs.alphaRoughness; 74 75 float attenuationL = NdotL / (NdotL + sqrt(r + (1.0 - r) * (NdotL * NdotL))); 76 float attenuationV = NdotV / (NdotV + sqrt(r + (1.0 - r) * (NdotV * NdotV))); 77 return 8.0 * attenuationL * attenuationV; 78} 79 80// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) 81// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz 82// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. 83float microfacetDistribution(PBRInfo pbrInputs) 84{ 85 float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; 86 float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; 87 return roughnessSq / (M_PI * f * f); 88} 89 90// Basic Lambertian diffuse 91// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog 92// See also [1], Equation 1 93vec3 diffuse(PBRInfo pbrInputs) 94{ 95 return pbrInputs.diffuseColor / M_PI; 96} 97 98#endif 99