Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
@@ -0,0 +1,97 @@
/**
* @file fullbrightShinyF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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;
#ifndef HAS_DIFFUSE_LOOKUP
uniform sampler2D diffuseMap;
#endif
in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_texcoord1;
in vec3 vary_position;
uniform samplerCube environmentMap;
vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
// reflection probe interface
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
#ifdef HAS_DIFFUSE_LOOKUP
vec4 color = diffuseLookup(vary_texcoord0.xy);
#else
vec4 color = texture(diffuseMap, vary_texcoord0.xy);
#endif
color.rgb *= vertex_color.rgb;
// SL-9632 HUDs are affected by Atmosphere
#ifndef IS_HUD
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
vec3 pos = vary_position;
calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten);
float env_intensity = vertex_color.a;
vec3 ambenv;
vec3 glossenv;
vec3 legacyenv;
vec3 norm = normalize(vary_texcoord1.xyz);
vec4 spec = vec4(0,0,0,0);
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, vec2(0), pos.xyz, norm.xyz, spec.a, env_intensity, false, amblit);
color.rgb = srgb_to_linear(color.rgb);
applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
#endif
color.a = 1.0;
frag_color = max(color, vec4(0));
}
@@ -0,0 +1,101 @@
/**
* @file class3/deferred/hazeF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
out vec4 frag_color;
// Inputs
uniform vec3 sun_dir;
uniform vec3 moon_dir;
uniform int sun_up_factor;
in vec2 vary_fragcoord;
vec4 getNorm(vec2 pos_screen);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
float getDepth(vec2 pos_screen);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
uniform vec4 waterPlane;
uniform int cube_snapshot;
uniform float sky_hdr_scale;
void main()
{
vec2 tc = vary_fragcoord.xy;
float depth = getDepth(tc.xy);
vec4 pos = getPositionWithDepth(tc, depth);
vec4 norm = getNorm(tc);
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
vec3 color = vec3(0);
float bloom = 0.0;
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten);
// mask off atmospherics below water (when camera is under water)
bool do_atmospherics = false;
if (dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0 ||
dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0)
{
do_atmospherics = true;
}
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
if (depth >= 1.0)
{
//should only be true of sky, clouds, sun/moon, and stars
discard;
}
float alpha = 0.0;
if (do_atmospherics)
{
alpha = atten.r;
color = srgb_to_linear(additive*2.0);
color *= sky_hdr_scale;
}
else
{
color = vec3(0,0,0);
alpha = 1.0;
}
frag_color = max(vec4(color.rgb, alpha), vec4(0)); //output linear since local lights will be added to this shader's results
}
@@ -0,0 +1,445 @@
/**
* @file materialF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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]*/
//class1/deferred/materialF.glsl
// This shader is used for both writing opaque/masked content to the gbuffer and writing blended content to the framebuffer during the alpha pass.
#define DIFFUSE_ALPHA_MODE_NONE 0
#define DIFFUSE_ALPHA_MODE_BLEND 1
#define DIFFUSE_ALPHA_MODE_MASK 2
#define DIFFUSE_ALPHA_MODE_EMISSIVE 3
uniform float emissive_brightness; // fullbright flag, 1.0 == fullbright, 0.0 otherwise
uniform int sun_up_factor;
uniform int classic_mode;
vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
vec3 scaleSoftClipFragLinear(vec3 l);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
vec3 srgb_to_linear(vec3 cs);
vec3 linear_to_srgb(vec3 cs);
uniform mat4 modelview_matrix;
uniform mat3 normal_matrix;
in vec3 vary_position;
void mirrorClip(vec3 pos);
vec4 encodeNormal(vec3 n, float env, float gbuffer_flag);
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
out vec4 frag_color;
#ifdef HAS_SUN_SHADOW
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
#endif
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
uniform samplerCube environmentMap;
uniform sampler2D lightFunc;
// Inputs
uniform vec4 morphFactor;
uniform vec3 camPosLocal;
uniform mat3 env_mat;
uniform float is_mirror;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
uniform mat4 proj_mat;
uniform mat4 inv_proj;
uniform vec2 screen_res;
uniform vec4 light_position[8];
uniform vec3 light_direction[8];
uniform vec4 light_attenuation[8];
uniform vec3 light_diffuse[8];
float getAmbientClamp();
void waterClip(vec3 pos);
vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance)
{
// SL-14895 inverted attenuation work-around
// This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct
// that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights()
// to recover the `adjusted_radius` value previously being sent as la.
float falloff_factor = (12.0 * fa) - 9.0;
float inverted_la = falloff_factor / la;
// Yes, it makes me want to cry as well. DJH
vec3 col = vec3(0);
//get light vector
vec3 lv = lp.xyz - v;
//get distance
float dist = length(lv);
float da = 1.0;
dist /= inverted_la;
if (dist > 0.0 && inverted_la > 0.0)
{
//normalize light vector
lv = normalize(lv);
//distance attenuation
float dist_atten = clamp(1.0 - (dist - 1.0*(1.0 - fa)) / fa, 0.0, 1.0);
dist_atten *= dist_atten;
dist_atten *= 2.0f;
if (dist_atten <= 0.0)
{
return col;
}
// spotlight coefficient.
float spot = max(dot(-ln, lv), is_pointlight);
da *= spot*spot; // GL_SPOT_EXPONENT=2
//angular attenuation
da *= dot(n, lv);
float lit = 0.0f;
float amb_da = ambiance;
if (da >= 0)
{
lit = clamp(da * dist_atten, 0.0, 1.0);
col = lit * light_col * diffuse;
amb_da += (da*0.5 + 0.5) * ambiance;
}
amb_da += (da*da*0.5 + 0.5) * ambiance;
amb_da *= dist_atten;
amb_da = min(amb_da, 1.0f - lit);
// SL-10969 need to see why these are blown out
//col.rgb += amb_da * light_col * diffuse;
if (spec.a > 0.0)
{
//vec3 ref = dot(pos+lv, norm);
vec3 h = normalize(lv + npos);
float nh = dot(n, h);
float nv = dot(n, npos);
float vh = dot(npos, h);
float sa = nh;
float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5;
float gtdenom = 2 * nh;
float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
if (nh > 0.0)
{
float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da);
vec3 speccol = lit*scol*light_col.rgb*spec.rgb;
speccol = clamp(speccol, vec3(0), vec3(1));
col += speccol;
float cur_glare = max(speccol.r, speccol.g);
cur_glare = max(cur_glare, speccol.b);
glare = max(glare, speccol.r);
glare += max(cur_glare, 0.0);
}
}
}
float final_scale = 1.0;
if (classic_mode > 0)
final_scale = 0.9;
return max(col * final_scale, vec3(0.0, 0.0, 0.0));
}
#else
out vec4 frag_data[4];
#endif
uniform sampler2D diffuseMap; //always in sRGB space
#ifdef HAS_NORMAL_MAP
uniform sampler2D bumpMap;
#endif
#ifdef HAS_SPECULAR_MAP
uniform sampler2D specularMap;
in vec2 vary_texcoord2;
#endif
uniform float env_intensity;
uniform vec4 specular_color; // specular color RGB and specular exponent (glossiness) in alpha
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
uniform float minimum_alpha;
#endif
#ifdef HAS_NORMAL_MAP
in vec3 vary_normal;
in vec3 vary_tangent;
flat in float vary_sign;
in vec2 vary_texcoord1;
#else
in vec3 vary_normal;
#endif
in vec4 vertex_color;
in vec2 vary_texcoord0;
// get the transformed normal and apply glossiness component from normal map
vec3 getNormal(inout float glossiness)
{
#ifdef HAS_NORMAL_MAP
vec4 vNt = texture(bumpMap, vary_texcoord1.xy);
glossiness *= vNt.a;
vNt.xyz = vNt.xyz * 2 - 1;
float sign = vary_sign;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
vec3 vB = sign * cross(vN, vT);
vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
return tnorm;
#else
return normalize(vary_normal);
#endif
}
vec4 getSpecular()
{
#ifdef HAS_SPECULAR_MAP
vec4 spec = texture(specularMap, vary_texcoord2.xy);
spec.rgb *= specular_color.rgb;
#else
vec4 spec = vec4(specular_color.rgb, 1.0);
#endif
return spec;
}
void alphaMask(float alpha)
{
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
// Comparing floats cast from 8-bit values, produces acne right at the 8-bit transition points
float bias = 0.001953125; // 1/512, or half an 8-bit quantization
if (alpha < minimum_alpha-bias)
{
discard;
}
#endif
}
void waterClip()
{
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
waterClip(vary_position.xyz);
#endif
}
float getEmissive(vec4 diffcol)
{
#if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE)
return emissive_brightness;
#else
return max(diffcol.a, emissive_brightness);
#endif
}
float getShadow(vec3 pos, vec3 norm)
{
#ifdef HAS_SUN_SHADOW
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
return sampleDirectionalShadow(pos, norm, vary_texcoord0.xy);
#else
return 1;
#endif
#else
return 1;
#endif
}
void main()
{
mirrorClip(vary_position);
waterClip();
// diffcol == diffuse map combined with vertex color
vec4 diffcol = texture(diffuseMap, vary_texcoord0.xy);
diffcol.rgb *= vertex_color.rgb;
alphaMask(diffcol.a);
// spec == specular map combined with specular color
vec4 spec = getSpecular();
float env = env_intensity * spec.a;
float glossiness = specular_color.a;
vec3 norm = getNormal(glossiness);
float emissive = getEmissive(diffcol);
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
//forward rendering, output lit linear color
diffcol.rgb = srgb_to_linear(diffcol.rgb);
spec.rgb = srgb_to_linear(spec.rgb);
spec.a = glossiness; // pack glossiness into spec alpha for lighting functions
vec3 pos = vary_position;
float shadow = getShadow(pos, norm);
vec4 diffuse = diffcol;
vec3 color = vec3(0,0,0);
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
float bloom = 0.0;
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten);
if (classic_mode > 0)
sunlit *= 1.35;
vec3 sunlit_linear = sunlit;
vec3 amblit_linear = amblit;
vec3 ambenv = amblit;
vec3 glossenv;
vec3 legacyenv;
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xy*0.5+0.5, pos.xyz, norm.xyz, glossiness, env, true, amblit_linear);
color = ambenv;
float da = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0);
if (classic_mode > 0)
{
da = pow(da,1.2);
vec3 sun_contrib = vec3(min(da, shadow));
color.rgb = srgb_to_linear(color.rgb * 0.9 + linear_to_srgb(sun_contrib) * sunlit_linear * 0.7);
sunlit_linear = srgb_to_linear(sunlit_linear);
}
else
{
vec3 sun_contrib = min(da, shadow) * sunlit_linear;
color.rgb += sun_contrib;
}
color *= diffcol.rgb;
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
float glare = 0.0;
if (glossiness > 0.0)
{
vec3 lv = light_dir.xyz;
vec3 h, l, v = -normalize(pos.xyz);
float nh, nl, nv, vh, lightDist;
vec3 n = norm.xyz;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
if (nl > 0.0 && nh > 0.0)
{
float lit = min(nl*6.0, 1.0);
float sa = nh;
float fres = pow(1 - vh, 5) * 0.4+0.5;
float gtdenom = 2 * nh;
float gt = max(0,(min(gtdenom * nv / vh, gtdenom * nl / vh)));
float scol = shadow*fres*texture(lightFunc, vec2(nh, glossiness)).r*gt/(nh*nl);
color.rgb += lit*scol*sunlit_linear.rgb*spec.rgb;
}
// add radiance map
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
}
color = mix(color.rgb, diffcol.rgb, emissive);
if (env > 0.0)
{ // add environmentmap
applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, env);
float cur_glare = max(max(legacyenv.r, legacyenv.g), legacyenv.b);
cur_glare = clamp(cur_glare, 0, 1);
cur_glare *= env;
glare += cur_glare;
}
vec3 npos = normalize(-pos.xyz);
vec3 light = vec3(0, 0, 0);
#define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, spec, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare, light_attenuation[i].w );
LIGHT_LOOP(1)
LIGHT_LOOP(2)
LIGHT_LOOP(3)
LIGHT_LOOP(4)
LIGHT_LOOP(5)
LIGHT_LOOP(6)
LIGHT_LOOP(7)
color += light;
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
glare *= 1.0-emissive;
glare = min(glare, 1.0);
float al = max(diffcol.a, glare) * vertex_color.a;
float final_scale = 1;
if (classic_mode > 0)
final_scale = 1.1;
frag_color = max(vec4(color * final_scale, al), vec4(0));
#else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer
// deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl
float flag = GBUFFER_FLAG_HAS_ATMOS;
frag_data[0] = max(vec4(diffcol.rgb, emissive), vec4(0)); // gbuffer is sRGB for legacy materials
frag_data[1] = max(vec4(spec.rgb, glossiness), vec4(0)); // XYZ = Specular color. W = Specular exponent.
frag_data[2] = encodeNormal(norm, env, flag); // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
#if defined(HAS_EMISSIVE)
frag_data[3] = vec4(0, 0, 0, 0);
#endif
#endif
}
@@ -0,0 +1,187 @@
/**
* @file class3\deferred\multiPointLightF.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 sampler2D lightFunc;
uniform vec3 env_mat[3];
uniform float sun_wash;
uniform int light_count;
uniform vec4 light[LIGHT_COUNT]; // .w = size; see C++ fullscreen_lights.push_back()
uniform vec4 light_col[LIGHT_COUNT]; // .a = falloff
uniform vec2 screen_res;
uniform float far_z;
uniform mat4 inv_proj;
uniform int classic_mode;
in vec4 vary_fragcoord;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
vec4 getPosition(vec2 pos_screen);
vec4 getNorm(vec2 screenpos);
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 c);
// Util
vec3 hue_to_rgb(float hue);
void pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
vec3 l, // surface point to light
out float nl,
out vec3 diff,
out vec3 spec);
GBufferInfo getGBuffer(vec2 screenpos);
void main()
{
vec3 final_color = vec3(0, 0, 0);
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
if (pos.z < far_z)
{
discard;
}
GBufferInfo gb = getGBuffer(tc);
vec3 n = gb.normal;
vec4 spec = gb.specular;
vec3 diffuse = gb.albedo.rgb;
vec3 h, l, v = -normalize(pos);
float nh, nv, vh, lightDist;
if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_HAS_PBR))
{
vec3 colorEmissive = gb.emissive.rgb;
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
vec3 f0 = vec3(0.04);
vec3 baseColor = diffuse.rgb;
vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
diffuseColor *= 1.0 - metallic;
vec3 specularColor = mix(f0, baseColor.rgb, metallic);
for (int light_idx = 0; light_idx < LIGHT_COUNT; ++light_idx)
{
vec3 lightColor = light_col[ light_idx ].rgb; // Already in linear, see pipeline.cpp: volume->getLightLinearColor();
float falloff = light_col[ light_idx ].a;
float lightSize = light[ light_idx ].w;
vec3 lv = light[ light_idx ].xyz - pos;
lightDist = length(lv);
float dist = lightDist / lightSize;
if (dist <= 1.0)
{
lv /= lightDist;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
vec3 intensity = dist_atten * lightColor * 3.25;
float nl = 0;
vec3 diff = vec3(0);
vec3 specPunc = vec3(0);
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv, nl, diff, specPunc);
final_color += intensity * clamp(nl * (diff + specPunc), vec3(0), vec3(10));
}
}
}
else
{
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
// As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
for (int i = 0; i < LIGHT_COUNT; ++i)
{
vec3 lv = light[i].xyz - pos;
float dist = length(lv);
dist /= light[i].w;
if (dist <= 1.0)
{
float nl = dot(n, lv);
if (nl > 0.0)
{
float lightDist;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
float fa = light_col[i].a;
float dist_atten = calcLegacyDistanceAttenuation(dist, fa);
float lit = nl * dist_atten;
vec3 col = light_col[i].rgb * lit * diffuse;
if (spec.a > 0.0)
{
lit = min(nl * 6.0, 1.0) * dist_atten;
float fres = pow(1 - vh, 5) * 0.4 + 0.5;
float gtdenom = 2 * nh;
float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh));
if (nh > 0.0)
{
float scol = fres * texture(lightFunc, vec2(nh, spec.a)).r * gt / (nh * nl);
col += lit * scol * light_col[i].rgb * spec.rgb;
}
}
final_color += col;
}
}
}
}
float final_scale = 1.0;
if (classic_mode > 0)
final_scale = 0.9;
frag_color.rgb = max(final_color * final_scale, vec3(0));
frag_color.a = 0.0;
#ifdef IS_AMD_CARD
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage
// away which leads to unfun crashes and artifacts.
vec4 dummy1 = light[0];
vec4 dummy2 = light_col[0];
vec4 dummy3 = light[LIGHT_COUNT - 1];
vec4 dummy4 = light_col[LIGHT_COUNT - 1];
#endif
}
@@ -0,0 +1,37 @@
/**
* @file class3\deferred\multiPointLightV.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$
*/
in vec3 position;
out vec4 vary_fragcoord;
void main()
{
//transform vertex
vec4 pos = vec4(position.xyz, 1.0);
vary_fragcoord = pos;
gl_Position = pos;
}
@@ -0,0 +1,158 @@
/**
* @file class3\deferred\pointLightF.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 sampler2D lightFunc;
uniform vec3 env_mat[3];
uniform float sun_wash;
// light params
uniform vec3 color;
uniform float falloff;
uniform float size;
in vec4 vary_fragcoord;
in vec3 trans_center;
uniform vec2 screen_res;
uniform mat4 inv_proj;
uniform vec4 viewport;
uniform int classic_mode;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
vec4 getNorm(vec2 screenpos);
vec4 getPosition(vec2 pos_screen);
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 c);
float getDepth(vec2 tc);
void pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
vec3 l, // surface point to light
out float nl,
out vec3 diff,
out vec3 spec);
GBufferInfo getGBuffer(vec2 screenpos);
void main()
{
vec3 final_color = vec3(0);
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
GBufferInfo gb = getGBuffer(tc);
vec3 n = gb.normal;
vec3 diffuse = gb.albedo.rgb;
vec4 spec = gb.specular;
// Common half vectors calcs
vec3 lv = trans_center.xyz-pos;
vec3 h, l, v = -normalize(pos);
float nh, nl, nv, vh, lightDist;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
if (lightDist >= size)
{
discard;
}
float dist = lightDist / size;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_HAS_PBR))
{
vec3 colorEmissive = gb.emissive.rgb;
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
vec3 f0 = vec3(0.04);
vec3 baseColor = diffuse.rgb;
vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
diffuseColor *= 1.0 - metallic;
vec3 specularColor = mix(f0, baseColor.rgb, metallic);
vec3 intensity = dist_atten * color * 3.25; // Legacy attenuation, magic number to balance with legacy materials
float nl = 0;
vec3 diffPunc = vec3(0);
vec3 specPunc = vec3(0);
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv), nl, diffPunc, specPunc);
final_color += intensity* clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10));
}
else
{
if (nl < 0.0)
{
discard;
}
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
float lit = nl * dist_atten;
final_color = color.rgb*lit*diffuse;
if (spec.a > 0.0)
{
lit = min(nl*6.0, 1.0) * dist_atten;
float sa = nh;
float fres = pow(1 - vh, 5) * 0.4+0.5;
float gtdenom = 2 * nh;
float gt = max(0,(min(gtdenom * nv / vh, gtdenom * nl / vh)));
if (nh > 0.0)
{
float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl);
final_color += lit*scol*color.rgb*spec.rgb;
}
}
if (dot(final_color, final_color) <= 0.0)
{
discard;
}
}
float final_scale = 1.0;
if (classic_mode > 0)
final_scale = 0.9;
frag_color.rgb = max(final_color * final_scale, vec3(0));
frag_color.a = 0.0;
}
@@ -0,0 +1,45 @@
/**
* @file class3\deferred\pointLightV.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$
*/
uniform mat4 modelview_projection_matrix;
uniform mat4 modelview_matrix;
in vec3 position;
uniform vec3 center;
uniform float size;
out vec4 vary_fragcoord;
out vec3 trans_center;
void main()
{
//transform vertex
vec3 p = position*size+center;
vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0);
vary_fragcoord = pos;
trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz;
gl_Position = pos;
}
@@ -0,0 +1,914 @@
/**
* @file class3/deferred/reflectionProbeF.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$
*/
#define FLT_MAX 3.402823466e+38
#if defined(SSR)
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness);
#endif
uniform samplerCubeArray reflectionProbes;
uniform samplerCubeArray irradianceProbes;
uniform sampler2D sceneMap;
uniform int cube_snapshot;
uniform float max_probe_lod;
uniform bool transparent_surface;
uniform int classic_mode;
#define MAX_REFMAP_COUNT 256 // must match LL_MAX_REFLECTION_PROBE_COUNT
layout (std140) uniform ReflectionProbes
{
// list of OBBs for user override probes
// box is a set of 3 planes outward facing planes and the depth of the box along that plane
// for each box refBox[i]...
/// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation
// box[3][0..2] - plane thickness
mat4 refBox[MAX_REFMAP_COUNT];
mat4 heroBox;
// list of bounding spheres for reflection probes sorted by distance to camera (closest first)
vec4 refSphere[MAX_REFMAP_COUNT];
// extra parameters
// x - irradiance scale
// y - radiance scale
// z - fade in
// w - znear
vec4 refParams[MAX_REFMAP_COUNT];
vec4 heroSphere;
// index of cube map in reflectionProbes for a corresponding reflection probe
// e.g. cube map channel of refSphere[2] is stored in refIndex[2]
// refIndex.x - cubemap channel in reflectionProbes
// refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
// refIndex.z - number of neighbors
// refIndex.w - priority, if negative, this probe has a box influence
ivec4 refIndex[MAX_REFMAP_COUNT];
// neighbor list data (refSphere indices, not cubemap array layer)
ivec4 refNeighbor[1024];
ivec4 refBucket[256];
// number of reflection probes present in refSphere
int refmapCount;
int heroShape;
int heroMipCount;
int heroProbeCount;
};
// Inputs
uniform mat3 env_mat;
// list of probeIndexes shader will actually use after "getRefIndex" is called
// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
int probeIndex[REF_SAMPLE_COUNT];
// number of probes stored in probeIndex
int probeInfluences = 0;
bool isAbove(vec3 pos, vec4 plane)
{
return (dot(plane.xyz, pos) + plane.w) > 0;
}
bool sample_automatic = true;
// return true if probe at index i influences position pos
bool shouldSampleProbe(int i, vec3 pos)
{
if (refIndex[i].w < 0)
{
vec4 v = refBox[i] * vec4(pos, 1.0);
if (abs(v.x) > 1 ||
abs(v.y) > 1 ||
abs(v.z) > 1)
{
return false;
}
// never allow automatic probes to encroach on box probes
sample_automatic = false;
}
else
{
if (refIndex[i].w == 0 && !sample_automatic)
{
return false;
}
vec3 delta = pos.xyz - refSphere[i].xyz;
float d = dot(delta, delta);
float r2 = refSphere[i].w;
r2 *= r2;
if (d > r2)
{ // outside bounding sphere
return false;
}
}
return true;
}
int getStartIndex(vec3 pos)
{
#if 1
int idx = clamp(int(floor(-pos.z)), 0, 255);
return clamp(refBucket[idx].x, 1, refmapCount+1);
#else
return 1;
#endif
}
// call before sampleRef
// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
void preProbeSample(vec3 pos)
{
#if REFMAP_LEVEL > 0
int start = getStartIndex(pos);
// TODO: make some sort of structure that reduces the number of distance checks
for (int i = start; i < refmapCount; ++i)
{
// found an influencing probe
if (shouldSampleProbe(i, pos))
{
probeIndex[probeInfluences] = i;
++probeInfluences;
int neighborIdx = refIndex[i].y;
if (neighborIdx != -1)
{
int neighborCount = refIndex[i].z;
int count = 0;
while (count < neighborCount)
{
// check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
// sample refNeighbor[neighborIdx].x
int idx = refNeighbor[neighborIdx].x;
if (shouldSampleProbe(idx, pos))
{
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
break;
}
}
count++;
if (count == neighborCount)
{
break;
}
// sample refNeighbor[neighborIdx].y
idx = refNeighbor[neighborIdx].y;
if (shouldSampleProbe(idx, pos))
{
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
break;
}
}
count++;
if (count == neighborCount)
{
break;
}
// sample refNeighbor[neighborIdx].z
idx = refNeighbor[neighborIdx].z;
if (shouldSampleProbe(idx, pos))
{
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
break;
}
}
count++;
if (count == neighborCount)
{
break;
}
// sample refNeighbor[neighborIdx].w
idx = refNeighbor[neighborIdx].w;
if (shouldSampleProbe(idx, pos))
{
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
break;
}
}
count++;
++neighborIdx;
}
break;
}
}
}
if (sample_automatic)
{ // probe at index 0 is a special probe for smoothing out automatic probes
probeIndex[probeInfluences++] = 0;
}
#else
probeIndex[probeInfluences++] = 0;
#endif
}
// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
// original reference implementation:
/*
bool intersect(const Ray &ray) const
{
float t0, t1; // solutions for t if the ray intersects
#if 0
// geometric solution
Vec3f L = center - orig;
float tca = L.dotProduct(dir);
// if (tca < 0) return false;
float d2 = L.dotProduct(L) - tca * tca;
if (d2 > radius2) return false;
float thc = sqrt(radius2 - d2);
t0 = tca - thc;
t1 = tca + thc;
#else
// analytic solution
Vec3f L = orig - center;
float a = dir.dotProduct(dir);
float b = 2 * dir.dotProduct(L);
float c = L.dotProduct(L) - radius2;
if (!solveQuadratic(a, b, c, t0, t1)) return false;
#endif
if (t0 > t1) std::swap(t0, t1);
if (t0 < 0) {
t0 = t1; // if t0 is negative, let's use t1 instead
if (t0 < 0) return false; // both t0 and t1 are negative
}
t = t0;
return true;
} */
// adapted -- assume that origin is inside sphere, return intersection of ray with edge of sphere
vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
{
float t0, t1; // solutions for t if the ray intersects
vec3 L = center - origin;
float tca = dot(L,dir);
float d2 = dot(L,L) - tca * tca;
float thc = sqrt(radius2 - d2);
t0 = tca - thc;
t1 = tca + thc;
vec3 v = origin + dir * t1;
return v;
}
void swap(inout float a, inout float b)
{
float t = a;
a = b;
b = a;
}
// debug implementation, make no assumptions about origin
void sphereIntersectDebug(vec3 origin, vec3 dir, vec3 center, float radius2, float depth, inout vec4 col)
{
float t[2]; // solutions for t if the ray intersects
// geometric solution
vec3 L = center - origin;
float tca = dot(L, dir);
// if (tca < 0) return false;
float d2 = dot(L, L) - tca * tca;
if (d2 > radius2) return;
float thc = sqrt(radius2 - d2);
t[0] = tca - thc;
t[1] = tca + thc;
for (int i = 0; i < 2; ++i)
{
if (t[i] > 0)
{
if (t[i] > depth)
{
float w = 0.125/((t[i]-depth)*0.125 + 1.0);
col += vec4(0, 0, w, w)*(1.0-min(col.a, 1.0));
}
else
{
float w = 0.25;
col += vec4(w,w,0,w)*(1.0-min(col.a, 1.0));
}
}
}
}
// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
/*
vec3 DirectionWS = normalize(PositionWS - CameraWS);
vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS);
// Intersection with OBB convertto unit box space
// Transform in local unit parallax cube space (scaled and rotated)
vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS);
vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS);
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
// Use Distance in WS directly to recover intersection
vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance;
vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS;
return texCUBE(envMap, ReflDirectionWS);
*/
// get point of intersection with given probe's box influence volume
// origin - ray origin in clip space
// dir - ray direction in clip space
// i - probe index in refBox/refSphere
// d - distance to nearest wall in clip space
// scale - scale of box, default 1.0
vec3 boxIntersect(vec3 origin, vec3 dir, mat4 i, out float d, float scale)
{
// Intersection with OBB convert to unit box space
// Transform in local unit parallax cube space (scaled and rotated)
mat4 clipToLocal = i;
vec3 RayLS = mat3(clipToLocal) * dir;
vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
d = 1.0-max(max(abs(PositionLS.x), abs(PositionLS.y)), abs(PositionLS.z));
vec3 Unitary = vec3(scale);
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
// Use Distance in CS directly to recover intersection
vec3 IntersectPositionCS = origin + dir * Distance;
return IntersectPositionCS;
}
vec3 boxIntersect(vec3 origin, vec3 dir, mat4 i, out float d)
{
return boxIntersect(origin, dir, i, d, 1.0);
}
void debugBoxCol(vec3 ro, vec3 rd, float t, vec3 p, inout vec4 col)
{
vec3 v = ro + rd * t;
v -= ro;
vec3 pos = p - ro;
bool behind = dot(v,v) > dot(pos,pos);
float w = 0.25;
if (behind)
{
w *= 0.5;
w /= (length(v)-length(pos))*0.5+1.0;
col += vec4(0,0,w,w)*(1.0-min(col.a, 1.0));
}
else
{
col += vec4(w,w,0,w)*(1.0-min(col.a, 1.0));
}
}
// cribbed from https://iquilezles.org/articles/intersectors/
// axis aligned box centered at the origin, with size boxSize
void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col)
{
vec3 rd = normalize(p-ro);
vec3 m = 1.0/rd; // can precompute if traversing a set of aligned boxes
vec3 n = m*ro; // can precompute if traversing a set of aligned boxes
vec3 k = abs(m)*boxSize;
vec3 t1 = -n - k;
vec3 t2 = -n + k;
float tN = max( max( t1.x, t1.y ), t1.z );
float tF = min( min( t2.x, t2.y ), t2.z );
if( tN>tF || tF<0.0) return ; // no intersection
float t = tN < 0 ? tF : tN;
debugBoxCol(ro, rd, t, p, col);
if (tN > 0) // eye is outside box, check backside, too
{
debugBoxCol(ro, rd, tF, p, col);
}
}
void boxIntersectDebug(vec3 origin, vec3 pos, mat4 i, inout vec4 col)
{
mat4 clipToLocal = i;
// transform into unit cube space
origin = (clipToLocal * vec4(origin, 1.0)).xyz;
pos = (clipToLocal * vec4(pos, 1.0)).xyz;
boxIntersectionDebug(origin, pos, vec3(1), col);
}
// get the weight of a sphere probe
// pos - position to be weighted
// dir - normal to be weighted
// origin - center of sphere probe
// r - radius of probe influence volume
// i - index of probe in refSphere
// dw - distance weight
float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, vec4 i, out float dw)
{
float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz - origin;
float d2 = max(length(delta), 0.001);
float atten = 1.0 - max(d2 - r1, 0.0) / max((r - r1), 0.001);
float w = 1.0 / d2;
w *= i.z;
dw = w * atten * max(r, 1.0)*4;
w *= atten;
return w;
}
// Tap a reflection probe
// pos - position of pixel
// dir - pixel normal
// w - weight of sample (distance and angular attenuation)
// dw - weight of sample (distance only)
// lod - which mip to sample (lower is higher res, sharper reflections)
// c - center of probe
// r2 - radius of probe squared
// i - index of probe
vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, float lod, vec3 c, int i)
{
// parallax adjustment
vec3 v;
if (refIndex[i].w < 0)
{ // box probe
float d = 0;
v = boxIntersect(pos, dir, refBox[i], d);
w = max(d, 0.001);
}
else
{ // sphere probe
float r = refSphere[i].w;
float rr = r * r;
v = sphereIntersect(pos, dir, c,
refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
w = sphereWeight(pos, dir, refSphere[i].xyz, r, refParams[i], dw);
}
v -= c;
vec3 d = normalize(v);
v = env_mat * v;
vec4 ret = textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), lod) * refParams[i].y;
return ret.rgb;
}
// Tap an irradiance map
// pos - position of pixel
// dir - pixel normal
// w - weight of sample (distance and angular attenuation)
// dw - weight of sample (distance only)
// i - index of probe
vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int i, vec3 amblit)
{
// parallax adjustment
vec3 v;
if (refIndex[i].w < 0)
{
float d = 0.0;
v = boxIntersect(pos, dir, refBox[i], d, 3.0);
w = max(d, 0.001);
}
else
{
float r = refSphere[i].w; // radius of sphere volume
// pad sphere for manual probe extending into automatic probe space
float rr = r * r;
v = sphereIntersect(pos, dir, c,
refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
w = sphereWeight(pos, dir, refSphere[i].xyz, r, refParams[i], dw);
}
v -= c;
v = env_mat * v;
vec3 col = textureLod(irradianceProbes, vec4(v.xyz, refIndex[i].x), 0).rgb * refParams[i].x;
col = mix(amblit, col, min(refParams[i].x, 1.0));
return col;
}
vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
{
float wsum[2];
wsum[0] = 0;
wsum[1] = 0;
float dwsum[2];
dwsum[0] = 0;
dwsum[1] = 0;
vec3 col[2];
col[0] = vec3(0);
col[1] = vec3(0);
for (int idx = 0; idx < probeInfluences; ++idx)
{
int i = probeIndex[idx];
int p = clamp(abs(refIndex[i].w), 0, 1);
if (p == 0 && !sample_automatic)
{
continue;
}
float w = 0;
float dw = 0;
vec3 refcol;
{
refcol = tapRefMap(pos, dir, w, dw, lod, refSphere[i].xyz, i);
col[p] += refcol.rgb*w;
wsum[p] += w;
dwsum[p] += dw;
}
}
// mix automatic and manual probes
if (sample_automatic && wsum[0] > 0.0)
{ // some automatic probes were sampled
col[0] *= 1.0/wsum[0];
if (wsum[1] > 0.0)
{ //some manual probes were sampled, mix between the two
col[1] *= 1.0/wsum[1];
col[1] = mix(col[0], col[1], min(dwsum[1], 1.0));
col[0] = vec3(0);
}
}
else if (wsum[1] > 0.0)
{
// manual probes were sampled but no automatic probes were
col[1] *= 1.0/wsum[1];
col[0] = vec3(0);
}
return col[1]+col[0];
}
vec3 sampleProbeAmbient(vec3 pos, vec3 dir, vec3 amblit)
{
// modified copy/paste of sampleProbes follows, will likely diverge from sampleProbes further
// as irradiance map mixing is tuned independently of radiance map mixing
float wsum[2];
wsum[0] = 0;
wsum[1] = 0;
float dwsum[2];
dwsum[0] = 0;
dwsum[1] = 0;
vec3 col[2];
col[0] = vec3(0);
col[1] = vec3(0);
for (int idx = 0; idx < probeInfluences; ++idx)
{
int i = probeIndex[idx];
int p = clamp(abs(refIndex[i].w), 0, 1);
if (p == 0 && !sample_automatic)
{
continue;
}
{
float w = 0;
float dw = 0;
vec3 refcol = tapIrradianceMap(pos, dir, w, dw, refSphere[i].xyz, i, amblit);
col[p] += refcol*w;
wsum[p] += w;
dwsum[p] += dw;
}
}
// mix automatic and manual probes
if (sample_automatic && wsum[0] > 0.0)
{ // some automatic probes were sampled
col[0] *= 1.0/wsum[0];
if (wsum[1] > 0.0)
{ //some manual probes were sampled, mix between the two
col[1] *= 1.0/wsum[1];
col[1] = mix(col[0], col[1], min(dwsum[1], 1.0));
col[0] = vec3(0);
}
}
else if (wsum[1] > 0.0)
{
// manual probes were sampled but no automatic probes were
col[1] *= 1.0/wsum[1];
col[0] = vec3(0);
}
return col[1]+col[0];
}
#if defined(HERO_PROBES)
uniform vec4 clipPlane;
uniform samplerCubeArray heroProbes;
void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness)
{
float clipDist = dot(pos.xyz, clipPlane.xyz) + clipPlane.w;
float w = 0;
float dw = 0;
float falloffMult = 10;
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
if (heroShape < 1)
{
float d = 0;
boxIntersect(pos, norm, heroBox, d, 1.0);
w = max(d, 0);
}
else
{
float r = heroSphere.w;
w = sphereWeight(pos, refnormpersp, heroSphere.xyz, r, vec4(1), dw);
}
clipDist = clipDist * 0.95 + 0.05;
clipDist = clamp(clipDist * falloffMult, 0, 1);
w = clamp(w * falloffMult * clipDist, 0, 1);
w = mix(0, w, clamp(glossiness - 0.75, 0, 1) * 4); // We only generate a quarter of the mips for the hero probes. Linearly interpolate between normal probes and hero probes based upon glossiness.
glossenv = mix(glossenv, textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0-glossiness)*heroMipCount).xyz, w);
}
#else
void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness)
{
}
#endif
void doProbeSample(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit)
{
// TODO - don't hard code lods
float reflection_lods = max_probe_lod;
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
ambenv = amblit;
if (classic_mode == 0)
ambenv = sampleProbeAmbient(pos, norm, amblit);
float lod = (1.0-glossiness)*reflection_lods;
glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
#if defined(SSR)
if (cube_snapshot != 1 && glossiness >= 0.9)
{
vec4 ssr = vec4(0);
if (transparent)
{
tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap, 1);
ssr.a *= glossiness;
}
else
{
tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap, glossiness);
}
glossenv = mix(glossenv, ssr.rgb, ssr.a);
}
#endif
tapHeroProbe(glossenv, pos, norm, glossiness);
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit)
{
preProbeSample(pos);
doProbeSample(ambenv, glossenv, tc, pos, norm, glossiness, transparent, amblit);
}
void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, vec3 amblit)
{
// don't sample automatic probes for water
sample_automatic = false;
preProbeSample(pos);
sample_automatic = true;
// always include void probe on water
probeIndex[probeInfluences++] = 0;
doProbeSample(ambenv, glossenv, tc, pos, norm, glossiness, false, amblit);
}
void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col)
{
vec3 origin = vec3(0,0,0);
bool manual_probe = abs(refIndex[i].w) > 0;
if (manual_probe)
{
if (refIndex[i].w < 0)
{
boxIntersectDebug(origin, pos, refBox[i], col);
}
else
{
float r = refSphere[i].w; // radius of sphere volume
float rr = r * r; // radius squared
float t = 0.0;
sphereIntersectDebug(origin, dir, refSphere[i].xyz, rr, depth, col);
}
}
}
vec4 sampleReflectionProbesDebug(vec3 pos)
{
vec4 col = vec4(0,0,0,0);
vec3 dir = normalize(pos);
float d = length(pos);
for (int i = 1; i < refmapCount; ++i)
{
debugTapRefMap(pos, dir, d, i, col);
}
#if 0 //debug getStartIndex
col.g = float(getStartIndex(pos));
col.g /= 255.0;
col.rb = vec2(0);
col.a = 1.0;
#endif
return col;
}
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit)
{
float reflection_lods = max_probe_lod;
preProbeSample(pos);
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
ambenv = amblit;
if (classic_mode == 0)
ambenv = sampleProbeAmbient(pos, norm, amblit);
if (glossiness > 0.0)
{
float lod = (1.0-glossiness)*reflection_lods;
glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
}
if (envIntensity > 0.0)
{
legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0);
}
#if defined(SSR)
if (cube_snapshot != 1)
{
vec4 ssr = vec4(0);
if (transparent)
{
tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap, 1);
ssr.a *= glossiness;
}
else
{
tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap, glossiness);
}
glossenv = mix(glossenv, ssr.rgb, ssr.a);
legacyenv = mix(legacyenv, ssr.rgb, ssr.a);
}
#endif
tapHeroProbe(glossenv, pos, norm, glossiness);
tapHeroProbe(legacyenv, pos, norm, 1.0);
glossenv = clamp(glossenv, vec3(0), vec3(10));
}
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
{
glossenv *= 0.5; // fudge darker
float fresnel = clamp(1.0+dot(normalize(pos.xyz), norm.xyz), 0.3, 1.0);
fresnel *= fresnel;
fresnel *= spec.a;
glossenv *= spec.rgb*fresnel;
glossenv *= vec3(1.0) - color; // fake energy conservation
color.rgb += glossenv*0.5;
}
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
{
vec3 reflected_color = legacyenv;
vec3 lookAt = normalize(pos);
float fresnel = 1.0+dot(lookAt, norm.xyz);
fresnel *= fresnel;
fresnel = min(fresnel+envIntensity, 1.0);
reflected_color *= (envIntensity*fresnel);
color = mix(color.rgb, reflected_color*0.5, envIntensity);
}
@@ -0,0 +1,90 @@
/**
* @file class3/deferred/screenSpaceReflPostF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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 vec2 screen_res;
uniform mat4 projection_matrix;
uniform mat4 inv_proj;
uniform float zNear;
uniform float zFar;
in vec2 vary_fragcoord;
in vec3 camera_ray;
uniform sampler2D specularRect;
uniform sampler2D diffuseRect;
uniform sampler2D diffuseMap;
vec4 getNorm(vec2 screenpos);
float getDepth(vec2 pos_screen);
float linearDepth(float d, float znear, float zfar);
float linearDepth01(float d, float znear, float zfar);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
vec4 getPosition(vec2 pos_screen);
float random (vec2 uv);
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness);
void main()
{
vec2 tc = vary_fragcoord.xy;
float depth = linearDepth01(getDepth(tc), zNear, zFar);
vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG()
vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz;
vec4 spec = texture(specularRect, tc);
vec2 hitpixel;
vec4 diffuse = texture(diffuseRect, tc);
vec3 specCol = spec.rgb;
vec4 fcol = texture(diffuseMap, tc);
if (GET_GBUFFER_FLAG(norm.w, GBUFFER_FLAG_HAS_PBR))
{
vec3 orm = specCol.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
vec3 f0 = vec3(0.04);
vec3 baseColor = diffuse.rgb;
vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
specCol = mix(f0, baseColor.rgb, metallic);
}
vec4 collectedColor = vec4(0);
float w = tapScreenSpaceReflection(4, tc, pos, norm.xyz, collectedColor, diffuseMap, 0.f);
collectedColor.rgb *= specCol.rgb;
fcol += collectedColor * w;
frag_color = max(fcol, vec4(0));
}
@@ -0,0 +1,48 @@
/**
* @file class3/deferred/screenSpaceReflPostV.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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$
*/
uniform mat4 projection_matrix;
uniform mat4 inv_proj;
in vec3 position;
uniform vec2 screen_res;
out vec2 vary_fragcoord;
out vec3 camera_ray;
void main()
{
//transform vertex
vec4 pos = vec4(position.xyz, 1.0);
gl_Position = pos;
vary_fragcoord = pos.xy * 0.5 + 0.5;
vec4 rayOrig = inv_proj * vec4(pos.xy, 1, 1);
camera_ray = rayOrig.xyz / rayOrig.w;
}
@@ -0,0 +1,394 @@
/**
* @file class3/deferred/screenSpaceReflUtil.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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$
*/
uniform sampler2D sceneMap;
uniform sampler2D sceneDepth;
uniform vec2 screen_res;
uniform mat4 projection_matrix;
//uniform float zNear;
//uniform float zFar;
uniform mat4 inv_proj;
uniform mat4 modelview_delta; // should be transform from last camera space to current camera space
uniform mat4 inv_modelview_delta;
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
float random (vec2 uv)
{
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function
}
// Based off of https://github.com/RoundedGlint585/ScreenSpaceReflection/
// A few tweaks here and there to suit our needs.
vec2 generateProjectedPosition(vec3 pos)
{
vec4 samplePosition = projection_matrix * vec4(pos, 1.f);
samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5;
return samplePosition.xy;
}
bool isBinarySearchEnabled = true;
bool isAdaptiveStepEnabled = true;
bool isExponentialStepEnabled = true;
bool debugDraw = false;
uniform float iterationCount;
uniform float rayStep;
uniform float distanceBias;
uniform float depthRejectBias;
uniform float glossySampleCount;
uniform float adaptiveStepMultiplier;
uniform float noiseSine;
float epsilon = 0.1;
float getLinearDepth(vec2 tc)
{
float depth = texture(sceneDepth, tc).r;
vec4 pos = getPositionWithDepth(tc, depth);
return -pos.z;
}
bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame)
{
// transform position and reflection into same coordinate frame as the sceneMap and sceneDepth
reflection += position;
position = (inv_modelview_delta * vec4(position, 1)).xyz;
reflection = (inv_modelview_delta * vec4(reflection, 1)).xyz;
reflection -= position;
depth = -position.z;
vec3 step = rayStep * reflection;
vec3 marchingPosition = position + step;
float delta;
float depthFromScreen;
vec2 screenPosition;
bool hit = false;
hitColor = vec4(0);
int i = 0;
if (depth > depthRejectBias)
{
for (; i < iterationCount && !hit; i++)
{
screenPosition = generateProjectedPosition(marchingPosition);
if (screenPosition.x > 1 || screenPosition.x < 0 ||
screenPosition.y > 1 || screenPosition.y < 0)
{
hit = false;
break;
}
depthFromScreen = getLinearDepth(screenPosition);
delta = abs(marchingPosition.z) - depthFromScreen;
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
{
break;
}
if (abs(delta) < distanceBias)
{
vec4 color = vec4(1);
if(debugDraw)
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
hitColor = texture(sceneMap, screenPosition) * color;
hitDepth = depthFromScreen;
hit = true;
break;
}
if (isBinarySearchEnabled && delta > 0)
{
break;
}
if (isAdaptiveStepEnabled)
{
float directionSign = sign(abs(marchingPosition.z) - depthFromScreen);
//this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging
//some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement
step = step * (1.0 - rayStep * max(directionSign, 0.0));
marchingPosition += step * (-directionSign);
}
else
{
marchingPosition += step;
}
if (isExponentialStepEnabled)
{
step *= adaptiveStepMultiplier;
}
}
if(isBinarySearchEnabled)
{
for(; i < iterationCount && !hit; i++)
{
step *= 0.5;
marchingPosition = marchingPosition - step * sign(delta);
screenPosition = generateProjectedPosition(marchingPosition);
if (screenPosition.x > 1 || screenPosition.x < 0 ||
screenPosition.y > 1 || screenPosition.y < 0)
{
hit = false;
break;
}
depthFromScreen = getLinearDepth(screenPosition);
delta = abs(marchingPosition.z) - depthFromScreen;
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
{
break;
}
if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias))
{
vec4 color = vec4(1);
if(debugDraw)
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
hitColor = texture(sceneMap, screenPosition) * color;
hitDepth = depthFromScreen;
hit = true;
break;
}
}
}
}
return hit;
}
uniform vec3 POISSON3D_SAMPLES[128] = vec3[128](
vec3(0.5433144, 0.1122154, 0.2501391),
vec3(0.6575254, 0.721409, 0.16286),
vec3(0.02888453, 0.05170321, 0.7573566),
vec3(0.06635678, 0.8286457, 0.07157445),
vec3(0.8957489, 0.4005505, 0.7916042),
vec3(0.3423355, 0.5053263, 0.9193521),
vec3(0.9694794, 0.9461077, 0.5406441),
vec3(0.9975473, 0.02789414, 0.7320132),
vec3(0.07781899, 0.3862341, 0.918594),
vec3(0.4439073, 0.9686955, 0.4055861),
vec3(0.9657035, 0.6624081, 0.7082613),
vec3(0.7712346, 0.07273269, 0.3292839),
vec3(0.2489169, 0.2550394, 0.1950516),
vec3(0.7249326, 0.9328285, 0.3352458),
vec3(0.6028461, 0.4424961, 0.5393377),
vec3(0.2879795, 0.7427881, 0.6619173),
vec3(0.3193627, 0.0486145, 0.08109283),
vec3(0.1233155, 0.602641, 0.4378719),
vec3(0.9800708, 0.211729, 0.6771586),
vec3(0.4894537, 0.3319927, 0.8087631),
vec3(0.4802743, 0.6358885, 0.814935),
vec3(0.2692913, 0.9911493, 0.9934899),
vec3(0.5648789, 0.8553897, 0.7784553),
vec3(0.8497344, 0.7870212, 0.02065313),
vec3(0.7503014, 0.2826185, 0.05412734),
vec3(0.8045461, 0.6167251, 0.9532926),
vec3(0.04225039, 0.2141281, 0.8678675),
vec3(0.07116079, 0.9971236, 0.3396397),
vec3(0.464099, 0.480959, 0.2775862),
vec3(0.6346927, 0.31871, 0.6588384),
vec3(0.449012, 0.8189669, 0.2736875),
vec3(0.452929, 0.2119148, 0.672004),
vec3(0.01506042, 0.7102436, 0.9800494),
vec3(0.1970513, 0.4713539, 0.4644522),
vec3(0.13715, 0.7253224, 0.5056525),
vec3(0.9006432, 0.5335414, 0.02206874),
vec3(0.9960898, 0.7961011, 0.01468861),
vec3(0.3386469, 0.6337739, 0.9310676),
vec3(0.1745718, 0.9114985, 0.1728188),
vec3(0.6342545, 0.5721557, 0.4553517),
vec3(0.1347412, 0.1137158, 0.7793725),
vec3(0.3574478, 0.3448052, 0.08741581),
vec3(0.7283059, 0.4753885, 0.2240275),
vec3(0.8293507, 0.9971212, 0.2747005),
vec3(0.6501846, 0.000688076, 0.7795712),
vec3(0.01149416, 0.4930083, 0.792608),
vec3(0.666189, 0.1875442, 0.7256873),
vec3(0.8538797, 0.2107637, 0.1547532),
vec3(0.5826825, 0.9750752, 0.9105834),
vec3(0.8914346, 0.08266425, 0.5484225),
vec3(0.4374518, 0.02987111, 0.7810078),
vec3(0.2287418, 0.1443802, 0.1176908),
vec3(0.2671157, 0.8929081, 0.8989366),
vec3(0.5425819, 0.5524959, 0.6963879),
vec3(0.3515188, 0.8304397, 0.0502702),
vec3(0.3354864, 0.2130747, 0.141169),
vec3(0.9729427, 0.3509927, 0.6098799),
vec3(0.7585629, 0.7115368, 0.9099342),
vec3(0.0140543, 0.6072157, 0.9436461),
vec3(0.9190664, 0.8497264, 0.1643751),
vec3(0.1538157, 0.3219983, 0.2984214),
vec3(0.8854713, 0.2968667, 0.8511457),
vec3(0.1910622, 0.03047311, 0.3571215),
vec3(0.2456353, 0.5568692, 0.3530164),
vec3(0.6927255, 0.8073994, 0.5808484),
vec3(0.8089353, 0.8969175, 0.3427134),
vec3(0.194477, 0.7985603, 0.8712182),
vec3(0.7256182, 0.5653068, 0.3985921),
vec3(0.9889427, 0.4584851, 0.8363391),
vec3(0.5718582, 0.2127113, 0.2950557),
vec3(0.5480209, 0.0193435, 0.2992659),
vec3(0.6598953, 0.09478426, 0.92187),
vec3(0.1385615, 0.2193868, 0.205245),
vec3(0.7623423, 0.1790726, 0.1508465),
vec3(0.7569032, 0.3773386, 0.4393887),
vec3(0.5842971, 0.6538072, 0.5224424),
vec3(0.9954313, 0.5763943, 0.9169143),
vec3(0.001311183, 0.340363, 0.1488652),
vec3(0.8167927, 0.4947158, 0.4454727),
vec3(0.3978434, 0.7106082, 0.002727509),
vec3(0.5459411, 0.7473233, 0.7062873),
vec3(0.4151598, 0.5614617, 0.4748358),
vec3(0.4440694, 0.1195122, 0.9624678),
vec3(0.1081301, 0.4813806, 0.07047641),
vec3(0.2402785, 0.3633997, 0.3898734),
vec3(0.2317942, 0.6488295, 0.4221864),
vec3(0.01145542, 0.9304277, 0.4105759),
vec3(0.3563728, 0.9228861, 0.3282344),
vec3(0.855314, 0.6949819, 0.3175117),
vec3(0.730832, 0.01478493, 0.5728671),
vec3(0.9304829, 0.02653277, 0.712552),
vec3(0.4132186, 0.4127623, 0.6084146),
vec3(0.7517329, 0.9978395, 0.1330464),
vec3(0.5210338, 0.4318751, 0.9721575),
vec3(0.02953994, 0.1375937, 0.9458942),
vec3(0.1835506, 0.9896691, 0.7919457),
vec3(0.3857062, 0.2682322, 0.1264563),
vec3(0.6319699, 0.8735335, 0.04390657),
vec3(0.5630485, 0.3339024, 0.993995),
vec3(0.90701, 0.1512893, 0.8970422),
vec3(0.3027443, 0.1144253, 0.1488708),
vec3(0.9149003, 0.7382028, 0.7914025),
vec3(0.07979286, 0.6892691, 0.2866171),
vec3(0.7743186, 0.8046008, 0.4399814),
vec3(0.3128662, 0.4362317, 0.6030678),
vec3(0.1133721, 0.01605821, 0.391872),
vec3(0.5185481, 0.9210006, 0.7889017),
vec3(0.8217013, 0.325305, 0.1668191),
vec3(0.8358996, 0.1449739, 0.3668382),
vec3(0.1778213, 0.5599256, 0.1327691),
vec3(0.06690693, 0.5508637, 0.07212365),
vec3(0.9750564, 0.284066, 0.5727578),
vec3(0.4350255, 0.8949825, 0.03574753),
vec3(0.8931149, 0.9177974, 0.8123496),
vec3(0.9055127, 0.989903, 0.813235),
vec3(0.2897243, 0.3123978, 0.5083504),
vec3(0.1519223, 0.3958645, 0.2640327),
vec3(0.6840154, 0.6463035, 0.2346607),
vec3(0.986473, 0.8714055, 0.3960275),
vec3(0.6819352, 0.4169535, 0.8379834),
vec3(0.9147297, 0.6144146, 0.7313942),
vec3(0.6554981, 0.5014008, 0.9748477),
vec3(0.9805915, 0.1318207, 0.2371372),
vec3(0.5980836, 0.06796348, 0.9941338),
vec3(0.6836596, 0.9917196, 0.2319056),
vec3(0.5276511, 0.2745509, 0.5422578),
vec3(0.829482, 0.03758276, 0.1240466),
vec3(0.2698198, 0.0002266169, 0.3449324)
);
vec3 getPoissonSample(int i) {
return POISSON3D_SAMPLES[i] * 2 - 1;
}
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness)
{
#ifdef TRANSPARENT_SURFACE
collectedColor = vec4(1, 0, 1, 1);
return 0;
#endif
collectedColor = vec4(0);
int hits = 0;
float depth = -viewPos.z;
vec3 rayDirection = normalize(reflect(viewPos, normalize(n)));
vec2 uv2 = tc * screen_res;
float c = (uv2.x + uv2.y) * 0.125;
float jitter = mod( c, 1.0);
vec2 screenpos = 1 - abs(tc * 2 - 1);
float vignette = clamp((abs(screenpos.x) * abs(screenpos.y)) * 16,0, 1);
vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5) * 5.5 - 0.8, 0, 1);
float zFar = 128.0;
vignette *= clamp(1.0+(viewPos.z/zFar), 0.0, 1.0);
vignette *= clamp(glossiness * 3 - 1.7, 0, 1);
vec4 hitpoint;
glossiness = 1 - glossiness;
totalSamples = int(max(glossySampleCount, glossySampleCount * glossiness * vignette));
totalSamples = max(totalSamples, 1);
if (glossiness < 0.35)
{
if (vignette > 0)
{
for (int i = 0; i < totalSamples; i++)
{
vec3 firstBasis = normalize(cross(getPoissonSample(i), rayDirection));
vec3 secondBasis = normalize(cross(rayDirection, firstBasis));
vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0)));
vec3 reflectionDirectionRandomized = rayDirection + ((firstBasis * coeffs.x + secondBasis * coeffs.y) * glossiness);
//float hitDepth;
bool hit = traceScreenRay(viewPos, normalize(reflectionDirectionRandomized), hitpoint, depth, depth, source);
hitpoint.a = 0;
if (hit)
{
++hits;
collectedColor += hitpoint;
collectedColor.a += 1;
}
}
if (hits > 0)
{
collectedColor /= hits;
}
else
{
collectedColor = vec4(0);
}
}
}
float hitAlpha = hits;
hitAlpha /= totalSamples;
collectedColor.a = hitAlpha * vignette;
return hits;
}
@@ -0,0 +1,285 @@
/**
* @file class3/deferred/softenLightF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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]*/
#define FLT_MAX 3.402823466e+38
out vec4 frag_color;
const float M_PI = 3.14159265;
#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO)
uniform sampler2D lightMap;
#endif
uniform sampler2D lightFunc;
uniform float blur_size;
uniform float blur_fidelity;
#if defined(HAS_SSAO)
uniform float ssao_irradiance_scale;
uniform float ssao_irradiance_max;
#endif
// Inputs
uniform vec4 clipPlane;
uniform mat3 env_mat;
uniform mat3 ssao_effect_mat;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
uniform int sun_up_factor;
uniform int classic_mode;
in vec2 vary_fragcoord;
uniform mat4 inv_proj;
uniform vec2 screen_res;
vec4 getNorm(vec2 pos_screen);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten);
vec3 scaleSoftClipFragLinear(vec3 l);
// reflection probe interface
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
float getDepth(vec2 pos_screen);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
uniform vec4 waterPlane;
uniform int cube_snapshot;
uniform float sky_hdr_scale;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor);
vec3 pbrBaseLight(vec3 diffuseColor,
vec3 specularColor,
float metallic,
vec3 pos,
vec3 norm,
float perceptualRoughness,
vec3 light_dir,
vec3 sunlit,
float scol,
vec3 radiance,
vec3 irradiance,
vec3 colorEmissive,
float ao,
vec3 additive,
vec3 atten);
GBufferInfo getGBuffer(vec2 screenpos);
vec3 clampHDRRange(vec3 color);
void adjustIrradiance(inout vec3 irradiance, float ambocc)
{
// use sky settings ambient or irradiance map sample, whichever is brighter
//irradiance = max(amblit_linear, irradiance);
#if defined(HAS_SSAO)
irradiance = mix(ssao_effect_mat * min(irradiance.rgb*ssao_irradiance_scale, vec3(ssao_irradiance_max)), irradiance.rgb, ambocc);
#endif
}
void main()
{
vec2 tc = vary_fragcoord.xy;
float depth = getDepth(tc.xy);
vec4 pos = getPositionWithDepth(tc, depth);
GBufferInfo gb = getGBuffer(tc);
vec3 colorEmissive = gb.emissive.rgb;
float envIntensity = gb.envIntensity;
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
vec4 baseColor = gb.albedo;
vec4 spec = gb.specular; // NOTE: PBR linear Emissive
#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO)
vec2 scol_ambocc = texture(lightMap, vary_fragcoord.xy).rg;
#endif
#if defined(HAS_SUN_SHADOW)
float scol = max(scol_ambocc.r, baseColor.a);
#else
float scol = 1.0;
#endif
#if defined(HAS_SSAO)
float ambocc = scol_ambocc.g;
#else
float ambocc = 1.0;
#endif
vec3 color = vec3(0);
float bloom = 0.0;
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, gb.normal, light_dir, sunlit, amblit, additive, atten);
if (classic_mode > 0)
sunlit *= 1.35;
vec3 sunlit_linear = sunlit;
vec3 amblit_linear = amblit;
vec3 radiance = vec3(0);
if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_HAS_PBR))
{
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
float ao = orm.r;
vec3 irradiance = amblit_linear;
// PBR IBL
float gloss = 1.0 - perceptualRoughness;
sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, gb.normal, gloss, false, amblit_linear);
adjustIrradiance(irradiance, ambocc);
vec3 diffuseColor;
vec3 specularColor;
calcDiffuseSpecular(baseColor.rgb, metallic, diffuseColor, specularColor);
vec3 v = -normalize(pos.xyz);
color = pbrBaseLight(diffuseColor, specularColor, metallic, v, gb.normal, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
}
else if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_HAS_HDRI))
{
// actual HDRI sky, just copy color value
color = colorEmissive.rgb;
}
else if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_SKIP_ATMOS))
{
//should only be true of WL sky, port over base color value and scale for fake HDR
#if defined(HAS_EMISSIVE)
color = colorEmissive.rgb;
#else
color = baseColor.rgb;
#endif
color = srgb_to_linear(color);
color *= sky_hdr_scale;
}
else
{
// legacy shaders are still writng sRGB to gbuffer
baseColor.rgb = srgb_to_linear(baseColor.rgb);
spec.rgb = srgb_to_linear(spec.rgb);
float da = clamp(dot(gb.normal, light_dir.xyz), 0.0, 1.0);
vec3 irradiance = amblit;
vec3 glossenv = vec3(0);
vec3 legacyenv = vec3(0);
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, gb.normal, spec.a, envIntensity, false, amblit_linear);
adjustIrradiance(irradiance, ambocc);
// apply lambertian IBL only (see pbrIbl)
color.rgb = irradiance;
if (classic_mode > 0)
{
da = pow(da,1.2);
vec3 sun_contrib = vec3(min(da, scol));
color.rgb = srgb_to_linear(color.rgb * 0.9 + (linear_to_srgb(sun_contrib) * sunlit_linear * 0.7));
sunlit_linear = srgb_to_linear(sunlit_linear);
}
else
{
vec3 sun_contrib = min(da, scol) * sunlit_linear;
color.rgb += sun_contrib;
}
color.rgb *= baseColor.rgb;
vec3 refnormpersp = reflect(pos.xyz, gb.normal);
if (spec.a > 0.0)
{
vec3 lv = light_dir.xyz;
vec3 h, l, v = -normalize(pos.xyz);
float nh, nl, nv, vh, lightDist;
vec3 n = gb.normal;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
if (nl > 0.0 && nh > 0.0)
{
float lit = min(nl*6.0, 1.0);
float sa = nh;
float fres = pow(1 - vh, 5) * 0.4+0.5;
float gtdenom = 2 * nh;
float gt = max(0,(min(gtdenom * nv / vh, gtdenom * nl / vh)));
scol *= fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl);
color.rgb += lit*scol*sunlit_linear.rgb*spec.rgb;
}
// add radiance map
applyGlossEnv(color, glossenv, spec, pos.xyz, gb.normal);
}
color.rgb = mix(color.rgb, baseColor.rgb, baseColor.a);
if (envIntensity > 0.0)
{ // add environment map
applyLegacyEnv(color, legacyenv, spec, pos.xyz, gb.normal, envIntensity);
}
}
//color.r = classic_mode > 0 ? 1.0 : 0.0;
float final_scale = 1;
if (classic_mode > 0)
final_scale = 1.1;
frag_color.rgb = clampHDRRange(color.rgb * final_scale); //output linear since local lights will be added to this shader's results
frag_color.a = 0.0;
}
@@ -0,0 +1,277 @@
/**
* @file class3\deferred\spotLightF.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 samplerCube environmentMap;
uniform sampler2D lightMap;
uniform sampler2D lightFunc;
uniform mat4 proj_mat; //screen space to light space
uniform float proj_near; //near clip for projection
uniform vec3 proj_p; //plane projection is emitting from (in screen space)
uniform vec3 proj_n;
uniform float proj_focus; //distance from plane to begin blurring
uniform float proj_lod; //(number of mips in proj map)
uniform float proj_range; //range between near clip and far clip plane of projection
uniform float proj_ambient_lod;
uniform float proj_ambiance;
uniform float near_clip;
uniform float far_clip;
uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
uniform float sun_wash;
uniform int proj_shadow_idx;
uniform float shadow_fade;
uniform int classic_mode;
// Light params
#if defined(MULTI_SPOTLIGHT)
uniform vec3 center;
#else
in vec3 trans_center;
#endif
uniform float size;
uniform vec3 color;
uniform float falloff;
in vec4 vary_fragcoord;
uniform vec2 screen_res;
uniform mat4 inv_proj;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc );
vec4 getNorm(vec2 screenpos);
vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv);
vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv );
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 cs);
vec4 texture2DLodSpecular(vec2 tc, float lod);
vec4 getPosition(vec2 pos_screen);
const float M_PI = 3.14159265;
void pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
vec3 l, // surface point to light
out float nl,
out vec3 diff,
out vec3 spec);
GBufferInfo getGBuffer(vec2 screenpos);
void main()
{
vec3 final_color = vec3(0,0,0);
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
vec3 lv;
vec4 proj_tc;
float dist, l_dist;
vec3 c;
#if defined(MULTI_SPOTLIGHT)
c = center;
#else
c = trans_center;
#endif
if (clipProjectedLightVars(c, pos, dist, l_dist, lv, proj_tc))
{
discard;
}
float shadow = 1.0;
if (proj_shadow_idx >= 0)
{
vec4 shd = texture(lightMap, tc);
shadow = (proj_shadow_idx==0)?shd.b:shd.a;
shadow += shadow_fade;
shadow = clamp(shadow, 0.0, 1.0);
}
GBufferInfo gb = getGBuffer(tc);
vec3 n = gb.normal;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
if (dist_atten <= 0.0)
{
discard;
}
lv = proj_origin-pos.xyz;
vec3 h, l, v = -normalize(pos);
float nh, nl, nv, vh, lightDist;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
vec3 diffuse = gb.albedo.rgb;
vec4 spec = gb.specular;
vec3 dlit = vec3(0, 0, 0);
vec3 slit = vec3(0, 0, 0);
vec3 amb_rgb = vec3(0);
if (GET_GBUFFER_FLAG(gb.gbufferFlag, GBUFFER_FLAG_HAS_PBR))
{
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
vec3 f0 = vec3(0.04);
vec3 baseColor = diffuse.rgb;
vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
diffuseColor *= 1.0 - metallic;
vec3 specularColor = mix(f0, baseColor.rgb, metallic);
vec3 diffPunc = vec3(0);
vec3 specPunc = vec3(0);
// We need this additional test inside a light's frustum since a spotlight's ambiance can be applied
if (proj_tc.x > 0.0 && proj_tc.x < 1.0
&& proj_tc.y > 0.0 && proj_tc.y < 1.0)
{
float lit = 0.0;
float amb_da = 0.0;
lv = normalize(lv);
if (nl > 0.0)
{
amb_da += (nl*0.5 + 0.5) * proj_ambiance;
dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy );
vec3 intensity = dist_atten * dlit * 3.25 * shadow; // Legacy attenuation, magic number to balance with legacy materials
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv), nl, diffPunc, specPunc);
final_color += intensity * clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10));
}
amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy ) * 3.25; //magic number to balance with legacy ambiance
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv), nl, diffPunc, specPunc);
final_color += amb_rgb * clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10));
}
}
else
{
float envIntensity = gb.envIntensity;
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
if (proj_tc.z > 0.0 &&
proj_tc.x < 1.0 &&
proj_tc.y < 1.0 &&
proj_tc.x > 0.0 &&
proj_tc.y > 0.0)
{
float amb_da = 0;
float lit = 0.0;
if (nl > 0.0)
{
lit = nl * dist_atten;
dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy );
final_color = dlit*lit*diffuse*shadow;
// unshadowed for consistency between forward and deferred?
amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance;
}
amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
final_color += diffuse.rgb * amb_rgb * max(dot(-normalize(lv), n), 0.0);
}
if (spec.a > 0.0)
{
dlit *= min(nl*6.0, 1.0) * dist_atten;
float fres = pow(1 - vh, 5)*0.4+0.5;
float gtdenom = 2 * nh;
float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh));
if (nh > 0.0)
{
float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl);
vec3 speccol = dlit*scol*spec.rgb*shadow;
speccol = clamp(speccol, vec3(0), vec3(1));
final_color += speccol;
}
}
if (envIntensity > 0.0)
{
vec3 ref = reflect(normalize(pos), n);
//project from point pos in direction ref to plane proj_p, proj_n
vec3 pdelta = proj_p-pos;
float ds = dot(ref, proj_n);
if (ds < 0.0)
{
vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
if (stc.z > 0.0)
{
stc /= stc.w;
if (stc.x < 1.0 &&
stc.y < 1.0 &&
stc.x > 0.0 &&
stc.y > 0.0)
{
final_color += color.rgb * texture2DLodSpecular(stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity;
}
}
}
}
}
//not sure why, but this line prevents MATBUG-194
final_color = max(final_color, vec3(0.0));
float final_scale = 1.0;
if (classic_mode > 0)
final_scale = 0.9;
//output linear
frag_color.rgb = final_color * final_scale;
frag_color.a = 0.0;
}
@@ -0,0 +1,76 @@
/**
* @file class3/deferred/waterHazeF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
out vec4 frag_color;
// Inputs
in vec4 vary_fragcoord;
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
float getDepth(vec2 pos_screen);
vec4 getWaterFogView(vec3 pos);
uniform int above_water;
uniform sampler2D exclusionTex;
void main()
{
vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5;
float depth = getDepth(tc.xy);
float mask = texture(exclusionTex, tc.xy).r;
if (above_water > 0)
{
// Just discard if we're in the exclusion mask.
// The previous invisiprim hack we're replacing would also crank up water fog desntiy.
// But doing that makes exclusion surfaces very slow as we'd need to render even more into the mask.
// - Geenz 2025-02-06
if (mask < 1)
{
discard;
}
// we want to depth test when the camera is above water, but some GPUs have a hard time
// with depth testing against render targets that are bound for sampling in the same shader
// so we do it manually here
float cur_depth = vary_fragcoord.z/vary_fragcoord.w*0.5+0.5;
if (cur_depth > depth)
{
discard;
}
}
vec4 pos = getPositionWithDepth(tc, depth);
vec4 fogged = getWaterFogView(pos.xyz);
fogged.a = max(pow(fogged.a, 1.7), 0);
frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results
}
@@ -0,0 +1,59 @@
/**
* @file class3/deferred/waterHazeV.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
in vec3 position;
uniform vec2 screen_res;
out vec4 vary_fragcoord;
// forwards
void setAtmosAttenuation(vec3 c);
void setAdditiveColor(vec3 c);
uniform vec4 waterPlane;
uniform int above_water;
uniform mat4 modelview_projection_matrix;
void main()
{
//transform vertex
vec4 pos = vec4(position.xyz, 1.0);
if (above_water > 0)
{
pos = modelview_projection_matrix*pos;
}
gl_Position = pos;
// appease OSX GLSL compiler/linker by touching all the varyings we said we would
setAtmosAttenuation(vec3(1));
setAdditiveColor(vec3(0));
vary_fragcoord = pos;
}
@@ -0,0 +1,87 @@
/**
* @file class3\environment\underWaterF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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$
*/
out vec4 frag_color;
uniform sampler2D bumpMap;
uniform sampler2D exclusionTex;
#ifdef TRANSPARENT_WATER
uniform sampler2D screenTex;
#endif
uniform vec4 fogCol;
uniform vec3 lightDir;
uniform vec3 specular;
uniform float lightExp;
uniform vec2 fbScale;
uniform float refScale;
uniform float znear;
uniform float zfar;
uniform float kd;
uniform vec4 waterPlane;
uniform vec3 eyeVec;
uniform vec4 waterFogColor;
uniform vec3 waterFogColorLinear;
uniform float waterFogKS;
uniform vec2 screenRes;
//bigWave is (refCoord.w, view.w);
in vec4 refCoord;
in vec4 littleWave;
in vec4 view;
in vec3 vary_position;
vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color);
void mirrorClip(vec3 position);
void main()
{
mirrorClip(vary_position);
vec2 screen_tc = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
float water_mask = texture(exclusionTex, screen_tc).r;
vec4 color;
//get detail normals
vec3 wave1 = texture(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
vec3 wave2 = texture(bumpMap, littleWave.xy).xyz*2.0-1.0;
vec3 wave3 = texture(bumpMap, littleWave.zw).xyz*2.0-1.0;
vec3 wavef = normalize(wave1+wave2+wave3);
//figure out distortion vector (ripply)
vec2 distort = screen_tc;
distort = mix(distort, distort+wavef.xy*refScale, water_mask);
#ifdef TRANSPARENT_WATER
vec4 fb = texture(screenTex, distort);
#else
vec4 fb = vec4(waterFogColorLinear, 0.0);
#endif
fb = applyWaterFogViewLinearNoClip(vary_position, fb);
frag_color = max(fb, vec4(0));
}
@@ -0,0 +1,349 @@
/**
* @file waterF.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$
*/
// class3/environment/waterF.glsl
#define WATER_MINIMAL 1
out vec4 frag_color;
#ifdef HAS_SUN_SHADOW
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
#endif
vec3 scaleSoftClipFragLinear(vec3 l);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
void mirrorClip(vec3 pos);
// PBR interface
vec2 BRDF(float NoV, float roughness);
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor);
void pbrIbl(vec3 diffuseColor,
vec3 specularColor,
vec3 radiance, // radiance map sample
vec3 irradiance, // irradiance map sample
float ao, // ambient occlusion factor
float nv, // normal dot view vector
float perceptualRoughness,
out vec3 diffuse,
out vec3 specular);
void pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
vec3 l, // surface point to light
out float nl,
out vec3 diff,
out vec3 spec);
vec3 pbrBaseLight(vec3 diffuseColor,
vec3 specularColor,
float metallic,
vec3 pos,
vec3 norm,
float perceptualRoughness,
vec3 light_dir,
vec3 sunlit,
float scol,
vec3 radiance,
vec3 irradiance,
vec3 colorEmissive,
float ao,
vec3 additive,
vec3 atten);
uniform sampler2D bumpMap;
uniform sampler2D bumpMap2;
uniform float blend_factor;
#ifdef TRANSPARENT_WATER
uniform sampler2D screenTex;
uniform sampler2D depthMap;
#endif
uniform sampler2D exclusionTex;
uniform int classic_mode;
uniform vec3 lightDir;
uniform vec3 specular;
uniform float blurMultiplier;
uniform float refScale;
uniform float kd;
uniform vec3 normScale;
uniform float fresnelScale;
uniform float fresnelOffset;
//bigWave is (refCoord.w, view.w);
in vec4 refCoord;
in vec4 littleWave;
in vec4 view;
in vec3 vary_position;
in vec3 vary_normal;
in vec3 vary_tangent;
in vec3 vary_light_dir;
vec3 BlendNormal(vec3 bump1, vec3 bump2)
{
vec3 n = mix(bump1, bump2, blend_factor);
return n;
}
vec3 srgb_to_linear(vec3 col);
vec3 linear_to_srgb(vec3 col);
vec3 atmosLighting(vec3 light);
vec3 scaleSoftClip(vec3 light);
vec3 toneMapNoExposure(vec3 color);
vec3 vN, vT, vB;
vec3 transform_normal(vec3 vNt)
{
return normalize(vNt.x * vT + vNt.y * vB + vNt.z * vN);
}
void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, vec3 amblit_linear);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit);
vec3 getPositionWithNDC(vec3 ndc);
void generateWaveNormals(out vec3 wave1, out vec3 wave2, out vec3 wave3)
{
// Generate all of our wave normals.
// We layer these back and forth.
vec2 bigwave = vec2(refCoord.w, view.w);
vec3 wave1_a = texture(bumpMap, bigwave).xyz * 2.0 - 1.0;
vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz * 2.0 - 1.0;
vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz * 2.0 - 1.0;
vec3 wave1_b = texture(bumpMap2, bigwave).xyz * 2.0 - 1.0;
vec3 wave2_b = texture(bumpMap2, littleWave.xy).xyz * 2.0 - 1.0;
vec3 wave3_b = texture(bumpMap2, littleWave.zw).xyz * 2.0 - 1.0;
wave1 = BlendNormal(wave1_a, wave1_b);
wave2 = BlendNormal(wave2_a, wave2_b);
wave3 = BlendNormal(wave3_a, wave3_b);
}
void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave1, vec3 wave2, vec3 wave3, vec3 wavef)
{
// We calculate the fresnel here.
// We do this by getting the dot product for each sets of waves, and applying scale and offset.
df3 = max(vec3(0), vec3(
dot(viewVec, wave1),
dot(viewVec, (wave2 + wave3) * 0.5),
dot(viewVec, wave3)
) * fresnelScale + fresnelOffset);
df3 *= df3;
df2 = max(vec2(0), vec2(
df3.x + df3.y + df3.z,
dot(viewVec, wavef) * fresnelScale + fresnelOffset
));
}
void main()
{
mirrorClip(vary_position);
vN = vary_normal;
vT = vary_tangent;
vB = cross(vN, vT);
vec3 pos = vary_position.xyz;
float linear_depth = 1 / -pos.z;
float dist = length(pos.xyz);
//normalize view vector
vec3 viewVec = normalize(pos.xyz);
// Setup our waves.
vec3 wave1 = vec3(0, 0, 1);
vec3 wave2 = vec3(0, 0, 1);
vec3 wave3 = vec3(0, 0, 1);
generateWaveNormals(wave1, wave2, wave3);
float dmod = sqrt(dist);
vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
vec3 df3 = vec3(0);
vec2 df2 = vec2(0);
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten);
calculateFresnelFactors(df3, df2, normalize(view.xyz), wave1, wave2, wave3, wavef);
vec3 waver = wavef*3;
vec3 up = transform_normal(vec3(0,0,1));
float vdu = -dot(viewVec, up)*2;
vec3 wave_ibl = wavef * normScale;
wave_ibl.z *= 2.0;
wave_ibl = transform_normal(normalize(wave_ibl));
vec3 norm = transform_normal(normalize(wavef));
vdu = clamp(vdu, 0, 1);
//wavef.z *= max(vdu*vdu*vdu, 0.1);
wavef = normalize(wavef);
//wavef = vec3(0, 0, 1);
wavef = transform_normal(wavef);
float dist2 = dist;
dist = max(dist, 5.0);
//figure out distortion vector (ripply)
vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0) * 2;
distort2 = clamp(distort2, vec2(0), vec2(0.999));
float shadow = 1.0f;
float water_mask = texture(exclusionTex, distort).r;
#ifdef HAS_SUN_SHADOW
shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort);
#endif
vec3 sunlit_linear = sunlit;
float fade = 1;
#ifdef TRANSPARENT_WATER
float depth = texture(depthMap, distort).r;
vec3 refPos = getPositionWithNDC(vec3(distort*2.0-vec2(1.0), depth*2.0-1.0));
// Calculate some distance fade in the water to better assist with refraction blending and reducing the refraction texture's "disconnect".
#ifdef SHORELINE_FADE
fade = max(0,min(1, (pos.z - refPos.z) / 10));
#else
fade = 1;
#endif
fade *= water_mask;
distort2 = mix(distort, distort2, min(1, fade * 10));
depth = texture(depthMap, distort2).r;
refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0));
if (pos.z < refPos.z - 0.05)
{
distort2 = distort;
}
vec4 fb = texture(screenTex, distort2);
#else
vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0));
if (water_mask < 1)
discard;
#endif
float metallic = 1.0;
float perceptualRoughness = blurMultiplier;
float gloss = 1 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
vec3 legacyenv = vec3(0);
// TODO: Make this an option.
#ifdef WATER_MINIMAL
sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit);
#elif WATER_MINIMAL_PLUS
sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, false, amblit);
#endif
vec3 diffuseColor = vec3(0);
vec3 specularColor = vec3(0);
vec3 specular_linear = srgb_to_linear(specular);
calcDiffuseSpecular(specular_linear, metallic, diffuseColor, specularColor);
vec3 v = -normalize(pos.xyz);
vec3 colorEmissive = vec3(0);
float ao = 1.0;
vec3 light_dir = transform_normal(lightDir);
float NdotV = clamp(abs(dot(norm, v)), 0.001, 1.0);
float nl = 0;
vec3 diffPunc = vec3(0);
vec3 specPunc = vec3(0);
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc);
vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow * atten;
radiance *= df2.y;
//radiance = toneMapNoExposure(radiance);
vec3 color = vec3(0);
color = mix(fb.rgb, radiance, min(1, df2.x)) + punctual.rgb;
float water_haze_scale = 4;
if (classic_mode > 0)
water_haze_scale = 1;
// This looks super janky, but we do this to restore water haze in the distance.
// These values were finagled in to try and bring back some of the distant brightening on legacy water. Also works reasonably well on PBR skies such as PBR midday.
// color = mix(color, additive * water_haze_scale, (1 - atten));
// We shorten the fade here at the shoreline so it doesn't appear too soft from a distance.
fade *= 60;
fade = min(1, fade);
color = mix(fb.rgb, color, fade);
float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0);
frag_color = min(vec4(1),max(vec4(color.rgb, spec * water_mask), vec4(0)));
}
@@ -0,0 +1,35 @@
/**
* @file class3\lighting\lightV.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, 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$
*/
// used for preview renders only
vec4 sumLights(vec3 pos, vec3 norm, vec4 color);
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color)
{
vec4 c = sumLights(pos, norm, color);
return c;
}
@@ -0,0 +1,66 @@
/**
* @file class3\lighting\sumLightsSpecularV.glsl
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2005, 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$
*/
float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol);
vec3 atmosAmbient();
vec3 atmosAffectDirectionalLight(float lightIntensity);
vec3 atmosGetDiffuseSunlightColor();
vec3 scaleDownLight(vec3 light);
uniform vec4 light_position[8];
uniform vec4 light_attenuation[8];
uniform vec3 light_diffuse[8];
vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor)
{
vec4 col = vec4(0.0, 0.0, 0.0, color.a);
vec3 view = normalize(pos);
/// collect all the specular values from each calcXXXLightSpecular() function
vec4 specularSum = vec4(0.0);
// Collect normal lights (need to be divided by two, as we later multiply by 2)
col.rgb += light_diffuse[1].rgb * calcDirectionalLightSpecular(specularColor, view, norm, light_position[1].xyz,light_diffuse[1].rgb, 1.0);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[2].xyz, light_attenuation[2].x, light_attenuation[2].y, light_diffuse[2].rgb);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[3].xyz, light_attenuation[3].x, light_attenuation[3].y, light_diffuse[3].rgb);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[4].xyz, light_attenuation[4].x, light_attenuation[4].y, light_diffuse[4].rgb);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[5].xyz, light_attenuation[5].x, light_attenuation[5].y, light_diffuse[5].rgb);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[6].xyz, light_attenuation[6].x, light_attenuation[6].y, light_diffuse[6].rgb);
col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[7].xyz, light_attenuation[7].x, light_attenuation[7].y, light_diffuse[7].rgb);
col.rgb = scaleDownLight(col.rgb);
// Add windlight lights
col.rgb += atmosAmbient();
col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz,atmosGetDiffuseSunlightColor(), 1.0));
col.rgb = min(col.rgb*color.rgb, 1.0);
specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0);
col.rgb += specularColor.rgb;
return col;
}