diff options
Diffstat (limited to 'indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl')
-rw-r--r-- | indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl b/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl new file mode 100644 index 0000000000..0753e73dc8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl @@ -0,0 +1,214 @@ +/** + * @file irradianceGenF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +/*[EXTRA_CODE_HERE]*/ + +out vec4 frag_color; + +uniform samplerCubeArray reflectionProbes; +uniform int sourceIdx; + +uniform float max_probe_lod; + +in vec3 vary_dir; + +// Code below is derived from the Khronos GLTF Sample viewer: +// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/source/shaders/ibl_filtering.frag + + +#define MATH_PI 3.1415926535897932384626433832795 + +float u_roughness = 1.0; +int u_sampleCount = 32; +float u_lodBias = 2.0; +int u_width = 64; + +// Hammersley Points on the Hemisphere +// CC BY 3.0 (Holger Dammertz) +// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html +// with adapted interface +float radicalInverse_VdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +// hammersley2d describes a sequence of points in the 2d unit square [0,1)^2 +// that can be used for quasi Monte Carlo integration +vec2 hammersley2d(int i, int N) { + return vec2(float(i)/float(N), radicalInverse_VdC(uint(i))); +} + +// Hemisphere Sample + +// TBN generates a tangent bitangent normal coordinate frame from the normal +// (the normal must be normalized) +mat3 generateTBN(vec3 normal) +{ + vec3 bitangent = vec3(0.0, 1.0, 0.0); + + float NdotUp = dot(normal, vec3(0.0, 1.0, 0.0)); + float epsilon = 0.0000001; + /*if (1.0 - abs(NdotUp) <= epsilon) + { + // Sampling +Y or -Y, so we need a more robust bitangent. + if (NdotUp > 0.0) + { + bitangent = vec3(0.0, 0.0, 1.0); + } + else + { + bitangent = vec3(0.0, 0.0, -1.0); + } + }*/ + + vec3 tangent = normalize(cross(bitangent, normal)); + bitangent = cross(normal, tangent); + + return mat3(tangent, bitangent, normal); +} + +struct MicrofacetDistributionSample +{ + float pdf; + float cosTheta; + float sinTheta; + float phi; +}; + +MicrofacetDistributionSample Lambertian(vec2 xi, float roughness) +{ + MicrofacetDistributionSample lambertian; + + // Cosine weighted hemisphere sampling + // http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#Cosine-WeightedHemisphereSampling + lambertian.cosTheta = sqrt(1.0 - xi.y); + lambertian.sinTheta = sqrt(xi.y); // equivalent to `sqrt(1.0 - cosTheta*cosTheta)`; + lambertian.phi = 2.0 * MATH_PI * xi.x; + + lambertian.pdf = lambertian.cosTheta / MATH_PI; // evaluation for solid angle, therefore drop the sinTheta + + return lambertian; +} + + +// getImportanceSample returns an importance sample direction with pdf in the .w component +vec4 getImportanceSample(int sampleIndex, vec3 N, float roughness) +{ + // generate a quasi monte carlo point in the unit square [0.1)^2 + vec2 xi = hammersley2d(sampleIndex, u_sampleCount); + + MicrofacetDistributionSample importanceSample; + + // generate the points on the hemisphere with a fitting mapping for + // the distribution (e.g. lambertian uses a cosine importance) + importanceSample = Lambertian(xi, roughness); + + // transform the hemisphere sample to the normal coordinate frame + // i.e. rotate the hemisphere to the normal direction + vec3 localSpaceDirection = normalize(vec3( + importanceSample.sinTheta * cos(importanceSample.phi), + importanceSample.sinTheta * sin(importanceSample.phi), + importanceSample.cosTheta + )); + mat3 TBN = generateTBN(N); + vec3 direction = TBN * localSpaceDirection; + + return vec4(direction, importanceSample.pdf); +} + +// Mipmap Filtered Samples (GPU Gems 3, 20.4) +// https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling +// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf +float computeLod(float pdf) +{ + // // Solid angle of current sample -- bigger for less likely samples + // float omegaS = 1.0 / (float(u_sampleCount) * pdf); + // // Solid angle of texel + // // note: the factor of 4.0 * MATH_PI + // float omegaP = 4.0 * MATH_PI / (6.0 * float(u_width) * float(u_width)); + // // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle + // // note that 0.5 * log2 is equivalent to log4 + // float lod = 0.5 * log2(omegaS / omegaP); + + // babylon introduces a factor of K (=4) to the solid angle ratio + // this helps to avoid undersampling the environment map + // this does not appear in the original formulation by Jaroslav Krivanek and Mark Colbert + // log4(4) == 1 + // lod += 1.0; + + // We achieved good results by using the original formulation from Krivanek & Colbert adapted to cubemaps + + // https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf + float lod = 0.5 * log2( 6.0 * float(u_width) * float(u_width) / (float(u_sampleCount) * pdf)); + + + return lod; +} + +vec4 filterColor(vec3 N) +{ + vec4 color = vec4(0.f); + + for(int i = 0; i < u_sampleCount; ++i) + { + vec4 importanceSample = getImportanceSample(i, N, 1.0); + + vec3 H = vec3(importanceSample.xyz); + float pdf = importanceSample.w; + + // mipmap filtered samples (GPU Gems 3, 20.4) + float lod = computeLod(pdf); + + // apply the bias to the lod + lod += u_lodBias; + + lod = clamp(lod, 0, max_probe_lod); + // sample lambertian at a lower resolution to avoid fireflies + vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod); + + color += lambertian; + } + + color /= float(u_sampleCount); + + return color; +} + +// entry point +void main() +{ + vec4 color = vec4(0); + + color = filterColor(vary_dir); + + frag_color = max(color, vec4(0)); +} + |