diff options
Diffstat (limited to 'indra/newview/app_settings')
6 files changed, 251 insertions, 280 deletions
| diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d262a1285f..41afca50f6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10382,6 +10382,17 @@      <key>Value</key>      <integer>256</integer>    </map> +  <key>RenderReflectionProbeResolution</key> +  <map> +    <key>Comment</key> +    <string>Resolution of reflection probe radiance maps (requires restart).  Will be set to the next highest power of two clamped to [64, 512].  Note that changing this value may consume a massive amount of video memory.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>256</integer> +  </map>    <key>RenderReflectionProbeDrawDistance</key>    <map> diff --git a/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl index 3e056aa048..2b1e794b52 100644 --- a/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl @@ -23,205 +23,11 @@   * $/LicenseInfo$   */ +// debug stub -/*[EXTRA_CODE_HERE]*/ - - -#ifdef DEFINE_GL_FRAGCOLOR  out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform samplerCubeArray   reflectionProbes; -uniform int sourceIdx; - -VARYING 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 = 16; -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) -{ -    //return  textureLod(uCubeMap, N, 3.0).rgb; -    vec4 color = vec4(0.f); -    float weight = 0.0f; - -    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, 6); -        // sample lambertian at a lower resolution to avoid fireflies -        vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod); - -        color += lambertian; -    } - -    if(weight != 0.0f) -    { -        color /= weight; -    } -    else -    { -        color /= float(u_sampleCount); -    } - -    return min(color*1.9, vec4(1)); -} - -// entry point  void main()  { -    vec4 color = vec4(0); - -    color = filterColor(vary_dir); -     -    frag_color = color; +    frag_color = vec4(0.5, 0, 0.5, 0);  } - diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl index 858052281b..e60ddcd569 100644 --- a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl @@ -37,6 +37,8 @@ VARYING vec3 vary_dir;  uniform float mipLevel;  uniform int u_width;  +uniform float max_probe_lod; +  // =============================================================================================================  // Parts of this file are (c) 2018 Sascha Willems @@ -128,7 +130,7 @@ vec4 prefilterEnvMap(vec3 R)  	float envMapDim = u_width;      int numSamples = 4; -    float numMips = 6.0; +    float numMips = max_probe_lod;      float roughness = mipLevel/numMips; 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..a4aec48c59 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl @@ -0,0 +1,231 @@ +/**  + * @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]*/ + + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform samplerCubeArray   reflectionProbes; +uniform int sourceIdx; + +uniform float max_probe_lod; + +VARYING 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 = 64; +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) +{ +    //return  textureLod(uCubeMap, N, 3.0).rgb; +    vec4 color = vec4(0.f); +    float weight = 0.0f; + +    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; +    } + +    if(weight != 0.0f) +    { +        color /= weight; +    } +    else +    { +        color /= float(u_sampleCount); +    } + +    color = min(color*1.9, vec4(1));  +    color = pow(color, vec4(0.5)); +    return color; +} + +// entry point +void main() +{ +    vec4 color = vec4(0); + +    color = filterColor(vary_dir); +     +    frag_color = color; +} + diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl index c69eba93b6..ba02070e45 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl @@ -162,90 +162,10 @@ float ambientLighting(vec3 norm, vec3 light_dir)  void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 additive,                           out vec3 atten)  { -#if 1      calcAtmosphericVars(inPositionEye, light_dir, 1.0, sunlit, amblit, additive, atten, false);      sunlit = srgb_to_linear(sunlit);      additive = srgb_to_linear(additive);      amblit = ambient_linear;      amblit *= ambientLighting(norm, light_dir); -#else  - -    //EXPERIMENTAL -- attempt to factor out srgb_to_linear conversions above -    vec3 rel_pos = inPositionEye; - -    //(TERRAIN) limit altitude -    if (abs(rel_pos.y) > max_y) rel_pos *= (max_y / rel_pos.y); - -    vec3  rel_pos_norm = normalize(rel_pos); -    float rel_pos_len  = length(rel_pos); -    vec3  sunlight     = (sun_up_factor == 1) ? vec3(sunlight_linear, 0.0) : vec3(moonlight_linear, 0.0); - -    // sunlight attenuation effect (hue and brightness) due to atmosphere -    // this is used later for sunlight modulation at various altitudes -    vec3 light_atten = (blue_density + vec3(haze_density * 0.25)) * (density_multiplier * max_y); -    // I had thought blue_density and haze_density should have equal weighting, -    // but attenuation due to haze_density tends to seem too strong - -    vec3 combined_haze = blue_density + vec3(haze_density); -    vec3 blue_weight   = blue_density / combined_haze; -    vec3 haze_weight   = vec3(haze_density) / combined_haze; - -    //(TERRAIN) compute sunlight from lightnorm y component. Factor is roughly cosecant(sun elevation) (for short rays like terrain) -    float above_horizon_factor = 1.0 / max(1e-6, lightnorm.y); -    sunlight *= exp(-light_atten * above_horizon_factor);  // for sun [horizon..overhead] this maps to an exp curve [0..1] - -    // main atmospheric scattering line integral -    float density_dist = rel_pos_len * density_multiplier; - -    // Transparency (-> combined_haze) -    // ATI Bugfix -- can't store combined_haze*density_dist*distance_multiplier in a variable because the ati -    // compiler gets confused. -    combined_haze = exp(-combined_haze * density_dist * distance_multiplier); - -    // final atmosphere attenuation factor -    atten = combined_haze.rgb; - -    // compute haze glow -    float haze_glow = dot(rel_pos_norm, lightnorm.xyz); - -    // dampen sun additive contrib when not facing it... -    // SL-13539: This "if" clause causes an "additive" white artifact at roughly 77 degreees. -    //    if (length(light_dir) > 0.01) -    haze_glow *= max(0.0f, dot(light_dir, rel_pos_norm)); - -    haze_glow = 1. - haze_glow; -    // haze_glow is 0 at the sun and increases away from sun -    haze_glow = max(haze_glow, .001);  // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) -    haze_glow *= glow.x; -    // higher glow.x gives dimmer glow (because next step is 1 / "angle") -    haze_glow = pow(haze_glow, glow.z); -    // glow.z should be negative, so we're doing a sort of (1 / "angle") function - -    // add "minimum anti-solar illumination" -    haze_glow += .25; - -    haze_glow *= sun_moon_glow_factor; - -    //vec3 amb_color = vec4(ambient_linear, 0.0); -    vec3 amb_color = ambient_color; - -    // increase ambient when there are more clouds -    vec3 tmpAmbient = amb_color + (vec3(1.) - amb_color) * cloud_shadow * 0.5; - -    // Similar/Shared Algorithms: -    //     indra\llinventory\llsettingssky.cpp                                        -- LLSettingsSky::calculateLightSettings() -    //     indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars() -    // haze color -    vec3 cs = sunlight.rgb * (1. - cloud_shadow); -    additive = (blue_horizon.rgb * blue_weight.rgb) * (cs + tmpAmbient.rgb) + (haze_horizon * haze_weight.rgb) * (cs * haze_glow + tmpAmbient.rgb); - -    // brightness of surface both sunlight and ambient -    sunlit = min(sunlight.rgb, vec3(1)); -    amblit = tmpAmbient.rgb; -    additive *= vec3(1.0 - combined_haze); - -    //sunlit = sunlight_linear; -    amblit = ambient_linear*0.8; -#endif  } diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 9793ab13de..bb3be7260b 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -36,6 +36,7 @@ uniform samplerCubeArray   reflectionProbes;  uniform samplerCubeArray   irradianceProbes;  uniform sampler2D sceneMap;  uniform int cube_snapshot; +uniform float max_probe_lod;  layout (std140) uniform ReflectionProbes  { @@ -623,7 +624,7 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir)      {          col *= 1.0/wsum;      } -     +      return col;  } @@ -631,7 +632,7 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect)  {      // TODO - don't hard code lods -    float reflection_lods = 6; +    float reflection_lods = max_probe_lod;      preProbeSample(pos);      vec3 refnormpersp = reflect(pos.xyz, norm.xyz); @@ -705,7 +706,7 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity)  {      // TODO - don't hard code lods -    float reflection_lods = 7; +    float reflection_lods = max_probe_lod;      preProbeSample(pos);      vec3 refnormpersp = reflect(pos.xyz, norm.xyz); | 
