17 KiB
Fiche STG-B2q-DIAG — Niveau N3 — Modèle prévu claude-opus-5-5 | utilisé claude-opus-5-5 — Agent orchestrateur STG (session principale) — Skills lp-lot, sk-protocol
STG-B2q-DIAG : personnages assis éliminés par le rendu (2026-10-14)
Fiche B2q, confiée à STG par Big Boss (CAM est pris par B2p ; le sujet touche le maillage des Person). DIAG en lecture seule, sans UE et
sans écriture hors de ce livrable. Lot STG, registre STG-TACHES.md.
Faits donnés par Big Boss :
- COMMUN-6, 05:28-05:32, au bar : la PNJ d'en face, puis le joueur assis, disparaissent selon l'angle de C2.
hidden=0, et aucune ligne T-occ : le rayon caméra → tête était libre. - COMMUN-7, 07:48, au café (« Having a meal ») : « Bridget a disparu ». Le joueur est assis
fnt_new048, place_67(journal :OccupyingFnt _67dès 07:47:45,currentAnimation=fnt_new048-f-0-sit,meshZ=-80.4) ; la capture montre une chaise vide.
Point de départ : hypothèse de CAM (etat\CAM\CAM-COMMUN6-DIAG.md § 8), reprise et vérifiée ci-dessous.
1. Sources
| Repère | Fichier |
|---|---|
| E1 | moteur UE 5.8, Engine\Source\Runtime\Engine\Private\Components\SkeletalMeshComponent.cpp l. 3417-3495 (USkeletalMeshComponent::CalcBounds) |
| E2 | idem, SkinnedMeshComponent.cpp l. 2169-2175 (CalcBounds) et l. 2225-2300 (CalcMeshBound) |
| P | etat\portage55\L6f\L6f_dump_Person.txt : graphes de Person (UserConstructionScript l. 1-12, NewProxy l. 1851-1955) |
| C | etat\CAM\CAM-T4_LPDumpComponents_20261011-004910.txt : composants SCS de Person (PenisSM, HairSM, DirtyTalkSM, parents CharacterMesh0) |
| A | Content\BPs\Person.uasset : table des noms (grep -c -a) |
| I | Config\DefaultEngine.ini l. 30 |
| J | journal en cours de COMMUN-7 (café) |
2. Ce qui est établi
2.1 Comment UE 5.8 calcule les bornes de rendu d'un SkeletalMesh (E1, E2)
USkeletalMeshComponent::CalcBounds appelle CalcMeshBound(RootBoneTranslation, bHasValidBodies, …). Dans CalcMeshBound, les cas sont
examinés dans cet ordre :
- composant invisible, ou
bComponentUseFixedSkelBounds: bornes de l'asset ; - composant leader en bornes fixes : bornes de l'asset du leader ;
- leader avec
bUseBoundsFromLeaderPoseComponent: bornes du leader ; - asset physique avec corps : AABB des corps, qui suivent les os, donc la pose ;
- leader avec asset physique : idem, sur les corps du leader ;
- sinon, bornes importées de l'asset (pose de référence, debout), décalées de la seule translation de l'os racine ;
puis BoxExtent *= BoundsScale, autour du même centre.
Sans asset physique, les bornes ne suivent donc pas la pose : seul le déplacement de l'os racine les déplace.
2.2 Les maillages des Person
- Pas d'asset physique sur
bridget_gpnimichael(CAM § 8 : aucun importPhysicsAsset). Les corps tombent dans le cas 6. - Composants (C) :
- le corps est
CharacterMesh0, hérité deACharacter; PenisSMetHairSMlui sont attachés.UserConstructionScriptleur donne le corps comme leader pose (P l. 1-12) ;DirtyTalkSMest un widget.
- le corps est
- Vêtements, cheveux et accessoires ajoutés par
Person::NewProxy(P l. 1851-1955) : sur chaque nouveau composant,SetBoundsScale(3.0),SetCastShadow(false),SetRenderCustomDepth(true),bUseAttachParentBound = true, puisSetLeaderPoseComponent(Mesh). Ces composants prennent donc les bornes du corps, et leurBoundsScale 3est sans effet (les bornes du parent sont reprises telles quelles). Conséquence : quand le corps est éliminé, tout disparaît avec lui (vêtements, cheveux). C'est bien « la chaise vide ». - Corps (
CharacterMesh0) : aucun graphe de Person ne règle ses bornes. La table des noms (A) ne contient nibComponentUseFixedSkelBounds, nibUseBoundsFromLeaderPoseComponent, nibIncludeComponentLocationIntoBounds. Ses 3 occurrences deBoundsScales'expliquent parSetBoundsScale/NewBoundsScale, ses 2 debUseAttachParentBoundpar le nœud deNewProxy. Une valeur deBoundsScalestockée sur le gabarit du corps n'est pas exclue sans lecture MCP. Estimé : 1 (défaut). r.AllowOcclusionQueries=True(I) : les requêtes d'occlusion sont actives.- Aucun C++ du projet ne touche aux bornes ni au culling (
grepdeBoundsScale,bUseAttachParentBoundetLeaderPosedansSource/: 0).
2.3 Les poses assises
- Assis, le corps joue l'animation de meuble dans l'Anim BP (
anim=bp:Daily_F_C currentAnimation=fnt_new048-f-0-sit), et le composant est relevé (meshZ-80,4 au lieu de -90). Les bornes restent celles de la pose debout, autour de la racine. - Ce DIAG n'établit pas de combien le corps s'écarte de la racine dans ces animations. Le journal ne relève ni les os en XY ni les bornes. Les relevés M1d (COMMUN-6) ne donnent que des hauteurs, en scène de couple.
3. Cause (estimée, forte)
Le corps assis est éliminé parce que ses bornes, celles de la pose debout autour de la racine, ne contiennent plus le corps. Les animations de meuble déplacent le bassin et non la racine. Deux mécanismes sont possibles, selon l'angle :
- occlusion : les bornes sont derrière la table, le comptoir ou le dossier, alors que le corps dépasse et est visible. La requête d'occlusion les juge cachées et élimine le maillage entier, vêtements compris. C'est le plus probable au bar et au café (tables), en C2 qui tourne autour ;
- frustum : les bornes sont hors du champ alors que le corps y est.
hidden=0 et l'absence de T-occ sont compatibles avec les deux. Trancher entre eux, et mesurer l'écart, demande le témoin du § 5.
À exclure, peu probable :
- la distance d'affichage (
MaxDrawDistance/CullDistance) : le joueur assis est proche ; - le
LOD: un maillage n'est pas éliminé par le LOD ; VisibilityBasedAnimTickOption: il arrête l'animation, pas l'affichage.
Observation annexe (hors B2q) : l'assiette et le sandwich qui flottent près de l'épaule de la PNJ au café sont un accessoire de place mal attaché. Mineur ; à noter pour plus tard.
4. Correctif proposé (C++ sans asset ; rien n'est écrit sans GO)
| Id | Geste | Coût d'écriture | Coût de rendu | Risque |
|---|---|---|---|---|
| B2q-a (recommandé) | BoundsScale adaptatif du corps. Toutes les 0,5 s, pour chaque Person_C visible de la pièce, on calcule l'écart entre le bassin (hip, sinon pelvis, sinon l'os 0) et le centre des bornes du corps, puis le facteur S = max(1, (écart + rayon des bornes) / rayon des bornes), borné à 4. On ne l'applique qu'en cas de changement de plus de 10 % : SetBoundsScale(S), UpdateBounds(), MarkRenderStateDirty(). Une ligne de journal par changement. Debout, S = 1 : pas de surcoût. Assis, couché ou en meuble, S couvre le corps déplacé. Les vêtements suivent (bUseAttachParentBound). |
≈ 50 lignes C++ (DirectControl ou Debug, fichier STG), N3, VAL, 1 build | seulement pour les personnages assis : leurs bornes sont jusqu'à 4 fois plus grandes, donc ils sont un peu plus souvent dessinés hors champ ou cachés (ombres comprises). Faible pour une dizaine de corps ; à mesurer au bar (stat unit avant/après) |
faible : les bornes de rendu ne servent ni aux collisions ni aux tracés |
| B2q-b (repli, plus simple) | BoundsScale = 3 fixe sur le corps de toutes les Person (balayage toutes les 2 s, comme le propose CAM) |
≈ 30 lignes | constant, sur tous les personnages, même debout | faible ; il peut ne pas suffire si l'écart dépasse ≈ 1,2 m |
| B2q-c | Asset physique pour bridget_gp et michael : des bornes exactes qui suivent les os |
2 gros assets dans l'éditeur, hors alpha | nul | les corps entrent dans les tracés Visibility (sondes C2, T-occ) |
| B2q-d | r.AllowOcclusionQueries=False |
1 ligne de config | global (tout le jeu) | ne règle pas le cas frustum ; non recommandé |
bIncludeComponentLocationIntoBounds (suggéré par Big Boss) n'ajoute à la boîte que le point d'origine du composant (E2 l. 2173-2175, E1
l. 3472-3487). Cela ne couvre pas un corps déplacé : non retenu.
5. Témoin proposé (T-cull, à mettre dans le même build ; recommandé même avec B2q-a)
Dans LPDebugSubsystem (relevé des personnes, actif avec -LPPersonsLog), toutes les 0,5 s, pour chaque Person_C non cachée à moins de
15 m de la caméra :
- une ligne de mesure par changement de pose de meuble (
currentAnimationouOccupyingFnt) :T-cull mesure <Person> anim=<fnt…> bassin a %.0f cm du centre des bornes (dans=%d) ; bornes %.0f x %.0f x %.0f ; BoundsScale %.2f ; physAsset=%d; - une ligne d'alerte si le bassin est à l'écran (
ProjectWorldLocationToScreendans le viewport) et que le corps n'a pas été rendu depuis 0,2 s (WasRecentlyRendered(0.2f)faux) :T-cull : <Person> non rendue, bassin a l'ecran, a %.0f cm du centre des bornes (dans=%d), occlusion=%d.
Ces lignes chiffrent l'écart réel des poses assises et tranchent entre occlusion et frustum (dans=0 avec le centre des bornes hors du
champ : frustum). Elles diront aussi si B2q-a suffit. Coût : ≈ 35 lignes, 1 build ; journal seulement.
5b. Complément (Big Boss, café, 07:48-07:49)
L'utilisateur rapporte : « les deux ont disparu ». Les deux personnages assis à la même table (le joueur et la PNJ) disparaissent en même
temps, sous un même angle de C2. Cela va dans le sens du § 3 : deux corps assis à la même table ont chacun leurs bornes debout centrées
sur leur racine, et les deux boîtes passent ensemble derrière le même plateau ou hors du champ au même angle. Une cause propre à un
personnage (vêtement, animation, hidden) est moins probable. Le mécanisme occlusion par la table reste le plus probable ; le témoin
T-cull le tranchera (dans=0 et occlusion=1 attendus pour les deux à la même heure).
6. Estimation et ordre proposé
- T-cull et B2q-a dans le même build (COMMUN-8 ou suivant), avec une VAL statique : ≈ 85 lignes, N3, 1 build.
- Essai :
- le bar (C2 autour de la PNJ d'en face, puis du joueur assis) ;
- le café, assis à
fnt_new048; - un personnage couché ;
stat unitavant et après, au bar.
- Si une disparition persiste avec une ligne
T-cullàdans=1, la cause n'est pas les bornes : ouvrir une fiche Ombres/occlusion.
7. Fichiers à commiter
Docs/Migration/etat/ST/STG/STG-B2q-DIAG.md.
Tours : 14
8. Complément après l'essai COMMUN-8 : B2q-a insuffisant au café (2026-10-14)
Demande de Big Boss : l'utilisateur dit « manque l'homme » (café, vers 09:09) ; l'homme assis est invisible, son téléphone flotte. DIAG en lecture seule, sans UE.
8.1 Ce que dit le journal (établi)
Source : D:\Game\LifePlay_Build_5.8_COMMUN-8_Development\Windows\LifePlay\Saved\Logs\LifePlay.log (10 128 lignes à la lecture).
- Bar, chambre (B2q-a a suffi) : bassin à 13-123 cm du centre des bornes selon le meuble (
fnt_chair06: 123 cm, une autre place : 47 cm) ; S monte à 1,5-4 et l'écart est couvert. - Café (
cafe___vin01, chargé à 09:07:11, placesfnt_new048_59,_60,_66,_67) : bassin à 290 cm (hommes, anim.fnt_new048-m-0-sit) et 297 cm (femmes,-f-0-sit) du centre des bornes. Les mesures sont identiques pour les quatre personnes de même sexe, au cm près. S plafonne à 4, et les alertesT-cull : … non rendue … dans=0, centre a l'ecran=0sont fréquentes :PlayerCharacter86,Person_C_214748193034,…9062,…9541. - Les capsules (
LPDebug persons) sont sur les places :PlayerCharacteren (-3131768, -14967061) sur_59,…930sur_60, la chaise sous chacun (visibleComp= la place, -41,1). Le téléphone flotte « à sa place » sur la capture. Le corps est donc à la place, et c'est le centre des bornes qui est à ≈ 3 m. - Fait nouveau, qui corrige le § 2.2 du DIAG : à la première vue de chaque personne, la ligne
B2q-apart deBoundsScale 3.00(5 lignes3.00 -> …, dont 33.00 -> 1.00). Le corps a déjà BoundsScale 3 dans le jeu d'origine : c'est le réglage du gabarit ou d'un Blueprint (le même 3 queNewProxy). L'estimation « 1 (défaut) » du § 2.2 était fausse. B2q-a ramène les personnes debout à 1 : c'est une baisse par rapport à l'origine (risque R3 de la VAL réalisé). Elle est sans dommage visible debout, puisque le bassin est à 13-16 cm du centre, mais il faut la corriger.
8.2 Pourquoi le centre des bornes est à 3 m (estimé, fort)
Sans asset physique, les bornes sont celles de l'asset, décalées de RootBoneTranslation, la translation de l'os racine dans la pose
courante (§ 2.1 ; moteur SkeletalMeshComponent.cpp l. 3449-3470). La capsule et le corps sont sur la place, et les bornes sont à 290 ou
297 cm, avec une valeur fixe par animation (hommes 290, femmes 297, sur 4 places différentes). Lecture : l'animation de meuble
fnt_new048-*-0-sit déplace l'os racine d'≈ 3 m, et l'os du bassin compense en sens inverse. Le corps reste sur la place, mais UE
croit que le maillage a suivi la racine. C'est la même cause que pour les écarts plus petits (fnt_chair06 : 123 cm). L'amplitude dépend
de l'animation, sans doute de la façon dont elle a été créée ou convertie : racine au pivot du groupe de meubles.
Non établi : la position de l'os racine n'est pas au journal. Le témoin du § 8.4 l'écrira.
Plafond nécessaire avec B2q-a : le facteur s'applique de façon uniforme aux trois axes. Un écart de 290 cm le long de l'axe mince des bornes
(demi-étendue 13 cm, épaisseur du corps en pose de référence) demande S ≈ (290 + 13) / 13 ≈ 23, soit des bornes de ≈ 6 × 29 × 41 m.
À ce niveau, la personne n'est plus jamais éliminée : la culling est de fait coupée pour elle.
8.3 Correctif proposé B2q-b (rien n'est écrit sans GO)
| Id | Geste | Coût d'écriture | Coût de rendu | Risque |
|---|---|---|---|---|
| B2q-b1 (recommandé pour l'alpha) | Dans FitPersonBounds : (1) plancher = l'échelle d'origine de chaque personne, relevée à la première vue (3 dans le jeu d'origine) : plus jamais en dessous, ce qui corrige la baisse de B2q-a ; (2) plafond porté à 25 ; le facteur est calculé comme aujourd'hui, au besoin réel par axe. |
≈ 15 lignes, N3, VAL, 1 build | seulement pour les personnes dont la pose sort des bornes (au café, toutes les assises) : elles ne sont plus jamais éliminées (frustum ni occlusion), ombres comprises. Au café, 4 à 6 corps Daz (≈ 50-100 k triangles chacun) toujours dessinés. Estimé faible à modéré ; à mesurer par les lignes LPDebug hitch au café (COMMUN-8 contre le build suivant) |
faible : aucun effet sur collisions ni tracés ; journal inchangé (une ligne par changement de plus de 10 %) |
| B2q-b2 (après l'alpha, juste) | Recentrer les bornes sur le bassin : réécrire RootBoneTranslation du corps avec la position du bassin (en espace composant) après l'évaluation de l'animation et avant le calcul des bornes ; les bornes suivent alors le corps à S = 3 |
≈ 30 lignes, mais l'ordre des ticks (animation, puis bornes, puis notre ticker) n'est pas établi sans essai ; N4 | nul | moyen : RootBoneTranslation est recalculé à chaque évaluation ; l'écriture peut être écrasée ou arriver trop tard (une image de retard) |
| B2q-b3 (après l'alpha) | Asset physique minimal créé en mémoire (un corps sphérique sur l'os du bassin, PhysicsAssetOverride), collision du corps mise à NoCollision : les bornes suivent les os (cas 4 du § 2.1) |
≈ 40 lignes, N4 | nul | élevé sans essai : création des corps physiques, entrée dans les tracés Visibility si la collision n'est pas coupée à temps, chemin bHasValidBodies à vérifier |
| B2q-b4 | Corriger les animations de meuble (racine au siège) | assets, hors alpha | nul | conversion de toutes les fnt_* |
Recommandation : B2q-b1 pour l'alpha (simple, sûr, coût borné aux seules personnes assises loin de leur racine), plus le témoin du § 8.4. B2q-b2 sera étudié après l'alpha si le coût mesuré gêne.
8.4 Témoin complété (même build, ≈ 5 lignes)
La ligne T-cull mesure donnera aussi la distance de l'os racine (os 0) au bassin et au composant :
… racine a %.0f cm du bassin, a %.0f cm du composant. Une racine à ≈ 3 m du bassin et du composant établit le § 8.2.
8.5 Cas d'essai à ajouter (build suivant)
- Café : assis au comptoir ou à une table
fnt_new048, avec les PNJ assis ; tourner C2 tout autour. Plus aucune disparition, plus aucune alerteT-cull … non rendue;B2q-a : … BoundsScale 3.00 -> 2x.xxetracine a ≈ 290-300 cm du bassin. - Debout : aucune ligne
B2q-a … -> 1.00(plancher à l'échelle d'origine). - Coût : lignes
LPDebug hitchau café, comparées à COMMUN-8.