Troika: Avertissement "Un grand nombre de requêtes WorkerModule ouvertes, certaines peuvent ne pas revenir"

Créé le 30 mars 2021  ·  14Commentaires  ·  Source: protectwise/troika

Bonjour, je vois un grand nombre d'avertissements provenant de troika-worker.utils.esm.js avec ce message.

Screen Shot 2021-03-29 at 8 19 42 PM

Tout a l'air de bien fonctionner pourtant

une idée?

Tous les 14 commentaires

Hmm, cet avertissement ne se déclenche pas tant qu'il n'y a pas > 1000 demandes de travail ouvertes. Avez-vous un très grand nombre d'instances de texte ?

Je le fais, mais pas plus de 1000 (du moins pas intentionnellement)

plutôt quelques centaines

Voici ce que je rends

Screen Shot 2021-03-30 at 11 03 39 AM

Mais alors, qu'est-ce que vous dites, c'est qu'il y a peut-être un bogue de mon côté où je crée plus d'instances que ce dont j'ai réellement besoin et une fois que j'ai franchi le nombre de 1000, cela commence à générer une erreur?

J'ai défini des instances qui n'ont pas de contenu sur .visible = false

mais je suppose que cela signifie toujours que l'instance existe

recommanderiez-vous au lieu d'utiliser le prop .visible de supprimer entièrement les instances inutilisées ?

Ahh, ça pourrait expliquer ça. Tous les appels à .sync() seront toujours envoyés au travailleur en arrière-plan même s'ils sont visibles:false , et ils s'accumuleront.

Je pense que je choisirais personnellement de créer/supprimer les étiquettes à la demande, ou au moins d'empêcher les appels .sync() pour les étiquettes masquées. Ces demandes de travailleur utilisent toutes le même travailleur, donc s'il est occupé à traiter des étiquettes masquées, cela pourrait retarder le traitement de vos étiquettes visibles.

Je fais cependant quelques hypothèses, n'ayant pas vu votre code LabelView exact. Il est toujours possible qu'il y ait un bogue de mon côté, alors LMK ce que vous trouvez.

J'ai juste essayé d'appeler .sync() uniquement lorsque .visible === true

mais toujours recevoir les avertissements

si à la place je ne crée que des instances pour les objets visibles et détruit ceux qui ne sont pas utilisés, les avertissements disparaissent

Hmm, Text lui-même n'appelle que sync() dans onBeforeRender, qui _ne devrait pas_ se déclencher si visible=false.

Votre code d'emballage LabelView est-il disponible partout où je peux jeter un coup d'œil ?

Cela fait partie d'un projet source fermé

mais voici la classe pertinente, qui pourrait suffire

import {Mesh, MeshBasicMaterial} from "three";
import R from "../../../../../../../../../../resources/Namespace";
import BaseView, {ViewType} from "./BaseView";
import {Text} from "troika-three-text";
import {GeometryInstances} from "../instances/GeometryInstances";
import {MaterialInstances} from "../instances/MaterialInstances";

export enum TextAlign {
    left = "left",
    right = "right",
    center = "center",
    justify = "justify",
}

export enum HorizontalAlign {
    left = "left",
    right = "right",
    center = "center",
}

export enum VerticalAlign {
    top = "top",
    topBaseline = "top-baseline",
    middle = "middle",
    bottomBaseline = "bottom-baseline",
    bottom = "bottom",
}

export interface ILabelData {
    content: string;
    fontFace?: string;
    fontSize?: number;
    alignment?: TextAlign;
    horizontalAlign?: HorizontalAlign;
    verticalAlign?: VerticalAlign;
    color?: string;
    opacity?: number;
    backgroundColor?: string;
    highlightable: boolean;
}

export default class LabelView extends BaseView {
    get viewObject() {
        return this._viewObject as any;
    }

    get content() {
        return this.textMesh.text;
    }

    set content(content: string) {
        if (content !== this.textMesh.text) {
            this.textMesh.text = content;
            this.textMesh.visible = !!content;

            this.syncIfVisible();
        }
    }

    private syncIfVisible() {
        // Better for perf: https://github.com/protectwise/troika/issues/112
        if (this.textMesh?.text && this.textMesh?.visible && this._isVisible) {
            this.textMesh.sync();
        }
    }

    set textAlign(alignment: TextAlign) {
        this.textMesh.textAlign = alignment;
        this.syncIfVisible();
    }

    set horizontalAlign(alignment: HorizontalAlign) {
        this.textMesh.anchorX = alignment;
        this.syncIfVisible();
    }

    set verticalAlign(alignment: VerticalAlign) {
        this.textMesh.anchorY = alignment;
        this.syncIfVisible();
    }

    private backgroundMesh: Mesh | undefined;
    private readonly textMesh: any;
    private readonly foregroundColor: string;
    private highlightable: boolean;

    constructor(labelData: ILabelData) {
        super(ViewType.Label);

        this.foregroundColor = labelData.color || R.colors.elements.labels.foreground;

        this.highlightable = labelData.highlightable;

        if (labelData.backgroundColor) {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                1);

            this.textMesh.addEventListener("synccomplete", () => {
                if (this.backgroundMesh) {
                    this._viewObject.remove(this.backgroundMesh);
                }

                if (this.textMesh.text) {
                    const bounds = this.textMesh.textRenderInfo.blockBounds;
                    this.backgroundMesh =
                        this.createBackgroundBox(bounds[0], bounds[1], bounds[2], bounds[3], 0);
                    this._viewObject.add(this.backgroundMesh);
                }
            });

        } else {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                0);
        }

        this.syncIfVisible();

        this._viewObject.add(this.textMesh);
    }

    public onFrameRendered(elapsedTime: number) {
        if (this.highlightable) {
            this.setLabelHighlightState();
        }
    }

    private setLabelHighlightState() {
        const labelMaterial = this.textMesh.material as MeshBasicMaterial;
        if (this._isHighlighted) {
            labelMaterial.color.set(R.colors.elements.labels.highlighted);
        } else {
            labelMaterial.color.set(this.foregroundColor);
        }
    }

    private createTextMesh(content: string,
                           fontFace = R.layout.labels.font_face.regular,
                           fontSize = R.layout.labels.font_size,
                           textAlign = TextAlign.center,
                           horizontalAlign = HorizontalAlign.center,
                           verticalAlign = VerticalAlign.middle,
                           color: string,
                           opacity = 1,
                           zLevel: number) {
        const labelMesh = new Text();

        labelMesh.font = fontFace;
        labelMesh.text = content || "";
        labelMesh.fontSize = fontSize;
        labelMesh.position.z = zLevel;
        labelMesh.color = color;
        labelMesh.textAlign = textAlign;
        labelMesh.anchorX = horizontalAlign;
        labelMesh.anchorY = verticalAlign;

        labelMesh.material.opacity = opacity;
        labelMesh.name = "LabelView";

        return labelMesh;
    }

    private createBackgroundBox(startX: number, startY: number, endX: number, endY: number, zLevel: number) {
        const paddingLeft = 1;
        const paddingRight = 2;
        const paddingTop = 1;
        const paddingBottom = 0;

        const width = Math.abs(startX) + Math.abs(endX) + paddingLeft + paddingRight;
        const height = Math.abs(startY) + Math.abs(endY) + (paddingTop + paddingBottom);

        const geometry = GeometryInstances.getInstance().getPlaneGeometryInstance(width, height);
        const material = MaterialInstances.getInstance().backgroundColorMaterial;
        const mesh = new Mesh(geometry, material);

        const posX = ((startX + endX) / 2) + (paddingLeft / 4);
        const posY = ((startY + endY) / 2) - (paddingBottom);

        // The z level of element in accordance with standards defined in resources
        mesh.position.set(posX, posY, zLevel);
        mesh.name = "LabelBackgroundBox";

        return mesh;
    }
}

Hmm, mon intuition serait que syncIfVisible() est appelé avant que .visible ne soit défini sur false, mais il est difficile de dire avec certitude sans savoir comment fonctionne votre système de vue.

Une autre chose que je remarque est que vous émettez des appels syncIfVisible après chaque modification de propriété individuelle (content, textAlign, horizontalAlign, etc.) qui émettra plus d'appels au travailleur que nécessaire. Si votre système de vue a un cycle de vie où vous pouvez émettre un seul appel de synchronisation après que toutes les propriétés individuelles sont définies, ce serait bien mieux.

D'après ce que vous avez décrit, je pense que cet avertissement se comporte comme prévu ; il a correctement mis en évidence un problème de performances. Je ferme ce sujet ; n'hésitez pas à le rouvrir si vous pensez différemment. Merci!

Je reviens juste à ça

Il s'avère donc que j'ai facilement plus de 1000 instances de texte dans ma scène. Mais là tout simplement pas tous visibles en même temps

Beaucoup d'entre eux apparaissent simplement au survol de certains objets

Je me demande donc quelle est la meilleure façon d'avancer ici:

  1. créer des instances uniquement pour le texte visible, puis démonter dès qu'il devient invisible ?
  2. utiliser des objets CSS ThreeJS à la place ?

Personnellement, je pencherais pour la première option. Je peux me tromper, mais je ne pense pas qu'il y ait un avantage à avoir tous ces objets d'étiquette cachés présents dans le graphe de scène.

J'ai compris

J'ai besoin de pouvoir les montrer rapidement au survol d'objets avec la souris

Recommanderiez-vous simplement de les détruire après utilisation et d'en créer de nouveaux au survol ou simplement de les supprimer de la scène des trois J à la place ?

Honnêtement, je ne pense pas qu'il y aura une différence notable de toute façon. Je commencerais par ce qui est le plus simple à gérer et à optimiser uniquement si vous remarquez un problème.

Personnellement, j'ai beaucoup utilisé l'approche créer/détruire, et c'est toujours très rapide pour moi.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

Ocelyn picture Ocelyn  ·  13Commentaires

drcmda picture drcmda  ·  11Commentaires

asbjornlystrup picture asbjornlystrup  ·  7Commentaires

stephencorwin picture stephencorwin  ·  39Commentaires

lojjic picture lojjic  ·  11Commentaires