overte-HifiExperiments/libraries/render-utils/src/SubsurfaceScattering.slh
2018-10-29 16:42:46 -07:00

195 lines
No EOL
5.2 KiB
Text

// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gateau on 6/8/16.
// Copyright 2016 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 SUBSURFACE_SCATTERING_SLH@>
<@def SUBSURFACE_SCATTERING_SLH@>
<@include render-utils/ShaderConstants.h@>
<@func declareSubsurfaceScatteringProfileSource()@>
float gaussian(float v, float r) {
const float _PI = 3.14159265358979523846;
return (1.0 / sqrt(2.0 * _PI * v)) * exp(-(r*r) / (2.0 * v));
}
vec3 scatter(float r) {
// r is the distance expressed in millimeter
// returns the scatter reflectance
// Values from GPU Gems 3 "Advanced Skin Rendering".
// Originally taken from real life samples.
const vec4 profile[6] = vec4[6](
vec4(0.0064, 0.233, 0.455, 0.649),
vec4(0.0484, 0.100, 0.336, 0.344),
vec4(0.1870, 0.118, 0.198, 0.000),
vec4(0.5670, 0.113, 0.007, 0.007),
vec4(1.9900, 0.358, 0.004, 0.000),
vec4(7.4100, 0.078, 0.000, 0.000)
);
const int profileNum = 6;
vec3 ret = vec3(0.0);
for (int i = 0; i < profileNum; i++) {
float v = profile[i].x * 1.414;
float g = gaussian(v, r);
ret += g * profile[i].yzw;
}
return ret;
}
<@endfunc@>
<@func declareSubsurfaceScatteringGenerateProfileMap()@>
<$declareSubsurfaceScatteringProfileSource()$>
vec3 generateProfile(vec2 uv) {
return scatter(uv.x * 2.0);
}
<@endfunc@>
<@func declareSubsurfaceScatteringProfileMap()@>
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_PROFILE) uniform sampler2D scatteringProfile;
vec3 scatter(float r) {
return texture(scatteringProfile, vec2(r * 0.5, 0.5)).rgb;
}
<@endfunc@>
<@func declareSubsurfaceScatteringIntegrate(NumIntegrationSteps)@>
vec3 integrate(float cosTheta, float skinRadius) {
// Angle from lighting direction.
float theta = acos(cosTheta);
vec3 totalWeights = vec3(0.0);
vec3 totalLight = vec3(0.0);
const float _PI = 3.14159265358979523846;
const float step = 2.0 * _PI / float(<$NumIntegrationSteps$>);
float a = -(_PI);
while (a <= (_PI)) {
float sampleAngle = theta + a;
float diffuse = clamp(cos(sampleAngle), 0.0, 1.0);
// Distance.
float sampleDist = abs(2.0 * skinRadius * sin(a * 0.5));
// Profile Weight.
vec3 weights = scatter(sampleDist);
totalWeights += weights;
totalLight += diffuse * weights;
a += step;
}
vec3 result = (totalLight / totalWeights);
return clamp(result, vec3(0.0), vec3(1.0));
}
<@endfunc@>
<@func declareSubsurfaceScatteringResource()@>
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_LUT) uniform sampler2D scatteringLUT;
vec3 fetchBRDF(float LdotN, float curvature) {
return texture(scatteringLUT, vec2( clamp(LdotN * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0))).xyz;
}
vec3 fetchBRDFSpectrum(vec3 LdotNSpectrum, float curvature) {
return vec3(
fetchBRDF(LdotNSpectrum.r, curvature).r,
fetchBRDF(LdotNSpectrum.g, curvature).g,
fetchBRDF(LdotNSpectrum.b, curvature).b);
}
// Subsurface Scattering parameters
struct ScatteringParameters {
vec4 normalBendInfo; // R, G, B, factor
vec4 curvatureInfo;// Offset, Scale, level
vec4 debugFlags;
};
LAYOUT(binding=RENDER_UTILS_BUFFER_SSSC_PARAMS) uniform subsurfaceScatteringParametersBuffer {
ScatteringParameters parameters;
};
vec3 getBendFactor() {
return parameters.normalBendInfo.xyz * parameters.normalBendInfo.w;
}
float getScatteringLevel() {
return parameters.curvatureInfo.z;
}
bool showBRDF() {
return parameters.curvatureInfo.w > 0.0;
}
bool showCurvature() {
return parameters.debugFlags.x > 0.0;
}
bool showDiffusedNormal() {
return parameters.debugFlags.y > 0.0;
}
float tuneCurvatureUnsigned(float curvature) {
return abs(curvature) * parameters.curvatureInfo.y + parameters.curvatureInfo.x;
}
float unpackCurvature(float packedCurvature) {
return (packedCurvature * 2.0 - 1.0);
}
vec3 evalScatteringBentNdotL(vec3 normal, vec3 midNormal, vec3 lowNormal, vec3 lightDir) {
vec3 bendFactorSpectrum = getBendFactor();
// vec3 rN = normalize(mix(normal, lowNormal, bendFactorSpectrum.x));
vec3 rN = normalize(mix(midNormal, lowNormal, bendFactorSpectrum.x));
vec3 gN = normalize(mix(midNormal, lowNormal, bendFactorSpectrum.y));
vec3 bN = normalize(mix(midNormal, lowNormal, bendFactorSpectrum.z));
vec3 NdotLSpectrum = vec3(dot(rN, lightDir), dot(gN, lightDir), dot(bN, lightDir));
return NdotLSpectrum;
}
<@endfunc@>
<@func declareSubsurfaceScatteringBRDF()@>
<$declareSubsurfaceScatteringResource()$>
vec3 evalSkinBRDF(vec3 lightDir, vec3 normal, vec3 midNormal, vec3 lowNormal, float curvature) {
if (showDiffusedNormal()) {
return lowNormal * 0.5 + vec3(0.5);
}
if (showCurvature()) {
float check = float(curvature > 0.0);
return vec3(check * curvature, 0.0, (1.0 - check) * -curvature);
}
vec3 bentNdotL = evalScatteringBentNdotL(normal, midNormal, lowNormal, lightDir);
float tunedCurvature = tuneCurvatureUnsigned(curvature);
vec3 brdf = fetchBRDFSpectrum(bentNdotL, tunedCurvature);
return brdf;
}
<@endfunc@>
<@endif@>