FIRE-35735 - Imposter/Impostor Avatar Exclusions

This change allows a user to keep using the imposter system, but protect Animesh avatars from not animating or having rendering issues. (Missing Attachments). This includes pets, control avatars, Animesh attachments, etc.

Added new setting FSImpostorAvatarExclude to control excluding Animated Mesh (Animesh) Avatars from using the Imposter rendering pipeline.

Setting is accessible in the Preferences -> Graphics -> Rendering in the misc. section labeled "Exclude Animesh Impostor Avatar".

There are four possible options:
None: Default, don't exclude any avatars.
User: Exclude only user avatars which have Animesh attached to them.
Control: Exclude only control avatars.
Both: Exclude both User Animesh avatars and control avatars.

There are rending issues as well as animation issues related to how the impostor system renders Animesh.

Updated LLVOAvatar.h to have new boolean flag tracking if the Avatar or any attachments are Animesh.

Added Enum to match the possible values stored in FSImpostorAvatarExclude .

Added checks to isVisuallyMuted, isTooComplex, isImpostor and shouldImpostor to prevent excluded Avatars from being added to the Impostor list.

Updated attachObject, updateAttachmentOverrides, detachObject to check if the Avatar or any of the attachments is an animated object and store in the mIsAnimesh flag.
master
minerjr 2025-07-07 10:29:13 -03:00
parent a8a25cd11c
commit a67b753ff5
4 changed files with 146 additions and 2 deletions

View File

@ -13235,6 +13235,26 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<real>0</real>
</map>
<key>FSImpostorAvatarExclude</key>
<map>
<key>Comment</key>
<string>Allows for Animesh User or Control Avatars to be excluded from using impostor rendering. Values are: (0 - None, 1 - User, 2 - Control, 3 - Both).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
<key>SanityCheckType</key>
<string>Between</string>
<key>SanityValue</key>
<array>
<integer>0</integer>
<integer>3</integer>
</array>
<key>SanityComment</key>
<string>Setting this value lower than 0 or higher than 3 has no effect.</string>
</map>
<key>RenderAvatarComplexityMode</key>
<map>
<key>Comment</key>

View File

@ -237,6 +237,17 @@ enum ERenderName
RENDER_NAME_FADE
};
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// Different settings based on FSImpostorAvatarExclude
enum EImpostorAvatarExclude
{
NONE, // Default, no avatar excluded
USER, // Check for mIsAnimesh only, exclude user Avatar's which are Animesh or have Animesh attachments
CONTROL, // Check for mIsControlAvatar only, exclude control avatars (avtars which don't have a user UUID assigned)
BOTH // Check both mIsAnimesh or mIsControlAvatar, exclude both User Amimesh and Control avatars.
};
// </FS:minerjr> [FIRE-35735]
#define JELLYDOLLS_SHOULD_IMPOSTOR
//-----------------------------------------------------------------------------
@ -4643,6 +4654,9 @@ bool LLVOAvatar::isVisuallyMuted()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // <FS:Beq/> Tracy accounting for imposter testing.
bool muted = false;
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// </FS:minerjr> [FIRE-35735]
// <FS:Ansariel> FIRE-11783: Always visually mute avatars that are muted
if (!isSelf() && isInMuteList())
@ -4677,6 +4691,13 @@ bool LLVOAvatar::isVisuallyMuted()
#else
muted = false;
#endif
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is set to be excluded, set the muted flag to false
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
muted = false;
}
// </FS:minerjr> [FIRE-35735]
}
// <FS:Ansariel> FIRE-11783: Always visually mute avatars that are muted
//else if (isInMuteList())
@ -4686,10 +4707,26 @@ bool LLVOAvatar::isVisuallyMuted()
// </FS:Ansariel>
else if (mIsControlAvatar)
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is set to control or both, set the the meted flag to false
if (impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL)
{
muted = false;
}
else
// </FS:minerjr> [FIRE-35735]
muted = isTooSlow();
}
else
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is an animesh and the FSImpostorAvatarExclude is either a USER or BOTH (Can use & as both 1 and 3 have 1 set)
if ((impostor_avatar_exclude & EImpostorAvatarExclude::USER) && mIsAnimesh)
{
muted = false;
}
else
// </FS:minerjr> [FIRE-35735]
muted = isTooComplex(); // <FS:Beq/> this should not trigger based on perfstats
}
}
@ -7585,6 +7622,10 @@ void LLVOAvatar::updateAttachmentOverrides()
}
}
#endif
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
}
void LLVOAvatar::notifyAttachmentMeshLoaded()
@ -8535,6 +8576,10 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
updateMeshVisibility();
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
return attachment;
}
@ -8860,6 +8905,10 @@ bool LLVOAvatar::detachObject(LLViewerObject *viewer_object)
}
updateMeshVisibility();
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;
return true;
@ -8870,6 +8919,10 @@ bool LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (iter != mPendingAttachment.end())
{
mPendingAttachment.erase(iter);
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
return true;
}
@ -9655,6 +9708,15 @@ bool LLVOAvatar::isTooComplex() const
}
else
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// If the avatar is set to be excluded, return that the avatar is not too complex
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
// Determine if visually muted or not
static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U);
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
@ -12098,8 +12160,23 @@ bool LLVOAvatar::isImpostor()
{
// <FS:Beq> render time handling using tooSlow()
// return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1));
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// Store the result of is visually muted as used in possibly 2 places
bool is_visual_muted = isVisuallyMuted();
// If the avatar is set to be excluded, return that the avatar is not an Impostor
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
return (
isVisuallyMuted() ||
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// isVisuallyMuted() ||
is_visual_muted || // Save from calling isVisuallyMuted a second time
// </FS:minerjr> [FIRE-35735]
isTooSlowWithoutShadows() ||
(sLimitNonImpostors && (mUpdatePeriod > 1) )
);
@ -12120,6 +12197,15 @@ bool LLVOAvatar::shouldImpostor(const F32 rank_factor)
// return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor);
// static LLCachedControl<bool> render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors");
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// If the avatar is set to be excluded, return that the avatar should not be impostored
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
if (isTooSlowWithoutShadows())
{
return true;

View File

@ -684,6 +684,7 @@ public:
// [/RLVa:KB]
// bool mNeedsImpostorUpdate;
S32 mLastImpostorUpdateReason;
bool mIsAnimesh; // <FS:minerjr> FIRE-35735: Imposter/Impostor Avatar Exclusions (Flag to track if avatar or attachments have Animated Mesh flagged)
F32SecondsImplicit mLastImpostorUpdateFrameTime;
const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; }
void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; }

View File

@ -1423,6 +1423,43 @@ If you do not understand the distinction then leave this control alone."
<check_box.commit_callback
function="Pref.RenderOptionUpdate" />
</check_box>
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left_delta="200"
width="200"
name="ExcludeAnimeshImposterLabel">
Exclude Animesh Impostor Avatar:
</text>
<combo_box
control_name="FSImpostorAvatarExclude"
height="23"
layout="topleft"
tool_tip="Allows for Animesh User or Control Avatars to be excluded from using impostor rendering."
left_pad="8"
top_delta="-4"
name="FSImpostorAvatarExclude"
width="80">
<combo_box.item
label="None"
name="0"
value="0"/>
<combo_box.item
label="User"
name="1"
value="1"/>
<combo_box.item
label="Control"
name="2"
value="2"/>
<combo_box.item
label="Both"
name="3"
value="3"/>
</combo_box>
<check_box
control_name="RenderAutoMaskAlphaDeferred"
height="16"
@ -1430,7 +1467,7 @@ If you do not understand the distinction then leave this control alone."
label="Render alpha masks"
tool_tip="When ticked this makes the Alpha masks (see-thru bits) render correctly"
layout="topleft"
left_delta="0"
left="20"
name="RenderAutoMaskAlphaDeferred"
top_pad="2"
width="256"/>