diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index e9bbdeead52..350e273bf05 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1339,6 +1339,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("minimum_alpha"); mReservedUniforms.push_back("emissive_brightness"); + mReservedUniforms.push_back("alpha_gamma"); // Deferred mReservedUniforms.push_back("shadow_matrix"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 1b638e6e065..56a78a0fab4 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -156,6 +156,7 @@ class LLShaderMgr MINIMUM_ALPHA, // "minimum_alpha" EMISSIVE_BRIGHTNESS, // "emissive_brightness" + ALPHA_GAMMA, // "alpha_gamma" DEFERRED_SHADOW_MATRIX, // "shadow_matrix" DEFERRED_ENV_MAT, // "env_mat" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d6a1fbd124f..21104414d51 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7478,6 +7478,28 @@ Value 0 + RenderLegacyAlphaGamma + + Comment + Gamma correction factor (clamped between 1.0 and 2.0) used to render non-PBR faces with alpha blend. 1.0 to disable. + Persist + 1 + Type + F32 + Value + 1.4 + + RenderLegacyAlphaGammaEnable + + Comment + TRUE to enable the alpha-gamma workaround (see RenderLegacyAlphaGamma). + Persist + 1 + Type + Boolean + Value + 1 + RenderLocalLightCount Comment diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index cc9d72fae61..8a52d6b0477 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -37,6 +37,7 @@ uniform mat3 env_mat; uniform vec3 sun_dir; uniform vec3 moon_dir; uniform int classic_mode; +uniform float alpha_gamma; #ifdef USE_DIFFUSE_TEX uniform sampler2D diffuseMap; @@ -215,7 +216,10 @@ void main() } color.rgb = diffuse_srgb.rgb; - color.a = final_alpha; + if (alpha_gamma != 0.0 && alpha_gamma != 1.0) + color.a = pow(final_alpha, alpha_gamma); + else + color.a = final_alpha; #else // FOR_IMPOSTOR @@ -254,25 +258,21 @@ void main() vec3 legacyenv; sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, frag, pos.xyz, norm.xyz, 0.0, 0.0, true, amblit_linear); - - float da = dot(norm.xyz, light_dir.xyz); - da = clamp(da, -1.0, 1.0); - - float final_da = da; - final_da = clamp(final_da, 0.0f, 1.0f); + float final_da = clamp(dot(norm.xyz, light_dir.xyz), 0.0f, 1.0f); vec4 color = vec4(0.0); - color.a = final_alpha; + if (alpha_gamma != 0.0 && alpha_gamma != 1.0) + color.a = pow(final_alpha, alpha_gamma); + else + color.a = final_alpha; color.rgb = irradiance; if (classic_mode > 0) { final_da = pow(final_da,1.2); vec3 sun_contrib = vec3(min(final_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 { @@ -300,9 +300,12 @@ void main() color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, color).rgb; #endif // #else // FOR_IMPOSTOR - float final_scale = 1; + float final_scale = 1.0; + // HACK: to get more saturated colors, which otherwise get washed out when alpha_gamma > 1.0. HB + if (alpha_gamma > 1.0) + final_scale = pow(alpha_gamma, 0.333333); if (classic_mode > 0) - final_scale = 1.1; + final_scale *= 1.1; #ifdef IS_HUD color.rgb = linear_to_srgb(color.rgb); final_scale = 1; @@ -311,4 +314,3 @@ void main() color.rgb *= final_scale; frag_color = max(color, vec4(0)); } - diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 5708fc319fa..83fa5469751 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -284,10 +284,10 @@ float getShadow(vec3 pos, vec3 norm) #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) return sampleDirectionalShadow(pos, norm, vary_texcoord0.xy); #else - return 1; + return 1.; #endif #else - return 1; + return 1.; #endif } @@ -348,9 +348,7 @@ void main() { 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 { @@ -407,14 +405,14 @@ void main() #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) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) - color += light; + color.rgb += light; color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; @@ -441,5 +439,3 @@ void main() #endif } - - diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 87b6ce6cb3a..a5ac7c79b53 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -595,6 +595,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) above_water = !above_water; } + // Gamma correction factor for alpha faces without PBR material, in PBR + // rendering mode. HB + static LLCachedControl use_gamma(gSavedSettings, + "RenderLegacyAlphaGammaEnable"); + static LLCachedControl legacy_gamma(gSavedSettings, + "RenderLegacyAlphaGamma"); + F32 alpha_gamma = use_gamma ? llclamp((F32)legacy_gamma, 1.f, 2.f) : 1.f; for (LLCullResult::sg_iterator i = begin; i != end; ++i) { @@ -760,6 +767,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[VRED], spec_color.mV[VGREEN], spec_color.mV[VBLUE], spec_color.mV[VALPHA]); current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); + // Alpha-gamma correction/workaround, which only applies to + // faces pertaining to a legacy (non-PBR) object. HB + LLViewerObject* objp = params.mRootObject.get(); + F32 agamma = objp && objp->getUsePBR() ? 1.f : alpha_gamma; + current_shader->uniform1f(LLShaderMgr::ALPHA_GAMMA, agamma); } } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 90ee95d424b..569c1c83723 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -238,6 +238,20 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); + // Gamma correction factor for alpha faces without PBR material. HB + static LLCachedControl use_gamma(gSavedSettings, + "RenderLegacyAlphaGammaEnable"); + static LLCachedControl legacy_gamma(gSavedSettings, + "RenderLegacyAlphaGamma"); + F32 alpha_gamma = use_gamma ? llclamp((F32)legacy_gamma, 1.f, 2.f) : 1.f; + // *HACK: we apply the _inverted_ correction because for the avatar's + // eyelashes (which is the only part still playing a role in today's + // avatars, the only other alpha-sensitive part being legacy hair, + // which are nowadays always "bald" (100% alpha) to let mesh hair or + // head replace them), the gamma is too strong (too much transparency) + // in PBR rendering mode. HB + sVertexProgram->uniform1f(LLShaderMgr::ALPHA_GAMMA, 1.f / alpha_gamma); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 3aaa3d60e87..b1e48975ee6 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -110,7 +110,8 @@ class LLDrawInfo final : public LLRefCount const LLMatrix4* mTextureMatrix = nullptr; const LLMatrix4* mModelMatrix = nullptr; - LLPointer mAvatar = nullptr; + LLPointer mAvatar; + LLPointer mRootObject; LLMeshSkinInfo* mSkinInfo = nullptr; // Material pointer here is likely for debugging only and are immaterial (zing!) @@ -136,6 +137,8 @@ class LLDrawInfo final : public LLRefCount U8 mShiny = 0; bool mFullbright = false; bool mHasGlow = false; + // Set to 'true' when a PBR material is actually used to render this face. HB + bool mHasPBR = false; struct CompareTexture { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index ed4856df114..ab619b3e773 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -312,7 +312,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mLastUpdateCached(false), mCachedMuteListUpdateTime(0), mCachedOwnerInMuteList(false), - mRiggedAttachedWarned(false) + mRiggedAttachedWarned(false), + mUsePBR(false) { if (!is_global) { @@ -6971,6 +6972,10 @@ void LLViewerObject::recursiveMarkForUpdate() void LLViewerObject::markForUpdate() { + if (!isReflectionProbe()) + { + getRootEdit()->mUsePBR = false; // This will be reevaluated. HB + } if (mDrawable.notNull()) { gPipeline.markTextured(mDrawable); @@ -7524,7 +7529,12 @@ const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const void LLViewerObject::rebuildMaterial() { llassert(!isDead()); - + // Note: do not reset mUsePBR on reflection probes (would cause probe + // rebuild every few seconds). HB + if (!isReflectionProbe()) + { + getRootEdit()->mUsePBR = false; // This will be reevaluated. HB + } faceMappingChanged(); gPipeline.markTextured(mDrawable); } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a9c2db60e46..332fd5d23ca 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -416,6 +416,9 @@ class LLViewerObject void fitFaceTexture(const U8 face); void sendTEUpdate() const; // Sends packed representation of all texture entry information + inline void setUsePBR() { mUsePBR = true; } + inline bool getUsePBR() const { return mUsePBR; } + virtual void setScale(const LLVector3 &scale, bool damped = false); S32 getAnimatedObjectMaxTris() const; @@ -983,6 +986,8 @@ class LLViewerObject EObjectUpdateType mLastUpdateType; bool mLastUpdateCached; + bool mUsePBR; + public: // reflection probe state bool mIsReflectionProbe = false; // if true, this object should register itself with LLReflectionProbeManager diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index aa230f46361..e426326692b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5295,7 +5295,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; } - bool selected = facep->getViewerObject()->isSelected(); + LLViewerObject* vobjp = facep->getViewerObject(); + bool selected = vobjp->isSelected(); if (selected && LLSelectMgr::getInstance()->mHideSelectedObjects) { @@ -5372,10 +5373,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U8 index = facep->getTextureIndex(); + bool has_pbr = false; LLMaterial* mat = nullptr; - LLUUID mat_id; - auto* gltf_mat = (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial(); llassert(gltf_mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr); if (gltf_mat != nullptr) @@ -5384,6 +5384,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, if (!facep->hasMedia() || (tex && tex->getType() != LLViewerTexture::MEDIA_TEXTURE)) { // no media texture, face texture will be unused tex = nullptr; + has_pbr = true; } } else @@ -5447,6 +5448,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, info->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && #endif info->mMaterialID == mat_id && + info->mHasPBR == has_pbr && info->mFullbright == fullbright && info->mBump == bump && (!mat || (info->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different @@ -5464,6 +5466,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, info->mTextureList.resize(index+1); info->mTextureList[index] = tex; } + // Make sure the PBR flag usage is set on the root object when PBR is + // used on this face. HB + if (has_pbr && info->mRootObject.notNull()) + { + info->mRootObject->setUsePBR(); + } info->validate(); } else @@ -5501,7 +5509,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mShaderMask = shader_mask; draw_info->mAvatar = facep->mAvatar; draw_info->mSkinInfo = facep->mSkinInfo; - + draw_info->mHasPBR = has_pbr; + draw_info->mRootObject = vobjp->getRootEdit(); + if (has_pbr) + { + draw_info->mRootObject->setUsePBR(); + } if (gltf_mat) { // just remember the material ID, render pools will reference the GLTF material