summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llrender/llglslshader.h1
-rw-r--r--indra/llrender/llshadermgr.cpp8
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl129
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl180
-rw-r--r--indra/newview/app_settings/shaders/class3/environment/waterF.glsl55
-rw-r--r--indra/newview/lldrawpoolwater.cpp231
-rw-r--r--indra/newview/llviewershadermgr.cpp37
-rw-r--r--indra/newview/llviewershadermgr.h1
8 files changed, 325 insertions, 317 deletions
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 58c456f134..873ab0cff5 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -59,6 +59,7 @@ public:
bool attachNothing = false;
bool hasHeroProbes = false;
bool isPBRTerrain = false;
+ bool hasTonemap = false;
};
// ============= Structure for caching shader uniforms ===============
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 25d8ccd4b3..4807c12226 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -291,6 +291,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
+ if (features->hasTonemap)
+ {
+ if (!shader->attachFragmentObject("deferred/tonemapUtilF.glsl"))
+ {
+ return false;
+ }
+ }
+
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->hasAtmospherics)
{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl
index fc6d4d7727..c4610bffac 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl
@@ -28,138 +28,11 @@
out vec4 frag_color;
uniform sampler2D diffuseRect;
-uniform sampler2D exposureMap;
-uniform vec2 screen_res;
in vec2 vary_fragcoord;
vec3 linear_to_srgb(vec3 cl);
-
-//===============================================================
-// tone mapping taken from Khronos sample implementation
-//===============================================================
-
-// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
-const mat3 ACESInputMat = mat3
-(
- 0.59719, 0.07600, 0.02840,
- 0.35458, 0.90834, 0.13383,
- 0.04823, 0.01566, 0.83777
-);
-
-
-// ODT_SAT => XYZ => D60_2_D65 => sRGB
-const mat3 ACESOutputMat = mat3
-(
- 1.60475, -0.10208, -0.00327,
- -0.53108, 1.10813, -0.07276,
- -0.07367, -0.00605, 1.07602
-);
-
-// ACES tone map (faster approximation)
-// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
-vec3 toneMapACES_Narkowicz(vec3 color)
-{
- const float A = 2.51;
- const float B = 0.03;
- const float C = 2.43;
- const float D = 0.59;
- const float E = 0.14;
- return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
-}
-
-
-// ACES filmic tone map approximation
-// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
-vec3 RRTAndODTFit(vec3 color)
-{
- vec3 a = color * (color + 0.0245786) - 0.000090537;
- vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081;
- return a / b;
-}
-
-
-// tone mapping
-vec3 toneMapACES_Hill(vec3 color)
-{
- color = ACESInputMat * color;
-
- // Apply RRT and ODT
- color = RRTAndODTFit(color);
-
- color = ACESOutputMat * color;
-
- // Clamp to [0, 1]
- color = clamp(color, 0.0, 1.0);
-
- return color;
-}
-
-// Khronos Neutral tonemapping
-// https://github.com/KhronosGroup/ToneMapping/tree/main
-// Input color is non-negative and resides in the Linear Rec. 709 color space.
-// Output color is also Linear Rec. 709, but in the [0, 1] range.
-vec3 PBRNeutralToneMapping( vec3 color )
-{
- const float startCompression = 0.8 - 0.04;
- const float desaturation = 0.15;
-
- float x = min(color.r, min(color.g, color.b));
- float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
- color -= offset;
-
- float peak = max(color.r, max(color.g, color.b));
- if (peak < startCompression) return color;
-
- const float d = 1. - startCompression;
- float newPeak = 1. - d * d / (peak + d - startCompression);
- color *= newPeak / peak;
-
- float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
- return mix(color, newPeak * vec3(1, 1, 1), g);
-}
-
-uniform float exposure;
-uniform float tonemap_mix;
-uniform int tonemap_type;
-
-vec3 toneMap(vec3 color)
-{
-#ifndef NO_POST
- float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
-
- color *= exposure * exp_scale;
-
- vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
-
- switch(tonemap_type)
- {
- case 0:
- color = PBRNeutralToneMapping(color);
- break;
- case 1:
- color = toneMapACES_Hill(color);
- break;
- }
-
- // mix tonemapped and linear here to provide adjustment
- color = mix(clamped_color, color, tonemap_mix);
-#endif
-
- return color;
-}
-
-//===============================================================
-
-void debugExposure(inout vec3 color)
-{
- float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
- exp_scale *= 0.5;
- if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1)
- {
- color = vec3(1,0,0);
- }
-}
+vec3 toneMap(vec3 color);
void main()
{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl
new file mode 100644
index 0000000000..a63b8d7c2b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl
@@ -0,0 +1,180 @@
+/**
+ * @file postDeferredTonemap.glsl
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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]*/
+
+uniform sampler2D exposureMap;
+uniform vec2 screen_res;
+in vec2 vary_fragcoord;
+
+//===============================================================
+// tone mapping taken from Khronos sample implementation
+//===============================================================
+
+// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
+const mat3 ACESInputMat = mat3
+(
+ 0.59719, 0.07600, 0.02840,
+ 0.35458, 0.90834, 0.13383,
+ 0.04823, 0.01566, 0.83777
+);
+
+
+// ODT_SAT => XYZ => D60_2_D65 => sRGB
+const mat3 ACESOutputMat = mat3
+(
+ 1.60475, -0.10208, -0.00327,
+ -0.53108, 1.10813, -0.07276,
+ -0.07367, -0.00605, 1.07602
+);
+
+// ACES tone map (faster approximation)
+// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
+vec3 toneMapACES_Narkowicz(vec3 color)
+{
+ const float A = 2.51;
+ const float B = 0.03;
+ const float C = 2.43;
+ const float D = 0.59;
+ const float E = 0.14;
+ return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
+}
+
+
+// ACES filmic tone map approximation
+// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+vec3 RRTAndODTFit(vec3 color)
+{
+ vec3 a = color * (color + 0.0245786) - 0.000090537;
+ vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081;
+ return a / b;
+}
+
+
+// tone mapping
+vec3 toneMapACES_Hill(vec3 color)
+{
+ color = ACESInputMat * color;
+
+ // Apply RRT and ODT
+ color = RRTAndODTFit(color);
+
+ color = ACESOutputMat * color;
+
+ // Clamp to [0, 1]
+ color = clamp(color, 0.0, 1.0);
+
+ return color;
+}
+
+// Khronos Neutral tonemapping
+// https://github.com/KhronosGroup/ToneMapping/tree/main
+// Input color is non-negative and resides in the Linear Rec. 709 color space.
+// Output color is also Linear Rec. 709, but in the [0, 1] range.
+vec3 PBRNeutralToneMapping( vec3 color )
+{
+ const float startCompression = 0.8 - 0.04;
+ const float desaturation = 0.15;
+
+ float x = min(color.r, min(color.g, color.b));
+ float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
+ color -= offset;
+
+ float peak = max(color.r, max(color.g, color.b));
+ if (peak < startCompression) return color;
+
+ const float d = 1. - startCompression;
+ float newPeak = 1. - d * d / (peak + d - startCompression);
+ color *= newPeak / peak;
+
+ float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
+ return mix(color, newPeak * vec3(1, 1, 1), g);
+}
+
+uniform float exposure;
+uniform float tonemap_mix;
+uniform int tonemap_type;
+
+vec3 toneMap(vec3 color)
+{
+#ifndef NO_POST
+ float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
+
+ color *= exposure * exp_scale;
+
+ vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
+
+ switch(tonemap_type)
+ {
+ case 0:
+ color = PBRNeutralToneMapping(color);
+ break;
+ case 1:
+ color = toneMapACES_Hill(color);
+ break;
+ }
+
+ // mix tonemapped and linear here to provide adjustment
+ color = mix(clamped_color, color, tonemap_mix);
+#endif
+
+ return color;
+}
+
+
+vec3 toneMapNoExposure(vec3 color)
+{
+#ifndef NO_POST
+ vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
+
+ switch(tonemap_type)
+ {
+ case 0:
+ color = PBRNeutralToneMapping(color);
+ break;
+ case 1:
+ color = toneMapACES_Hill(color);
+ break;
+ }
+
+ // mix tonemapped and linear here to provide adjustment
+ color = mix(clamped_color, color, tonemap_mix);
+#endif
+
+ return color;
+}
+
+
+//===============================================================
+
+void debugExposure(inout vec3 color)
+{
+ float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
+ exp_scale *= 0.5;
+ if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1)
+ {
+ color = vec3(1,0,0);
+ }
+}
diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
index 7027e3796e..c56e38d016 100644
--- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
@@ -90,21 +90,15 @@ uniform sampler2D depthMap;
uniform sampler2D exclusionTex;
-uniform float sunAngle;
-uniform float sunAngle2;
+uniform int classic_mode;
uniform vec3 lightDir;
uniform vec3 specular;
-uniform float lightExp;
+uniform float blurMultiplier;
uniform float refScale;
uniform float kd;
-uniform vec2 screenRes;
uniform vec3 normScale;
uniform float fresnelScale;
uniform float fresnelOffset;
-uniform float blurMultiplier;
-uniform vec4 waterFogColor;
-uniform vec3 waterFogColorLinear;
-
//bigWave is (refCoord.w, view.w);
in vec4 refCoord;
@@ -126,6 +120,7 @@ vec3 linear_to_srgb(vec3 col);
vec3 atmosLighting(vec3 light);
vec3 scaleSoftClip(vec3 light);
+vec3 toneMapNoExposure(vec3 color);
vec3 vN, vT, vB;
@@ -171,18 +166,18 @@ void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave
// We calculate the fresnel here.
// We do this by getting the dot product for each sets of waves, and applying scale and offset.
- df3 = vec3(
+ df3 = max(vec3(0), vec3(
dot(viewVec, wave1),
dot(viewVec, (wave2 + wave3) * 0.5),
dot(viewVec, wave3)
- ) * fresnelScale + fresnelOffset;
+ ) * fresnelScale + fresnelOffset);
df3 *= df3;
- df2 = vec2(
+ df2 = max(vec2(0), vec2(
df3.x + df3.y + df3.z,
dot(viewVec, wavef) * fresnelScale + fresnelOffset
- );
+ ));
}
void main()
@@ -194,6 +189,7 @@ void main()
vB = cross(vN, vT);
vec3 pos = vary_position.xyz;
+ float linear_depth = 1 / -pos.z;
float dist = length(pos.xyz);
@@ -216,6 +212,12 @@ void main()
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;
@@ -230,7 +232,7 @@ void main()
vec3 norm = transform_normal(normalize(wavef));
vdu = clamp(vdu, 0, 1);
- wavef.z *= max(vdu*vdu*vdu, 0.1);
+ //wavef.z *= max(vdu*vdu*vdu, 0.1);
wavef = normalize(wavef);
@@ -245,11 +247,6 @@ void main()
distort2 = clamp(distort2, vec2(0), vec2(0.999));
- vec3 sunlit;
- vec3 amblit;
- vec3 additive;
- vec3 atten;
-
float shadow = 1.0f;
float water_mask = texture(exclusionTex, distort).r;
@@ -258,8 +255,6 @@ void main()
shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort);
#endif
- calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten);
-
vec3 sunlit_linear = srgb_to_linear(sunlit);
float fade = 0;
#ifdef TRANSPARENT_WATER
@@ -289,8 +284,8 @@ void main()
#endif
float metallic = 1.0;
- float perceptualRoughness = 0.1;
- float gloss = 0.95;
+ float perceptualRoughness = blurMultiplier;
+ float gloss = 1 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
@@ -300,7 +295,7 @@ void main()
#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, 1, false, amblit);
+ sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, false, amblit);
#endif
vec3 diffuseColor = vec3(0);
@@ -323,20 +318,26 @@ void main()
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;
-
+ radiance *= df2.y;
+ //radiance = toneMapNoExposure(radiance);
vec3 color = vec3(0);
- color = mix(fb.rgb, radiance * df2.y, df2.x * 0.99999) + punctual.rgb;
+ 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 += color * min(vec3(4),pow(1 - atten, vec3(1.35)) * 16 * fade);
+ // 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.05);
+ 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)));
}
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index c27f5ef486..32de0e5ee7 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -176,154 +176,133 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
light_diffuse *= (1.5f + (6.f * ground_proj_sq));
}
- // set up normal maps filtering
- for (auto norm_map : mWaterNormp)
- {
- if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
- }
+ LLTexUnit::eTextureFilterOptions filter_mode = has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT;
LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
LLGLSLShader *shader = nullptr;
- // two passes, first with standard water shader bound, second with edge water shader bound
- for (int edge = 0; edge < 2; edge++)
+ // One pass, one of two shaders. Void water and region water share state.
+ // There isn't a good reason anymore to really have void water run in a separate pass.
+ // It also just introduced a bunch of weird state consistency stuff that we really don't need.
+ // Not to mention, re-binding the the same shader and state for that shader is kind of wasteful.
+ // - Geenz 2025-02-11
+ // select shader
+ if (underwater)
{
- // select shader
- if (underwater)
- {
- shader = &gUnderWaterProgram;
- }
- else
- {
- if (edge)
- {
- shader = &gWaterEdgeProgram;
- }
- else
- {
- shader = &gWaterProgram;
- }
- }
-
- gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
-
- //bind normal map
- S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
- S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
-
- LLViewerTexture* tex_a = mWaterNormp[0];
- LLViewerTexture* tex_b = mWaterNormp[1];
+ shader = &gUnderWaterProgram;
+ }
+ else
+ {
+ shader = &gWaterProgram;
+ }
- F32 blend_factor = (F32)pwater->getBlendFactor();
+ gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
- gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
+ LLViewerTexture* tex_a = mWaterNormp[0];
+ LLViewerTexture* tex_b = mWaterNormp[1];
- if (tex_a && (!tex_b || (tex_a == tex_b)))
- {
- gGL.getTexUnit(bumpTex)->bind(tex_a);
- blend_factor = 0; // only one tex provided, no blending
- }
- else if (tex_b && !tex_a)
- {
- gGL.getTexUnit(bumpTex)->bind(tex_b);
- blend_factor = 0; // only one tex provided, no blending
- }
- else if (tex_b != tex_a)
- {
- gGL.getTexUnit(bumpTex)->bind(tex_a);
- gGL.getTexUnit(bumpTex2)->bind(tex_b);
- }
+ F32 blend_factor = (F32)pwater->getBlendFactor();
- shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
+ if (tex_a && (!tex_b || (tex_a == tex_b)))
+ {
+ shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
+ tex_a->setFilteringOption(filter_mode);
+ blend_factor = 0; // only one tex provided, no blending
+ }
+ else if (tex_b && !tex_a)
+ {
+ shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_b);
+ tex_a->setFilteringOption(filter_mode);
+ blend_factor = 0; // only one tex provided, no blending
+ }
+ else if (tex_b != tex_a)
+ {
+ shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
+ tex_a->setFilteringOption(filter_mode);
+ shader->bindTexture(LLViewerShaderMgr::BUMP_MAP2, tex_b);
+ tex_b->setFilteringOption(filter_mode);
+ }
- // bind reflection texture from RenderTarget
- S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
+ shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
- F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] };
+ shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
- shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
- shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
+ F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
- F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
+ shader->bindTexture(LLShaderMgr::WATER_SCREENTEX, &gPipeline.mWaterDis);
- if (screentex > -1)
- {
- shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
- gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
- }
+ if (mShaderLevel == 1)
+ {
+ fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
+ }
- if (mShaderLevel == 1)
- {
- fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
- }
+ F32 water_height = environment.getWaterHeight();
+ F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
+ shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
+ shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
+ shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
- F32 water_height = environment.getWaterHeight();
- F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
- shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
- shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
- shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+ shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
- shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
- shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
- shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, 1, fog_color_linear.mV);
+ shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
+ shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
- shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
- shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
+ shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
- shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
- shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
+ shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
+ shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
+ shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
+ shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, fmaxf(0, pwater->getBlurMultiplier()) * 2);
- shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
+ static LLStaticHashedString s_exposure("exposure");
+ static LLStaticHashedString tonemap_mix("tonemap_mix");
+ static LLStaticHashedString tonemap_type("tonemap_type");
- shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
- shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
- shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
- shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
+ static LLCachedControl<F32> exposure(gSavedSettings, "RenderExposure", 1.f);
- F32 sunAngle = llmax(0.f, light_dir.mV[1]);
- F32 scaledAngle = 1.f - sunAngle;
+ F32 e = llclamp(exposure(), 0.5f, 4.f);
- shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
- shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
- shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
- shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle);
- shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
+ static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", false);
- // SL-15861 This was changed from getRotatedLightNorm() as it was causing
- // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
- LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
- shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
+ shader->uniform1f(s_exposure, e);
+ static LLCachedControl<U32> tonemap_type_setting(gSavedSettings, "RenderTonemapType", 0U);
+ shader->uniform1i(tonemap_type, tonemap_type_setting);
+ shader->uniform1f(tonemap_mix, psky->getTonemapMix(should_auto_adjust()));
- shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+ F32 sunAngle = llmax(0.f, light_dir.mV[1]);
+ F32 scaledAngle = 1.f - sunAngle;
- if (LLViewerCamera::getInstance()->cameraUnderWater())
- {
- shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
- }
- else
- {
- shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
- }
+ shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
- LLGLDisable cullface(GL_CULL_FACE);
+ // SL-15861 This was changed from getRotatedLightNorm() as it was causing
+ // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
+ LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
+ shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
- pushWaterPlanes(edge);
+ shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
- shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
- shader->disableTexture(LLShaderMgr::BUMP_MAP);
+ if (LLViewerCamera::getInstance()->cameraUnderWater())
+ {
+ shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
+ }
+ else
+ {
+ shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
+ }
- // clean up
- gPipeline.unbindDeferredShader(*shader);
+ LLGLDisable cullface(GL_CULL_FACE);
- gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
- }
+ // Only push the water planes once.
+ // Previously we did this twice: once for void water and one for region water.
+ // However, the void water and region water shaders are the same exact shader.
+ // They also had the same exact state with the sole exception setting an edge water flag.
+ // That flag was not actually used anywhere in the shaders.
+ // - Geenz 2025-02-11
+ pushWaterPlanes(0);
- gGL.getTexUnit(0)->activate();
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ // clean up
+ gPipeline.unbindDeferredShader(*shader);
gGL.setColorMask(true, false);
}
@@ -333,22 +312,18 @@ void LLDrawPoolWater::pushWaterPlanes(int pass)
LLVOWater* water = nullptr;
for (LLFace* const& face : mDrawFace)
{
- if (!face)
- continue;
water = static_cast<LLVOWater*>(face->getViewerObject());
- if (!water)
- continue;
- if ((bool)pass == (bool)water->getIsEdgePatch())
+ face->renderIndexed();
+
+ // Note non-void water being drawn, updates required
+ // Previously we had some logic to determine if this pass was also our water edge pass.
+ // Now we only have one pass. Check if we're doing a region water plane or void water plane.
+ // - Geenz 2025-02-11
+ if (!water->getIsEdgePatch())
{
- face->renderIndexed();
-
- // Note non-void water being drawn, updates required
- if (!pass) // SL-16461 remove !LLPipeline::sUseOcclusion check
- {
- sNeedsReflectionUpdate = true;
- sNeedsDistortionUpdate = true;
- }
+ sNeedsReflectionUpdate = true;
+ sNeedsDistortionUpdate = true;
}
}
}
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index ac4519e593..a0a9906724 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -114,7 +114,6 @@ LLGLSLShader gObjectAlphaMaskNoColorProgram;
//environment shaders
LLGLSLShader gWaterProgram;
-LLGLSLShader gWaterEdgeProgram;
LLGLSLShader gUnderWaterProgram;
//interface shaders
@@ -410,7 +409,6 @@ void LLViewerShaderMgr::finalizeShaderList()
//ONLY shaders that need WL Param management should be added here
mShaderList.push_back(&gAvatarProgram);
mShaderList.push_back(&gWaterProgram);
- mShaderList.push_back(&gWaterEdgeProgram);
mShaderList.push_back(&gAvatarEyeballProgram);
mShaderList.push_back(&gImpostorProgram);
mShaderList.push_back(&gObjectBumpProgram);
@@ -877,6 +875,7 @@ std::string LLViewerShaderMgr::loadBasicShaders()
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/pbrterrainUtilF.glsl", 1) );
+ index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/tonemapUtilF.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", has_reflection_probes ? 3 : 2) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
@@ -909,7 +908,6 @@ bool LLViewerShaderMgr::loadShadersWater()
if (mShaderLevel[SHADER_WATER] == 0)
{
gWaterProgram.unload();
- gWaterEdgeProgram.unload();
gUnderWaterProgram.unload();
return true;
}
@@ -923,6 +921,7 @@ bool LLViewerShaderMgr::loadShadersWater()
gWaterProgram.mFeatures.hasGamma = true;
gWaterProgram.mFeatures.hasSrgb = true;
gWaterProgram.mFeatures.hasReflectionProbes = true;
+ gWaterProgram.mFeatures.hasTonemap = true;
gWaterProgram.mFeatures.hasShadows = use_sun_shadow;
gWaterProgram.mShaderFiles.clear();
gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER));
@@ -946,36 +945,6 @@ bool LLViewerShaderMgr::loadShadersWater()
if (success)
{
- // load water shader
- gWaterEdgeProgram.mName = "Water Edge Shader";
- gWaterEdgeProgram.mFeatures.calculatesAtmospherics = true;
- gWaterEdgeProgram.mFeatures.hasAtmospherics = true;
- gWaterEdgeProgram.mFeatures.hasGamma = true;
- gWaterEdgeProgram.mFeatures.hasSrgb = true;
- gWaterEdgeProgram.mFeatures.hasReflectionProbes = true;
- gWaterEdgeProgram.mFeatures.hasShadows = use_sun_shadow;
- gWaterEdgeProgram.mShaderFiles.clear();
- gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER));
- gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER));
- gWaterEdgeProgram.clearPermutations();
- gWaterEdgeProgram.addPermutation("WATER_EDGE", "1");
- if (LLPipeline::sRenderTransparentWater)
- {
- gWaterEdgeProgram.addPermutation("TRANSPARENT_WATER", "1");
- }
-
- if (use_sun_shadow)
- {
- gWaterEdgeProgram.addPermutation("HAS_SUN_SHADOW", "1");
- }
- gWaterEdgeProgram.mShaderGroup = LLGLSLShader::SG_WATER;
- gWaterEdgeProgram.mShaderLevel = mShaderLevel[SHADER_WATER];
- success = gWaterEdgeProgram.createShader();
- llassert(success);
- }
-
- if (success)
- {
//load under water vertex shader
gUnderWaterProgram.mName = "Underwater Shader";
gUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
@@ -2484,6 +2453,7 @@ bool LLViewerShaderMgr::loadShadersDeferred()
gDeferredPostTonemapProgram.mName = "Deferred Tonemap Post Process";
gDeferredPostTonemapProgram.mFeatures.hasSrgb = true;
gDeferredPostTonemapProgram.mFeatures.isDeferred = true;
+ gDeferredPostTonemapProgram.mFeatures.hasTonemap = true;
gDeferredPostTonemapProgram.mShaderFiles.clear();
gDeferredPostTonemapProgram.clearPermutations();
gDeferredPostTonemapProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER));
@@ -2498,6 +2468,7 @@ bool LLViewerShaderMgr::loadShadersDeferred()
gNoPostTonemapProgram.mName = "No Post Tonemap Post Process";
gNoPostTonemapProgram.mFeatures.hasSrgb = true;
gNoPostTonemapProgram.mFeatures.isDeferred = true;
+ gNoPostTonemapProgram.mFeatures.hasTonemap = true;
gNoPostTonemapProgram.mShaderFiles.clear();
gNoPostTonemapProgram.clearPermutations();
gNoPostTonemapProgram.addPermutation("NO_POST", "1");
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 6326de9a6b..7ad2da9464 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -192,7 +192,6 @@ extern LLGLSLShader gObjectAlphaMaskNoColorProgram;
//environment shaders
extern LLGLSLShader gWaterProgram;
-extern LLGLSLShader gWaterEdgeProgram;
extern LLGLSLShader gUnderWaterProgram;
extern LLGLSLShader gGlowProgram;
extern LLGLSLShader gGlowExtractProgram;