237 lines · 9.1 KB · Text
RawDownload
<!//  LightingModel.slh//  fragment shader////  Created by Sam Gateau on 1/25/14.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html!><@if not SHADING_MODEL_SLH@><@def SHADING_MODEL_SLH@> <@include LightingModel.slh@> <@func declareBeckmannSpecular()@> TEXTURE(RENDER_UTILS_TEXTURE_SSSC_SPECULAR_BECKMANN, sampler2D, scatteringSpecularBeckmann); float fetchSpecularBeckmann(float ndoth, float roughness) {    return pow(2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0);} vec2 skinSpecular(SurfaceData surface, float intensity) {    vec2 result = vec2(0.0, 1.0);    if (surface.ndotl > 0.0) {        float PH = fetchSpecularBeckmann(surface.ndoth, surface.roughness);        float F = fresnelSchlickScalar(0.028, surface);        float frSpec = max(PH * F / dot(surface.halfDir, surface.halfDir), 0.0);        result.x = surface.ndotl * intensity * frSpec;        result.y -= F;    }     return result;}<@endfunc@> <@func declareEvalPBRShading()@> float evalSmithInvG1(float roughness4, float ndotd) {    return ndotd + sqrt(roughness4+ndotd*ndotd*(1.0-roughness4));} SurfaceData initSurfaceData(float roughness, vec3 normal, vec3 eyeDir) {    SurfaceData surface;    surface.eyeDir = eyeDir;    surface.normal = normal;    surface.roughness = mix(0.01, 1.0, roughness);    surface.roughness2 = surface.roughness * surface.roughness;    surface.roughness4 = surface.roughness2 * surface.roughness2;    surface.ndotv = clamp(dot(normal, eyeDir), 0.0, 1.0);    surface.smithInvG1NdotV = evalSmithInvG1(surface.roughness4, surface.ndotv);     // These values will be set when we know the light direction, in updateSurfaceDataWithLight    surface.ndoth = 0.0;    surface.ndotl = 0.0;    surface.ldoth = 0.0;    surface.lightDir = vec3(0,0,1);    surface.halfDir = vec3(0,0,1);     return surface;} void updateSurfaceDataWithLight(inout SurfaceData surface, vec3 lightDir) {    surface.lightDir = lightDir;    surface.halfDir = normalize(surface.eyeDir + lightDir);    vec3 dots;    dots.x = dot(surface.normal, surface.halfDir);    dots.y = dot(surface.normal, surface.lightDir);    dots.z = dot(surface.halfDir, surface.lightDir);    dots = clamp(dots, vec3(0), vec3(1));    surface.ndoth = dots.x;    surface.ndotl = dots.y;    surface.ldoth = dots.z;} vec3 fresnelSchlickColor(vec3 fresnelColor, SurfaceData surface) {    float base = 1.0 - surface.ldoth;    //float exponential = pow(base, 5.0);    float base2 = base * base;    float exponential = base * base2 * base2;    return vec3(exponential) + fresnelColor * (1.0 - exponential);} float fresnelSchlickScalar(float fresnelScalar, SurfaceData surface) {    float base = 1.0 - surface.ldoth;    //float exponential = pow(base, 5.0);    float base2 = base * base;    float exponential = base * base2 * base2;    return (exponential) + fresnelScalar * (1.0 - exponential);} float specularDistribution(SurfaceData surface) {    // See https://www.khronos.org/assets/uploads/developers/library/2017-web3d/glTF-2.0-Launch_Jun17.pdf    // for details of equations, especially page 20    float denom = (surface.ndoth*surface.ndoth * (surface.roughness4 - 1.0) + 1.0);    denom *= denom;    // Add geometric factors G1(n,l) and G1(n,v)    float smithInvG1NdotL = evalSmithInvG1(surface.roughness4, surface.ndotl);    denom *= surface.smithInvG1NdotV * smithInvG1NdotL;    // Don't divide by PI as this is part of the light normalization factor    float power = surface.roughness4 / denom;    return power;} // Frag Shading returns the diffuse amount as W and the specular rgb as xyzvec4 evalPBRShading(float metallic, vec3 fresnel, SurfaceData surface) {    // Incident angle attenuation    float angleAttenuation = surface.ndotl;     // Specular Lighting    vec3 fresnelColor = fresnelSchlickColor(fresnel, surface);    float power = specularDistribution(surface);    vec3 specular = fresnelColor * power * angleAttenuation;    float diffuse = (1.0 - metallic) * angleAttenuation * (1.0 - fresnelColor.x);     // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that    // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit    // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means".    // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf    // page 23 paragraph "Punctual light sources")    return vec4(specular, diffuse);} // Frag Shading returns the diffuse amount as W and the specular rgb as xyzvec4 evalPBRShadingDielectric(SurfaceData surface, float fresnel) {    // Incident angle attenuation    float angleAttenuation = surface.ndotl;     // Specular Lighting    float fresnelScalar = fresnelSchlickScalar(fresnel, surface);    float power = specularDistribution(surface);    vec3 specular = vec3(fresnelScalar) * power * angleAttenuation;    float diffuse = angleAttenuation * (1.0 - fresnelScalar);     // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that    // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit    // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means".    // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf    // page 23 paragraph "Punctual light sources")    return vec4(specular, diffuse);} vec4 evalPBRShadingMetallic(SurfaceData surface, vec3 fresnel) {    // Incident angle attenuation    float angleAttenuation = surface.ndotl;     // Specular Lighting    vec3 fresnelColor = fresnelSchlickColor(fresnel, surface);    float power = specularDistribution(surface);    vec3 specular = fresnelColor * power * angleAttenuation;     // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that    // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit    // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means".    // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf    // page 23 paragraph "Punctual light sources")    return vec4(specular, 0.f);} <@endfunc@>   <$declareEvalPBRShading()$> void evalFragShading(out vec3 diffuse, out vec3 specular,    float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo) {    vec4 shading = evalPBRShading(metallic, fresnel, surface);    diffuse = vec3(shading.w);    diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());    specular = shading.xyz;} <$declareBeckmannSpecular()$><@include SubsurfaceScattering.slh@><$declareSubsurfaceScatteringBRDF()$>  void evalFragShading(out vec3 diffuse, out vec3 specular,    float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo,    float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature) {    if (scattering * isScatteringEnabled() > 0.0) {        vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);        diffuse = mix(vec3(surface.ndotl), brdf, scattering);         // Specular Lighting        vec2 specularBrdf = skinSpecular(surface, 1.0);                diffuse *= specularBrdf.y;        specular = vec3(specularBrdf.x);    } else {        vec4 shading = evalPBRShading(metallic, fresnel, surface);        diffuse = vec3(shading.w);        specular = shading.xyz;    }    diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());}  void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,    float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo,    float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature) {    vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);    float NdotL = surface.ndotl;    diffuse = mix(vec3(NdotL), brdf, scattering);     // Specular Lighting    vec2 specularBrdf = skinSpecular(surface, 1.0);            diffuse *= specularBrdf.y;    specular = vec3(specularBrdf.x);    diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());} void evalFragShadingGloss(out vec3 diffuse, out vec3 specular,    float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo) {    vec4 shading = evalPBRShading(metallic, fresnel, surface);    diffuse = vec3(shading.w);    diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());    specular = shading.xyz;} vec3 evalSpecularWithOpacity(vec3 specular, float opacity) {    return specular / mix(1.0, opacity, float(opacity > 0.0));} <@if not GETFRESNEL0@><@def GETFRESNEL0@>vec3 getFresnelF0(float metallic, vec3 metalF0) {    // Enable continuous metallness value by lerping between dielectric    // and metal fresnel F0 value based on the "metallic" parameter    return mix(vec3(0.03), metalF0, metallic);}<@endif@> <@endif@>