Troika: Aviso "Grande número de solicitações WorkerModule abertas, algumas podem não estar retornando"

Criado em 30 mar. 2021  ·  14Comentários  ·  Fonte: protectwise/troika

Olá, estou vendo uma grande quantidade de avisos vindos do troika-worker.utils.esm.js com esta mensagem.

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

Tudo parece estar funcionando bem embora

qualquer ideia?

Todos 14 comentários

Hmm, esse aviso não é acionado até que haja mais de 1.000 solicitações de trabalho abertas. Você tem um número muito grande de instâncias de texto?

Eu faço, mas não mais de 1000 (pelo menos não intencionalmente)

mais como algumas centenas

Aqui está o que estou renderizando

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

Mas então o que você está dizendo que talvez haja um bug do meu lado onde eu crio mais instâncias do que eu realmente preciso e uma vez que eu cruzo a contagem de 1000, ele começa a gerar um erro?

Eu tenho configurado instâncias que não têm conteúdo para .visible = false

mas acho que isso ainda significa que a instância existe

você recomendaria em vez de usar a prop .visible para remover completamente as instâncias não utilizadas?

Ah, isso pode explicar. Quaisquer chamadas para .sync() ainda serão emitidas para o trabalhador em segundo plano, mesmo se visible:false , e elas se acumularão.

Eu acho que pessoalmente optaria por criar/descartar os rótulos sob demanda, ou pelo menos evitar chamadas .sync() para os ocultos. Todas essas solicitações de trabalhador usam o mesmo trabalhador, portanto, se estiver ocupado processando rótulos ocultos, isso poderá atrasar o processamento de seus visíveis.

Estou fazendo algumas suposições, porém, não tendo visto seu código exato do LabelView. Ainda é possível que haja um bug do meu lado, então LMK o que você encontra.

Apenas tentei chamar .sync() quando .visible === true

mas ainda recebendo os avisos

se, em vez disso, eu apenas criar instâncias para objetos visíveis e destruir os não utilizados, os avisos desaparecerão

Hmm, Text si só chama sync() em onBeforeRender, que _não deveria_ acionar se visible=false.

O código do seu wrapper LabelView está disponível em qualquer lugar que eu possa dar uma olhada?

Faz parte de um projeto de código fechado

mas aqui está a classe relevante, que pode ser suficiente

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, meu palpite seria syncIfVisible() sendo chamado antes de .visible ser definido como false, mas é difícil dizer com certeza sem saber como seu sistema de visualização funciona.

Outra coisa que estou notando é que você está emitindo chamadas syncIfVisible após cada alteração de propriedade individual (content, textAlign, horizontalAlign, etc.) que emitirá mais chamadas para o trabalhador do que o necessário. Se o seu sistema de visualização tiver um ciclo de vida em que você possa emitir uma única chamada de sincronização depois que todas as propriedades individuais forem definidas, isso seria muito melhor.

Pelo que você descreveu, acho que esse aviso está se comportando conforme o esperado; ele destacou corretamente um problema de desempenho. Estou encerrando este assunto; sinta-se à vontade para reabri-lo se você acredita de forma diferente. Obrigado!

Apenas voltando a isso

Então acontece que eu facilmente tenho mais de 1000 instâncias de texto na minha cena. Mas nem todos são visíveis ao mesmo tempo

Muitos deles aparecem apenas ao passar o mouse sobre certos objetos

Então eu estou querendo saber qual é o melhor caminho a seguir aqui:

  1. criar instâncias apenas para texto visível e desmontar assim que ficar invisível?
  2. usar objetos CSS ThreeJS em vez disso?

Pessoalmente, eu iria para a primeira opção. Posso estar errado, mas não acho que haja nenhum benefício em ter todos esses objetos de rótulo ocultos presentes no gráfico de cena.

Entendi

Eu preciso ser capaz de mostrá-los rapidamente ao passar o mouse sobre objetos

Você recomendaria apenas destruí-los após o uso e criar novos ao passar o mouse ou apenas removê-los da cena dos três Js?

Honestamente, não acho que haverá uma diferença notável de qualquer maneira. Eu começaria com o que for mais simples de gerenciar e otimizar somente se você notar um problema.

Pessoalmente, eu fiz muito a abordagem de criar/destruir, e é sempre muito rápido para mim.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Ocelyn picture Ocelyn  ·  13Comentários

asbjornlystrup picture asbjornlystrup  ·  7Comentários

drcmda picture drcmda  ·  11Comentários

atlmtw picture atlmtw  ·  47Comentários

lojjic picture lojjic  ·  11Comentários